diff --git a/changelogs/fragments/7143.yml b/changelogs/fragments/7143.yml new file mode 100644 index 000000000000..dfc286467ab0 --- /dev/null +++ b/changelogs/fragments/7143.yml @@ -0,0 +1,2 @@ +feat: +- [MDS] Observability Datasource Plugin migration with MDS support ([#7143](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/7143)) \ No newline at end of file diff --git a/changelogs/fragments/7163.yml b/changelogs/fragments/7163.yml new file mode 100644 index 000000000000..0b9609a4de20 --- /dev/null +++ b/changelogs/fragments/7163.yml @@ -0,0 +1,2 @@ +fix: +- [MDS] Fix the dsm plugin setup when mds feature flag is disabled ([#7163](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/7163)) \ No newline at end of file diff --git a/changelogs/fragments/7371.yml b/changelogs/fragments/7371.yml new file mode 100644 index 000000000000..a78822aa5114 --- /dev/null +++ b/changelogs/fragments/7371.yml @@ -0,0 +1,2 @@ +feat: +- [MDS] Observability Datasource Plugin migration with MDS support for Data Connection Table ([#7371](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/7371)) \ No newline at end of file diff --git a/src/core/public/doc_links/doc_links_service.ts b/src/core/public/doc_links/doc_links_service.ts index 41f97033c5e3..edfb02f6c35c 100644 --- a/src/core/public/doc_links/doc_links_service.ts +++ b/src/core/public/doc_links/doc_links_service.ts @@ -419,6 +419,8 @@ export class DocLinksService { dataSource: { // https://opensearch.org/docs/latest/dashboards/discover/multi-data-sources/ guide: `${OPENSEARCH_DASHBOARDS_VERSIONED_DOCS}discover/multi-data-sources/`, + // https://opensearch.org/docs/latest/dashboards/management/S3-data-source/ + s3DataSource: `${OPENSEARCH_DASHBOARDS_VERSIONED_DOCS}management/S3-data-source/`, }, visualize: { // https://opensearch.org/docs/latest/dashboards/visualize/viz-index/ @@ -821,6 +823,7 @@ export interface DocLinksStart { readonly browser: string; readonly dataSource: { readonly guide: string; + readonly s3DataSource: string; }; readonly visualize: Record; readonly management: Record; diff --git a/src/plugins/dashboard/public/application/components/dashboard_listing/__snapshots__/dashboard_listing.test.tsx.snap b/src/plugins/dashboard/public/application/components/dashboard_listing/__snapshots__/dashboard_listing.test.tsx.snap index 215591e2d4c5..68f84dc3394e 100644 --- a/src/plugins/dashboard/public/application/components/dashboard_listing/__snapshots__/dashboard_listing.test.tsx.snap +++ b/src/plugins/dashboard/public/application/components/dashboard_listing/__snapshots__/dashboard_listing.test.tsx.snap @@ -831,6 +831,7 @@ exports[`dashboard listing hideWriteControls 1`] = ` "browser": "https://opensearch.org/docs/mocked-test-branch/dashboards/browser-compatibility", "dataSource": Object { "guide": "https://opensearch.org/docs/mocked-test-branch/dashboards/discover/multi-data-sources/", + "s3DataSource": "https://opensearch.org/docs/mocked-test-branch/dashboards/management/S3-data-source/", }, "devTools": "https://opensearch.org/docs/mocked-test-branch/dashboards/dev-tools/index-dev/", "dql": Object { @@ -2018,6 +2019,7 @@ exports[`dashboard listing render table listing with initial filters from URL 1` "browser": "https://opensearch.org/docs/mocked-test-branch/dashboards/browser-compatibility", "dataSource": Object { "guide": "https://opensearch.org/docs/mocked-test-branch/dashboards/discover/multi-data-sources/", + "s3DataSource": "https://opensearch.org/docs/mocked-test-branch/dashboards/management/S3-data-source/", }, "devTools": "https://opensearch.org/docs/mocked-test-branch/dashboards/dev-tools/index-dev/", "dql": Object { @@ -3266,6 +3268,7 @@ exports[`dashboard listing renders call to action when no dashboards exist 1`] = "browser": "https://opensearch.org/docs/mocked-test-branch/dashboards/browser-compatibility", "dataSource": Object { "guide": "https://opensearch.org/docs/mocked-test-branch/dashboards/discover/multi-data-sources/", + "s3DataSource": "https://opensearch.org/docs/mocked-test-branch/dashboards/management/S3-data-source/", }, "devTools": "https://opensearch.org/docs/mocked-test-branch/dashboards/dev-tools/index-dev/", "dql": Object { @@ -4514,6 +4517,7 @@ exports[`dashboard listing renders table rows 1`] = ` "browser": "https://opensearch.org/docs/mocked-test-branch/dashboards/browser-compatibility", "dataSource": Object { "guide": "https://opensearch.org/docs/mocked-test-branch/dashboards/discover/multi-data-sources/", + "s3DataSource": "https://opensearch.org/docs/mocked-test-branch/dashboards/management/S3-data-source/", }, "devTools": "https://opensearch.org/docs/mocked-test-branch/dashboards/dev-tools/index-dev/", "dql": Object { @@ -5762,6 +5766,7 @@ exports[`dashboard listing renders warning when listingLimit is exceeded 1`] = ` "browser": "https://opensearch.org/docs/mocked-test-branch/dashboards/browser-compatibility", "dataSource": Object { "guide": "https://opensearch.org/docs/mocked-test-branch/dashboards/discover/multi-data-sources/", + "s3DataSource": "https://opensearch.org/docs/mocked-test-branch/dashboards/management/S3-data-source/", }, "devTools": "https://opensearch.org/docs/mocked-test-branch/dashboards/dev-tools/index-dev/", "dql": Object { diff --git a/src/plugins/dashboard/public/application/components/dashboard_top_nav/__snapshots__/dashboard_top_nav.test.tsx.snap b/src/plugins/dashboard/public/application/components/dashboard_top_nav/__snapshots__/dashboard_top_nav.test.tsx.snap index acc6217ab4f9..a48e917ce8e3 100644 --- a/src/plugins/dashboard/public/application/components/dashboard_top_nav/__snapshots__/dashboard_top_nav.test.tsx.snap +++ b/src/plugins/dashboard/public/application/components/dashboard_top_nav/__snapshots__/dashboard_top_nav.test.tsx.snap @@ -723,6 +723,7 @@ exports[`Dashboard top nav render in embed mode 1`] = ` "browser": "https://opensearch.org/docs/mocked-test-branch/dashboards/browser-compatibility", "dataSource": Object { "guide": "https://opensearch.org/docs/mocked-test-branch/dashboards/discover/multi-data-sources/", + "s3DataSource": "https://opensearch.org/docs/mocked-test-branch/dashboards/management/S3-data-source/", }, "devTools": "https://opensearch.org/docs/mocked-test-branch/dashboards/dev-tools/index-dev/", "dql": Object { @@ -1732,6 +1733,7 @@ exports[`Dashboard top nav render in embed mode, and force hide filter bar 1`] = "browser": "https://opensearch.org/docs/mocked-test-branch/dashboards/browser-compatibility", "dataSource": Object { "guide": "https://opensearch.org/docs/mocked-test-branch/dashboards/discover/multi-data-sources/", + "s3DataSource": "https://opensearch.org/docs/mocked-test-branch/dashboards/management/S3-data-source/", }, "devTools": "https://opensearch.org/docs/mocked-test-branch/dashboards/dev-tools/index-dev/", "dql": Object { @@ -2741,6 +2743,7 @@ exports[`Dashboard top nav render in embed mode, components can be forced show b "browser": "https://opensearch.org/docs/mocked-test-branch/dashboards/browser-compatibility", "dataSource": Object { "guide": "https://opensearch.org/docs/mocked-test-branch/dashboards/discover/multi-data-sources/", + "s3DataSource": "https://opensearch.org/docs/mocked-test-branch/dashboards/management/S3-data-source/", }, "devTools": "https://opensearch.org/docs/mocked-test-branch/dashboards/dev-tools/index-dev/", "dql": Object { @@ -3750,6 +3753,7 @@ exports[`Dashboard top nav render in full screen mode with appended URL param bu "browser": "https://opensearch.org/docs/mocked-test-branch/dashboards/browser-compatibility", "dataSource": Object { "guide": "https://opensearch.org/docs/mocked-test-branch/dashboards/discover/multi-data-sources/", + "s3DataSource": "https://opensearch.org/docs/mocked-test-branch/dashboards/management/S3-data-source/", }, "devTools": "https://opensearch.org/docs/mocked-test-branch/dashboards/dev-tools/index-dev/", "dql": Object { @@ -4759,6 +4763,7 @@ exports[`Dashboard top nav render in full screen mode, no componenets should be "browser": "https://opensearch.org/docs/mocked-test-branch/dashboards/browser-compatibility", "dataSource": Object { "guide": "https://opensearch.org/docs/mocked-test-branch/dashboards/discover/multi-data-sources/", + "s3DataSource": "https://opensearch.org/docs/mocked-test-branch/dashboards/management/S3-data-source/", }, "devTools": "https://opensearch.org/docs/mocked-test-branch/dashboards/dev-tools/index-dev/", "dql": Object { @@ -5768,6 +5773,7 @@ exports[`Dashboard top nav render with all components 1`] = ` "browser": "https://opensearch.org/docs/mocked-test-branch/dashboards/browser-compatibility", "dataSource": Object { "guide": "https://opensearch.org/docs/mocked-test-branch/dashboards/discover/multi-data-sources/", + "s3DataSource": "https://opensearch.org/docs/mocked-test-branch/dashboards/management/S3-data-source/", }, "devTools": "https://opensearch.org/docs/mocked-test-branch/dashboards/dev-tools/index-dev/", "dql": Object { diff --git a/src/plugins/data_source_management/opensearch_dashboards.json b/src/plugins/data_source_management/opensearch_dashboards.json index 824f9eacc9f6..691667eee458 100644 --- a/src/plugins/data_source_management/opensearch_dashboards.json +++ b/src/plugins/data_source_management/opensearch_dashboards.json @@ -3,8 +3,8 @@ "version": "opensearchDashboards", "server": false, "ui": true, - "requiredPlugins": ["management", "dataSource", "indexPatternManagement"], - "optionalPlugins": [], + "requiredPlugins": ["management", "indexPatternManagement"], + "optionalPlugins": ["dataSource"], "requiredBundles": ["opensearchDashboardsReact", "dataSource", "opensearchDashboardsUtils"], "extraPublicDirs": ["public/components/utils"] } diff --git a/src/plugins/data_source_management/public/components/breadcrumbs.test.ts b/src/plugins/data_source_management/public/components/breadcrumbs.test.ts index fbf1c62bb7dc..50c6b5a0655e 100644 --- a/src/plugins/data_source_management/public/components/breadcrumbs.test.ts +++ b/src/plugins/data_source_management/public/components/breadcrumbs.test.ts @@ -3,7 +3,14 @@ * SPDX-License-Identifier: Apache-2.0 */ -import { getCreateBreadcrumbs, getEditBreadcrumbs, getListBreadcrumbs } from './breadcrumbs'; +import { + getCreateBreadcrumbs, + getEditBreadcrumbs, + getListBreadcrumbs, + getCreateOpenSearchDataSourceBreadcrumbs, + getCreateAmazonS3DataSourceBreadcrumbs, + getCreatePrometheusDataSourceBreadcrumbs, +} from './breadcrumbs'; import { mockDataSourceAttributesWithAuth } from '../mocks'; describe('DataSourceManagement: breadcrumbs.ts', () => { @@ -26,4 +33,25 @@ describe('DataSourceManagement: breadcrumbs.ts', () => { expect(bc[1].text).toBe(mockDataSourceAttributesWithAuth.title); expect(bc[1].href).toBe(`/${mockDataSourceAttributesWithAuth.id}`); }); + + test('get create OpenSearch breadcrumb', () => { + const bc = getCreateOpenSearchDataSourceBreadcrumbs(); + expect(bc.length).toBe(3); + expect(bc[2].text).toBe('Open Search'); + expect(bc[2].href).toBe('/configure/OpenSearch'); + }); + + test('get create Amazon S3 breadcrumb', () => { + const bc = getCreateAmazonS3DataSourceBreadcrumbs(); + expect(bc.length).toBe(3); + expect(bc[2].text).toBe('Amazon S3'); + expect(bc[2].href).toBe('/configure/AmazonS3AWSGlue'); + }); + + test('get create Prometheus breadcrumb', () => { + const bc = getCreatePrometheusDataSourceBreadcrumbs(); + expect(bc.length).toBe(3); + expect(bc[2].text).toBe('Prometheus'); + expect(bc[2].href).toBe('/configure/Prometheus'); + }); }); diff --git a/src/plugins/data_source_management/public/components/breadcrumbs.ts b/src/plugins/data_source_management/public/components/breadcrumbs.ts index ad1b470c89d4..cabe632d9dac 100644 --- a/src/plugins/data_source_management/public/components/breadcrumbs.ts +++ b/src/plugins/data_source_management/public/components/breadcrumbs.ts @@ -28,6 +28,50 @@ export function getCreateBreadcrumbs() { }, ]; } +export function getCreateOpenSearchDataSourceBreadcrumbs() { + return [ + ...getCreateBreadcrumbs(), + { + text: i18n.translate( + 'dataSourcesManagement.dataSources.createOpenSearchDataSourceBreadcrumbs', + { + defaultMessage: 'Open Search', + } + ), + href: `/configure/OpenSearch`, + }, + ]; +} + +export function getCreateAmazonS3DataSourceBreadcrumbs() { + return [ + ...getCreateBreadcrumbs(), + { + text: i18n.translate( + 'dataSourcesManagement.dataSources.createAmazonS3DataSourceBreadcrumbs', + { + defaultMessage: 'Amazon S3', + } + ), + href: `/configure/AmazonS3AWSGlue`, + }, + ]; +} + +export function getCreatePrometheusDataSourceBreadcrumbs() { + return [ + ...getCreateBreadcrumbs(), + { + text: i18n.translate( + 'dataSourcesManagement.dataSources.createPrometheusDataSourceBreadcrumbs', + { + defaultMessage: 'Prometheus', + } + ), + href: `/configure/Prometheus`, + }, + ]; +} export function getEditBreadcrumbs(dataSource: DataSourceAttributes) { return [ diff --git a/src/plugins/data_source_management/public/components/constants.tsx b/src/plugins/data_source_management/public/components/constants.tsx index bfb720980132..8d9d369de382 100644 --- a/src/plugins/data_source_management/public/components/constants.tsx +++ b/src/plugins/data_source_management/public/components/constants.tsx @@ -5,6 +5,7 @@ import { i18n } from '@osd/i18n'; import { DataSourceOption } from './data_source_menu/types'; +import { DatasourceType } from '../types'; export const LocalCluster: DataSourceOption = { label: i18n.translate('dataSource.localCluster', { @@ -19,3 +20,29 @@ export const NO_COMPATIBLE_DATASOURCES_MESSAGE = 'No compatible data sources are export const ADD_COMPATIBLE_DATASOURCES_MESSAGE = 'Add a compatible data source.'; export { DEFAULT_DATA_SOURCE_UI_SETTINGS_ID } from '../../common'; + +export const OPENSEARCH_DOCUMENTATION_URL = + 'https://opensearch.org/docs/latest/dashboards/management/data-sources/'; + +export const OPENSEARCH_S3_DOCUMENTATION_URL = + 'https://opensearch.org/docs/latest/dashboards/management/S3-data-source/'; + +export const OPENSEARCH_ACC_DOCUMENTATION_URL = + 'https://opensearch.org/docs/latest/dashboards/management/accelerate-external-data/'; +export const QUERY_RESTRICTED = 'query-restricted'; +export const QUERY_ALL = 'query-all'; + +export const DatasourceTypeToDisplayName: { [key in DatasourceType]: string } = { + PROMETHEUS: 'Prometheus', + S3GLUE: 'Amazon S3', +}; + +export const PrometheusURL = 'Prometheus'; +export const AmazonS3URL = 'AmazonS3AWSGlue'; + +export const UrlToDatasourceType: { [key: string]: DatasourceType } = { + [PrometheusURL]: 'PROMETHEUS', + [AmazonS3URL]: 'S3GLUE', +}; + +export type AuthMethod = 'noauth' | 'basicauth' | 'awssigv4'; diff --git a/src/plugins/data_source_management/public/components/create_data_source_wizard/create_data_source_wizard.test.tsx b/src/plugins/data_source_management/public/components/create_data_source_wizard/create_data_source_wizard.test.tsx index 5bffaee5d3d9..353acd36aaea 100644 --- a/src/plugins/data_source_management/public/components/create_data_source_wizard/create_data_source_wizard.test.tsx +++ b/src/plugins/data_source_management/public/components/create_data_source_wizard/create_data_source_wizard.test.tsx @@ -107,7 +107,7 @@ describe('Datasource Management: Create Datasource Wizard', () => { await component.find(formIdentifier).first().prop('handleCancel')(); }); - expect(history.push).toBeCalledWith(''); + expect(history.push).toBeCalledWith('/create'); }); }); diff --git a/src/plugins/data_source_management/public/components/create_data_source_wizard/create_data_source_wizard.tsx b/src/plugins/data_source_management/public/components/create_data_source_wizard/create_data_source_wizard.tsx index 671647c48f48..0be281a20a38 100644 --- a/src/plugins/data_source_management/public/components/create_data_source_wizard/create_data_source_wizard.tsx +++ b/src/plugins/data_source_management/public/components/create_data_source_wizard/create_data_source_wizard.tsx @@ -14,7 +14,7 @@ import { DataSourceTableItem, ToastMessageItem, } from '../../types'; -import { getCreateBreadcrumbs } from '../breadcrumbs'; +import { getCreateOpenSearchDataSourceBreadcrumbs } from '../breadcrumbs'; import { CreateDataSourceForm } from './components/create_form'; import { createSingleDataSource, @@ -45,7 +45,7 @@ export const CreateDataSourceWizard: React.FunctionComponent { - setBreadcrumbs(getCreateBreadcrumbs()); + setBreadcrumbs(getCreateOpenSearchDataSourceBreadcrumbs()); getExistingDataSourceNames(); }); @@ -130,7 +130,7 @@ export const CreateDataSourceWizard: React.FunctionComponent props.history.push('')} + handleCancel={() => props.history.push('/create')} existingDatasourceNamesList={existingDatasourceNamesList} /> {isLoading ? : null} diff --git a/src/plugins/data_source_management/public/components/data_source_creation_panel/__snapshots__/create_data_source_card_view.test.tsx.snap b/src/plugins/data_source_management/public/components/data_source_creation_panel/__snapshots__/create_data_source_card_view.test.tsx.snap new file mode 100644 index 000000000000..e17647be766f --- /dev/null +++ b/src/plugins/data_source_management/public/components/data_source_creation_panel/__snapshots__/create_data_source_card_view.test.tsx.snap @@ -0,0 +1,85 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`CreateDataSourceCardView renders correctly 1`] = ` + + + + + } + onClick={[Function]} + title="Amazon S3" + titleElement="span" + /> + + + + } + onClick={[Function]} + title="Prometheus" + titleElement="span" + /> + + + + } + onClick={[Function]} + title="OpenSearch" + titleElement="span" + /> + + + + +`; diff --git a/src/plugins/data_source_management/public/components/data_source_creation_panel/__snapshots__/create_data_source_panel.test.tsx.snap b/src/plugins/data_source_management/public/components/data_source_creation_panel/__snapshots__/create_data_source_panel.test.tsx.snap new file mode 100644 index 000000000000..f2c61eecb4db --- /dev/null +++ b/src/plugins/data_source_management/public/components/data_source_creation_panel/__snapshots__/create_data_source_panel.test.tsx.snap @@ -0,0 +1,25 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`CreateDataSourcePanel renders correctly 1`] = ` + + + + + + + + + + + + +`; diff --git a/src/plugins/data_source_management/public/components/data_source_creation_panel/__snapshots__/create_data_source_panel_header.test.tsx.snap b/src/plugins/data_source_management/public/components/data_source_creation_panel/__snapshots__/create_data_source_panel_header.test.tsx.snap new file mode 100644 index 000000000000..37a770d5b362 --- /dev/null +++ b/src/plugins/data_source_management/public/components/data_source_creation_panel/__snapshots__/create_data_source_panel_header.test.tsx.snap @@ -0,0 +1,34 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`CreateDataSourcePanelHeader renders correctly 1`] = ` + + + +

+ +

+
+ + +

+ +

+
+
+
+`; diff --git a/src/plugins/data_source_management/public/components/data_source_creation_panel/create_data_source_card_view.test.tsx b/src/plugins/data_source_management/public/components/data_source_creation_panel/create_data_source_card_view.test.tsx new file mode 100644 index 000000000000..eb63df65ece3 --- /dev/null +++ b/src/plugins/data_source_management/public/components/data_source_creation_panel/create_data_source_card_view.test.tsx @@ -0,0 +1,105 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import React from 'react'; +import { shallow } from 'enzyme'; +import { EuiCard, EuiIcon } from '@elastic/eui'; +import { CreateDataSourceCardView, DatasourceCard } from './create_data_source_card_view'; +import { AMAZON_S3_URL, PROMETHEUS_URL, OPENSEARCH_URL } from '../../constants'; +import { createMemoryHistory } from 'history'; + +describe('CreateDataSourceCardView', () => { + const history = createMemoryHistory(); + const defaultProps = { + history, + featureFlagStatus: true, + }; + + const shallowComponent = (props = defaultProps) => + shallow(); + + test('renders correctly', () => { + const wrapper = shallowComponent(); + expect(wrapper).toMatchSnapshot(); + }); + + test('renders correct datasource cards', () => { + const wrapper = shallowComponent(); + const cards = wrapper.find(EuiCard); + + expect(cards).toHaveLength(3); + + const expectedDatasources: DatasourceCard[] = [ + { + name: 'S3GLUE', + displayName: 'Amazon S3', + description: 'Connect to Amazon S3 via AWS Glue Data Catalog', + displayIcon: ( + + ), + onClick: expect.any(Function), + }, + { + name: 'PROMETHEUS', + displayName: 'Prometheus', + description: 'Connect to Prometheus', + displayIcon: ( + + ), + onClick: expect.any(Function), + }, + { + name: 'OPENSEARCH', + displayName: 'OpenSearch', + description: 'Connect to OpenSearch', + displayIcon: ( + + ), + onClick: expect.any(Function), + }, + ]; + + expectedDatasources.forEach((datasource, index) => { + const card = cards.at(index); + expect(card.prop('title')).toEqual(datasource.displayName); + expect(card.prop('description')).toEqual(datasource.description); + expect(card.prop('icon')?.type).toEqual(datasource.displayIcon?.type); + }); + }); + + test('does not render OpenSearch card when featureFlagStatus is false', () => { + const wrapper = shallowComponent({ ...defaultProps, featureFlagStatus: false }); + const cards = wrapper.find(EuiCard); + + expect(cards).toHaveLength(2); + expect(cards.someWhere((card) => card.prop('title') === 'OpenSearch')).toBe(false); + }); + + test('handles card click events', () => { + const pushSpy = jest.spyOn(history, 'push'); + const wrapper = shallowComponent(); + + const s3Card = wrapper.find('[data-test-subj="datasource_card_s3glue"]'); + const prometheusCard = wrapper.find('[data-test-subj="datasource_card_prometheus"]'); + const opensearchCard = wrapper.find('[data-test-subj="datasource_card_opensearch"]'); + + s3Card.simulate('click'); + expect(pushSpy).toHaveBeenCalledWith(`/configure/${AMAZON_S3_URL}`); + + prometheusCard.simulate('click'); + expect(pushSpy).toHaveBeenCalledWith(`/configure/${PROMETHEUS_URL}`); + + if (defaultProps.featureFlagStatus) { + opensearchCard.simulate('click'); + expect(pushSpy).toHaveBeenCalledWith(`/configure/${OPENSEARCH_URL}`); + } + }); +}); diff --git a/src/plugins/data_source_management/public/components/data_source_creation_panel/create_data_source_card_view.tsx b/src/plugins/data_source_management/public/components/data_source_creation_panel/create_data_source_card_view.tsx new file mode 100644 index 000000000000..758acb312dc2 --- /dev/null +++ b/src/plugins/data_source_management/public/components/data_source_creation_panel/create_data_source_card_view.tsx @@ -0,0 +1,82 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { EuiPanel, EuiCard, EuiFlexGroup, EuiFlexItem, EuiSpacer, EuiIcon } from '@elastic/eui'; +import React from 'react'; +import { History } from 'history'; +import s3Svg from '../direct_query_data_sources_components/icons/s3_logo.svg'; +import prometheusSvg from '../direct_query_data_sources_components/icons/prometheus_logo.svg'; +import opensearchLogSvg from '../direct_query_data_sources_components/icons/opensearch_logo.svg'; +import { AMAZON_S3_URL, PROMETHEUS_URL, OPENSEARCH_URL } from '../../constants'; + +export interface DatasourceCard { + name: string; + displayName: string; + description: string; + displayIcon: JSX.Element; + onClick: () => void; +} + +interface CreateDataSourceCardViewProps { + history: History; + featureFlagStatus: boolean; +} + +export function CreateDataSourceCardView({ + history, + featureFlagStatus, +}: CreateDataSourceCardViewProps) { + const Datasources: DatasourceCard[] = [ + { + name: 'S3GLUE', + displayName: 'Amazon S3', + description: 'Connect to Amazon S3 via AWS Glue Data Catalog', + displayIcon: , + onClick: () => history.push(`/configure/${AMAZON_S3_URL}`), + }, + { + name: 'PROMETHEUS', + displayName: 'Prometheus', + description: 'Connect to Prometheus', + displayIcon: , + onClick: () => history.push(`/configure/${PROMETHEUS_URL}`), + }, + ...(featureFlagStatus + ? [ + { + name: 'OPENSEARCH', + displayName: 'OpenSearch', + description: 'Connect to OpenSearch', + displayIcon: , + onClick: () => history.push(`/configure/${OPENSEARCH_URL}`), + }, + ] + : []), + ]; + + const renderRows = (datasources: DatasourceCard[]) => { + return ( + <> + + {datasources.map((i) => ( + + + + ))} + + + + ); + }; + + return {renderRows(Datasources)}; +} diff --git a/src/plugins/data_source_management/public/components/data_source_creation_panel/create_data_source_description.tsx b/src/plugins/data_source_management/public/components/data_source_creation_panel/create_data_source_description.tsx new file mode 100644 index 000000000000..91f13c66624e --- /dev/null +++ b/src/plugins/data_source_management/public/components/data_source_creation_panel/create_data_source_description.tsx @@ -0,0 +1,24 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { EuiSpacer, EuiText, EuiTitle, EuiHorizontalRule } from '@elastic/eui'; +import React from 'react'; + +export const NewDatasourceDescription = () => { + return ( +
+ +

Create a new data source

+
+ + + + Connect to a compatible data source or compute engine to bring your data into OpenSearch and + OpenSearch Dashboards. + + +
+ ); +}; diff --git a/src/plugins/data_source_management/public/components/data_source_creation_panel/create_data_source_panel.test.tsx b/src/plugins/data_source_management/public/components/data_source_creation_panel/create_data_source_panel.test.tsx new file mode 100644 index 000000000000..5884dadc5876 --- /dev/null +++ b/src/plugins/data_source_management/public/components/data_source_creation_panel/create_data_source_panel.test.tsx @@ -0,0 +1,64 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import React from 'react'; +import { shallow } from 'enzyme'; +import { CreateDataSourcePanel } from './create_data_source_panel'; +import { CreateDataSourcePanelHeader } from './create_data_source_panel_header'; +import { CreateDataSourceCardView } from './create_data_source_card_view'; +import { useOpenSearchDashboards } from '../../../../opensearch_dashboards_react/public'; +import { getCreateBreadcrumbs } from '../breadcrumbs'; +import { DataSourceManagementContext } from '../../types'; +import { RouteComponentProps } from 'react-router-dom'; + +jest.mock('../../../../opensearch_dashboards_react/public'); +jest.mock('../breadcrumbs'); +jest.mock('./create_data_source_panel_header', () => ({ + CreateDataSourcePanelHeader: () =>
CreateDataSourcePanelHeader
, +})); +jest.mock('./create_data_source_card_view', () => ({ + CreateDataSourceCardView: () =>
CreateDataSourceCardView
, +})); + +describe('CreateDataSourcePanel', () => { + const mockedContext = { + services: { + chrome: {}, + setBreadcrumbs: jest.fn(), + notifications: { + toasts: { + addSuccess: jest.fn(), + addDanger: jest.fn(), + }, + }, + uiSettings: {}, + }, + }; + + beforeAll(() => { + (useOpenSearchDashboards as jest.Mock).mockReturnValue(mockedContext); + (getCreateBreadcrumbs as jest.Mock).mockReturnValue([{ text: 'Create Data Source' }]); + }); + + const defaultProps: RouteComponentProps & { featureFlagStatus: boolean } = { + featureFlagStatus: true, + history: { push: jest.fn() } as any, + location: {} as any, + match: {} as any, + }; + + const shallowComponent = (props = defaultProps) => shallow(); + + test('renders correctly', () => { + const wrapper = shallowComponent(); + expect(wrapper).toMatchSnapshot(); + }); + + test('renders CreateDataSourcePanelHeader and CreateDataSourceCardView', () => { + const wrapper = shallowComponent(); + expect(wrapper.find(CreateDataSourcePanelHeader)).toHaveLength(1); + expect(wrapper.find(CreateDataSourceCardView)).toHaveLength(1); + }); +}); diff --git a/src/plugins/data_source_management/public/components/data_source_creation_panel/create_data_source_panel.tsx b/src/plugins/data_source_management/public/components/data_source_creation_panel/create_data_source_panel.tsx new file mode 100644 index 000000000000..7e6761d51254 --- /dev/null +++ b/src/plugins/data_source_management/public/components/data_source_creation_panel/create_data_source_panel.tsx @@ -0,0 +1,48 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { EuiFlexGroup, EuiFlexItem, EuiPageHeader, EuiPanel } from '@elastic/eui'; +import React, { useEffect } from 'react'; +import { RouteComponentProps } from 'react-router-dom'; +import { CreateDataSourcePanelHeader } from './create_data_source_panel_header'; +import { CreateDataSourceCardView } from './create_data_source_card_view'; +import { useOpenSearchDashboards } from '../../../../opensearch_dashboards_react/public'; +import { getCreateBreadcrumbs } from '../breadcrumbs'; +import { DataSourceManagementContext } from '../../types'; + +interface CreateDataSourcePanelProps extends RouteComponentProps { + featureFlagStatus: boolean; +} + +export const CreateDataSourcePanel: React.FC = ({ + featureFlagStatus, + ...props +}) => { + const { + chrome, + setBreadcrumbs, + notifications: { toasts }, + uiSettings, + } = useOpenSearchDashboards().services; + + useEffect(() => { + setBreadcrumbs(getCreateBreadcrumbs()); + }, [setBreadcrumbs]); + + return ( + + + + + + + + + + + + + ); +}; diff --git a/src/plugins/data_source_management/public/components/data_source_creation_panel/create_data_source_panel_header.test.tsx b/src/plugins/data_source_management/public/components/data_source_creation_panel/create_data_source_panel_header.test.tsx new file mode 100644 index 000000000000..05af9a27d554 --- /dev/null +++ b/src/plugins/data_source_management/public/components/data_source_creation_panel/create_data_source_panel_header.test.tsx @@ -0,0 +1,35 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import React from 'react'; +import { shallow } from 'enzyme'; +import { CreateDataSourcePanelHeader } from './create_data_source_panel_header'; +import { EuiFlexGroup, EuiTitle, EuiText } from '@elastic/eui'; +import { FormattedMessage } from '@osd/i18n/react'; + +describe('CreateDataSourcePanelHeader', () => { + const shallowComponent = () => shallow(); + + test('renders correctly', () => { + const wrapper = shallowComponent(); + expect(wrapper).toMatchSnapshot(); + }); + + test('contains correct title and description', () => { + const wrapper = shallowComponent(); + + const titleMessage = wrapper.find(EuiTitle).find(FormattedMessage); + expect(titleMessage.prop('id')).toEqual('dataSourcesManagement.createDataSourcePanel.title'); + expect(titleMessage.prop('defaultMessage')).toEqual('Create Data Source'); + + const descriptionMessage = wrapper.find(EuiText).find(FormattedMessage); + expect(descriptionMessage.prop('id')).toEqual( + 'dataSourcesManagement.createDataSourcePanel.description' + ); + expect(descriptionMessage.prop('defaultMessage')).toEqual( + 'Select a data source type to get started.' + ); + }); +}); diff --git a/src/plugins/data_source_management/public/components/data_source_creation_panel/create_data_source_panel_header.tsx b/src/plugins/data_source_management/public/components/data_source_creation_panel/create_data_source_panel_header.tsx new file mode 100644 index 000000000000..ac3cec5cdddc --- /dev/null +++ b/src/plugins/data_source_management/public/components/data_source_creation_panel/create_data_source_panel_header.tsx @@ -0,0 +1,34 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { EuiFlexGroup, EuiFlexItem, EuiSpacer, EuiText, EuiTitle } from '@elastic/eui'; +import React from 'react'; +import { FormattedMessage } from '@osd/i18n/react'; + +export const CreateDataSourcePanelHeader: React.FC = () => { + return ( + + + +

+ +

+
+ + +

+ +

+
+
+
+ ); +}; diff --git a/src/plugins/data_source_management/public/components/data_source_home_panel/__snapshots__/data_source_home_panel.test.tsx.snap b/src/plugins/data_source_management/public/components/data_source_home_panel/__snapshots__/data_source_home_panel.test.tsx.snap new file mode 100644 index 000000000000..4db09dab5b2a --- /dev/null +++ b/src/plugins/data_source_management/public/components/data_source_home_panel/__snapshots__/data_source_home_panel.test.tsx.snap @@ -0,0 +1,75 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`DataSourceHomePanel renders correctly 1`] = ` + + + + + + + + + + + + + + + + + + + Direct query connections + + + OpenSearch connections + + + + + + + + + +`; diff --git a/src/plugins/data_source_management/public/components/data_source_home_panel/__snapshots__/data_source_page_header.test.tsx.snap b/src/plugins/data_source_management/public/components/data_source_home_panel/__snapshots__/data_source_page_header.test.tsx.snap new file mode 100644 index 000000000000..ab527a7307f6 --- /dev/null +++ b/src/plugins/data_source_management/public/components/data_source_home_panel/__snapshots__/data_source_page_header.test.tsx.snap @@ -0,0 +1,34 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`DataSourceHeader renders correctly 1`] = ` + + + +

+ +

+
+ + +

+ +

+
+
+
+`; diff --git a/src/plugins/data_source_management/public/components/data_source_home_panel/data_source_home_panel.test.tsx b/src/plugins/data_source_management/public/components/data_source_home_panel/data_source_home_panel.test.tsx new file mode 100644 index 000000000000..cbc1f015c6f3 --- /dev/null +++ b/src/plugins/data_source_management/public/components/data_source_home_panel/data_source_home_panel.test.tsx @@ -0,0 +1,99 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import React from 'react'; +import { shallow, mount } from 'enzyme'; +import { RouteComponentProps } from 'react-router-dom'; +import { EuiTab } from '@elastic/eui'; +import { DataSourceHomePanel } from './data_source_home_panel'; +import { DataSourceTableWithRouter } from '../data_source_table/data_source_table'; +import { ManageDirectQueryDataConnectionsTable } from '../direct_query_data_sources_components/direct_query_data_connection/manage_direct_query_data_connections_table'; +import { CreateButton } from '../create_button'; +import { useOpenSearchDashboards } from '../../../../opensearch_dashboards_react/public'; +import { getListBreadcrumbs } from '../breadcrumbs'; + +jest.mock('../../../../opensearch_dashboards_react/public'); +jest.mock('../breadcrumbs'); +jest.mock('../data_source_table/data_source_table', () => ({ + DataSourceTableWithRouter: () =>
DataSourceTableWithRouter
, +})); +jest.mock( + '../direct_query_data_sources_components/direct_query_data_connection/manage_direct_query_data_connections_table', + () => ({ + ManageDirectQueryDataConnectionsTable: () =>
ManageDirectQueryDataConnectionsTable
, + }) +); +jest.mock('../create_button', () => ({ + CreateButton: ({ history, dataTestSubj }) => ( + + ), +})); + +describe('DataSourceHomePanel', () => { + const mockedContext = { + services: { + setBreadcrumbs: jest.fn(), + notifications: {}, + http: {}, + savedObjects: {}, + uiSettings: {}, + }, + }; + + beforeAll(() => { + (useOpenSearchDashboards as jest.Mock).mockReturnValue(mockedContext); + (getListBreadcrumbs as jest.Mock).mockReturnValue([{ text: 'Data sources' }]); + }); + + const defaultProps: RouteComponentProps & { featureFlagStatus: boolean } = { + featureFlagStatus: true, + history: { push: jest.fn() } as any, + location: {} as any, + match: {} as any, + }; + + const shallowComponent = (props = defaultProps) => shallow(); + const mountComponent = (props = defaultProps) => mount(); + + test('renders correctly', () => { + const wrapper = shallowComponent(); + expect(wrapper).toMatchSnapshot(); + }); + + test('renders DataSourceTableWithRouter when manageOpensearchDataSources tab is selected', () => { + const wrapper = mountComponent(); + wrapper.find(EuiTab).at(1).simulate('click'); + expect(wrapper.find(DataSourceTableWithRouter)).toHaveLength(1); + expect(wrapper.find(ManageDirectQueryDataConnectionsTable)).toHaveLength(0); + }); + + test('renders ManageDirectQueryDataConnectionsTable when manageDirectQueryDataSources tab is selected', () => { + const wrapper = mountComponent(); + wrapper.find(EuiTab).at(0).simulate('click'); + expect(wrapper.find(ManageDirectQueryDataConnectionsTable)).toHaveLength(1); + expect(wrapper.find(DataSourceTableWithRouter)).toHaveLength(0); + }); + + test('handles tab changes', () => { + const wrapper = mountComponent(); + expect(wrapper.find(ManageDirectQueryDataConnectionsTable)).toHaveLength(1); + wrapper.find(EuiTab).at(1).simulate('click'); + expect(wrapper.find(DataSourceTableWithRouter)).toHaveLength(1); + }); + + test('does not render OpenSearch connections tab when featureFlagStatus is false', () => { + const wrapper = shallowComponent({ ...defaultProps, featureFlagStatus: false }); + expect(wrapper.find(EuiTab)).toHaveLength(1); + }); + + test('calls history.push when CreateButton is clicked', () => { + const historyMock = { push: jest.fn() }; + const wrapper = mountComponent({ ...defaultProps, history: historyMock }); + wrapper.find('button[data-test-subj="createDataSourceButton"]').simulate('click'); + expect(historyMock.push).toHaveBeenCalledWith('/create'); + }); +}); diff --git a/src/plugins/data_source_management/public/components/data_source_home_panel/data_source_home_panel.tsx b/src/plugins/data_source_management/public/components/data_source_home_panel/data_source_home_panel.tsx new file mode 100644 index 000000000000..3cedbb9641c0 --- /dev/null +++ b/src/plugins/data_source_management/public/components/data_source_home_panel/data_source_home_panel.tsx @@ -0,0 +1,111 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import React, { useEffect, useState } from 'react'; +import { RouteComponentProps } from 'react-router-dom'; +import { + EuiFlexGroup, + EuiFlexItem, + EuiSpacer, + EuiTabs, + EuiTab, + EuiPageHeader, + EuiPanel, +} from '@elastic/eui'; +import { DataSourceHeader } from './data_source_page_header'; +import { DataSourceTableWithRouter } from '../data_source_table/data_source_table'; +import { ManageDirectQueryDataConnectionsTable } from '../direct_query_data_sources_components/direct_query_data_connection/manage_direct_query_data_connections_table'; +import { CreateButton } from '../create_button'; +import { useOpenSearchDashboards } from '../../../../opensearch_dashboards_react/public'; +import { getListBreadcrumbs } from '../breadcrumbs'; +import { DataSourceManagementContext } from '../../types'; + +interface DataSourceHomePanelProps extends RouteComponentProps { + featureFlagStatus: boolean; +} + +export const DataSourceHomePanel: React.FC = ({ + featureFlagStatus, + ...props +}) => { + const { setBreadcrumbs, notifications, http, savedObjects, uiSettings } = useOpenSearchDashboards< + DataSourceManagementContext + >().services; + + const [selectedTabId, setSelectedTabId] = useState('manageDirectQueryDataSources'); + + useEffect(() => { + setBreadcrumbs(getListBreadcrumbs()); + }, [setBreadcrumbs]); + + const onSelectedTabChanged = (id: string) => { + setSelectedTabId(id); + }; + + const tabs = [ + { + id: 'manageDirectQueryDataSources', + name: 'Direct query connections', + }, + ...(featureFlagStatus + ? [ + { + id: 'manageOpensearchDataSources', + name: 'OpenSearch connections', + }, + ] + : []), + ]; + + const renderTabs = () => { + return tabs.map((tab) => ( + onSelectedTabChanged(tab.id)} + isSelected={tab.id === selectedTabId} + key={tab.id} + > + {tab.name} + + )); + }; + + return ( + + + + + + + + + + + + + + + + + {renderTabs()} + + + + {selectedTabId === 'manageOpensearchDataSources' && featureFlagStatus && ( + + )} + {selectedTabId === 'manageDirectQueryDataSources' && ( + + )} + + + + ); +}; diff --git a/src/plugins/data_source_management/public/components/data_source_home_panel/data_source_page_header.test.tsx b/src/plugins/data_source_management/public/components/data_source_home_panel/data_source_page_header.test.tsx new file mode 100644 index 000000000000..8773bb0b3055 --- /dev/null +++ b/src/plugins/data_source_management/public/components/data_source_home_panel/data_source_page_header.test.tsx @@ -0,0 +1,41 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import React from 'react'; +import { shallow } from 'enzyme'; +import { DataSourceHeader } from './data_source_page_header'; +import { EuiTitle, EuiText } from '@elastic/eui'; +import { FormattedMessage } from '@osd/i18n/react'; + +describe('DataSourceHeader', () => { + const defaultProps = { + history: {} as any, + location: {} as any, + match: {} as any, + }; + + const shallowComponent = (props = defaultProps) => shallow(); + + test('renders correctly', () => { + const wrapper = shallowComponent(); + expect(wrapper).toMatchSnapshot(); + }); + + test('contains correct title and description', () => { + const wrapper = shallowComponent(); + + const titleMessage = wrapper.find(EuiTitle).find(FormattedMessage); + expect(titleMessage.prop('id')).toEqual('dataSourcesManagement.dataSourcesTable.title'); + expect(titleMessage.prop('defaultMessage')).toEqual('Data Sources'); + + const descriptionMessage = wrapper.find(EuiText).find(FormattedMessage); + expect(descriptionMessage.prop('id')).toEqual( + 'dataSourcesManagement.dataSourcesTable.description' + ); + expect(descriptionMessage.prop('defaultMessage')).toEqual( + 'Create and manage data source connections.' + ); + }); +}); diff --git a/src/plugins/data_source_management/public/components/data_source_home_panel/data_source_page_header.tsx b/src/plugins/data_source_management/public/components/data_source_home_panel/data_source_page_header.tsx new file mode 100644 index 000000000000..9fa99fa9296d --- /dev/null +++ b/src/plugins/data_source_management/public/components/data_source_home_panel/data_source_page_header.tsx @@ -0,0 +1,37 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { EuiFlexGroup, EuiFlexItem, EuiSpacer, EuiText, EuiTitle } from '@elastic/eui'; +import React from 'react'; +import { FormattedMessage } from '@osd/i18n/react'; +import { RouteComponentProps } from 'react-router-dom'; + +type DataSourceHeaderProps = RouteComponentProps; + +export const DataSourceHeader: React.FC = () => { + return ( + + + +

+ +

+
+ + +

+ +

+
+
+
+ ); +}; diff --git a/src/plugins/data_source_management/public/components/data_source_table/__snapshots__/data_source_table.test.tsx.snap b/src/plugins/data_source_management/public/components/data_source_table/__snapshots__/data_source_table.test.tsx.snap index 05fd70496974..842c3e3d07ba 100644 --- a/src/plugins/data_source_management/public/components/data_source_table/__snapshots__/data_source_table.test.tsx.snap +++ b/src/plugins/data_source_management/public/components/data_source_table/__snapshots__/data_source_table.test.tsx.snap @@ -30,317 +30,145 @@ exports[`DataSourceTable should get datasources failed should render empty table location={Object {}} match={Object {}} > - - +
+ +
-
- +
-
- -
- -

- - - Data Sources - - -

-
- -
- - -
-

- - - Create and manage data source connections to help you retrieve data from multiple OpenSearch compatible sources. - - -

-
-
-
- - -
- - - - - - - -
-
-
- - -
- - -
- - + No Data Source Connections have been created yet. + + +
+ + +
+ + + -
- -
- - - No Data Source Connections have been created yet. - - -
-
- -
- - - - - - - - -
- - -
- -
- - + + + + + + + + +
+ + +
+ `; @@ -452,75 +280,247 @@ exports[`DataSourceTable should get datasources successful should render normall location={Object {}} match={Object {}} > - + + Delete + + + + + + , + } + } + selection={ + Object { + "onSelectionChange": [Function], + } + } + sorting={ + Object { + "sort": Object { + "direction": "asc", + "field": "title", + }, + } + } + tableLayout="fixed" > - -
+ + + Delete + + + + + + + } >
- -

