From d60dc588a1b79191316199202d72b172e51431bc Mon Sep 17 00:00:00 2001 From: tygao Date: Tue, 21 May 2024 16:55:04 +0800 Subject: [PATCH 01/12] add data source selection service Signed-off-by: tygao --- .../data_source_aggregated_view.tsx | 11 ++++- .../create_data_source_menu.tsx | 10 ++++- .../data_source_menu/data_source_menu.tsx | 13 +++++- .../components/data_source_menu/types.ts | 2 + .../data_source_multi_selectable.tsx | 21 ++++++++-- .../data_source_selectable.tsx | 26 ++++++++---- .../create_data_source_selector.tsx | 11 ++++- .../data_source_selector.tsx | 20 ++++++--- .../data_source_view/data_source_view.tsx | 42 ++++++++++--------- .../public/components/utils.ts | 6 +++ .../data_source_management/public/plugin.ts | 21 +++++++++- .../service/data_source_selection_service.ts | 37 ++++++++++++++++ 12 files changed, 175 insertions(+), 45 deletions(-) create mode 100644 src/plugins/data_source_management/public/service/data_source_selection_service.ts diff --git a/src/plugins/data_source_management/public/components/data_source_aggregated_view/data_source_aggregated_view.tsx b/src/plugins/data_source_management/public/components/data_source_aggregated_view/data_source_aggregated_view.tsx index 1d48965fa041..c3d38ad73f06 100644 --- a/src/plugins/data_source_management/public/components/data_source_aggregated_view/data_source_aggregated_view.tsx +++ b/src/plugins/data_source_management/public/components/data_source_aggregated_view/data_source_aggregated_view.tsx @@ -27,6 +27,7 @@ import { DataSourceItem } from '../data_source_item'; import { DataSourceDropDownHeader } from '../drop_down_header'; import './data_source_aggregated_view.scss'; import { DataSourceMenuPopoverButton } from '../popover_button/popover_button'; +import { DataSourceSelection } from '../../service/data_source_selection_service'; interface DataSourceAggregatedViewProps { savedObjectsClient: SavedObjectsClientContract; @@ -38,6 +39,7 @@ interface DataSourceAggregatedViewProps { displayAllCompatibleDataSources: boolean; uiSettings?: IUiSettingsClient; application?: ApplicationStart; + dataSourceSelection: DataSourceSelection; } interface DataSourceAggregatedViewState extends DataSourceBaseState { @@ -46,6 +48,7 @@ interface DataSourceAggregatedViewState extends DataSourceBaseState { switchChecked: boolean; defaultDataSource: string | null; incompatibleDataSourcesExist: boolean; + componentId: string; } interface DataSourceOptionDisplay extends DataSourceOption { @@ -70,11 +73,13 @@ export class DataSourceAggregatedView extends React.Component< switchChecked: false, defaultDataSource: null, incompatibleDataSourcesExist: false, + componentId: props.dataSourceSelection.generateComponentId(), }; } componentWillUnmount() { this._isMounted = false; + this.props.dataSourceSelection.remove(this.state.componentId); } onDataSourcesClick() { @@ -188,7 +193,11 @@ export class DataSourceAggregatedView extends React.Component< }); } - const numSelectedItems = items.filter((item) => item.checked === 'on').length; + const selectedItems = items.filter((item) => item.checked === 'on'); + // For read-only cases, also need to set default selected result. + this.props.dataSourceSelection.selectDataSource(this.state.componentId, selectedItems); + + const numSelectedItems = selectedItems.length; const titleComponent = ( () { const application = getApplication(); const uiSettings = getUiSettings(); const hideLocalCluster = getHideLocalCluster().enabled; + const dataSourceSelection = getDataSourceSelection(); return (props: DataSourceMenuProps) => { if (props.setMenuMountPoint) { return ( @@ -24,6 +30,7 @@ export function createDataSourceMenu() { uiSettings={uiSettings} hideLocalCluster={hideLocalCluster} application={application} + dataSourceSelection={dataSourceSelection} /> @@ -35,6 +42,7 @@ export function createDataSourceMenu() { uiSettings={uiSettings} hideLocalCluster={hideLocalCluster} application={application} + dataSourceSelection={dataSourceSelection} /> ); }; diff --git a/src/plugins/data_source_management/public/components/data_source_menu/data_source_menu.tsx b/src/plugins/data_source_management/public/components/data_source_menu/data_source_menu.tsx index 60776af403d2..98bff74b135b 100644 --- a/src/plugins/data_source_management/public/components/data_source_menu/data_source_menu.tsx +++ b/src/plugins/data_source_management/public/components/data_source_menu/data_source_menu.tsx @@ -19,7 +19,14 @@ import { import { DataSourceSelectable } from '../data_source_selectable'; export function DataSourceMenu(props: DataSourceMenuProps): ReactElement | null { - const { componentType, componentConfig, uiSettings, hideLocalCluster, application } = props; + const { + componentType, + componentConfig, + uiSettings, + hideLocalCluster, + application, + dataSourceSelection, + } = props; function renderDataSourceView(config: DataSourceViewConfig): ReactElement | null { const { @@ -41,6 +48,7 @@ export function DataSourceMenu(props: DataSourceMenuProps): ReactElement | onSelectedDataSources={onSelectedDataSources} uiSettings={uiSettings} application={application} + dataSourceSelection={dataSourceSelection} /> ); } @@ -58,6 +66,7 @@ export function DataSourceMenu(props: DataSourceMenuProps): ReactElement | onSelectedDataSources={onSelectedDataSources!} uiSettings={uiSettings} application={application} + dataSourceSelection={dataSourceSelection} /> ); } @@ -84,6 +93,7 @@ export function DataSourceMenu(props: DataSourceMenuProps): ReactElement | fullWidth={fullWidth} uiSettings={uiSettings} application={application} + dataSourceSelection={dataSourceSelection} /> ); } @@ -110,6 +120,7 @@ export function DataSourceMenu(props: DataSourceMenuProps): ReactElement | displayAllCompatibleDataSources={displayAllCompatibleDataSources} uiSettings={uiSettings} application={application} + dataSourceSelection={dataSourceSelection} /> ); } diff --git a/src/plugins/data_source_management/public/components/data_source_menu/types.ts b/src/plugins/data_source_management/public/components/data_source_menu/types.ts index debf8d928258..05c1eb9c2681 100644 --- a/src/plugins/data_source_management/public/components/data_source_menu/types.ts +++ b/src/plugins/data_source_management/public/components/data_source_menu/types.ts @@ -10,6 +10,7 @@ import { IUiSettingsClient, ApplicationStart, } from '../../../../../core/public'; +import { DataSourceSelection } from '../../service/data_source_selection_service'; import { DataSourceAttributes } from '../../types'; export interface DataSourceOption { @@ -40,6 +41,7 @@ export interface DataSourceMenuProps { uiSettings?: IUiSettingsClient; application?: ApplicationStart; setMenuMountPoint?: (menuMount: MountPoint | undefined) => void; + dataSourceSelection: DataSourceSelection; } export const DataSourceComponentType = { diff --git a/src/plugins/data_source_management/public/components/data_source_multi_selectable/data_source_multi_selectable.tsx b/src/plugins/data_source_management/public/components/data_source_multi_selectable/data_source_multi_selectable.tsx index 481df093d741..dc8101c23db3 100644 --- a/src/plugins/data_source_management/public/components/data_source_multi_selectable/data_source_multi_selectable.tsx +++ b/src/plugins/data_source_management/public/components/data_source_multi_selectable/data_source_multi_selectable.tsx @@ -19,6 +19,7 @@ import { } from '../utils'; import { DataSourceBaseState } from '../data_source_menu/types'; import { DataSourceErrorMenu } from '../data_source_error_menu'; +import { DataSourceSelection } from '../../service/data_source_selection_service'; export interface DataSourceMultiSeletableProps { savedObjectsClient: SavedObjectsClientContract; @@ -28,6 +29,7 @@ export interface DataSourceMultiSeletableProps { fullWidth: boolean; uiSettings?: IUiSettingsClient; application?: ApplicationStart; + dataSourceSelection: DataSourceSelection; } interface DataSourceMultiSeletableState extends DataSourceBaseState { @@ -35,6 +37,7 @@ interface DataSourceMultiSeletableState extends DataSourceBaseState { selectedOptions: SelectedDataSourceOption[]; defaultDataSource: string | null; incompatibleDataSourcesExist: boolean; + componentId: string; } export class DataSourceMultiSelectable extends React.Component< @@ -53,11 +56,21 @@ export class DataSourceMultiSelectable extends React.Component< showEmptyState: false, showError: false, incompatibleDataSourcesExist: false, + componentId: props.dataSourceSelection.generateComponentId(), }; } componentWillUnmount() { this._isMounted = false; + const { componentId } = this.state; + this.props.dataSourceSelection.remove(componentId); + } + + onSelectedDataSources(dataSources: SelectedDataSourceOption[]) { + this.props.dataSourceSelection.selectDataSource(this.state.componentId, dataSources); + if (this.props.onSelectedDataSources) { + this.props.onSelectedDataSources(dataSources); + } } async componentDidMount() { @@ -96,7 +109,7 @@ export class DataSourceMultiSelectable extends React.Component< changeState: this.onEmptyState.bind(this, !!fetchedDataSources?.length), notifications: this.props.notifications, application: this.props.application, - callback: this.props.onSelectedDataSources, + callback: this.onSelectedDataSources, incompatibleDataSourcesExist: !!fetchedDataSources?.length, }); return; @@ -108,12 +121,12 @@ export class DataSourceMultiSelectable extends React.Component< defaultDataSource, }); - this.props.onSelectedDataSources(selectedOptions); + this.onSelectedDataSources(selectedOptions); } catch (error) { handleDataSourceFetchError( this.onError.bind(this), this.props.notifications, - this.props.onSelectedDataSources + this.onSelectedDataSources ); } } @@ -131,7 +144,7 @@ export class DataSourceMultiSelectable extends React.Component< this.setState({ selectedOptions, }); - this.props.onSelectedDataSources(selectedOptions.filter((option) => option.checked === 'on')); + this.onSelectedDataSources(selectedOptions.filter((option) => option.checked === 'on')); } render() { diff --git a/src/plugins/data_source_management/public/components/data_source_selectable/data_source_selectable.tsx b/src/plugins/data_source_management/public/components/data_source_selectable/data_source_selectable.tsx index fd1c685676f0..a3751a8fc82c 100644 --- a/src/plugins/data_source_management/public/components/data_source_selectable/data_source_selectable.tsx +++ b/src/plugins/data_source_management/public/components/data_source_selectable/data_source_selectable.tsx @@ -37,6 +37,7 @@ import { DataSourceDropDownHeader } from '../drop_down_header'; import '../button_title.scss'; import './data_source_selectable.scss'; import { DataSourceMenuPopoverButton } from '../popover_button/popover_button'; +import { DataSourceSelection } from '../../service/data_source_selection_service'; interface DataSourceSelectableProps { savedObjectsClient: SavedObjectsClientContract; @@ -49,6 +50,7 @@ interface DataSourceSelectableProps { selectedOption?: DataSourceOption[]; dataSourceFilter?: (dataSource: SavedObject) => boolean; uiSettings?: IUiSettingsClient; + dataSourceSelection: DataSourceSelection; } interface DataSourceSelectableState extends DataSourceBaseState { @@ -57,6 +59,7 @@ interface DataSourceSelectableState extends DataSourceBaseState { defaultDataSource: string | null; incompatibleDataSourcesExist: boolean; selectedOption?: DataSourceOption[]; + componentId: string; } export class DataSourceSelectable extends React.Component< @@ -76,6 +79,7 @@ export class DataSourceSelectable extends React.Component< showEmptyState: false, showError: false, incompatibleDataSourcesExist: false, + componentId: props.dataSourceSelection.generateComponentId(), }; this.onChange.bind(this); @@ -83,6 +87,7 @@ export class DataSourceSelectable extends React.Component< componentWillUnmount() { this._isMounted = false; + this.props.dataSourceSelection.remove(this.state.componentId); } onClick() { @@ -93,6 +98,11 @@ export class DataSourceSelectable extends React.Component< this.setState({ ...this.state, isPopoverOpen: false }); } + onSelectedDataSources(dataSources: DataSourceOption[]) { + this.props.dataSourceSelection.selectDataSource(this.state.componentId, dataSources); + this.props.onSelectedDataSources(dataSources); + } + // Update the checked status of the selected data source. getUpdatedDataSourceOptions( selectedDataSourceId: string, @@ -119,7 +129,7 @@ export class DataSourceSelectable extends React.Component< selectedOption: [], defaultDataSource, }); - this.props.onSelectedDataSources([]); + this.onSelectedDataSources([]); return; } const updatedDataSourceOptions: DataSourceOption[] = this.getUpdatedDataSourceOptions( @@ -132,7 +142,7 @@ export class DataSourceSelectable extends React.Component< selectedOption: [{ id, label: dsOption.label }], defaultDataSource, }); - this.props.onSelectedDataSources([{ id, label: dsOption.label }]); + this.onSelectedDataSources([{ id, label: dsOption.label }]); } handleDefaultDataSource(dataSourceOptions: DataSourceOption[], defaultDataSource: string | null) { @@ -146,7 +156,7 @@ export class DataSourceSelectable extends React.Component< // no active option, show warning if (selectedDataSource.length === 0) { this.props.notifications.addWarning('No connected data source available.'); - this.props.onSelectedDataSources([]); + this.onSelectedDataSources([]); return; } @@ -162,7 +172,7 @@ export class DataSourceSelectable extends React.Component< defaultDataSource, }); - this.props.onSelectedDataSources(selectedDataSource); + this.onSelectedDataSources(selectedDataSource); } async componentDidMount() { @@ -193,7 +203,7 @@ export class DataSourceSelectable extends React.Component< changeState: this.onEmptyState.bind(this, !!fetchedDataSources?.length), notifications: this.props.notifications, application: this.props.application, - callback: this.props.onSelectedDataSources, + callback: this.onSelectedDataSources, incompatibleDataSourcesExist: !!fetchedDataSources?.length, }); return; @@ -212,7 +222,7 @@ export class DataSourceSelectable extends React.Component< handleDataSourceFetchError( this.onError.bind(this), this.props.notifications, - this.props.onSelectedDataSources + this.onSelectedDataSources ); } } @@ -237,9 +247,7 @@ export class DataSourceSelectable extends React.Component< isPopoverOpen: false, }); - this.props.onSelectedDataSources([ - { id: selectedDataSource.id!, label: selectedDataSource.label }, - ]); + this.onSelectedDataSources([{ id: selectedDataSource.id!, label: selectedDataSource.label }]); } } diff --git a/src/plugins/data_source_management/public/components/data_source_selector/create_data_source_selector.tsx b/src/plugins/data_source_management/public/components/data_source_selector/create_data_source_selector.tsx index 0630b04e823c..83f9210b04c4 100644 --- a/src/plugins/data_source_management/public/components/data_source_selector/create_data_source_selector.tsx +++ b/src/plugins/data_source_management/public/components/data_source_selector/create_data_source_selector.tsx @@ -7,13 +7,20 @@ import React from 'react'; import { IUiSettingsClient } from 'src/core/public'; import { DataSourcePluginSetup } from 'src/plugins/data_source/public'; import { DataSourceSelector, DataSourceSelectorProps } from './data_source_selector'; +import { DataSourceSelection } from '../../service/data_source_selection_service'; export function createDataSourceSelector( uiSettings: IUiSettingsClient, - dataSourcePluginSetup: DataSourcePluginSetup + dataSourcePluginSetup: DataSourcePluginSetup, + dataSourceSelection: DataSourceSelection ) { const { hideLocalCluster } = dataSourcePluginSetup; return (props: DataSourceSelectorProps) => ( - + ); } diff --git a/src/plugins/data_source_management/public/components/data_source_selector/data_source_selector.tsx b/src/plugins/data_source_management/public/components/data_source_selector/data_source_selector.tsx index 8d2a90943b9f..bd55c4591f23 100644 --- a/src/plugins/data_source_management/public/components/data_source_selector/data_source_selector.tsx +++ b/src/plugins/data_source_management/public/components/data_source_selector/data_source_selector.tsx @@ -13,6 +13,7 @@ import { DataSourceAttributes } from '../../types'; import { DataSourceItem } from '../data_source_item'; import './data_source_selector.scss'; import { DataSourceOption } from '../data_source_menu/types'; +import { DataSourceSelection } from '../../service/data_source_selection_service'; export const LocalCluster: DataSourceOption = { label: i18n.translate('dataSource.localCluster', { @@ -35,6 +36,7 @@ export interface DataSourceSelectorProps { compressed?: boolean; uiSettings?: IUiSettingsClient; isClearable?: boolean; + dataSourceSelection: DataSourceSelection; } interface DataSourceSelectorState { @@ -42,6 +44,7 @@ interface DataSourceSelectorState { allDataSources: Array>; defaultDataSource: string | null; dataSourceOptions: DataSourceOption[]; + componentId: string; } export class DataSourceSelector extends React.Component< @@ -58,11 +61,18 @@ export class DataSourceSelector extends React.Component< defaultDataSource: '', selectedOption: this.props.hideLocalCluster ? [] : [LocalCluster], dataSourceOptions: [], + componentId: props.dataSourceSelection.generateComponentId(), }; } componentWillUnmount() { this._isMounted = false; + this.props.dataSourceSelection.remove(this.state.componentId); + } + + onSelectedDataSource(dataSource: DataSourceOption[]) { + this.props.dataSourceSelection.selectDataSource(this.state.componentId, dataSource); + this.props.onSelectedDataSource(dataSource); } handleSelectedOption( @@ -90,7 +100,7 @@ export class DataSourceSelector extends React.Component< defaultDataSource, allDataSources, }); - this.props.onSelectedDataSource(selectedOption); + this.onSelectedDataSource(selectedOption); } handleDefaultDataSource( @@ -108,7 +118,7 @@ export class DataSourceSelector extends React.Component< // No active option, did not find valid option if (selectedDataSource.length === 0) { this.props.notifications.addWarning('No connected data source available.'); - this.props.onSelectedDataSource([]); + this.onSelectedDataSource([]); return; } @@ -119,7 +129,7 @@ export class DataSourceSelector extends React.Component< defaultDataSource, allDataSources, }); - this.props.onSelectedDataSource(selectedDataSource); + this.onSelectedDataSource(selectedDataSource); } async componentDidMount() { @@ -146,7 +156,7 @@ export class DataSourceSelector extends React.Component< // 4. Error state if filter filters out everything if (!dataSourceOptions.length) { this.props.notifications.addWarning('No connected data source available.'); - this.props.onSelectedDataSource([]); + this.onSelectedDataSource([]); return; } @@ -185,7 +195,7 @@ export class DataSourceSelector extends React.Component< this.setState({ selectedOption: e, }); - this.props.onSelectedDataSource(e); + this.onSelectedDataSource(e); } render() { diff --git a/src/plugins/data_source_management/public/components/data_source_view/data_source_view.tsx b/src/plugins/data_source_management/public/components/data_source_view/data_source_view.tsx index f0d53ab92ddf..827899aa6b16 100644 --- a/src/plugins/data_source_management/public/components/data_source_view/data_source_view.tsx +++ b/src/plugins/data_source_management/public/components/data_source_view/data_source_view.tsx @@ -4,14 +4,7 @@ */ import React from 'react'; -import { i18n } from '@osd/i18n'; -import { - EuiPopover, - EuiButtonEmpty, - EuiContextMenuPanel, - EuiPanel, - EuiSelectable, -} from '@elastic/eui'; +import { EuiPopover, EuiContextMenuPanel, EuiPanel, EuiSelectable } from '@elastic/eui'; import { SavedObjectsClientContract, ToastsStart, @@ -26,6 +19,7 @@ import { DataSourceItem } from '../data_source_item'; import { LocalCluster } from '../constants'; import './data_source_view.scss'; import { DataSourceMenuPopoverButton } from '../popover_button/popover_button'; +import { DataSourceSelection } from '../../service/data_source_selection_service'; interface DataSourceViewProps { fullWidth: boolean; @@ -37,12 +31,14 @@ interface DataSourceViewProps { uiSettings?: IUiSettingsClient; dataSourceFilter?: (dataSource: any) => boolean; onSelectedDataSources?: (dataSources: DataSourceOption[]) => void; + dataSourceSelection: DataSourceSelection; } interface DataSourceViewState extends DataSourceBaseState { selectedOption: DataSourceOption[]; isPopoverOpen: boolean; defaultDataSource: string | null; + componentId: string; } export class DataSourceView extends React.Component { @@ -57,11 +53,14 @@ export class DataSourceView extends React.Component( 'HideLocalCluster' ); + +// This will maintain an unified data source selection instance among components and export it to other plugin. +export const [getDataSourceSelection, setDataSourceSelection] = createGetterSetter< + DataSourceSelection +>('DataSourceSelection'); diff --git a/src/plugins/data_source_management/public/plugin.ts b/src/plugins/data_source_management/public/plugin.ts index 7f0eb9760be2..66bb3e583119 100644 --- a/src/plugins/data_source_management/public/plugin.ts +++ b/src/plugins/data_source_management/public/plugin.ts @@ -21,7 +21,13 @@ import { noAuthCredentialAuthMethod, sigV4AuthMethod, usernamePasswordAuthMethod import { DataSourceSelectorProps } from './components/data_source_selector/data_source_selector'; import { createDataSourceMenu } from './components/data_source_menu/create_data_source_menu'; import { DataSourceMenuProps } from './components/data_source_menu'; -import { setApplication, setHideLocalCluster, setUiSettings } from './components/utils'; +import { + setApplication, + setHideLocalCluster, + setUiSettings, + setDataSourceSelection, +} from './components/utils'; +import { DataSourceSelection } from './service/data_source_selection_service'; export interface DataSourceManagementSetupDependencies { management: ManagementSetup; @@ -35,6 +41,7 @@ export interface DataSourceManagementPluginSetup { DataSourceSelector: React.ComponentType; getDataSourceMenu: () => React.ComponentType>; }; + dataSourceSelection: DataSourceSelection; } export interface DataSourceManagementPluginStart { @@ -53,6 +60,7 @@ export class DataSourceManagementPlugin > { private started = false; private authMethodsRegistry = new AuthenticationMethodRegistry(); + private dataSourceSelection = new DataSourceSelection(); public setup( core: CoreSetup, @@ -105,10 +113,19 @@ export class DataSourceManagementPlugin setHideLocalCluster({ enabled: dataSource.hideLocalCluster }); setUiSettings(uiSettings); + // This instance will be passed to data source selector component. + setDataSourceSelection(this.dataSourceSelection); + return { registerAuthenticationMethod, + // Other plugins can get this instance from setupDeps and use to get selected data sources. + dataSourceSelection: this.dataSourceSelection, ui: { - DataSourceSelector: createDataSourceSelector(uiSettings, dataSource), + DataSourceSelector: createDataSourceSelector( + uiSettings, + dataSource, + this.dataSourceSelection + ), getDataSourceMenu: () => createDataSourceMenu(), }, }; diff --git a/src/plugins/data_source_management/public/service/data_source_selection_service.ts b/src/plugins/data_source_management/public/service/data_source_selection_service.ts new file mode 100644 index 000000000000..39d19a6ad5a5 --- /dev/null +++ b/src/plugins/data_source_management/public/service/data_source_selection_service.ts @@ -0,0 +1,37 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import uuid from 'uuid'; +import { BehaviorSubject } from 'rxjs'; +import { DataSourceOption } from '../components/data_source_menu/types'; + +export class DataSourceSelection { + private selectedDataSource$ = new BehaviorSubject(new Map()); + + public selectDataSource = (componentId: string, dataSource: DataSourceOption[]) => { + const newMap = new Map(this.selectedDataSource$.value); + newMap.set(componentId, dataSource); + this.selectedDataSource$.next(newMap); + }; + + public remove = (componentId: string) => { + const newMap = new Map(this.selectedDataSource$.value); + newMap.delete(componentId); + this.selectedDataSource$.next(newMap); + }; + + public getSelectionValue = () => { + return this.selectedDataSource$.value; + }; + + // Plugins can use returned subject to subscribe update. + public getSelection$ = () => { + return this.selectedDataSource$; + }; + + public generateComponentId = () => { + return uuid.v4(); + }; +} From 99734b221ded701a274236225e4a284e7a2b0d19 Mon Sep 17 00:00:00 2001 From: tygao Date: Thu, 23 May 2024 16:56:57 +0800 Subject: [PATCH 02/12] export generateComponentId in util Signed-off-by: tygao --- .../data_source_aggregated_view.tsx | 3 ++- .../data_source_multi_selectable.tsx | 3 ++- .../data_source_selectable/data_source_selectable.tsx | 3 ++- .../data_source_selector/data_source_selector.tsx | 9 +++++++-- .../components/data_source_view/data_source_view.tsx | 4 ++-- .../data_source_management/public/components/utils.ts | 5 +++++ 6 files changed, 20 insertions(+), 7 deletions(-) diff --git a/src/plugins/data_source_management/public/components/data_source_aggregated_view/data_source_aggregated_view.tsx b/src/plugins/data_source_management/public/components/data_source_aggregated_view/data_source_aggregated_view.tsx index c3d38ad73f06..d63b25f98e2a 100644 --- a/src/plugins/data_source_management/public/components/data_source_aggregated_view/data_source_aggregated_view.tsx +++ b/src/plugins/data_source_management/public/components/data_source_aggregated_view/data_source_aggregated_view.tsx @@ -16,6 +16,7 @@ import { getDataSourcesWithFields, handleDataSourceFetchError, handleNoAvailableDataSourceError, + generateComponentId, } from '../utils'; import { SavedObject } from '../../../../../core/public'; import { DataSourceAttributes } from '../../types'; @@ -73,7 +74,7 @@ export class DataSourceAggregatedView extends React.Component< switchChecked: false, defaultDataSource: null, incompatibleDataSourcesExist: false, - componentId: props.dataSourceSelection.generateComponentId(), + componentId: generateComponentId(), }; } diff --git a/src/plugins/data_source_management/public/components/data_source_multi_selectable/data_source_multi_selectable.tsx b/src/plugins/data_source_management/public/components/data_source_multi_selectable/data_source_multi_selectable.tsx index dc8101c23db3..087cc42f29ad 100644 --- a/src/plugins/data_source_management/public/components/data_source_multi_selectable/data_source_multi_selectable.tsx +++ b/src/plugins/data_source_management/public/components/data_source_multi_selectable/data_source_multi_selectable.tsx @@ -16,6 +16,7 @@ import { getDataSourcesWithFields, handleDataSourceFetchError, handleNoAvailableDataSourceError, + generateComponentId, } from '../utils'; import { DataSourceBaseState } from '../data_source_menu/types'; import { DataSourceErrorMenu } from '../data_source_error_menu'; @@ -56,7 +57,7 @@ export class DataSourceMultiSelectable extends React.Component< showEmptyState: false, showError: false, incompatibleDataSourcesExist: false, - componentId: props.dataSourceSelection.generateComponentId(), + componentId: generateComponentId(), }; } diff --git a/src/plugins/data_source_management/public/components/data_source_selectable/data_source_selectable.tsx b/src/plugins/data_source_management/public/components/data_source_selectable/data_source_selectable.tsx index a3751a8fc82c..ce5dbbd1126e 100644 --- a/src/plugins/data_source_management/public/components/data_source_selectable/data_source_selectable.tsx +++ b/src/plugins/data_source_management/public/components/data_source_selectable/data_source_selectable.tsx @@ -24,6 +24,7 @@ import { getFilteredDataSources, handleDataSourceFetchError, handleNoAvailableDataSourceError, + generateComponentId, } from '../utils'; import { LocalCluster } from '../data_source_selector/data_source_selector'; import { SavedObject } from '../../../../../core/public'; @@ -79,7 +80,7 @@ export class DataSourceSelectable extends React.Component< showEmptyState: false, showError: false, incompatibleDataSourcesExist: false, - componentId: props.dataSourceSelection.generateComponentId(), + componentId: generateComponentId(), }; this.onChange.bind(this); diff --git a/src/plugins/data_source_management/public/components/data_source_selector/data_source_selector.tsx b/src/plugins/data_source_management/public/components/data_source_selector/data_source_selector.tsx index bd55c4591f23..5ac9d9073672 100644 --- a/src/plugins/data_source_management/public/components/data_source_selector/data_source_selector.tsx +++ b/src/plugins/data_source_management/public/components/data_source_selector/data_source_selector.tsx @@ -8,7 +8,12 @@ import { i18n } from '@osd/i18n'; import { EuiComboBox } from '@elastic/eui'; import { SavedObjectsClientContract, ToastsStart, SavedObject } from 'opensearch-dashboards/public'; import { IUiSettingsClient } from 'src/core/public'; -import { getDataSourcesWithFields, getDefaultDataSource, getFilteredDataSources } from '../utils'; +import { + getDataSourcesWithFields, + getDefaultDataSource, + getFilteredDataSources, + generateComponentId, +} from '../utils'; import { DataSourceAttributes } from '../../types'; import { DataSourceItem } from '../data_source_item'; import './data_source_selector.scss'; @@ -61,7 +66,7 @@ export class DataSourceSelector extends React.Component< defaultDataSource: '', selectedOption: this.props.hideLocalCluster ? [] : [LocalCluster], dataSourceOptions: [], - componentId: props.dataSourceSelection.generateComponentId(), + componentId: generateComponentId(), }; } diff --git a/src/plugins/data_source_management/public/components/data_source_view/data_source_view.tsx b/src/plugins/data_source_management/public/components/data_source_view/data_source_view.tsx index 827899aa6b16..92de0fbea4ef 100644 --- a/src/plugins/data_source_management/public/components/data_source_view/data_source_view.tsx +++ b/src/plugins/data_source_management/public/components/data_source_view/data_source_view.tsx @@ -13,7 +13,7 @@ import { import { IUiSettingsClient } from 'src/core/public'; import { DataSourceBaseState, DataSourceOption } from '../data_source_menu/types'; import { DataSourceErrorMenu } from '../data_source_error_menu'; -import { getDataSourceById, handleDataSourceFetchError } from '../utils'; +import { getDataSourceById, handleDataSourceFetchError, generateComponentId } from '../utils'; import { DataSourceDropDownHeader } from '../drop_down_header'; import { DataSourceItem } from '../data_source_item'; import { LocalCluster } from '../constants'; @@ -53,7 +53,7 @@ export class DataSourceView extends React.Component('DataSourceSelection'); + +export const generateComponentId = () => { + return uuid.v4(); +}; From 4d6f40755370faca4aa3ff0376e4afda56d6cfc1 Mon Sep 17 00:00:00 2001 From: tygao Date: Thu, 23 May 2024 17:49:07 +0800 Subject: [PATCH 03/12] update tests and type Signed-off-by: tygao --- .../data_source_aggregated_view.test.tsx | 13 +++ .../data_source_menu.test.tsx.snap | 108 ++++++++++++++++++ .../create_data_source_menu.test.tsx | 7 ++ .../create_data_source_menu.tsx | 7 +- .../data_source_menu.test.tsx | 11 ++ .../data_source_multi_selectable.test.tsx | 10 ++ .../create_data_source_selector.test.tsx | 7 +- .../create_data_source_selector.tsx | 4 +- .../data_source_selector.test.tsx | 21 ++++ .../data_source_view.test.tsx | 12 +- .../data_source_view/data_source_view.tsx | 6 +- 11 files changed, 197 insertions(+), 9 deletions(-) diff --git a/src/plugins/data_source_management/public/components/data_source_aggregated_view/data_source_aggregated_view.test.tsx b/src/plugins/data_source_management/public/components/data_source_aggregated_view/data_source_aggregated_view.test.tsx index 43b22ed219ee..b141cc541da7 100644 --- a/src/plugins/data_source_management/public/components/data_source_aggregated_view/data_source_aggregated_view.test.tsx +++ b/src/plugins/data_source_management/public/components/data_source_aggregated_view/data_source_aggregated_view.test.tsx @@ -28,6 +28,7 @@ import { NO_COMPATIBLE_DATASOURCES_MESSAGE, NO_DATASOURCES_CONNECTED_MESSAGE, } from '../constants'; +import { DataSourceSelection } from '../../service/data_source_selection_service'; describe('DataSourceAggregatedView: read all view (displayAllCompatibleDataSources is set to true)', () => { let component: ShallowWrapper, React.Component<{}, {}, any>>; @@ -35,6 +36,7 @@ describe('DataSourceAggregatedView: read all view (displayAllCompatibleDataSourc const { toasts } = notificationServiceMock.createStartContract(); const uiSettings = uiSettingsServiceMock.createStartContract(); const application = applicationServiceMock.createStartContract(); + const dataSourceSelection = new DataSourceSelection(); const nextTick = () => new Promise((res) => process.nextTick(res)); beforeEach(() => { @@ -118,6 +120,7 @@ describe('DataSourceAggregatedView: read all view (displayAllCompatibleDataSourc uiSettings={uiSettings} activeDataSourceIds={activeDataSourceIds} dataSourceFilter={filter} + dataSourceSelection={dataSourceSelection} /> ); @@ -163,6 +166,7 @@ describe('DataSourceAggregatedView: read active view (displayAllCompatibleDataSo let client: SavedObjectsClientContract; const { toasts } = notificationServiceMock.createStartContract(); const uiSettings = uiSettingsServiceMock.createStartContract(); + const dataSourceSelection = new DataSourceSelection(); const nextTick = () => new Promise((res) => process.nextTick(res)); beforeEach(() => { @@ -235,6 +239,7 @@ describe('DataSourceAggregatedView: read active view (displayAllCompatibleDataSo activeDataSourceIds={activeDataSourceIds} dataSourceFilter={filter} uiSettings={uiSettings} + dataSourceSelection={dataSourceSelection} /> ); await nextTick(); @@ -284,6 +289,7 @@ describe('DataSourceAggregatedView empty state test with local cluster hiding', const { toasts } = notificationServiceMock.createStartContract(); const uiSettings = uiSettingsServiceMock.createStartContract(); const application = applicationServiceMock.createStartContract(); + const dataSourceSelection = new DataSourceSelection(); const nextTick = () => new Promise((res) => process.nextTick(res)); beforeEach(() => { @@ -345,6 +351,7 @@ describe('DataSourceAggregatedView empty state test with local cluster hiding', uiSettings={uiSettings} activeDataSourceIds={activeDataSourceIds} dataSourceFilter={filter} + dataSourceSelection={dataSourceSelection} /> ); @@ -369,6 +376,7 @@ describe('DataSourceAggregatedView empty state test due to filter out with local const { toasts } = notificationServiceMock.createStartContract(); const uiSettings = uiSettingsServiceMock.createStartContract(); const application = applicationServiceMock.createStartContract(); + const dataSourceSelection = new DataSourceSelection(); const nextTick = () => new Promise((res) => process.nextTick(res)); beforeEach(() => { @@ -414,6 +422,7 @@ describe('DataSourceAggregatedView empty state test due to filter out with local uiSettings={uiSettings} activeDataSourceIds={activeDataSourceIds} dataSourceFilter={filter} + dataSourceSelection={dataSourceSelection} /> ); const noCompatibleDataSourcesMessage = `${NO_COMPATIBLE_DATASOURCES_MESSAGE} ${ADD_COMPATIBLE_DATASOURCES_MESSAGE}`; @@ -439,6 +448,7 @@ describe('DataSourceAggregatedView error state test no matter hide local cluster const { toasts } = notificationServiceMock.createStartContract(); const uiSettings = uiSettingsServiceMock.createStartContract(); const application = applicationServiceMock.createStartContract(); + const dataSourceSelection = new DataSourceSelection(); const nextTick = () => new Promise((res) => process.nextTick(res)); beforeEach(() => { @@ -500,6 +510,7 @@ describe('DataSourceAggregatedView error state test no matter hide local cluster uiSettings={uiSettings} activeDataSourceIds={activeDataSourceIds} dataSourceFilter={filter} + dataSourceSelection={dataSourceSelection} /> ); @@ -514,6 +525,7 @@ describe('DataSourceAggregatedView error state test no matter hide local cluster describe('DataSourceAggregatedView warning messages', () => { const client = {} as any; const uiSettings = uiSettingsServiceMock.createStartContract(); + const dataSourceSelection = new DataSourceSelection(); const nextTick = () => new Promise((res) => process.nextTick(res)); let toasts: IToasts; const noDataSourcesConnectedMessage = `${NO_DATASOURCES_CONNECTED_MESSAGE} ${CONNECT_DATASOURCES_MESSAGE}`; @@ -559,6 +571,7 @@ describe('DataSourceAggregatedView warning messages', () => { activeDataSourceIds={activeDataSourceIds} dataSourceFilter={(_) => false} uiSettings={uiSettings} + dataSourceSelection={dataSourceSelection} /> ); await nextTick(); diff --git a/src/plugins/data_source_management/public/components/data_source_menu/__snapshots__/data_source_menu.test.tsx.snap b/src/plugins/data_source_management/public/components/data_source_menu/__snapshots__/data_source_menu.test.tsx.snap index 4dc6ce29141a..1e7de76875f7 100644 --- a/src/plugins/data_source_management/public/components/data_source_menu/__snapshots__/data_source_menu.test.tsx.snap +++ b/src/plugins/data_source_management/public/components/data_source_menu/__snapshots__/data_source_menu.test.tsx.snap @@ -2,6 +2,24 @@ exports[`DataSourceMenu can render data source view when only pass id in the activeOption 1`] = `