diff --git a/src/plugins/data_source_management/public/components/data_source_selector/__snapshots__/data_source_selector.test.tsx.snap b/src/plugins/data_source_management/public/components/data_source_selector/__snapshots__/data_source_selector.test.tsx.snap
index 2b8e3eba860d..7161ee957596 100644
--- a/src/plugins/data_source_management/public/components/data_source_selector/__snapshots__/data_source_selector.test.tsx.snap
+++ b/src/plugins/data_source_management/public/components/data_source_selector/__snapshots__/data_source_selector.test.tsx.snap
@@ -13,6 +13,7 @@ exports[`DataSourceSelector should render normally with local cluster is hidden
options={Array []}
placeholder="Select a data source"
prepend="Data source"
+ renderOption={[Function]}
selectedOptions={Array []}
singleSelection={
Object {
@@ -43,6 +44,7 @@ exports[`DataSourceSelector should render normally with local cluster not hidden
}
placeholder="Select a data source"
prepend="Data source"
+ renderOption={[Function]}
selectedOptions={
Array [
Object {
@@ -92,6 +94,7 @@ exports[`DataSourceSelector: check dataSource options should always place local
}
placeholder="Select a data source"
prepend="Data source"
+ renderOption={[Function]}
selectedOptions={
Array [
Object {
@@ -137,6 +140,57 @@ exports[`DataSourceSelector: check dataSource options should filter options if c
}
placeholder="Select a data source"
prepend="Data source"
+ renderOption={[Function]}
+ selectedOptions={
+ Array [
+ Object {
+ "id": "",
+ "label": "Local cluster",
+ },
+ ]
+ }
+ singleSelection={
+ Object {
+ "asPlainText": true,
+ }
+ }
+ sortMatchesBy="none"
+/>
+`;
+
+exports[`DataSourceSelector: check dataSource options should get default datasource if uiSettings exists 1`] = `
+
+`;
+
+exports[`DataSourceSelector: check dataSource options should show default datasource if configured 1`] = `
+ {
let client: SavedObjectsClientContract;
+ let uiSettings: IUiSettingsClient;
const { toasts } = notificationServiceMock.createStartContract();
beforeEach(() => {
@@ -27,7 +29,7 @@ describe('create data source selector', () => {
hideLocalCluster: false,
fullWidth: false,
};
- const TestComponent = createDataSourceSelector();
+ const TestComponent = createDataSourceSelector(uiSettings);
const component = render();
expect(component).toMatchSnapshot();
expect(client.find).toBeCalledWith({
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 ff6b7503a0bb..485d192668a5 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
@@ -4,8 +4,11 @@
*/
import React from 'react';
+import { IUiSettingsClient } from 'src/core/public';
import { DataSourceSelector, DataSourceSelectorProps } from './data_source_selector';
-export function createDataSourceSelector() {
- return (props: DataSourceSelectorProps) => ;
+export function createDataSourceSelector(uiSettings: IUiSettingsClient) {
+ return (props: DataSourceSelectorProps) => (
+
+ );
}
diff --git a/src/plugins/data_source_management/public/components/data_source_selector/data_source_selector.test.tsx b/src/plugins/data_source_management/public/components/data_source_selector/data_source_selector.test.tsx
index 86eb892e8cd8..bb4547a47a6b 100644
--- a/src/plugins/data_source_management/public/components/data_source_selector/data_source_selector.test.tsx
+++ b/src/plugins/data_source_management/public/components/data_source_selector/data_source_selector.test.tsx
@@ -5,11 +5,16 @@
import { ShallowWrapper, shallow } from 'enzyme';
import { DataSourceSelector } from './data_source_selector';
-import { SavedObjectsClientContract } from '../../../../../core/public';
+import { SavedObjectsClientContract, IUiSettingsClient } from '../../../../../core/public';
import { notificationServiceMock } from '../../../../../core/public/mocks';
import React from 'react';
-import { getDataSourcesWithFieldsResponse, mockResponseForSavedObjectsCalls } from '../../mocks';
+import {
+ getDataSourcesWithFieldsResponse,
+ mockManagementPlugin,
+ mockResponseForSavedObjectsCalls,
+} from '../../mocks';
import { AuthType } from 'src/plugins/data_source/common/data_sources';
+import * as utils from '../utils';
describe('DataSourceSelector', () => {
let component: ShallowWrapper, React.Component<{}, {}, any>>;
@@ -69,6 +74,8 @@ describe('DataSourceSelector: check dataSource options', () => {
let client: SavedObjectsClientContract;
const { toasts } = notificationServiceMock.createStartContract();
const nextTick = () => new Promise((res) => process.nextTick(res));
+ const mockedContext = mockManagementPlugin.createDataSourceManagementContext();
+ const uiSettings = mockedContext.uiSettings;
beforeEach(async () => {
client = {
@@ -170,4 +177,49 @@ describe('DataSourceSelector: check dataSource options', () => {
expect(component).toMatchSnapshot();
expect(toasts.addWarning).toBeCalledTimes(0);
});
+
+ it('should get default datasource if uiSettings exists', async () => {
+ spyOn(uiSettings, 'get').and.returnValue({});
+ component = shallow(
+
+ );
+
+ component.instance().componentDidMount!();
+ await nextTick();
+ expect(component).toMatchSnapshot();
+ expect(uiSettings.get).toBeCalledWith('defaultDataSource', null);
+ expect(toasts.addWarning).toBeCalledTimes(0);
+ });
+
+ it('should show default datasource if configured', async () => {
+ spyOn(utils, 'getFilterDataSources').and.returnValue([]);
+ spyOn(utils, 'getDefaultDataSource').and.returnValue([]);
+ spyOn(uiSettings, 'get').and.returnValue({});
+ component = shallow(
+
+ );
+
+ component.instance().componentDidMount!();
+ await nextTick();
+ expect(component).toMatchSnapshot();
+ expect(utils.getFilterDataSources).toHaveBeenCalled();
+ expect(utils.getDefaultDataSource).toHaveBeenCalled();
+ expect(toasts.addWarning).toBeCalledTimes(0);
+ });
});
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 3e9f4c377160..96e2731a0dec 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
@@ -5,9 +5,10 @@
import React from 'react';
import { i18n } from '@osd/i18n';
-import { EuiComboBox } from '@elastic/eui';
+import { EuiComboBox, EuiBadge, EuiFlexItem, EuiFlexGroup } from '@elastic/eui';
import { SavedObjectsClientContract, ToastsStart, SavedObject } from 'opensearch-dashboards/public';
-import { getDataSourcesWithFields } from '../utils';
+import { IUiSettingsClient } from 'src/core/public';
+import { getDataSourcesWithFields, getDefaultDataSource, getFilterDataSources } from '../utils';
import { DataSourceAttributes } from '../../types';
export const LocalCluster: DataSourceOption = {
@@ -29,6 +30,8 @@ export interface DataSourceSelectorProps {
removePrepend?: boolean;
dataSourceFilter?: (dataSource: SavedObject) => boolean;
compressed?: boolean;
+ uiSettings?: IUiSettingsClient;
+ showDefault?: (source: DataSourceOption) => void;
}
interface DataSourceSelectorState {
@@ -76,6 +79,20 @@ export class DataSourceSelector extends React.Component<
allDataSources: fetchedDataSources,
});
}
+ if (this.props.showDefault) {
+ const dataSources = getFilterDataSources(
+ this.state.allDataSources,
+ this.props.dataSourceFilter
+ );
+ const defaultDataSource = getDefaultDataSource(
+ dataSources,
+ LocalCluster,
+ this.props.uiSettings,
+ this.props.hideLocalCluster,
+ this.props.defaultOption
+ );
+ this.props.showDefault(defaultDataSource);
+ }
})
.catch(() => {
this.props.notifications.addWarning(
@@ -100,15 +117,17 @@ export class DataSourceSelector extends React.Component<
? 'Select a data source'
: this.props.placeholderText;
- const dataSources = this.props.dataSourceFilter
- ? this.state.allDataSources.filter((ds) => this.props.dataSourceFilter!(ds))
- : this.state.allDataSources;
+ const dataSources = getFilterDataSources(
+ this.state.allDataSources,
+ this.props.dataSourceFilter
+ );
const options = dataSources.map((ds) => ({ id: ds.id, label: ds.attributes?.title || '' }));
if (!this.props.hideLocalCluster) {
options.unshift(LocalCluster);
}
+ const defaultDataSource = this.props.uiSettings?.get('defaultDataSource', null) ?? null;
return (
(
+
+ {option.label}
+ {option.id === defaultDataSource && (
+
+ Default
+
+ )}
+
+ )}
/>
);
}
diff --git a/src/plugins/data_source_management/public/components/utils.test.ts b/src/plugins/data_source_management/public/components/utils.test.ts
index f2b1f709cb18..57b42440ac99 100644
--- a/src/plugins/data_source_management/public/components/utils.test.ts
+++ b/src/plugins/data_source_management/public/components/utils.test.ts
@@ -16,6 +16,8 @@ import {
updateDataSourceById,
handleSetDefaultDatasource,
setFirstDataSourceAsDefault,
+ getFilterDataSources,
+ getDefaultDataSource,
} from './utils';
import { coreMock } from '../../../../core/public/mocks';
import {
@@ -28,6 +30,7 @@ import {
mockResponseForSavedObjectsCalls,
mockUiSettingsCalls,
getSingleDataSourceResponse,
+ getDataSource,
} from '../mocks';
import {
AuthType,
@@ -35,9 +38,10 @@ import {
sigV4AuthMethod,
usernamePasswordAuthMethod,
} from '../types';
-import { HttpStart } from 'opensearch-dashboards/public';
+import { HttpStart, SavedObject } from 'opensearch-dashboards/public';
import { AuthenticationMethod, AuthenticationMethodRegistry } from '../auth_registry';
import { deepEqual } from 'assert';
+import { DataSourceAttributes } from 'src/plugins/data_source/common/data_sources'; // Import the missing 'SigV4Content' here
const { savedObjects } = coreMock.createStart();
const { uiSettings } = coreMock.createStart();
@@ -495,4 +499,84 @@ describe('DataSourceManagement: Utils.ts', () => {
expect(deepEqual(registedAuthTypeCredentials, expectExtractedAuthCredentials));
});
});
+
+ describe('Check on get filter datasource', () => {
+ test('should return all data sources when no filter is provided', () => {
+ const dataSources: Array> = [
+ {
+ id: '1',
+ type: '',
+ references: [],
+ attributes: {
+ title: 'DataSource 1',
+ endpoint: '',
+ auth: { type: AuthType.NoAuth, credentials: undefined },
+ name: AuthType.NoAuth,
+ },
+ },
+ ];
+
+ const result = getFilterDataSources(dataSources);
+
+ expect(result).toEqual(dataSources);
+ });
+
+ test('should return filtered data sources when a filter is provided', () => {
+ const filter = (dataSource: SavedObject) => dataSource.id === '2';
+ const result = getFilterDataSources(getDataSource, filter);
+
+ expect(result).toEqual([
+ {
+ id: '2',
+ type: '',
+ references: [],
+ attributes: {
+ title: 'DataSource 1',
+ endpoint: '',
+ auth: { type: AuthType.NoAuth, credentials: undefined },
+ name: AuthType.NoAuth,
+ },
+ },
+ ]);
+ });
+ });
+ describe('getDefaultDataSource', () => {
+ const LocalCluster = { id: 'local', label: 'Local Cluster' };
+ const hideLocalCluster = false;
+ const defaultOption = [{ id: '2', label: 'Default Option' }];
+
+ it('should return the default option if it exists in the data sources', () => {
+ const result = getDefaultDataSource(
+ getDataSource,
+ LocalCluster,
+ uiSettings,
+ hideLocalCluster,
+ defaultOption
+ );
+ expect(result).toEqual(defaultOption[0]);
+ });
+
+ it('should return local cluster if it exists and no default options in the data sources', () => {
+ mockUiSettingsCalls(uiSettings, 'get', null);
+ const result = getDefaultDataSource(
+ getDataSource,
+ LocalCluster,
+ uiSettings,
+ hideLocalCluster
+ );
+ expect(result).toEqual(LocalCluster);
+ });
+
+ it('should return the default datasource if hideLocalCluster is false', () => {
+ mockUiSettingsCalls(uiSettings, 'get', '1');
+ const result = getDefaultDataSource(getDataSource, LocalCluster, uiSettings, true);
+ expect(result).toEqual({ id: '1', label: 'DataSource 1' });
+ });
+
+ it('should return an empty default data source if no default option, hideLocalCluster is ture and no default datasource', () => {
+ mockUiSettingsCalls(uiSettings, 'get', null);
+ const result = getDefaultDataSource(getDataSource, LocalCluster, uiSettings, true);
+ expect(result).toEqual({ id: '', label: '' });
+ });
+ });
});
diff --git a/src/plugins/data_source_management/public/components/utils.ts b/src/plugins/data_source_management/public/components/utils.ts
index b911203cd288..cdb8120128c9 100644
--- a/src/plugins/data_source_management/public/components/utils.ts
+++ b/src/plugins/data_source_management/public/components/utils.ts
@@ -16,6 +16,7 @@ import {
noAuthCredentialAuthMethod,
} from '../types';
import { AuthenticationMethodRegistry } from '../auth_registry';
+import { DataSourceOption } from './data_source_selector/data_source_selector';
export async function getDataSources(savedObjectsClient: SavedObjectsClientContract) {
return savedObjectsClient
@@ -78,6 +79,41 @@ export async function setFirstDataSourceAsDefault(
}
}
+export function getFilterDataSources(
+ dataSources: Array>,
+ filter?: (dataSource: SavedObject) => boolean
+) {
+ return filter ? dataSources.filter((ds) => filter!(ds)) : dataSources;
+}
+
+export function getDefaultDataSource(
+ dataSources: Array>,
+ LocalCluster: DataSourceOption,
+ uiSettings?: IUiSettingsClient,
+ hideLocalCluster?: boolean,
+ defaultOption?: DataSourceOption[]
+) {
+ let defaultShowingDataSource: DataSourceOption;
+
+ if (defaultOption && dataSources.find((dataSource) => dataSource.id === defaultOption?.[0].id)) {
+ defaultShowingDataSource = defaultOption?.[0];
+ } else if (
+ uiSettings &&
+ uiSettings?.get('defaultDataSource', null) !== null &&
+ dataSources.find((dataSource) => dataSource.id === uiSettings?.get('defaultDataSource'))
+ ) {
+ const ds = dataSources.find(
+ (dataSource) => dataSource.id === uiSettings?.get('defaultDataSource')
+ );
+ defaultShowingDataSource = { id: ds!.id, label: ds!.attributes?.title || '' };
+ } else if (!hideLocalCluster) {
+ defaultShowingDataSource = LocalCluster;
+ } else {
+ defaultShowingDataSource = { id: '', label: '' };
+ }
+ return defaultShowingDataSource;
+}
+
export async function getDataSourceById(
id: string,
savedObjectsClient: SavedObjectsClientContract
diff --git a/src/plugins/data_source_management/public/mocks.ts b/src/plugins/data_source_management/public/mocks.ts
index d04fc2a362d3..910d56de61a8 100644
--- a/src/plugins/data_source_management/public/mocks.ts
+++ b/src/plugins/data_source_management/public/mocks.ts
@@ -78,6 +78,42 @@ export const getSingleDataSourceResponse = {
],
};
+export const getDataSource = [
+ {
+ id: '1',
+ type: '',
+ references: [],
+ attributes: {
+ title: 'DataSource 1',
+ endpoint: '',
+ auth: { type: AuthType.NoAuth, credentials: undefined },
+ name: AuthType.NoAuth,
+ },
+ },
+ {
+ id: '2',
+ type: '',
+ references: [],
+ attributes: {
+ title: 'DataSource 1',
+ endpoint: '',
+ auth: { type: AuthType.NoAuth, credentials: undefined },
+ name: AuthType.NoAuth,
+ },
+ },
+ {
+ id: '3',
+ type: '',
+ references: [],
+ attributes: {
+ title: 'DataSource 1',
+ endpoint: '',
+ auth: { type: AuthType.NoAuth, credentials: undefined },
+ name: AuthType.NoAuth,
+ },
+ },
+];
+
/* Mock data responses - JSON*/
export const getDataSourcesResponse = {
savedObjects: [
diff --git a/src/plugins/data_source_management/public/plugin.ts b/src/plugins/data_source_management/public/plugin.ts
index 9e6da39dc08b..c6a978ae7b61 100644
--- a/src/plugins/data_source_management/public/plugin.ts
+++ b/src/plugins/data_source_management/public/plugin.ts
@@ -57,6 +57,7 @@ export class DataSourceManagementPlugin
{ management, indexPatternManagement, dataSource }: DataSourceManagementSetupDependencies
) {
const opensearchDashboardsSection = management.sections.section.opensearchDashboards;
+ const uiSettings = core.uiSettings;
if (!opensearchDashboardsSection) {
throw new Error('`opensearchDashboards` management section not found.');
@@ -102,7 +103,7 @@ export class DataSourceManagementPlugin
return {
registerAuthenticationMethod,
ui: {
- DataSourceSelector: createDataSourceSelector(),
+ DataSourceSelector: createDataSourceSelector(uiSettings),
getDataSourceMenu: () => createDataSourceMenu(),
},
};
diff --git a/src/plugins/dev_tools/public/application.tsx b/src/plugins/dev_tools/public/application.tsx
index 3d3655b3bd64..41f08a1ea08e 100644
--- a/src/plugins/dev_tools/public/application.tsx
+++ b/src/plugins/dev_tools/public/application.tsx
@@ -39,6 +39,7 @@ import {
ApplicationStart,
ChromeStart,
CoreStart,
+ IUiSettingsClient,
NotificationsStart,
SavedObjectsStart,
ScopedHistory,
@@ -48,7 +49,6 @@ import { DataSourceSelector } from '../../data_source_management/public';
import { DevToolApp } from './dev_tool';
import { DevToolsSetupDependencies } from './plugin';
import { addHelpMenuToAppChrome } from './utils/util';
-
interface DevToolsWrapperProps {
devTools: readonly DevToolApp[];
activeDevTool: DevToolApp;
@@ -57,6 +57,7 @@ interface DevToolsWrapperProps {
notifications: NotificationsStart;
dataSourceEnabled: boolean;
hideLocalCluster: boolean;
+ uiSettings: IUiSettingsClient;
}
interface MountedDevToolDescriptor {
@@ -73,6 +74,7 @@ function DevToolsWrapper({
notifications: { toasts },
dataSourceEnabled,
hideLocalCluster,
+ uiSettings,
}: DevToolsWrapperProps) {
const mountedTool = useRef(null);
@@ -140,6 +142,7 @@ function DevToolsWrapper({
disabled={!dataSourceEnabled}
hideLocalCluster={hideLocalCluster}
fullWidth={false}
+ uiSettings={uiSettings}
/>
) : null}
@@ -213,7 +216,7 @@ function setBreadcrumbs(chrome: ChromeStart) {
}
export function renderApp(
- { application, chrome, docLinks, savedObjects, notifications }: CoreStart,
+ { application, chrome, docLinks, savedObjects, notifications, uiSettings }: CoreStart,
element: HTMLElement,
history: ScopedHistory,
devTools: readonly DevToolApp[],
@@ -251,6 +254,7 @@ export function renderApp(
notifications={notifications}
dataSourceEnabled={dataSourceEnabled}
hideLocalCluster={hideLocalCluster}
+ uiSettings={uiSettings}
/>
)}
/>
diff --git a/src/plugins/home/public/application/components/tutorial_directory.js b/src/plugins/home/public/application/components/tutorial_directory.js
index cb13d06bfb18..a36f231b38ca 100644
--- a/src/plugins/home/public/application/components/tutorial_directory.js
+++ b/src/plugins/home/public/application/components/tutorial_directory.js
@@ -236,6 +236,7 @@ class TutorialDirectoryUi extends React.Component {
onSelectedDataSource={this.onSelectedDataSourceChange}
disabled={!isDataSourceEnabled}
hideLocalCluster={isLocalClusterHidden}
+ uiSettings={getServices().uiSettings}
/>
) : null;