- - - Data Sources - - -

-
- -
- - -
-

- +

- - Create and manage data source connections to help you retrieve data from multiple OpenSearch compatible sources. - - -

-
- +
+ + + + +
+ + + + + +
+
+
+
+ + +
- - - - - - - + + + + +
+
- -
- - + +
+ + - - Delete - - - - - - , - } + "name": "Description", + "sortable": [Function], + "truncateText": true, + }, + ] + } + isSelectable={true} + itemId="id" + items={ + Array [ + Object { + "description": "alpha test datasource", + "id": "alpha-test", + "sort": "alpha-test", + "title": "alpha-test", + }, + Object { + "description": "beta test datasource", + "id": "beta-test", + "sort": "beta-test", + "title": "beta-test", + }, + Object { + "description": "test datasource", + "id": "test", + "sort": "test", + "title": "test", + }, + Object { + "description": "test datasource2", + "id": "test2", + "sort": "test", + "title": "test", + }, + ] + } + loading={false} + noItemsMessage="No items found" + onChange={[Function]} + pagination={ + Object { + "hidePerPageOptions": undefined, + "pageIndex": 0, + "pageSize": 10, + "pageSizeOptions": Array [ + 5, + 10, + 25, + 50, + ], + "totalItemCount": 4, } - selection={ - Object { - "onSelectionChange": [Function], - } + } + responsive={true} + selection={ + Object { + "onSelectionChange": [Function], } - sorting={ - Object { - "sort": Object { - "direction": "asc", - "field": "title", - }, - } + } + sorting={ + Object { + "allowNeutralSort": false, + "sort": Object { + "direction": "asc", + "field": "Title", + }, } - tableLayout="fixed" + } + tableLayout="fixed" + > +
- - - Delete - - - - - - - } - > - +
-
- -
- - -
+
+
+ Select all rows +
-
-
-
-
-
- -
+ +
+
+ - -
- - + + + } + closePopover={[Function]} + display="inlineBlock" + hasArrow={true} + isOpen={false} + ownFocus={true} + panelPaddingSize="none" > - - - -
-
-
- -
-
-
- -
- - + + + + + + + Sorting + + + + + + +
+
+ +
+ +
+ +
+ +
+ + -
-
- -
+ + + + + + + + + +
+ + +
+ +
+
+ + +
+ + + + + + + + + + + + + + + + + + - -
-
-
- - + + +
- +
+ -
- - - + -
-
- - - -
-
-
-
- + alpha-test + + + + +
- -
- -
- - - + + + + + + + - - - - - - - +
-
- - +
+
+ + + + + + +
- - + + + + + - - - - - + + + + + + + - - + - - - - + + + + + + - - + + + + + - - - - - + + + + + + + - - - - + + + + + + + + + - - + + + + + + - - - - + + + + + + + + + + + + +
+
+ + alpha test datasource + +
+
+ - -
-
- - -
- -
-
- - -
-
+
-
+
+ -
+
-
- -
-
- - -
- -
-
- - + +
-
+
+ Title +
+
+ -
-
- Title -
-
- - - -
-
+ -
- alpha test datasource + + Default + + + + -
-
-
-
- - -
- -
-
- - -
-
+
+ -
- Title -
-
- - - + +
-
+
+ Title +
+
+ -
-
- beta test datasource + + test + -
-
+
+ + test datasource2 + +
+
+
+
+ +
+ +
+ + + +
+ +
+ + + : + 10 + + } + closePopover={[Function]} + display="inlineBlock" + hasArrow={true} + isOpen={false} + ownFocus={true} + panelPaddingSize="none" + > +
- - - -
- - + + + -
- -
-
- - -
- - - - -
- Title -
-
- - - - - - - - - Default - - - - - - - - -
- -
- - -
- - test datasource - -
- -
- - - - - - -
- - -
- -
-
- - -
- - - - -
- Title -
-
- - - -
- -
- - -
- - test datasource2 + Rows per page + + : + 10 + -
- -
- - - - - - -
- -
- + + +
+
+ +
+ +
- - - -
- -
- - - : - 10 - + + -
-
- -
-
-
-
-
- - - -
-
-
+
+
- -
- -
- -
- - +
+ +
+ +
+ +
+ `; @@ -3576,1246 +3155,61 @@ exports[`DataSourceTable should not manage datasources when canManageDataSource location={Object {}} match={Object {}} > - +
+ + - -
- +
-
- -
- -

