Skip to content

Commit

Permalink
[MD] Able to hide "Local Cluster" option (opensearch-project#5827)
Browse files Browse the repository at this point in the history
* [LocalCluster] support in devtool and index pattern creation page

Signed-off-by: Xinrui Bai <xinruiba@amazon.com>

* [LocalCluster] support default cluster in home tutorial page

Signed-off-by: Xinrui Bai <xinruiba@amazon.com>

* [LocalCluster] support default cluster in object import page

Signed-off-by: Xinrui Bai <xinruiba@amazon.com>

---------

Signed-off-by: Xinrui Bai <xinruiba@amazon.com>
  • Loading branch information
xinruiba committed Feb 15, 2024
1 parent e08bf30 commit 26fc902
Show file tree
Hide file tree
Showing 37 changed files with 721 additions and 189 deletions.
2 changes: 1 addition & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ Inspired from [Keep a Changelog](https://keepachangelog.com/en/1.0.0/)
- [Multiple Datasource] Add datasource picker component and use it in devtools and tutorial page when multiple datasource is enabled ([#5756](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/5756))
- [Multiple Datasource] Add datasource picker to import saved object flyout when multiple data source is enabled ([#5781](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/5781))
- [Multiple Datasource] Add interfaces to register add-on authentication method from plug-in module ([#5851](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/5851))
- [Multiple Datasource] Able to Hide "Local Cluster" option from datasource DropDown ([#5827](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/5827))

### 🐛 Bug Fixes

Expand Down Expand Up @@ -66,7 +67,6 @@ Inspired from [Keep a Changelog](https://keepachangelog.com/en/1.0.0/)
- [BUG] Remove duplicate sample data as id 90943e30-9a47-11e8-b64d-95841ca0b247 ([5668](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/5668))
- [BUG][Multiple Datasource] Fix datasource testing connection unexpectedly passed with wrong endpoint [#5663](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/5663)
- [Table Visualization] Fix filter action buttons for split table aggregations ([#5619](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/5619))
- [BUG][Multiple Datasource] Datasource id is required if multiple datasource is enabled and no default cluster supported [#5751](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/5751)

### 🚞 Infrastructure

Expand Down
4 changes: 2 additions & 2 deletions config/opensearch_dashboards.yml
Original file line number Diff line number Diff line change
Expand Up @@ -237,8 +237,8 @@

# Set the value of this setting to true to enable multiple data source feature.
#data_source.enabled: false
# Set the value of this setting to false to disable default cluster in data source feature.
#data_source.defaultCluster: true
# Set the value of this setting to true to hide local cluster in data source feature.
#data_source.hideLocalCluster: false
# Set the value of these settings to customize crypto materials to encryption saved credentials
# in data sources.
#data_source.encryption.wrappingKeyName: 'changeme'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ import { getEndpointFromPosition } from '../../../../../lib/autocomplete/get_end
import * as consoleMenuActions from '../console_menu_actions';
import { Editor } from './editor';

describe('Legacy (Ace) Console Editor Component Smoke Test', () => {
describe('Legacy (Ace) Console Editor Component Smoke Test with dataSourceId', () => {
let mockedAppContextValue: ContextValue;
const sandbox = sinon.createSandbox();

Expand All @@ -63,7 +63,70 @@ describe('Legacy (Ace) Console Editor Component Smoke Test', () => {
<ServicesContextProvider value={mockedAppContextValue}>
<RequestContextProvider>
<EditorContextProvider settings={{} as any}>
<Editor initialTextValue="" />
<Editor initialTextValue="" dataSourceId="Some dataSource Id" />
</EditorContextProvider>
</RequestContextProvider>
</ServicesContextProvider>
</I18nProvider>
);

beforeEach(() => {
document.queryCommandSupported = sinon.fake(() => true);
mockedAppContextValue = serviceContextMock.create();
});

afterEach(() => {
jest.clearAllMocks();
sandbox.restore();
});

it('calls send current request to OpenSearch', async () => {
(getEndpointFromPosition as jest.Mock).mockReturnValue({ patterns: [] });
(sendRequestToOpenSearch as jest.Mock).mockRejectedValue({});
const editor = doMount();
act(() => {
editor.find('[data-test-subj~="sendRequestButton"]').simulate('click');
});
await nextTick();
expect(sendRequestToOpenSearch).toBeCalledTimes(1);
});

it('opens docs', () => {
const stub = sandbox.stub(consoleMenuActions, 'getDocumentation');
const editor = doMount();
const consoleMenuToggle = editor.find('[data-test-subj~="toggleConsoleMenu"]').last();
consoleMenuToggle.simulate('click');

const docsButton = editor.find('[data-test-subj~="consoleMenuOpenDocs"]').last();
docsButton.simulate('click');

expect(stub.callCount).toBe(1);
});

it('prompts auto-indent', () => {
const stub = sandbox.stub(consoleMenuActions, 'autoIndent');
const editor = doMount();
const consoleMenuToggle = editor.find('[data-test-subj~="toggleConsoleMenu"]').last();
consoleMenuToggle.simulate('click');

const autoIndentButton = editor.find('[data-test-subj~="consoleMenuAutoIndent"]').last();
autoIndentButton.simulate('click');

expect(stub.callCount).toBe(1);
});
});

describe('Legacy (Ace) Console Editor Component Smoke Test with empty dataSourceId (Local Cluster)', () => {
let mockedAppContextValue: ContextValue;
const sandbox = sinon.createSandbox();

const doMount = () =>
mount(
<I18nProvider>
<ServicesContextProvider value={mockedAppContextValue}>
<RequestContextProvider>
<EditorContextProvider settings={{} as any}>
<Editor initialTextValue="" dataSourceId="" />
</EditorContextProvider>
</RequestContextProvider>
</ServicesContextProvider>
Expand Down Expand Up @@ -115,3 +178,73 @@ describe('Legacy (Ace) Console Editor Component Smoke Test', () => {
expect(stub.callCount).toBe(1);
});
});

describe('Legacy (Ace) Console Editor Component Smoke Test with dataSouceId undefined', () => {
let mockedAppContextValue: ContextValue;
const sandbox = sinon.createSandbox();

const doMount = () =>
mount(
<I18nProvider>
<ServicesContextProvider value={mockedAppContextValue}>
<RequestContextProvider>
<EditorContextProvider settings={{} as any}>
<Editor initialTextValue="" />
</EditorContextProvider>
</RequestContextProvider>
</ServicesContextProvider>
</I18nProvider>
);

beforeEach(() => {
document.queryCommandSupported = sinon.fake(() => true);
mockedAppContextValue = serviceContextMock.create();
});

afterEach(() => {
jest.clearAllMocks();
sandbox.restore();
});

it('diasbles send request button', async () => {
(getEndpointFromPosition as jest.Mock).mockReturnValue({ patterns: [] });
(sendRequestToOpenSearch as jest.Mock).mockRejectedValue({});
const editor = doMount();
expect(editor.find('[data-test-subj~="sendRequestButton"]').get(0).props.disabled);
});

it('not able to send current request to OpenSearch', async () => {
(getEndpointFromPosition as jest.Mock).mockReturnValue({ patterns: [] });
(sendRequestToOpenSearch as jest.Mock).mockRejectedValue({});
const editor = doMount();
act(() => {
editor.find('[data-test-subj~="sendRequestButton"]').simulate('click');
});
await nextTick();
expect(sendRequestToOpenSearch).toBeCalledTimes(0);
});

it('opens docs', () => {
const stub = sandbox.stub(consoleMenuActions, 'getDocumentation');
const editor = doMount();
const consoleMenuToggle = editor.find('[data-test-subj~="toggleConsoleMenu"]').last();
consoleMenuToggle.simulate('click');

const docsButton = editor.find('[data-test-subj~="consoleMenuOpenDocs"]').last();
docsButton.simulate('click');

expect(stub.callCount).toBe(1);
});

it('prompts auto-indent', () => {
const stub = sandbox.stub(consoleMenuActions, 'autoIndent');
const editor = doMount();
const consoleMenuToggle = editor.find('[data-test-subj~="toggleConsoleMenu"]').last();
consoleMenuToggle.simulate('click');

const autoIndentButton = editor.find('[data-test-subj~="consoleMenuAutoIndent"]').last();
autoIndentButton.simulate('click');

expect(stub.callCount).toBe(1);
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -228,6 +228,11 @@ function EditorUI({ initialTextValue, dataSourceId }: EditorProps) {
});
}, [sendCurrentRequestToOpenSearch, openDocumentation]);

const tooltipDefaultMessage =
dataSourceId === undefined ? `Select a data source` : `Click to send request`;

const toolTipButtonDiasbled = dataSourceId === undefined;

return (
<div style={abs} className="conApp">
<div className="conApp__editor">
Expand All @@ -240,16 +245,17 @@ function EditorUI({ initialTextValue, dataSourceId }: EditorProps) {
<EuiFlexItem>
<EuiToolTip
content={i18n.translate('console.sendRequestButtonTooltip', {
defaultMessage: 'Click to send request',
defaultMessage: tooltipDefaultMessage,
})}
>
<button
onClick={sendCurrentRequestToOpenSearch}
data-test-subj="sendRequestButton"
aria-label={i18n.translate('console.sendRequestButtonTooltip', {
defaultMessage: 'Click to send request',
defaultMessage: tooltipDefaultMessage,
})}
className="conApp__editorActionButton conApp__editorActionButton--success"
disabled={toolTipButtonDiasbled}
>
<EuiIcon type="play" />
</button>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,14 @@ import { IOpenSearchSearchRequest } from '..';
export const decideClient = async (
context: RequestHandlerContext,
request: IOpenSearchSearchRequest,
withDataSourceEnabled: boolean = false,
withLongNumeralsSupport: boolean = false
): Promise<OpenSearchClient> => {
const defaultOpenSearchClient = withLongNumeralsSupport
? context.core.opensearch.client.asCurrentUserWithLongNumeralsSupport
: context.core.opensearch.client.asCurrentUser;

return withDataSourceEnabled && request.dataSourceId && context.dataSource
? await context.dataSource.opensearch.getClient(request.dataSourceId)
: defaultOpenSearchClient;
// if data source feature is disabled, return default opensearch client of current user
const client =
request.dataSourceId && context.dataSource
? await context.dataSource.opensearch.getClient(request.dataSourceId)
: withLongNumeralsSupport
? context.core.opensearch.client.asCurrentUserWithLongNumeralsSupport
: context.core.opensearch.client.asCurrentUser;
return client;
};
Original file line number Diff line number Diff line change
Expand Up @@ -33,20 +33,11 @@ import { pluginInitializerContextConfigMock } from '../../../../../core/server/m
import { opensearchSearchStrategyProvider } from './opensearch_search_strategy';
import { DataSourceError } from '../../../../data_source/server/lib/error';
import { DataSourcePluginSetup } from '../../../../data_source/server';
import { SearchUsage } from '../collectors';

describe('OpenSearch search strategy', () => {
const mockLogger: any = {
debug: () => {},
};
const mockSearchUsage: SearchUsage = {
trackError(): Promise<void> {
return Promise.resolve(undefined);
},
trackSuccess(duration: number): Promise<void> {
return Promise.resolve(undefined);
},
};
const body = {
body: {
_shards: {
Expand Down Expand Up @@ -140,21 +131,8 @@ describe('OpenSearch search strategy', () => {
expect(response).toHaveProperty('rawResponse');
});

it('dataSource enabled and default cluster disabled, send request with dataSourceId get data source client', async () => {
const mockDataSourcePluginSetupWithDataSourceEnabled: DataSourcePluginSetup = {
createDataSourceError(err: any): DataSourceError {
return new DataSourceError({});
},
dataSourceEnabled: jest.fn(() => true),
defaultClusterEnabled: jest.fn(() => false),
};

const opensearchSearch = await opensearchSearchStrategyProvider(
mockConfig$,
mockLogger,
mockSearchUsage,
mockDataSourcePluginSetupWithDataSourceEnabled
);
it('dataSource enabled, send request with dataSourceId get data source client', async () => {
const opensearchSearch = await opensearchSearchStrategyProvider(mockConfig$, mockLogger);

await opensearchSearch.search(
(mockDataSourceEnabledContext as unknown) as RequestHandlerContext,
Expand All @@ -166,35 +144,6 @@ describe('OpenSearch search strategy', () => {
expect(mockOpenSearchApiCaller).not.toBeCalled();
});

it('dataSource enabled and default cluster disabled, send request with empty dataSourceId should throw exception', async () => {
const mockDataSourcePluginSetupWithDataSourceEnabled: DataSourcePluginSetup = {
createDataSourceError(err: any): DataSourceError {
return new DataSourceError({});
},
dataSourceEnabled: jest.fn(() => true),
defaultClusterEnabled: jest.fn(() => false),
};

try {
const opensearchSearch = opensearchSearchStrategyProvider(
mockConfig$,
mockLogger,
mockSearchUsage,
mockDataSourcePluginSetupWithDataSourceEnabled
);

await opensearchSearch.search(
(mockDataSourceEnabledContext as unknown) as RequestHandlerContext,
{
dataSourceId: '',
}
);
} catch (e) {
expect(e).toBeTruthy();
expect(e).toBeInstanceOf(DataSourceError);
}
});

it('dataSource disabled, send request with dataSourceId get default client', async () => {
const opensearchSearch = await opensearchSearchStrategyProvider(mockConfig$, mockLogger);

Expand All @@ -205,47 +154,8 @@ describe('OpenSearch search strategy', () => {
expect(mockDataSourceApiCaller).not.toBeCalled();
});

it('dataSource enabled and default cluster enabled, send request with dataSourceId get datasource client', async () => {
const mockDataSourcePluginSetupWithDataSourceEnabled: DataSourcePluginSetup = {
createDataSourceError(err: any): DataSourceError {
return new DataSourceError({});
},
dataSourceEnabled: jest.fn(() => true),
defaultClusterEnabled: jest.fn(() => true),
};

const opensearchSearch = await opensearchSearchStrategyProvider(
mockConfig$,
mockLogger,
mockSearchUsage,
mockDataSourcePluginSetupWithDataSourceEnabled
);

await opensearchSearch.search(
(mockDataSourceEnabledContext as unknown) as RequestHandlerContext,
{
dataSourceId,
}
);
expect(mockDataSourceApiCaller).toBeCalled();
expect(mockOpenSearchApiCaller).not.toBeCalled();
});

it('dataSource enabled and default cluster enabled, send request without dataSourceId get default client', async () => {
const mockDataSourcePluginSetupWithDataSourceEnabled: DataSourcePluginSetup = {
createDataSourceError(err: any): DataSourceError {
return new DataSourceError({});
},
dataSourceEnabled: jest.fn(() => true),
defaultClusterEnabled: jest.fn(() => true),
};

const opensearchSearch = await opensearchSearchStrategyProvider(
mockConfig$,
mockLogger,
mockSearchUsage,
mockDataSourcePluginSetupWithDataSourceEnabled
);
it('dataSource enabled, send request without dataSourceId get default client', async () => {
const opensearchSearch = await opensearchSearchStrategyProvider(mockConfig$, mockLogger);

await opensearchSearch.search((mockContext as unknown) as RequestHandlerContext, {});
expect(mockOpenSearchApiCaller).toBeCalled();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,20 +73,7 @@ export const opensearchSearchStrategyProvider = (
});

try {
if (
dataSource?.dataSourceEnabled() &&
!dataSource?.defaultClusterEnabled() &&
!request.dataSourceId
) {
throw new Error(`Data source id is required when no openseach hosts config provided`);
}

const client = await decideClient(
context,
request,
dataSource?.dataSourceEnabled(),
withLongNumeralsSupport
);
const client = await decideClient(context, request, withLongNumeralsSupport);
const promise = shimAbortSignal(client.search(params), options?.abortSignal);

const { body: rawResponse } = (await promise) as ApiResponse<SearchResponse<any>>;
Expand All @@ -105,7 +92,7 @@ export const opensearchSearchStrategyProvider = (
} catch (e) {
if (usage) usage.trackError();

if (dataSource?.dataSourceEnabled()) {
if (dataSource && request.dataSourceId) {
throw dataSource.createDataSourceError(e);
}
throw e;
Expand Down
Loading

0 comments on commit 26fc902

Please sign in to comment.