diff --git a/src/plugins/home/public/application/components/sample_data_set_card.js b/src/plugins/home/public/application/components/sample_data_set_card.js index 3ec86826639a..7d8b97a1c982 100644 --- a/src/plugins/home/public/application/components/sample_data_set_card.js +++ b/src/plugins/home/public/application/components/sample_data_set_card.js @@ -57,11 +57,11 @@ export class SampleDataSetCard extends React.Component { }; install = () => { - this.props.onInstall(this.props.id); + this.props.onInstall(this.props.id, this.props.dataSourceId); }; uninstall = () => { - this.props.onUninstall(this.props.id); + this.props.onUninstall(this.props.id, this.props.dataSourceId); }; renderBtn = () => { diff --git a/src/plugins/home/public/application/components/sample_data_set_cards.js b/src/plugins/home/public/application/components/sample_data_set_cards.js index 31735d203dda..0234f5f4a6e0 100644 --- a/src/plugins/home/public/application/components/sample_data_set_cards.js +++ b/src/plugins/home/public/application/components/sample_data_set_cards.js @@ -67,10 +67,21 @@ export class SampleDataSetCards extends React.Component { this.loadSampleDataSets(); } - loadSampleDataSets = async () => { + componentDidUpdate(prevProps) { + if (this.props.isDataSourceEnabled) { + this._isMounted = true; + if (prevProps && prevProps.dataSourceId !== this.props.dataSourceId) { + this.setState({ dataSourceId: this.props.dataSourceId }, () => + this.loadSampleDataSets(this.state.dataSourceId) + ); + } + } + } + + loadSampleDataSets = async (dataSourceId) => { let sampleDataSets; try { - sampleDataSets = await listSampleDataSets(); + sampleDataSets = await listSampleDataSets(dataSourceId); } catch (fetchError) { this.toastNotifications.addDanger({ title: i18n.translate('home.sampleDataSet.unableToLoadListErrorMessage', { @@ -93,7 +104,7 @@ export class SampleDataSetCards extends React.Component { }); }; - install = async (id) => { + install = async (id, dataSourceId) => { const targetSampleDataSet = this.state.sampleDataSets.find((sampleDataSet) => { return sampleDataSet.id === id; }); @@ -103,7 +114,7 @@ export class SampleDataSetCards extends React.Component { })); try { - await installSampleDataSet(id, targetSampleDataSet.defaultIndex); + await installSampleDataSet(id, targetSampleDataSet.defaultIndex, dataSourceId); } catch (fetchError) { if (this._isMounted) { this.setState((prevState) => ({ @@ -141,7 +152,7 @@ export class SampleDataSetCards extends React.Component { }); }; - uninstall = async (id) => { + uninstall = async (id, dataSourceId) => { const targetSampleDataSet = this.state.sampleDataSets.find((sampleDataSet) => { return sampleDataSet.id === id; }); @@ -151,7 +162,7 @@ export class SampleDataSetCards extends React.Component { })); try { - await uninstallSampleDataSet(id, targetSampleDataSet.defaultIndex); + await uninstallSampleDataSet(id, targetSampleDataSet.defaultIndex, dataSourceId); } catch (fetchError) { if (this._isMounted) { this.setState((prevState) => ({ @@ -213,6 +224,7 @@ export class SampleDataSetCards extends React.Component { previewUrl={this.props.addBasePath(this.lightOrDarkImage(sampleDataSet))} onInstall={this.install} onUninstall={this.uninstall} + dataSourceId={this.state.dataSourceId} /> ); diff --git a/src/plugins/home/public/application/components/tutorial_directory.js b/src/plugins/home/public/application/components/tutorial_directory.js index ce9cf071d3a0..36d8fc862633 100644 --- a/src/plugins/home/public/application/components/tutorial_directory.js +++ b/src/plugins/home/public/application/components/tutorial_directory.js @@ -37,6 +37,7 @@ import { getServices } from '../opensearch_dashboards_services'; import { EuiPage, + EuiPanel, EuiTabs, EuiTab, EuiFlexItem, @@ -45,10 +46,10 @@ import { EuiSpacer, EuiTitle, EuiPageBody, + EuiComboBox, } from '@elastic/eui'; import { getTutorials } from '../load_tutorials'; - import { injectI18n, FormattedMessage } from '@osd/i18n/react'; import { i18n } from '@osd/i18n'; @@ -81,6 +82,7 @@ class TutorialDirectoryUi extends React.Component { selectedTabId: openTab, tutorialCards: [], notices: getServices().tutorialService.getDirectoryNotices(), + isDataSourceEnabled: !!getServices().dataSource, }; } @@ -152,6 +154,30 @@ class TutorialDirectoryUi extends React.Component { return a.name.toLowerCase().localeCompare(b.name.toLowerCase()); }); + if (this.state.isDataSourceEnabled) { + this.getDataSources(getServices().savedObjectsClient) + .then((fetchedDataSources) => { + if (fetchedDataSources?.length) { + const dataSourceOptions = fetchedDataSources.map((dataSource) => ({ + id: dataSource.id, + label: dataSource.title, + })); + + this.setState({ + // eslint-disable-line react/no-did-mount-set-state + dataSources: dataSourceOptions, + }); + } + }) + .catch(() => { + getServices().toastNotifications.addWarning( + i18n.translate('devTool.devToolWrapper.fetchDataSourceError', { + defaultMessage: 'Unable to fetch existing data sources', + }) + ); + }); + } + this.setState({ // eslint-disable-line react/no-did-mount-set-state tutorialCards: tutorialCards, @@ -164,6 +190,12 @@ class TutorialDirectoryUi extends React.Component { }); }; + onSelectedDataSourceChange = (e) => { + this.setState({ selectedOption: e }); + const dataSourceId = e[0] ? e[0].id : undefined; + this.setState({ selectedDataSourceId: dataSourceId }); + }; + renderTabs = () => { return this.tabs.map((tab, index) => ( { if (this.state.selectedTabId === SAMPLE_DATA_TAB_ID) { - return ; + return ( + + ); } return ( @@ -210,6 +248,30 @@ class TutorialDirectoryUi extends React.Component { ); }; + renderDataSourceSelector = () => { + const { isDataSourceEnabled, dataSources, selectedOption } = this.state; + + return isDataSourceEnabled ? ( +
+ +
+ ) : null; + }; + renderNotices = () => { const notices = getServices().tutorialService.getDirectoryNotices(); return notices.length ? ( @@ -260,19 +322,54 @@ class TutorialDirectoryUi extends React.Component { ); }; - render() { + renderPageBody = () => { return ( - - - {this.renderHeader()} - - {this.renderTabs()} - - {this.renderTabContent()} - - + + {this.renderHeader()} + + {this.renderDataSourceSelector()} + {this.renderTabs()} + + {this.renderTabContent()} + + ); + }; + + render() { + const { isDataSourceEnabled } = this.state; + + return isDataSourceEnabled ? ( + + {this.renderPageBody()} + + ) : ( + {this.renderPageBody()} ); } + + getDataSources = (savedObjectsClient) => { + return savedObjectsClient + .find({ + type: 'data-source', + fields: ['id', 'description', 'title'], + perPage: 10000, + }) + .then( + (response) => + response?.savedObjects?.map?.((source) => { + const id = source.id; + const title = source.get('title'); + const description = source.get('description'); + + return { + id, + title, + description, + sort: `${title}`, + }; + }) || [] + ); + }; } TutorialDirectoryUi.propTypes = { diff --git a/src/plugins/home/public/application/opensearch_dashboards_services.ts b/src/plugins/home/public/application/opensearch_dashboards_services.ts index 84d174984fac..60f9e70621ff 100644 --- a/src/plugins/home/public/application/opensearch_dashboards_services.ts +++ b/src/plugins/home/public/application/opensearch_dashboards_services.ts @@ -46,6 +46,7 @@ import { FeatureCatalogueRegistry } from '../services/feature_catalogue'; import { EnvironmentService } from '../services/environment'; import { ConfigSchema } from '../../config'; import { HomePluginBranding } from '..'; +import { DataSourcePluginStart } from '../../../data_source/public'; export interface HomeOpenSearchDashboardsServices { indexPatternService: any; @@ -71,6 +72,7 @@ export interface HomeOpenSearchDashboardsServices { getInjectedVar: (name: string, defaultValue?: any) => unknown; getBranding: () => HomePluginBranding; }; + dataSource?: DataSourcePluginStart; } let services: HomeOpenSearchDashboardsServices | null = null; diff --git a/src/plugins/home/public/plugin.ts b/src/plugins/home/public/plugin.ts index 03823c5da179..1538156a801e 100644 --- a/src/plugins/home/public/plugin.ts +++ b/src/plugins/home/public/plugin.ts @@ -56,11 +56,13 @@ import { UsageCollectionSetup } from '../../usage_collection/public'; import { UrlForwardingSetup, UrlForwardingStart } from '../../url_forwarding/public'; import { AppNavLinkStatus } from '../../../core/public'; import { PLUGIN_ID, HOME_APP_BASE_PATH } from '../common/constants'; +import { DataSourcePluginStart } from '../../data_source/public'; export interface HomePluginStartDependencies { data: DataPublicPluginStart; telemetry?: TelemetryPluginStart; urlForwarding: UrlForwardingStart; + dataSource?: DataSourcePluginStart; } export interface HomePluginSetupDependencies { @@ -96,7 +98,7 @@ export class HomePublicPlugin : () => {}; const [ coreStart, - { telemetry, data, urlForwarding: urlForwardingStart }, + { telemetry, data, urlForwarding: urlForwardingStart, dataSource }, ] = await core.getStartServices(); setServices({ trackUiMetric, @@ -119,6 +121,7 @@ export class HomePublicPlugin tutorialService: this.tutorialService, featureCatalogue: this.featuresCatalogueRegistry, injectedMetadata: coreStart.injectedMetadata, + dataSource, }); coreStart.chrome.docTitle.change( i18n.translate('home.pageTitle', { defaultMessage: 'Home' })