- - - Data Sources - - -

-
- -
- - -
-

- - - Create and manage data source connections to help you retrieve data from multiple OpenSearch compatible sources. - - -

-
-
-
- - -
- - - - - - - -
-
-
- - -
- - -
- - -
- -
- - - No Data Source Connections have been created yet. - - -
-
- -
- -
- - -
- -
- - + + No Data Source Connections have been created yet. + + +
+ + +
+ +
+
+ +
+ `; diff --git a/src/plugins/data_source_management/public/components/data_source_table/data_source_table.tsx b/src/plugins/data_source_management/public/components/data_source_table/data_source_table.tsx index 0f1abb2d755b..9a4264f1ec4f 100644 --- a/src/plugins/data_source_management/public/components/data_source_table/data_source_table.tsx +++ b/src/plugins/data_source_management/public/components/data_source_table/data_source_table.tsx @@ -8,21 +8,17 @@ import { EuiButton, EuiButtonEmpty, EuiConfirmModal, - EuiFlexGroup, EuiFlexItem, EuiInMemoryTable, - EuiPageContent, EuiPanel, EuiSpacer, EuiText, - EuiTitle, } from '@elastic/eui'; import React, { useState } from 'react'; import { RouteComponentProps, withRouter } from 'react-router-dom'; import { useEffectOnce } from 'react-use'; import { i18n } from '@osd/i18n'; import { FormattedMessage } from '@osd/i18n/react'; -import { getListBreadcrumbs } from '../breadcrumbs'; import { reactRouterNavigate, useOpenSearchDashboards, @@ -70,9 +66,6 @@ export const DataSourceTable = ({ history }: RouteComponentProps) => { /* useEffectOnce hook to avoid these methods called multiple times when state is updated. */ useEffectOnce(() => { - /* Update breadcrumb*/ - setBreadcrumbs(getListBreadcrumbs()); - /* Browser - Page Title */ chrome.docTitle.change( i18n.translate('dataSourcesManagement.dataSourcesTable.dataSourcesTitle', { @@ -202,28 +195,22 @@ export const DataSourceTable = ({ history }: RouteComponentProps) => { defaultFocusedButton="confirm" >

- { - - } +

- { - - } +

- { - - } +

) : null; @@ -292,48 +279,6 @@ export const DataSourceTable = ({ history }: RouteComponentProps) => { }; /* Render Ui elements*/ - /* Create Data Source button */ - const createButton = ; - const createButtonEmptyState = ( - - ); - - /* Render header*/ - const renderHeader = () => { - return ( - - - -

- { - - } -

-
- - -

- { - - } -

-
-
- {createButton} -
- ); - }; - /* Render table */ const renderTableContent = () => { return ( @@ -356,6 +301,14 @@ export const DataSourceTable = ({ history }: RouteComponentProps) => { }; const renderEmptyState = () => { + const createButtonEmptyState = ( + + ); + return ( <> @@ -366,12 +319,10 @@ export const DataSourceTable = ({ history }: RouteComponentProps) => { data-test-subj="datasourceTableEmptyState" > - { - - } + {canManageDataSource ? createButtonEmptyState : null} @@ -381,34 +332,15 @@ export const DataSourceTable = ({ history }: RouteComponentProps) => { ); }; - const renderContent = () => { - return ( - <> - - {/* Header */} - {renderHeader()} - - - - {/* Delete confirmation modal*/} - {tableRenderDeleteModal()} - - {!isLoading && (!dataSources || !dataSources.length) - ? renderEmptyState() - : renderTableContent()} - - {isDeleting ? : null} - - ); - }; - - return renderContent(); + return ( + <> + {tableRenderDeleteModal()} + {!isLoading && (!dataSources || !dataSources.length) + ? renderEmptyState() + : renderTableContent()} + {isDeleting ? : null} + + ); }; export const DataSourceTableWithRouter = withRouter(DataSourceTable); diff --git a/src/plugins/data_source_management/public/components/direct_query_data_sources_components/direct_query_data_connection/__snapshots__/direct_query_data_source_delete_modal.test.tsx.snap b/src/plugins/data_source_management/public/components/direct_query_data_sources_components/direct_query_data_connection/__snapshots__/direct_query_data_source_delete_modal.test.tsx.snap new file mode 100644 index 000000000000..1865cefc626b --- /dev/null +++ b/src/plugins/data_source_management/public/components/direct_query_data_sources_components/direct_query_data_connection/__snapshots__/direct_query_data_source_delete_modal.test.tsx.snap @@ -0,0 +1,60 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`DeleteModal renders correctly 1`] = ` + + + + + Delete Item + + + + + Are you sure you want to delete this item? + + + The action cannot be undone. + + + + + + + + + + + Cancel + + + Delete + + + + +`; diff --git a/src/plugins/data_source_management/public/components/direct_query_data_sources_components/direct_query_data_connection/__snapshots__/manage_direct_query_data_connections_table.test.tsx.snap b/src/plugins/data_source_management/public/components/direct_query_data_sources_components/direct_query_data_connection/__snapshots__/manage_direct_query_data_connections_table.test.tsx.snap new file mode 100644 index 000000000000..9177634e0a2f --- /dev/null +++ b/src/plugins/data_source_management/public/components/direct_query_data_sources_components/direct_query_data_connection/__snapshots__/manage_direct_query_data_connections_table.test.tsx.snap @@ -0,0 +1,920 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`ManageDirectQueryDataConnectionsTable renders correctly 1`] = ` + + +
+ +
+ + +
+ +
+ +
+ +
+ + +
+ + +
+ + + +
+
+ + + Local cluster + + + +
+ +
+
+ +
+ +
+ + + + + + + + +
+
+
+
+ + +
+ + +
+ + +
+ + +
+
+ + + + +
+ + + + + +
+
+
+
+
+
+
+
+
+ + +
+ + + +
+
+ +
+ +
+ +
+ + +
+ +
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + Name + + + + + + + + + + + + Status + + + + + + + + + + + + Actions + + + + + +
+
+ + No items found + +
+
+
+
+
+ + +
+ +
+ +
+ + +`; diff --git a/src/plugins/data_source_management/public/components/direct_query_data_sources_components/direct_query_data_connection/direct_query_data_source_delete_modal.test.tsx b/src/plugins/data_source_management/public/components/direct_query_data_sources_components/direct_query_data_connection/direct_query_data_source_delete_modal.test.tsx new file mode 100644 index 000000000000..a766ab4617c8 --- /dev/null +++ b/src/plugins/data_source_management/public/components/direct_query_data_sources_components/direct_query_data_connection/direct_query_data_source_delete_modal.test.tsx @@ -0,0 +1,76 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import React from 'react'; +import { shallow, mount } from 'enzyme'; +import { DeleteModal } from './direct_query_data_source_delete_modal'; +import { + EuiButtonEmpty, + EuiFieldText, + EuiModalBody, + EuiModalHeaderTitle, + EuiText, +} from '@elastic/eui'; + +describe('DeleteModal', () => { + const defaultProps = { + onCancel: jest.fn(), + onConfirm: jest.fn(), + title: 'Delete Item', + message: 'Are you sure you want to delete this item?', + prompt: 'delete', + }; + + const shallowComponent = (props = defaultProps) => shallow(); + const mountComponent = (props = defaultProps) => mount(); + + test('renders correctly', () => { + const wrapper = shallowComponent(); + expect(wrapper).toMatchSnapshot(); + }); + + test('displays the correct title and message', () => { + const wrapper = mountComponent(); + expect(wrapper.find(EuiModalHeaderTitle).text()).toEqual('Delete Item'); + expect(wrapper.find(EuiModalBody).find(EuiText).at(0).text()).toEqual( + 'Are you sure you want to delete this item?' + ); + }); + + test('disables the delete button initially', () => { + const wrapper = mountComponent(); + const deleteButton = wrapper.find('button[data-test-subj="popoverModal__deleteButton"]'); + expect(deleteButton.prop('disabled')).toBe(true); + }); + + test('enables the delete button when the correct prompt is entered', () => { + const wrapper = mountComponent(); + const input = wrapper.find(EuiFieldText); + input.simulate('change', { target: { value: 'delete' } }); + wrapper.update(); + const deleteButton = wrapper.find('button[data-test-subj="popoverModal__deleteButton"]'); + setTimeout(() => { + expect(deleteButton.prop('disabled')).toBe(false); + }, 1000); + }); + + test('calls onCancel when the cancel button is clicked', () => { + const wrapper = mountComponent(); + wrapper.find(EuiButtonEmpty).simulate('click'); + expect(defaultProps.onCancel).toHaveBeenCalled(); + }); + + test('calls onConfirm when the delete button is clicked', () => { + const wrapper = mountComponent(); + const input = wrapper.find(EuiFieldText); + input.simulate('change', { target: { value: 'delete' } }); + wrapper.update(); + const deleteButton = wrapper.find('button[data-test-subj="popoverModal__deleteButton"]'); + setTimeout(() => { + deleteButton.simulate('click'); + expect(defaultProps.onConfirm).toHaveBeenCalled(); + }, 1000); + }); +}); diff --git a/src/plugins/data_source_management/public/components/direct_query_data_sources_components/direct_query_data_connection/direct_query_data_source_delete_modal.tsx b/src/plugins/data_source_management/public/components/direct_query_data_sources_components/direct_query_data_connection/direct_query_data_source_delete_modal.tsx new file mode 100644 index 000000000000..bf343fa6b5ca --- /dev/null +++ b/src/plugins/data_source_management/public/components/direct_query_data_sources_components/direct_query_data_connection/direct_query_data_source_delete_modal.tsx @@ -0,0 +1,82 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import React, { useState } from 'react'; +import { + EuiOverlayMask, + EuiModal, + EuiButton, + EuiButtonEmpty, + EuiFieldText, + EuiForm, + EuiFormRow, + EuiModalBody, + EuiModalFooter, + EuiModalHeader, + EuiModalHeaderTitle, + EuiSpacer, + EuiText, +} from '@elastic/eui'; + +export const DeleteModal = ({ + onCancel, + onConfirm, + title, + message, + prompt, +}: { + onCancel: ( + event?: React.KeyboardEvent | React.MouseEvent + ) => void; + onConfirm: (event?: React.MouseEvent) => void; + title: string; + message: string; + prompt?: string; +}) => { + const [value, setValue] = useState(''); + const onChange = (e: React.ChangeEvent) => { + setValue(e.target.value); + }; + const deletePrompt = prompt ?? 'delete'; + return ( + + + + {title} + + + + {message} + The action cannot be undone. + + + + onChange(e)} + data-test-subj="popoverModal__deleteTextInput" + /> + + + + + + Cancel + onConfirm()} + color="danger" + fill + disabled={value !== deletePrompt} + data-test-subj="popoverModal__deleteButton" + > + Delete + + + + + ); +}; diff --git a/src/plugins/data_source_management/public/components/direct_query_data_sources_components/direct_query_data_connection/manage_direct_query_data_connections_table.test.tsx b/src/plugins/data_source_management/public/components/direct_query_data_sources_components/direct_query_data_connection/manage_direct_query_data_connections_table.test.tsx new file mode 100644 index 000000000000..06d1dc61d166 --- /dev/null +++ b/src/plugins/data_source_management/public/components/direct_query_data_sources_components/direct_query_data_connection/manage_direct_query_data_connections_table.test.tsx @@ -0,0 +1,128 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import React from 'react'; +import { act } from 'react-dom/test-utils'; +import { mount, ReactWrapper } from 'enzyme'; +import { + HttpStart, + NotificationsStart, + SavedObjectsStart, + IUiSettingsClient, +} from 'opensearch-dashboards/public'; +import { EuiFieldSearch, EuiInMemoryTable, EuiLoadingSpinner } from '@elastic/eui'; +import { ManageDirectQueryDataConnectionsTable } from './manage_direct_query_data_connections_table'; + +const mockHttp = ({ + get: jest.fn(), +} as unknown) as jest.Mocked; + +const mockNotifications = ({ + toasts: { addDanger: jest.fn(), addSuccess: jest.fn(), addWarning: jest.fn() }, +} as unknown) as jest.Mocked; + +const mockSavedObjects = ({ + client: {}, +} as unknown) as jest.Mocked; + +const mockUiSettings = ({} as unknown) as jest.Mocked; + +const defaultProps = { + http: mockHttp, + notifications: mockNotifications, + savedObjects: mockSavedObjects, + uiSettings: mockUiSettings, + featureFlagStatus: true, +}; + +describe('ManageDirectQueryDataConnectionsTable', () => { + let wrapper: ReactWrapper; + + beforeEach(() => { + jest.clearAllMocks(); + }); + + test('renders correctly', async () => { + mockHttp.get.mockResolvedValueOnce([]); // Mock an empty array for the initial fetch + + await act(async () => { + wrapper = mount(); + }); + wrapper.update(); + expect(wrapper).toMatchSnapshot(); + }); + + test('displays loading spinner while fetching data', async () => { + let resolveFetch; + const fetchPromise = new Promise((resolve) => { + resolveFetch = resolve; + }); + mockHttp.get.mockImplementation(() => fetchPromise); + + await act(async () => { + wrapper = mount(); + }); + + wrapper.update(); + + expect(wrapper.find(EuiLoadingSpinner).exists()).toBe(true); + + // Simulate fetch completion + await act(async () => { + resolveFetch([]); + }); + wrapper.update(); + }); + + test('fetches and displays data connections', async () => { + mockHttp.get.mockResolvedValueOnce([ + { + name: 'Test Connection', + connector: 'S3GLUE', + status: 'ACTIVE', + }, + ]); + + await act(async () => { + wrapper = mount(); + }); + wrapper.update(); + + expect(wrapper.find(EuiInMemoryTable).prop('items')).toHaveLength(1); + }); + + test('filters data connections based on search text', async () => { + mockHttp.get.mockResolvedValueOnce([ + { + name: 'Test Connection', + connector: 'S3GLUE', + status: 'ACTIVE', + }, + { + name: 'Another Connection', + connector: 'PROMETHEUS', + status: 'INACTIVE', + }, + ]); + + await act(async () => { + wrapper = mount(); + }); + wrapper.update(); + + const searchInput = wrapper.find(EuiFieldSearch); + expect(searchInput.exists()).toBe(true); + + await act(async () => { + searchInput.find('input').simulate('change', { target: { value: 'Test' } }); + }); + wrapper.update(); + + const table = wrapper.find(EuiInMemoryTable); + const items = table.prop('items') as any[]; + expect(items).toHaveLength(1); + expect(items[0].name).toBe('Test Connection'); + }); +}); diff --git a/src/plugins/data_source_management/public/components/direct_query_data_sources_components/direct_query_data_connection/manage_direct_query_data_connections_table.tsx b/src/plugins/data_source_management/public/components/direct_query_data_sources_components/direct_query_data_connection/manage_direct_query_data_connections_table.tsx new file mode 100644 index 000000000000..0209067d2078 --- /dev/null +++ b/src/plugins/data_source_management/public/components/direct_query_data_sources_components/direct_query_data_connection/manage_direct_query_data_connections_table.tsx @@ -0,0 +1,283 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { + EuiFlexGroup, + EuiFlexItem, + EuiHealth, + EuiIcon, + EuiInMemoryTable, + EuiLink, + EuiOverlayMask, + EuiPageBody, + EuiSpacer, + EuiTableFieldDataColumnType, + EuiFieldSearch, + EuiLoadingSpinner, + EuiText, +} from '@elastic/eui'; +import React, { useCallback, useEffect, useState } from 'react'; +import { + HttpStart, + IUiSettingsClient, + NotificationsStart, + SavedObjectsStart, +} from 'opensearch-dashboards/public'; +import { + DirectQueryDatasourceDetails, + DirectQueryDatasourceStatus, + DirectQueryDatasourceType, +} from '../../../types'; +import { DeleteModal } from './direct_query_data_source_delete_modal'; +import PrometheusLogo from '../icons/prometheus_logo.svg'; +import S3Logo from '../icons/s3_logo.svg'; +import { DataSourceSelector } from '../../data_source_selector'; +import { DataSourceOption } from '../../data_source_menu/types'; + +interface DataConnection { + connectionType: DirectQueryDatasourceType; + name: string; + dsStatus: DirectQueryDatasourceStatus; +} + +interface ManageDirectQueryDataConnectionsTableProps { + http: HttpStart; + notifications: NotificationsStart; + savedObjects: SavedObjectsStart; + uiSettings: IUiSettingsClient; + featureFlagStatus: boolean; +} + +// Custom truncate function +const truncate = (text: string, length: number) => { + if (text.length <= length) return text; + return text.substring(0, length) + '...'; +}; + +export const ManageDirectQueryDataConnectionsTable: React.FC = ({ + http, + notifications, + savedObjects, + uiSettings, + featureFlagStatus, +}) => { + const [data, setData] = useState([]); + const [isModalVisible, setIsModalVisible] = useState(false); + const [modalLayout, setModalLayout] = useState(); + const [selectedDataSourceId, setSelectedDataSourceId] = useState(''); + const [searchText, setSearchText] = useState(''); + const [isLoading, setIsLoading] = useState(false); + + const fetchDataSources = useCallback(() => { + const endpoint = + featureFlagStatus && selectedDataSourceId !== undefined + ? `/api/dataconnections/dataSourceMDSId=${selectedDataSourceId}` + : `/api/dataconnections`; + + setIsLoading(true); + + http + .get(endpoint) + .then((res: DirectQueryDatasourceDetails[]) => { + const dataConnections = res.map((dataConnection: DirectQueryDatasourceDetails) => ({ + name: dataConnection.name, + connectionType: dataConnection.connector, + dsStatus: dataConnection.status, + })); + setData(dataConnections); + }) + .catch((err) => { + notifications.toasts.addDanger('Could not fetch data sources'); + }) + .finally(() => { + setIsLoading(false); + }); + }, [http, notifications.toasts, selectedDataSourceId, featureFlagStatus]); + + useEffect(() => { + fetchDataSources(); + }, [fetchDataSources]); + + const handleSelectedDataSourceChange = (e: DataSourceOption[]) => { + const dataSourceId = e[0] ? e[0].id : ''; + setSelectedDataSourceId(dataSourceId); + }; + + const deleteConnection = (connectionName: string) => { + setData(data.filter((connection) => !(connection.name === connectionName))); + }; + + const displayDeleteModal = (connectionName: string) => { + setModalLayout( + { + setIsModalVisible(false); + deleteConnection(connectionName); + }} + onCancel={() => { + setIsModalVisible(false); + }} + title={`Delete ${connectionName}`} + message={`Are you sure you want to delete ${connectionName}?`} + /> + ); + setIsModalVisible(true); + }; + + const actions = [ + { + name: (datasource: DataConnection) => + `Query in ${ + datasource.connectionType === 'PROMETHEUS' ? 'Metrics Analytics' : 'Observability Logs' + }`, + isPrimary: true, + icon: 'discoverApp', + type: 'icon', + onClick: () => {}, + 'data-test-subj': 'action-query', + }, + { + name: 'Accelerate performance', + isPrimary: false, + icon: 'bolt', + type: 'icon', + available: (datasource: DataConnection) => datasource.connectionType !== 'PROMETHEUS', + onClick: () => {}, + 'data-test-subj': 'action-accelerate', + }, + { + name: 'Integrate data', + isPrimary: false, + icon: 'integrationGeneral', + type: 'icon', + available: (datasource: DataConnection) => datasource.connectionType !== 'PROMETHEUS', + onClick: () => {}, + 'data-test-subj': 'action-integrate', + }, + { + name: 'Delete', + description: 'Delete this data source', + icon: 'trash', + color: 'danger', + type: 'icon', + onClick: (datasource: DataConnection) => displayDeleteModal(datasource.name), + isPrimary: false, + 'data-test-subj': 'action-delete', + }, + ]; + + const icon = (record: DataConnection) => { + switch (record.connectionType) { + case 'S3GLUE': + return ; + case 'PROMETHEUS': + return ; + default: + return <>; + } + }; + + const tableColumns = [ + { + field: 'name', + name: 'Name', + sortable: true, + truncateText: true, + render: (value, record: DataConnection) => ( + + {icon(record)} + + + {truncate(record.name, 100)} + + + + ), + }, + { + field: 'status', + name: 'Status', + sortable: true, + truncateText: true, + render: (value, record: DataConnection) => + record.dsStatus === 'ACTIVE' ? ( + Active + ) : ( + Inactive + ), + }, + { + field: 'actions', + name: 'Actions', + actions, + }, + ] as Array>; + + const customSearchBar = ( + + {featureFlagStatus && ( + + + + )} + + setSearchText(e.target.value)} + isClearable + fullWidth={true} + /> + + + ); + + const entries = data.filter((dataconnection) => + dataconnection.name.toLowerCase().includes(searchText.toLowerCase()) + ); + + return ( + + + + + {customSearchBar} + + {isLoading ? ( +
+ + + Loading direct query data connections... +
+ ) : ( + + )} +
+
+ {isModalVisible && modalLayout} +
+ ); +}; diff --git a/src/plugins/data_source_management/public/components/direct_query_data_sources_components/direct_query_data_source_configuration/__snapshots__/query_permissions.test.tsx.snap b/src/plugins/data_source_management/public/components/direct_query_data_sources_components/direct_query_data_source_configuration/__snapshots__/query_permissions.test.tsx.snap new file mode 100644 index 000000000000..1eb30007471b --- /dev/null +++ b/src/plugins/data_source_management/public/components/direct_query_data_sources_components/direct_query_data_source_configuration/__snapshots__/query_permissions.test.tsx.snap @@ -0,0 +1,187 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`QueryPermissionsConfiguration renders correctly 1`] = ` + + + +
+ +
+ +
+ +
+

