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 a9030ec6c9d..fdc5d2c7508 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 @@ -44,6 +44,7 @@ export function DataSourceMenu(props: DataSourceMenuProps): ReactElement | savedObjectsClient={savedObjects!} notifications={notifications!.toasts} onSelectedDataSources={onSelectedDataSources!} + uiSettings={uiSettings} /> ); } diff --git a/src/plugins/data_source_management/public/components/data_source_multi_selectable/__snapshots__/data_source_filter_group.test.tsx.snap b/src/plugins/data_source_management/public/components/data_source_multi_selectable/__snapshots__/data_source_filter_group.test.tsx.snap index 665f9cfa27d..fe89b140951 100644 --- a/src/plugins/data_source_management/public/components/data_source_multi_selectable/__snapshots__/data_source_filter_group.test.tsx.snap +++ b/src/plugins/data_source_management/public/components/data_source_multi_selectable/__snapshots__/data_source_filter_group.test.tsx.snap @@ -62,7 +62,17 @@ exports[`DataSourceFilterGroup should render normally 1`] = ` } } > - name1 + @@ -204,7 +214,33 @@ Object { - name1 +
+
+ name1 +
+
+ + + + Default + + + +
+
@@ -497,7 +533,15 @@ Object { - name1 +
+
+ name1 +
+
diff --git a/src/plugins/data_source_management/public/components/data_source_multi_selectable/__snapshots__/data_source_multi_selectable.test.tsx.snap b/src/plugins/data_source_management/public/components/data_source_multi_selectable/__snapshots__/data_source_multi_selectable.test.tsx.snap index 627a1169c15..9f457a898d7 100644 --- a/src/plugins/data_source_management/public/components/data_source_multi_selectable/__snapshots__/data_source_multi_selectable.test.tsx.snap +++ b/src/plugins/data_source_management/public/components/data_source_multi_selectable/__snapshots__/data_source_multi_selectable.test.tsx.snap @@ -2,6 +2,7 @@ exports[`DataSourceMultiSelectable should render normally with local cluster hidden 1`] = ` @@ -9,6 +10,7 @@ exports[`DataSourceMultiSelectable should render normally with local cluster hid exports[`DataSourceMultiSelectable should render normally with local cluster not hidden 1`] = ` diff --git a/src/plugins/data_source_management/public/components/data_source_multi_selectable/data_source_filter_group.test.tsx b/src/plugins/data_source_management/public/components/data_source_multi_selectable/data_source_filter_group.test.tsx index 62bf10ec831..b75dbdf8a55 100644 --- a/src/plugins/data_source_management/public/components/data_source_multi_selectable/data_source_filter_group.test.tsx +++ b/src/plugins/data_source_management/public/components/data_source_multi_selectable/data_source_filter_group.test.tsx @@ -17,6 +17,7 @@ describe('DataSourceFilterGroup', () => { mockCallBack(items)} + defaultDataSource="1" /> ); expect(component).toMatchSnapshot(); @@ -28,6 +29,7 @@ describe('DataSourceFilterGroup', () => { mockCallBack(items)} + defaultDataSource="1" /> ); const button = await container.findByTestId('dataSourceFilterGroupButton'); diff --git a/src/plugins/data_source_management/public/components/data_source_multi_selectable/data_source_filter_group.tsx b/src/plugins/data_source_management/public/components/data_source_multi_selectable/data_source_filter_group.tsx index 8d0e22beada..948a788268d 100644 --- a/src/plugins/data_source_management/public/components/data_source_multi_selectable/data_source_filter_group.tsx +++ b/src/plugins/data_source_management/public/components/data_source_multi_selectable/data_source_filter_group.tsx @@ -16,6 +16,7 @@ import { EuiButtonEmpty, } from '@elastic/eui'; import { DataSourceOption } from '../data_source_selector/data_source_selector'; +import { DataSourceOptionItem } from '../data_source_option'; export interface SelectedDataSourceOption extends DataSourceOption { label: string; @@ -27,6 +28,7 @@ export interface SelectedDataSourceOption extends DataSourceOption { export interface DataSourceFilterGroupProps { selectedOptions: SelectedDataSourceOption[]; setSelectedOptions: (options: SelectedDataSourceOption[]) => void; + defaultDataSource: string | null; } type SelectionToggleOptionIds = 'select_all' | 'deselect_all'; @@ -45,6 +47,7 @@ const selectionToggleButtons = [ export const DataSourceFilterGroup: React.FC = ({ selectedOptions, setSelectedOptions, + defaultDataSource, }) => { const [isPopoverOpen, setIsPopoverOpen] = useState(false); const [selectionToggleSelectedId, setSelectionToggleSelectedId] = useState< @@ -148,7 +151,7 @@ export const DataSourceFilterGroup: React.FC = ({ showIcons={true} style={itemStyle} > - {item.label} + ); })} diff --git a/src/plugins/data_source_management/public/components/data_source_multi_selectable/data_source_multi_selectable.test.tsx b/src/plugins/data_source_management/public/components/data_source_multi_selectable/data_source_multi_selectable.test.tsx index afe65f55462..448eb404d99 100644 --- a/src/plugins/data_source_management/public/components/data_source_multi_selectable/data_source_multi_selectable.test.tsx +++ b/src/plugins/data_source_management/public/components/data_source_multi_selectable/data_source_multi_selectable.test.tsx @@ -5,7 +5,11 @@ import { SavedObjectsClientContract } from 'opensearch-dashboards/public'; import { notificationServiceMock } from '../../../../../core/public/mocks'; -import { getDataSourcesWithFieldsResponse, mockResponseForSavedObjectsCalls } from '../../mocks'; +import { + getDataSourcesWithFieldsResponse, + mockResponseForSavedObjectsCalls, + mockManagementPlugin, +} from '../../mocks'; import { ShallowWrapper, shallow } from 'enzyme'; import { DataSourceMultiSelectable } from './data_source_multi_selectable'; import React from 'react'; @@ -17,8 +21,12 @@ describe('DataSourceMultiSelectable', () => { let client: SavedObjectsClientContract; const { toasts } = notificationServiceMock.createStartContract(); const nextTick = () => new Promise((res) => process.nextTick(res)); + const mockedContext = mockManagementPlugin.createDataSourceManagementContext(); + const uiSettings = mockedContext.uiSettings; beforeEach(() => { + jest.clearAllMocks(); + client = { find: jest.fn().mockResolvedValue([]), } as any; @@ -102,4 +110,40 @@ describe('DataSourceMultiSelectable', () => { expect(callbackMock).toBeCalledWith([]); }); + + it('should retrun correct state when ui Settings provided', async () => { + spyOn(uiSettings, 'get').and.returnValue('test1'); + component = shallow( + + ); + await component.instance().componentDidMount!(); + expect(uiSettings.get).toBeCalledWith('defaultDataSource', null); + expect(component.state('defaultDataSource')).toEqual('test1'); + expect(component.state('selectedOptions')).toHaveLength(3); + }); + + it('should retrun correct state when ui Settings provided and hide cluster is false', async () => { + spyOn(uiSettings, 'get').and.returnValue('test1'); + component = shallow( + + ); + await component.instance().componentDidMount!(); + expect(uiSettings.get).toBeCalledWith('defaultDataSource', null); + expect(component.state('defaultDataSource')).toEqual('test1'); + expect(component.state('selectedOptions')).toHaveLength(4); + }); }); 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 2bcf5789918..1a1d958b618 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 @@ -6,6 +6,7 @@ import React from 'react'; import { SavedObjectsClientContract, ToastsStart } from 'opensearch-dashboards/public'; import { i18n } from '@osd/i18n'; +import { IUiSettingsClient } from 'src/core/public'; import { DataSourceFilterGroup, SelectedDataSourceOption } from './data_source_filter_group'; import { getDataSourcesWithFields } from '../utils'; @@ -15,11 +16,13 @@ export interface DataSourceMultiSeletableProps { onSelectedDataSources: (dataSources: SelectedDataSourceOption[]) => void; hideLocalCluster: boolean; fullWidth: boolean; + uiSettings?: IUiSettingsClient; } interface DataSourceMultiSeletableState { dataSourceOptions: SelectedDataSourceOption[]; selectedOptions: SelectedDataSourceOption[]; + defaultDataSource: string | null; } export class DataSourceMultiSelectable extends React.Component< @@ -34,6 +37,7 @@ export class DataSourceMultiSelectable extends React.Component< this.state = { dataSourceOptions: [], selectedOptions: [], + defaultDataSource: null, }; } @@ -43,46 +47,49 @@ export class DataSourceMultiSelectable extends React.Component< async componentDidMount() { this._isMounted = true; - getDataSourcesWithFields(this.props.savedObjectsClient, ['id', 'title', 'auth.type']) - .then((fetchedDataSources) => { - if (fetchedDataSources?.length) { - // all data sources are selected by default on initial page load - const selectedOptions: SelectedDataSourceOption[] = fetchedDataSources.map( - (dataSource) => ({ - id: dataSource.id, - label: dataSource.attributes?.title || '', - checked: 'on', - visible: true, - }) - ); + try { + const defaultDataSource = this.props.uiSettings?.get('defaultDataSource', null) ?? null; + let selectedOptions: SelectedDataSourceOption[] = []; + const fetchedDataSources = await getDataSourcesWithFields(this.props.savedObjectsClient, [ + 'id', + 'title', + 'auth.type', + ]); - if (!this.props.hideLocalCluster) { - selectedOptions.unshift({ - id: '', - label: 'Local cluster', - checked: 'on', - visible: true, - }); - } + if (fetchedDataSources?.length) { + selectedOptions = fetchedDataSources.map((dataSource) => ({ + id: dataSource.id, + label: dataSource.attributes?.title || '', + checked: 'on', + visible: true, + })); + } - if (!this._isMounted) return; - this.setState({ - ...this.state, - selectedOptions, - }); + if (!this.props.hideLocalCluster) { + selectedOptions.unshift({ + id: '', + label: 'Local cluster', + checked: 'on', + visible: true, + }); + } - this.props.onSelectedDataSources( - selectedOptions.filter((option) => option.checked === 'on') - ); - } - }) - .catch(() => { - this.props.notifications.addWarning( - i18n.translate('dataSource.fetchDataSourceError', { - defaultMessage: 'Unable to fetch existing data sources', - }) - ); + if (!this._isMounted) return; + + this.setState({ + ...this.state, + selectedOptions, + defaultDataSource, }); + + this.props.onSelectedDataSources(selectedOptions); + } catch (error) { + this.props.notifications.addWarning( + i18n.translate('dataSource.fetchDataSourceError', { + defaultMessage: 'Unable to fetch existing data sources', + }) + ); + } } onChange(selectedOptions: SelectedDataSourceOption[]) { @@ -98,6 +105,7 @@ export class DataSourceMultiSelectable extends React.Component< ); } diff --git a/src/plugins/data_source_management/public/components/data_source_option.test.tsx b/src/plugins/data_source_management/public/components/data_source_option.test.tsx new file mode 100644 index 00000000000..7d6375f47d2 --- /dev/null +++ b/src/plugins/data_source_management/public/components/data_source_option.test.tsx @@ -0,0 +1,46 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { shallow } from 'enzyme'; +import React from 'react'; +import { EuiBadge, EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; +import { DataSourceOptionItem } from './data_source_option'; +import { SelectedDataSourceOption } from './data_source_multi_selectable/data_source_filter_group'; + +describe('Test on ShowDataSourceOption', () => { + it('should render the component with label', () => { + const item: SelectedDataSourceOption = { + id: '1', + label: 'DataSource 1', + visible: true, + }; + const defaultDataSource = null; + + const component = shallow( + + ); + + expect(component.find(EuiFlexGroup)).toHaveLength(1); + expect(component.find(EuiFlexItem)).toHaveLength(1); + expect(component.find(EuiBadge)).toHaveLength(0); + }); + + it('should render the component with label and default badge', () => { + const item = { + id: '1', + label: 'DataSource 1', + visible: true, + }; + const defaultDataSource = '1'; + + const component = shallow( + + ); + + expect(component.find(EuiFlexGroup)).toHaveLength(1); + expect(component.find(EuiFlexItem)).toHaveLength(2); + expect(component.find(EuiBadge)).toHaveLength(1); + }); +}); diff --git a/src/plugins/data_source_management/public/components/data_source_option.tsx b/src/plugins/data_source_management/public/components/data_source_option.tsx new file mode 100644 index 00000000000..cb5dac27d5a --- /dev/null +++ b/src/plugins/data_source_management/public/components/data_source_option.tsx @@ -0,0 +1,29 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import React from 'react'; +import { EuiFlexGroup, EuiFlexItem, EuiBadge } from '@elastic/eui'; +import { SelectedDataSourceOption } from './data_source_multi_selectable/data_source_filter_group'; + +export interface DataSourceOptionItemProps { + item: SelectedDataSourceOption; + defaultDataSource: string | null; +} + +export const DataSourceOptionItem: React.FC = ({ + item, + defaultDataSource, +}) => { + return ( + + {item.label} + {item.id === defaultDataSource && ( + + Default + + )} + + ); +};