Skip to content

Commit

Permalink
Add datasource picker component and use it in devtools and tutorial p…
Browse files Browse the repository at this point in the history
…age when multiple datasource is enabled (opensearch-project#5756) (opensearch-project#5759)

* add datasource picker as a component and use it in devtools and add sample data page
* wraps prepend with i18n and fix typo

---------

Signed-off-by: Lu Yu <[email protected]>
(cherry picked from commit b2d2b26)
Signed-off-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
  • Loading branch information
1 parent 54aca34 commit 844ad26
Show file tree
Hide file tree
Showing 4 changed files with 110 additions and 111 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,5 @@
"requiredPlugins": ["management", "dataSource", "indexPatternManagement"],
"optionalPlugins": [],
"requiredBundles": ["opensearchDashboardsReact"],
"extraPublicDirs": ["public/components/utils"]
"extraPublicDirs": ["public/components/utils", "public/components/data_source_picker/data_source_picker"]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
/*
* Copyright OpenSearch Contributors
* SPDX-License-Identifier: Apache-2.0
*/

import React from 'react';
import { getDataSources } from '../utils';
import { i18n } from '@osd/i18n';
import { EuiComboBox } from '@elastic/eui';

export const LocalCluster = {
label: i18n.translate('dataSource.localCluster', {
defaultMessage: 'Local cluster',
}),
id: '',
};

export class DataSourcePicker extends React.Component {
constructor(props) {
super(props);

this.state = {
dataSources: [],
selectedOption: [LocalCluster],
};
}

componentWillUnmount() {
this._isMounted = false;
}

async componentDidMount() {
this._isMounted = true;
getDataSources(this.props.savedObjectsClient)
.then((fetchedDataSources) => {
if (fetchedDataSources?.length) {
const dataSourceOptions = fetchedDataSources.map((dataSource) => ({
id: dataSource.id,
label: dataSource.title,
}));

dataSourceOptions.push(LocalCluster);

if (!this._isMounted) return;
this.setState({
...this.state,
dataSources: dataSourceOptions,
});
}
})
.catch(() => {
this.props.notifications.addWarning(
i18n.translate('dataSource.fetchDataSourceError', {
defaultMessage: 'Unable to fetch existing data sources',
})
);
});
}

onChange(e) {
if (!this._isMounted) return;
this.setState({
selectedOption: e,
});
this.props.onSelectedDataSource(e);
}

render() {
return (
<EuiComboBox
aria-label={i18n.translate('dataSourceComboBoxAriaLabel', {
defaultMessage: 'Select a data source',
})}
placeholder={i18n.translate('dataSourceComboBoxPlaceholder', {
defaultMessage: 'Select a data source',
})}
singleSelection={{ asPlainText: true }}
options={this.state.dataSources}
selectedOptions={this.state.selectedOption}
onChange={(e) => this.onChange(e)}
prepend={i18n.translate('dataSourceComboBoxPrepend', {
defaultMessage: 'Data source',
})}
compressed
isDisabled={this.props.disabled}
/>
);
}
}
66 changes: 8 additions & 58 deletions src/plugins/dev_tools/public/application.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,18 +28,10 @@
* under the License.
*/

import React, { useEffect, useRef, useState } from 'react';
import React, { useEffect, useRef } from 'react';
import ReactDOM from 'react-dom';
import { HashRouter as Router, Switch, Route, Redirect } from 'react-router-dom';
import {
EuiTab,
EuiTabs,
EuiToolTip,
EuiComboBox,
EuiFlexGroup,
EuiFlexItem,
EuiComboBoxOptionOption,
} from '@elastic/eui';
import { EuiTab, EuiTabs, EuiToolTip, EuiComboBoxOptionOption } from '@elastic/eui';
import { I18nProvider } from '@osd/i18n/react';
import { i18n } from '@osd/i18n';

Expand All @@ -52,9 +44,8 @@ import {
ScopedHistory,
} from 'src/core/public';

import { useEffectOnce } from 'react-use';
// eslint-disable-next-line @osd/eslint/no-restricted-paths
import { getDataSources } from '../../data_source_management/public/components/utils';
import { DataSourcePicker } from '../../data_source_management/public/components/data_source_picker/data_source_picker';
import { DevToolApp } from './dev_tool';
import { DevToolsSetupDependencies } from './plugin';
import { addHelpMenuToAppChrome } from './utils/util';
Expand All @@ -74,11 +65,6 @@ interface MountedDevToolDescriptor {
unmountHandler: () => void;
}

interface DataSourceOption extends EuiComboBoxOptionOption {
id: string;
label: string;
}

function DevToolsWrapper({
devTools,
activeDevTool,
Expand All @@ -88,8 +74,6 @@ function DevToolsWrapper({
dataSourceEnabled,
}: DevToolsWrapperProps) {
const mountedTool = useRef<MountedDevToolDescriptor | null>(null);
const [dataSources, setDataSources] = useState<DataSourceOption[]>([]);
const [selectedOptions, setSelectedOptions] = useState<DataSourceOption[]>([]);

useEffect(
() => () => {
Expand All @@ -100,33 +84,8 @@ function DevToolsWrapper({
[]
);

useEffectOnce(() => {
fetchDataSources();
});

const fetchDataSources = () => {
getDataSources(savedObjects.client)
.then((fetchedDataSources) => {
if (fetchedDataSources?.length) {
const dataSourceOptions = fetchedDataSources.map((dataSource) => ({
id: dataSource.id,
label: dataSource.title,
}));
setDataSources(dataSourceOptions);
}
})
.catch(() => {
toasts.addDanger(
i18n.translate('devTools.devToolWrapper.fetchDataSourceError', {
defaultMessage: 'Unable to fetch existing data sources',
})
);
});
};

const onChange = async (e: Array<EuiComboBoxOptionOption<any>>) => {
const dataSourceId = e[0] ? e[0].id : undefined;
setSelectedOptions(e);
await remount(mountedTool.current!.mountpoint, dataSourceId);
};

Expand Down Expand Up @@ -173,20 +132,11 @@ function DevToolsWrapper({
))}
{dataSourceEnabled ? (
<div className="devAppDataSourcePicker">
<EuiComboBox
aria-label={i18n.translate('devTools.devToolWrapper.DataSourceComboBoxAriaLabel', {
defaultMessage: 'Select a data source',
})}
placeholder={i18n.translate('devTools.devToolWrapper.DataSourceComboBoxPlaceholder', {
defaultMessage: 'Select a data source',
})}
singleSelection={{ asPlainText: true }}
options={dataSources}
selectedOptions={selectedOptions}
onChange={onChange}
prepend="Data source"
compressed
isDisabled={!dataSourceEnabled}
<DataSourcePicker
savedObjectsClient={savedObjects.client}
notifications={toasts}
onSelectedDataSource={onChange}
disabled={!dataSourceEnabled}
/>
</div>
) : null}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ import { Synopsis } from './synopsis';
import { SampleDataSetCards } from './sample_data_set_cards';
import { getServices } from '../opensearch_dashboards_services';
// eslint-disable-next-line @osd/eslint/no-restricted-paths
import { getDataSources } from '../../../../data_source_management/public/components/utils';
import { DataSourcePicker } from '../../../../data_source_management/public/components/data_source_picker/data_source_picker';

import {
EuiPage,
Expand All @@ -48,7 +48,6 @@ import {
EuiSpacer,
EuiTitle,
EuiPageBody,
EuiComboBox,
} from '@elastic/eui';

import { getTutorials } from '../load_tutorials';
Expand All @@ -62,9 +61,6 @@ const homeTitle = i18n.translate('home.breadcrumbs.homeTitle', { defaultMessage:
const addDataTitle = i18n.translate('home.breadcrumbs.addDataTitle', {
defaultMessage: 'Add data',
});
const localCluster = i18n.translate('home.dataSource.localCluster', {
defaultMessage: 'Local Cluster',
});

class TutorialDirectoryUi extends React.Component {
constructor(props) {
Expand All @@ -88,7 +84,6 @@ class TutorialDirectoryUi extends React.Component {
tutorialCards: [],
notices: getServices().tutorialService.getDirectoryNotices(),
isDataSourceEnabled: !!getServices().dataSource,
selectedOption: [{ label: localCluster }],
};
}

Expand Down Expand Up @@ -160,31 +155,6 @@ class TutorialDirectoryUi extends React.Component {
return a.name.toLowerCase().localeCompare(b.name.toLowerCase());
});

if (this.state.isDataSourceEnabled) {
getDataSources(getServices().savedObjectsClient)
.then((fetchedDataSources) => {
if (fetchedDataSources?.length) {
const dataSourceOptions = fetchedDataSources.map((dataSource) => ({
id: dataSource.id,
label: dataSource.title,
}));

dataSourceOptions.push({ label: localCluster });
this.setState({
// eslint-disable-line react/no-did-mount-set-state
dataSources: dataSourceOptions,
});
}
})
.catch(() => {
getServices().toastNotifications.addWarning(
i18n.translate('home.dataSource.fetchDataSourceError', {
defaultMessage: 'Unable to fetch existing data sources',
})
);
});
}

this.setState({
// eslint-disable-line react/no-did-mount-set-state
tutorialCards: tutorialCards,
Expand All @@ -197,12 +167,6 @@ 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) => (
<EuiTab
Expand Down Expand Up @@ -255,25 +219,21 @@ class TutorialDirectoryUi extends React.Component {
);
};

onSelectedDataSourceChange = (e) => {
const dataSourceId = e[0] ? e[0].id : undefined;
this.setState({ selectedDataSourceId: dataSourceId });
};

renderDataSourceSelector = () => {
const { isDataSourceEnabled, dataSources, selectedOption } = this.state;
const { isDataSourceEnabled } = this.state;

return isDataSourceEnabled ? (
<div className="sampledataSourcePicker">
<EuiComboBox
aria-label={i18n.translate('sampleData.DataSourceComboBoxAriaLabel', {
defaultMessage: 'Select a Data Source',
})}
placeholder={i18n.translate('sampleData.DataSourceComboBoxPlaceholder', {
defaultMessage: 'Select a Data Source',
})}
singleSelection={{ asPlainText: true }}
options={dataSources}
selectedOptions={selectedOption}
onChange={this.onSelectedDataSourceChange}
prepend="DataSource"
compressed
isDisabled={!isDataSourceEnabled}
<DataSourcePicker
savedObjectsClient={getServices().savedObjectsClient}
notifications={getServices().toastNotifications}
onSelectedDataSource={this.onSelectedDataSourceChange}
disabled={!isDataSourceEnabled}
/>
</div>
) : null;
Expand Down

0 comments on commit 844ad26

Please sign in to comment.