+ Query permissions +

+
+
+ +
+

+ Control which OpenSearch roles have permission to query and index data from this data source. +

+
+
+
+
+ +
+ + Query access level + , + "compressed": undefined, + } + } + name="query-radio-group" + onChange={[Function]} + options={ + Array [ + Object { + "disabled": false, + "id": "query-restricted", + "label": "Restricted - accessible by users with specific OpenSearch roles", + }, + Object { + "disabled": false, + "id": "query-all", + "label": "Admin only - only accessible by the admin", + }, + ] + } + > + + Query access level + , + "compressed": undefined, + } + } + > +
+ + + + Query access level + + + + +
+ +
+ +
+ + +
+ +
+ +
+ +
+
+
+
+
+
+
+
+
+
+
+`; diff --git a/src/plugins/data_source_management/public/components/direct_query_data_sources_components/direct_query_data_source_configuration/amazon_s3/__snapshots__/configure_amazon_s3_data_source.test.tsx.snap b/src/plugins/data_source_management/public/components/direct_query_data_sources_components/direct_query_data_source_configuration/amazon_s3/__snapshots__/configure_amazon_s3_data_source.test.tsx.snap new file mode 100644 index 000000000000..c90faa94daf8 --- /dev/null +++ b/src/plugins/data_source_management/public/components/direct_query_data_sources_components/direct_query_data_source_configuration/amazon_s3/__snapshots__/configure_amazon_s3_data_source.test.tsx.snap @@ -0,0 +1,1253 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`ConfigureS3DatasourcePanel renders correctly 1`] = ` + + + + +
+ +
+ +

+ Configure Amazon S3 data source +

+
+ +
+ + +
+
+ + + Setup Amazon EMR as execution engine first + +
+ +
+ +
+ +
+ +
+ Connect to Amazon S3 via AWS Glue Data Catalog with Amazon EMR as an execution engine. +
+
+
+
+
+
+
+
+
+
+ +
+ + +
+

+ Data source details +

+
+
+ +
+ + + +
+
+ + + +
+
+ + +
+
+ + + + +
+
+
+
+ +
+ Connection name that OpenSearch Dashboards references. This name should be descriptive and concise. +
+
+
+
+
+
+ +
+
+ + + +
+
+ + +