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}
+
+ );
+};