diff --git a/CHANGELOG.md b/CHANGELOG.md index 77d1fad31e9c..48c2d6561e42 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -86,6 +86,7 @@ Inspired from [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) - [Mulitple Datasource] Add multi data source support to TSVB ([#6298](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/6298)) - [Multiple Datasource] Add installedPlugins list to data source saved object ([#6348](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/6348)) - [Multiple Datasource] Add default icon in multi-selectable picker ([#6357](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/6357)) +- [Multiple Datasource] Add empty state component for no connected data source ([#6499](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/6499)) - [Workspace] Add APIs to support plugin state in request ([#6303](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/6303)) - [Workspace] Filter left nav menu items according to the current workspace ([#6234](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/6234)) - [Multiple Datasource] Add multi data source support to Timeline ([#6385](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/6385)) 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 dda3da78363b..c77a49a75831 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 { SavedObjectsClientContract, ToastsStart } from 'opensearch-dashboards/p import { getDataSourcesWithFields, handleDataSourceFetchError } from '../utils'; import { SavedObject } from '../../../../../core/public'; import { DataSourceAttributes } from '../../types'; +import { NoDataSource } from '../no_data_source'; import { DataSourceErrorMenu } from '../data_source_error_menu'; import { DataSourceBaseState } from '../data_source_menu/types'; @@ -46,6 +47,7 @@ export class DataSourceAggregatedView extends React.Component< this.state = { isPopoverOpen: false, allDataSourcesIdToTitleMap: new Map(), + showEmptyState: false, showError: false, }; } @@ -73,7 +75,6 @@ export class DataSourceAggregatedView extends React.Component< this.props.dataSourceFilter!(ds) ); } - const allDataSourcesIdToTitleMap = new Map(); filteredDataSources.forEach((ds) => { @@ -101,6 +102,9 @@ export class DataSourceAggregatedView extends React.Component< } render() { + if (this.state.showEmptyState) { + return ; + } if (this.state.showError) { return ; } 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 bc645a0b885f..9c011a2e8e47 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 @@ -20,6 +20,7 @@ import { DataSourceSelectable } from '../data_source_selectable'; export function DataSourceMenu(props: DataSourceMenuProps): ReactElement | null { const { componentType, componentConfig, uiSettings, hideLocalCluster, application } = props; + function renderDataSourceView(config: DataSourceViewConfig): ReactElement | null { const { activeOption, 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 483f08c524bc..d6d960c0e40a 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 @@ -29,6 +29,7 @@ export interface DataSourceBaseConfig { } export interface DataSourceBaseState { + showEmptyState: boolean; showError: boolean; } 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 25122a801e84..8e842f70b4f5 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 @@ -7,6 +7,7 @@ import React from 'react'; import { SavedObjectsClientContract, ToastsStart } from 'opensearch-dashboards/public'; import { IUiSettingsClient } from 'src/core/public'; import { DataSourceFilterGroup, SelectedDataSourceOption } from './data_source_filter_group'; +import { NoDataSource } from '../no_data_source'; import { getDataSourcesWithFields, handleDataSourceFetchError } from '../utils'; import { DataSourceBaseState } from '../data_source_menu/types'; import { DataSourceErrorMenu } from '../data_source_error_menu'; @@ -39,6 +40,7 @@ export class DataSourceMultiSelectable extends React.Component< dataSourceOptions: [], selectedOptions: [], defaultDataSource: null, + showEmptyState: false, showError: false, }; } @@ -82,6 +84,7 @@ export class DataSourceMultiSelectable extends React.Component< ...this.state, selectedOptions, defaultDataSource, + showEmptyState: (fetchedDataSources?.length === 0 && this.props.hideLocalCluster) || false, }); this.props.onSelectedDataSources(selectedOptions); @@ -107,6 +110,9 @@ export class DataSourceMultiSelectable extends React.Component< } render() { + if (this.state.showEmptyState) { + return ; + } if (this.state.showError) { return ; } diff --git a/src/plugins/data_source_management/public/components/data_source_selectable/data_source_selectable.test.tsx b/src/plugins/data_source_management/public/components/data_source_selectable/data_source_selectable.test.tsx index c836dd011085..1ced7e3872c1 100644 --- a/src/plugins/data_source_management/public/components/data_source_selectable/data_source_selectable.test.tsx +++ b/src/plugins/data_source_management/public/components/data_source_selectable/data_source_selectable.test.tsx @@ -139,6 +139,7 @@ describe('DataSourceSelectable', () => { ], defaultDataSource: null, isPopoverOpen: false, + showEmptyState: false, selectedOption: [ { id: 'test2', @@ -159,6 +160,7 @@ describe('DataSourceSelectable', () => { ], defaultDataSource: null, isPopoverOpen: false, + showEmptyState: false, selectedOption: [ { checked: 'on', @@ -337,6 +339,7 @@ describe('DataSourceSelectable', () => { ], defaultDataSource: null, isPopoverOpen: false, + showEmptyState: false, selectedOption: [ { id: 'test2', @@ -371,6 +374,7 @@ describe('DataSourceSelectable', () => { defaultDataSource: null, isPopoverOpen: false, selectedOption: [], + showEmptyState: false, showError: true, }); @@ -385,6 +389,7 @@ describe('DataSourceSelectable', () => { ], defaultDataSource: null, isPopoverOpen: false, + showEmptyState: false, selectedOption: [ { checked: 'on', 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 4e2278c280b6..ec4af533c5df 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,8 @@ import { } from '../data_source_menu/types'; import { DataSourceErrorMenu } from '../data_source_error_menu'; import { DataSourceItem } from '../data_source_item'; +import { NoDataSource } from '../no_data_source'; +import './data_source_selectable.scss'; import { DataSourceDropDownHeader } from '../drop_down_header'; import '../button_title.scss'; import './data_source_selectable.scss'; @@ -81,6 +83,7 @@ export class DataSourceSelectable extends React.Component< isPopoverOpen: false, selectedOption: [], defaultDataSource: null, + showEmptyState: false, showError: false, }; @@ -186,6 +189,10 @@ export class DataSourceSelectable extends React.Component< this.props.dataSourceFilter ); + if (dataSourceOptions.length === 0 && this.props.hideLocalCluster) { + this.setState({ showEmptyState: true }); + } + if (!this.props.hideLocalCluster) { dataSourceOptions.unshift(LocalCluster); } @@ -243,6 +250,9 @@ export class DataSourceSelectable extends React.Component< }; render() { + if (this.state.showEmptyState) { + return ; + } if (this.state.showError) { return ; } 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 420bb5927145..810413db1f8c 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 @@ -17,6 +17,7 @@ import { handleNoAvailableDataSourceError, } from '../utils'; import { LocalCluster } from '../constants'; +import { NoDataSource } from '../no_data_source'; interface DataSourceViewProps { fullWidth: boolean; @@ -43,6 +44,7 @@ export class DataSourceView extends React.Component; + } if (this.state.showError) { return ; } diff --git a/src/plugins/data_source_management/public/components/no_data_source/__snapshots__/no_data_source.test.tsx.snap b/src/plugins/data_source_management/public/components/no_data_source/__snapshots__/no_data_source.test.tsx.snap new file mode 100644 index 000000000000..8c9f1339fed4 --- /dev/null +++ b/src/plugins/data_source_management/public/components/no_data_source/__snapshots__/no_data_source.test.tsx.snap @@ -0,0 +1,14 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`NoDataSource should render normally 1`] = ` + + No data sources + +`; diff --git a/src/plugins/data_source_management/public/components/no_data_source/index.tsx b/src/plugins/data_source_management/public/components/no_data_source/index.tsx new file mode 100644 index 000000000000..71fcabf9145c --- /dev/null +++ b/src/plugins/data_source_management/public/components/no_data_source/index.tsx @@ -0,0 +1,6 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +export { NoDataSource } from './no_data_source'; diff --git a/src/plugins/data_source_management/public/components/no_data_source/no_data_source.test.tsx b/src/plugins/data_source_management/public/components/no_data_source/no_data_source.test.tsx new file mode 100644 index 000000000000..380c6ad77e4f --- /dev/null +++ b/src/plugins/data_source_management/public/components/no_data_source/no_data_source.test.tsx @@ -0,0 +1,16 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { ShallowWrapper, shallow } from 'enzyme'; +import React from 'react'; +import { NoDataSource } from './no_data_source'; + +describe('NoDataSource', () => { + let component: ShallowWrapper, React.Component<{}, {}, any>>; + it('should render normally', () => { + component = shallow(); + expect(component).toMatchSnapshot(); + }); +}); diff --git a/src/plugins/data_source_management/public/components/no_data_source/no_data_source.tsx b/src/plugins/data_source_management/public/components/no_data_source/no_data_source.tsx new file mode 100644 index 000000000000..2f9cf8c8415a --- /dev/null +++ b/src/plugins/data_source_management/public/components/no_data_source/no_data_source.tsx @@ -0,0 +1,24 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import React from 'react'; + +import { EuiButtonEmpty } from '@elastic/eui'; + +export const NoDataSource = () => { + const label = ' No data sources'; + return ( + + {label} + + ); +};