From 73becc42f93b51265baa1d981c264d27e472f970 Mon Sep 17 00:00:00 2001 From: Derek Ho Date: Thu, 7 Sep 2023 10:36:47 -0400 Subject: [PATCH 01/22] Manage datasources (#967) * fix name change bug and modify test to test behavior Signed-off-by: Derek Ho * get rid of lint Signed-off-by: Derek Ho * test for flyout Signed-off-by: Derek Ho * flyout to medium size Signed-off-by: Derek Ho * make accelerate extensible Signed-off-by: Derek Ho * get datasources and hook up to pplservice Signed-off-by: Derek Ho * get flint working Signed-off-by: Derek Ho * add datasource page with steps and buttons on bottom bar Signed-off-by: Derek Ho * datasources as a new plugin and mostly working Signed-off-by: Derek Ho * hook up manage to show datasources call Signed-off-by: Derek Ho * update two tables with descriptions Signed-off-by: Derek Ho * make some updates to the page Signed-off-by: Derek Ho * cleanup unused files for data connections Signed-off-by: Derek Ho * cleanup and add overview panel columns Signed-off-by: Derek Ho * render tabs Signed-off-by: Derek Ho * add unit tests Signed-off-by: Derek Ho * update data test subj and snapshot Signed-off-by: Derek Ho * Add datasources to management overview Signed-off-by: Derek Ho * remove spark logo and update snapshot Signed-off-by: Derek Ho * refactor routes out Signed-off-by: Derek Ho * separate out the roles Signed-off-by: Derek Ho * bump version back to 3.0 Signed-off-by: Derek Ho --------- Signed-off-by: Derek Ho --- .cypress/integration/10_datasources.spec.js | 20 + common/constants/data_connections.ts | 7 + common/constants/shared.ts | 11 +- opensearch_dashboards.json | 3 + public/components/app.tsx | 2 + .../__snapshots__/datasource.test.tsx.snap | 309 ++++++++ ...anage_datasource_description.test.tsx.snap | 50 ++ .../manage_datasource_table.test.tsx.snap | 695 ++++++++++++++++++ .../components/__tests__/datasource.test.tsx | 39 + .../manage_datasource_description.test.tsx | 22 + .../manage_datasource_table.test.tsx | 36 + .../components/__tests__/testing_constants.ts | 75 ++ .../components/datasource.tsx | 178 +++++ .../components/datasources_header.tsx | 38 + .../manage_datasource_description.tsx | 24 + .../components/manage_datasource_table.tsx | 159 ++++ public/components/data_connections/home.tsx | 52 ++ .../available_integration_overview_page.tsx | 3 +- public/plugin.ts | 20 + public/types.ts | 2 + .../opensearch_observability_plugin.ts | 2 +- server/adaptors/ppl_plugin.ts | 26 +- .../routes/datasources/datasources_router.ts | 62 ++ server/routes/index.ts | 2 + 24 files changed, 1832 insertions(+), 5 deletions(-) create mode 100644 .cypress/integration/10_datasources.spec.js create mode 100644 common/constants/data_connections.ts create mode 100644 public/components/data_connections/components/__tests__/__snapshots__/datasource.test.tsx.snap create mode 100644 public/components/data_connections/components/__tests__/__snapshots__/manage_datasource_description.test.tsx.snap create mode 100644 public/components/data_connections/components/__tests__/__snapshots__/manage_datasource_table.test.tsx.snap create mode 100644 public/components/data_connections/components/__tests__/datasource.test.tsx create mode 100644 public/components/data_connections/components/__tests__/manage_datasource_description.test.tsx create mode 100644 public/components/data_connections/components/__tests__/manage_datasource_table.test.tsx create mode 100644 public/components/data_connections/components/__tests__/testing_constants.ts create mode 100644 public/components/data_connections/components/datasource.tsx create mode 100644 public/components/data_connections/components/datasources_header.tsx create mode 100644 public/components/data_connections/components/manage_datasource_description.tsx create mode 100644 public/components/data_connections/components/manage_datasource_table.tsx create mode 100644 public/components/data_connections/home.tsx create mode 100644 server/routes/datasources/datasources_router.ts diff --git a/.cypress/integration/10_datasources.spec.js b/.cypress/integration/10_datasources.spec.js new file mode 100644 index 000000000..c4ef7618f --- /dev/null +++ b/.cypress/integration/10_datasources.spec.js @@ -0,0 +1,20 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +/// + + const moveToDatasourcesHome = () => { + cy.visit(`${Cypress.env('opensearchDashboards')}/app/datasources`); + }; + + describe('Basic sanity test for datasources plugin', () => { + it('Navigates to datasources plugin and expects the correct header', () => { + moveToDatasourcesHome(); + cy.get('[data-test-subj="datasources-header"]').should('exist'); + }); +}); + + + diff --git a/common/constants/data_connections.ts b/common/constants/data_connections.ts new file mode 100644 index 000000000..ce031cb6e --- /dev/null +++ b/common/constants/data_connections.ts @@ -0,0 +1,7 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +export const OPENSEARCH_DOCUMENTATION_URL = + 'https://opensearch.org/docs/latest/data-connections/index'; diff --git a/common/constants/shared.ts b/common/constants/shared.ts index 2d10c08e2..f69456221 100644 --- a/common/constants/shared.ts +++ b/common/constants/shared.ts @@ -14,6 +14,7 @@ export const DSL_CAT = '/cat.indices'; export const DSL_MAPPING = '/indices.getFieldMapping'; export const OBSERVABILITY_BASE = '/api/observability'; export const INTEGRATIONS_BASE = '/api/integrations'; +export const DATASOURCES_BASE = '/api/datasources'; export const EVENT_ANALYTICS = '/event_analytics'; export const SAVED_OBJECTS = '/saved_objects'; export const SAVED_QUERY = '/query'; @@ -23,6 +24,7 @@ export const SAVED_VISUALIZATION = '/vis'; export const PPL_ENDPOINT = '/_plugins/_ppl'; export const SQL_ENDPOINT = '/_plugins/_sql'; export const DSL_ENDPOINT = '/_plugins/_dsl'; +export const DATASOURCES_ENDPOINT = '/_plugins/_query/_datasources'; export const observabilityID = 'observability-logs'; export const observabilityTitle = 'Observability'; @@ -56,6 +58,10 @@ export const observabilityIntegrationsID = 'integrations'; export const observabilityIntegrationsTitle = 'Integrations'; export const observabilityIntegrationsPluginOrder = 9020; +export const observabilityDatasourcesID = 'datasources'; +export const observabilityDatasourcesTitle = 'Datasources'; +export const observabilityDatasourcesPluginOrder = 9030; + // Shared Constants export const SQL_DOCUMENTATION_URL = 'https://opensearch.org/docs/latest/search-plugins/sql/index/'; export const PPL_DOCUMENTATION_URL = @@ -74,10 +80,13 @@ export const PPL_NEWLINE_REGEX = /[\n\r]+/g; // Observability plugin URI const BASE_OBSERVABILITY_URI = '/_plugins/_observability'; -const BASE_INTEGRATIONS_URI = '/_plugins/_integrations'; // Used later in front-end for routing +const BASE_DATASOURCES_URI = '/_plugins/_query/_datasources'; export const OPENSEARCH_PANELS_API = { OBJECT: `${BASE_OBSERVABILITY_URI}/object`, }; +export const OPENSEARCH_DATASOURCES_API = { + DATASOURCE: `${BASE_DATASOURCES_URI}`, +}; // Saved Objects export const SAVED_OBJECT = '/object'; diff --git a/opensearch_dashboards.json b/opensearch_dashboards.json index 17267478d..7abafdabd 100644 --- a/opensearch_dashboards.json +++ b/opensearch_dashboards.json @@ -17,5 +17,8 @@ "uiActions", "urlForwarding", "visualizations" + ], + "optionalPlugins": [ + "managementOverview" ] } \ No newline at end of file diff --git a/public/components/app.tsx b/public/components/app.tsx index ac3fa5772..cb7ba34e4 100644 --- a/public/components/app.tsx +++ b/public/components/app.tsx @@ -19,6 +19,7 @@ import { EventAnalytics } from './event_analytics'; import { Home as MetricsHome } from './metrics/index'; import { Main as NotebooksHome } from './notebooks/components/main'; import { Home as TraceAnalyticsHome } from './trace_analytics/home'; +import { Home as DatasourcesHome } from './data_connections/home'; interface ObservabilityAppDeps { CoreStartProp: CoreStart; @@ -44,6 +45,7 @@ const pages = { notebooks: NotebooksHome, dashboards: CustomPanelsHome, integrations: IntegrationsHome, + datasources: DatasourcesHome, }; export const App = ({ diff --git a/public/components/data_connections/components/__tests__/__snapshots__/datasource.test.tsx.snap b/public/components/data_connections/components/__tests__/__snapshots__/datasource.test.tsx.snap new file mode 100644 index 000000000..793dde104 --- /dev/null +++ b/public/components/data_connections/components/__tests__/__snapshots__/datasource.test.tsx.snap @@ -0,0 +1,309 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Datasource Page test Renders datasource page with data 1`] = ` +
+
+
+
+
+
+
+

+

+
+
+
+
+
+
+
+
+
+ Connection title +
+
+ my_spark3 +
+
+
+
+ Access control +
+
+ - +
+
+
+
+
+
+
+
+ Connection description +
+
+ my_spark3 +
+
+
+
+ Connection status +
+
+ j-3UNQLT1MPBGLG +
+
+
+
+
+
+
+
+
+
+ +
+
+
+
+
+
+
+
+ +
+
+ + + +
+

+ Query your data in Data Explorer or Observability Logs. +

+
+
+
+
+
+
+
+ +
+
+ + + +
+

+ Accelerate performance through OpenSearch indexing. +

+
+
+
+
+
+
+
+
+
+
+ + + +
+
+
+
+
+`; diff --git a/public/components/data_connections/components/__tests__/__snapshots__/manage_datasource_description.test.tsx.snap b/public/components/data_connections/components/__tests__/__snapshots__/manage_datasource_description.test.tsx.snap new file mode 100644 index 000000000..b9ab1040b --- /dev/null +++ b/public/components/data_connections/components/__tests__/__snapshots__/manage_datasource_description.test.tsx.snap @@ -0,0 +1,50 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Manage Datasource Description test Renders manage datasource description 1`] = ` + +
+ +

+ Manage existing data connections +

+
+ +
+ + +
+ +
+ Manage already created data source connections. +
+
+
+
+ +
+
+
+ +`; diff --git a/public/components/data_connections/components/__tests__/__snapshots__/manage_datasource_table.test.tsx.snap b/public/components/data_connections/components/__tests__/__snapshots__/manage_datasource_table.test.tsx.snap new file mode 100644 index 000000000..8206d792b --- /dev/null +++ b/public/components/data_connections/components/__tests__/__snapshots__/manage_datasource_table.test.tsx.snap @@ -0,0 +1,695 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Manage Datasource Table test Renders manage datasource table with data 1`] = ` +
+
+
+
+
+
+

+ Data connections +

+
+
+
+
+
+ Connect and manage compatible OpenSearch Dashboard data sources and compute. + + + Learn more + + +
+
+
+
+
+
+

+ Manage existing data connections +

+
+
+
+ Manage already created data source connections. +
+
+
+
+
+
+
+
+
+ +
+ + + +
+
+
+
+
+
+
+
+ +
+
+
+
+
+
+
+
+
+
+
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ + + Name + + + + + + Connection Status + + + + + + Actions + + +
+
+ Name +
+
+
+ +
+
+
+ Connection Status +
+
+
+
+
+
+ Actions +
+
+ +
+
+
+ Name +
+
+
+ +
+
+
+ Connection Status +
+
+
+
+
+
+ Actions +
+
+ +
+
+
+ Name +
+
+
+ +
+
+
+ Connection Status +
+
+
+
+
+
+ Actions +
+
+ +
+
+
+ Name +
+
+
+ +
+
+
+ Connection Status +
+
+
+
+
+
+ Actions +
+
+ +
+
+
+
+
+
+
+
+
+ +
+
+
+
+ +
+
+
+
+
+
+
+
+
+`; diff --git a/public/components/data_connections/components/__tests__/datasource.test.tsx b/public/components/data_connections/components/__tests__/datasource.test.tsx new file mode 100644 index 000000000..8294e0598 --- /dev/null +++ b/public/components/data_connections/components/__tests__/datasource.test.tsx @@ -0,0 +1,39 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { configure, mount } from 'enzyme'; +import Adapter from 'enzyme-adapter-react-16'; +import { act, waitFor } from '@testing-library/react'; +import React from 'react'; +import { DataConnectionsDescription } from '../manage_datasource_description'; +import { ManageDatasourcesTable } from '../manage_datasource_table'; +import { describeDatasource, showDatasourceData } from './testing_constants'; +import { DataSource } from '../datasource'; +import ReactDOM from 'react-dom'; + +describe('Datasource Page test', () => { + configure({ adapter: new Adapter() }); + + it('Renders datasource page with data', async () => { + const http = { + get: jest.fn().mockResolvedValue(describeDatasource), + }; + const pplService = { + fetch: jest.fn(), + }; + const mockChrome = { + setBreadcrumbs: jest.fn(), + }; + const wrapper = mount(); + const container = document.createElement('div'); + await act(() => { + ReactDOM.render( + , + container + ); + }); + expect(container).toMatchSnapshot(); + }); +}); diff --git a/public/components/data_connections/components/__tests__/manage_datasource_description.test.tsx b/public/components/data_connections/components/__tests__/manage_datasource_description.test.tsx new file mode 100644 index 000000000..e6380b0d5 --- /dev/null +++ b/public/components/data_connections/components/__tests__/manage_datasource_description.test.tsx @@ -0,0 +1,22 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { configure, mount } from 'enzyme'; +import Adapter from 'enzyme-adapter-react-16'; +import { waitFor } from '@testing-library/react'; +import React from 'react'; +import { DataConnectionsDescription } from '../manage_datasource_description'; + +describe('Manage Datasource Description test', () => { + configure({ adapter: new Adapter() }); + + it('Renders manage datasource description', async () => { + const wrapper = mount(); + + await waitFor(() => { + expect(wrapper).toMatchSnapshot(); + }); + }); +}); diff --git a/public/components/data_connections/components/__tests__/manage_datasource_table.test.tsx b/public/components/data_connections/components/__tests__/manage_datasource_table.test.tsx new file mode 100644 index 000000000..599a7a235 --- /dev/null +++ b/public/components/data_connections/components/__tests__/manage_datasource_table.test.tsx @@ -0,0 +1,36 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { configure } from 'enzyme'; +import Adapter from 'enzyme-adapter-react-16'; +import { act } from '@testing-library/react'; +import React from 'react'; +import { ManageDatasourcesTable } from '../manage_datasource_table'; +import { showDatasourceData } from './testing_constants'; +import ReactDOM from 'react-dom'; + +describe('Manage Datasource Table test', () => { + configure({ adapter: new Adapter() }); + + it('Renders manage datasource table with data', async () => { + const http = { + get: jest.fn().mockResolvedValue(showDatasourceData), + }; + const pplService = { + fetch: jest.fn(), + }; + const mockChrome = { + setBreadcrumbs: jest.fn(), + }; + const container = document.createElement('div'); + await act(() => { + ReactDOM.render( + , + container + ); + }); + expect(container).toMatchSnapshot(); + }); +}); diff --git a/public/components/data_connections/components/__tests__/testing_constants.ts b/public/components/data_connections/components/__tests__/testing_constants.ts new file mode 100644 index 000000000..5cad33957 --- /dev/null +++ b/public/components/data_connections/components/__tests__/testing_constants.ts @@ -0,0 +1,75 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +export const showDatasourceData = [ + { + name: 'my_spark3', + connector: 'SPARK', + allowedRoles: [], + properties: { + 'spark.connector': 'emr', + 'spark.datasource.flint.host': '0.0.0.0', + 'spark.datasource.flint.integration': + 'https://aws.oss.sonatype.org/content/repositories/snapshots/org/opensearch/opensearch-spark-standalone_2.12/0.1.0-SNAPSHOT/opensearch-spark-standalone_2.12-0.1.0-20230731.182705-3.jar', + 'spark.datasource.flint.port': '9200', + 'spark.datasource.flint.scheme': 'http', + 'emr.cluster': 'j-3UNQLT1MPBGLG', + }, + }, + { + name: 'my_spark4', + connector: 'SPARK', + allowedRoles: [], + properties: { + 'spark.connector': 'emr', + 'spark.datasource.flint.host': '15.248.1.68', + 'spark.datasource.flint.integration': + 'https://aws.oss.sonatype.org/content/repositories/snapshots/org/opensearch/opensearch-spark-standalone_2.12/0.1.0-SNAPSHOT/opensearch-spark-standalone_2.12-0.1.0-20230731.182705-3.jar', + 'spark.datasource.flint.port': '9200', + 'spark.datasource.flint.scheme': 'http', + 'emr.cluster': 'j-3UNQLT1MPBGLG', + }, + }, + { + name: 'my_spark', + connector: 'SPARK', + allowedRoles: [], + properties: { + 'spark.connector': 'emr', + 'spark.datasource.flint.host': '0.0.0.0', + 'spark.datasource.flint.port': '9200', + 'spark.datasource.flint.scheme': 'http', + 'spark.datasource.flint.region': 'xxx', + 'emr.cluster': 'xxx', + }, + }, + { + name: 'my_spark2', + connector: 'SPARK', + allowedRoles: [], + properties: { + 'spark.connector': 'emr', + 'spark.datasource.flint.host': '0.0.0.0', + 'spark.datasource.flint.port': '9200', + 'spark.datasource.flint.scheme': 'http', + 'emr.cluster': 'j-3UNQLT1MPBGLG', + }, + }, +]; + +export const describeDatasource = { + name: 'my_spark3', + connector: 'SPARK', + allowedRoles: [], + properties: { + 'spark.connector': 'emr', + 'spark.datasource.flint.host': '0.0.0.0', + 'spark.datasource.flint.integration': + 'https://aws.oss.sonatype.org/content/repositories/snapshots/org/opensearch/opensearch-spark-standalone_2.12/0.1.0-SNAPSHOT/opensearch-spark-standalone_2.12-0.1.0-20230731.182705-3.jar', + 'spark.datasource.flint.port': '9200', + 'spark.datasource.flint.scheme': 'http', + 'emr.cluster': 'j-3UNQLT1MPBGLG', + }, +}; diff --git a/public/components/data_connections/components/datasource.tsx b/public/components/data_connections/components/datasource.tsx new file mode 100644 index 000000000..19c6b9fbe --- /dev/null +++ b/public/components/data_connections/components/datasource.tsx @@ -0,0 +1,178 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { + EuiFlexGroup, + EuiFlexItem, + EuiPage, + EuiPageBody, + EuiSpacer, + EuiTitle, + EuiText, + EuiPanel, + EuiPageHeader, + EuiPageHeaderSection, + EuiAccordion, + EuiIcon, + EuiCard, + EuiTab, + EuiTabs, +} from '@elastic/eui'; +import React, { useEffect, useState } from 'react'; +import { DATASOURCES_BASE } from '../../../../common/constants/shared'; + +interface DatasourceDetails { + allowedRoles: string[]; + name: string; + cluster: string; +} + +export function DataSource(props: any) { + const { dataSource, pplService, http } = props; + const [datasourceDetails, setDatasourceDetails] = useState({ + allowedRoles: [], + name: '', + cluster: '', + }); + + useEffect(() => { + http.get(`${DATASOURCES_BASE}/${dataSource}`).then((data) => + setDatasourceDetails({ + allowedRoles: data.allowedRoles, + name: data.name, + cluster: data.properties['emr.cluster'], + }) + ); + }, []); + + const tabs = [ + { + id: 'data', + name: 'Data', + disabled: false, + }, + { + id: 'access_control', + name: 'Access control', + disabled: false, + }, + { + id: 'connection_configuration', + name: 'Connection configuration', + disabled: false, + }, + ]; + + const [selectedTabId, setSelectedTabId] = useState('data'); + + const onSelectedTabChanged = (id) => { + setSelectedTabId(id); + }; + + const renderTabs = () => { + return tabs.map((tab, index) => ( + onSelectedTabChanged(tab.id)} + isSelected={tab.id === selectedTabId} + disabled={tab.disabled} + key={index} + > + {tab.name} + + )); + }; + + const renderOverview = () => { + return ( + + + + + + Connection title + + {datasourceDetails.name || '-'} + + + + Access control + + {datasourceDetails.allowedRoles && datasourceDetails.allowedRoles.length + ? datasourceDetails.allowedRoles + : '-'} + + + + + + + + Connection description + + {datasourceDetails.name || '-'} + + + + Connection status + + {datasourceDetails.cluster || '-'} + + + + + + + + ); + }; + + return ( + + + + + + + +

{dataSource}

+
+
+
+
+
+ + {renderOverview()} + + + + + } + title={'Query data'} + description="Query your data in Data Explorer or Observability Logs." + onClick={() => {}} + /> + + + } + title={'Accelerate performance'} + description="Accelerate performance through OpenSearch indexing." + onClick={() => {}} + /> + + + + {renderTabs()} + + +
+
+ ); +} diff --git a/public/components/data_connections/components/datasources_header.tsx b/public/components/data_connections/components/datasources_header.tsx new file mode 100644 index 000000000..8c0ceb724 --- /dev/null +++ b/public/components/data_connections/components/datasources_header.tsx @@ -0,0 +1,38 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { + EuiLink, + EuiPageHeader, + EuiPageHeaderSection, + EuiSpacer, + EuiText, + EuiTitle, +} from '@elastic/eui'; +import _ from 'lodash'; +import React from 'react'; +import { OPENSEARCH_DOCUMENTATION_URL } from '../../../../common/constants/data_connections'; + +export function DataConnectionsHeader() { + return ( +
+ + + +

Data connections

+
+
+
+ + + Connect and manage compatible OpenSearch Dashboard data sources and compute.{' '} + + Learn more + + + +
+ ); +} diff --git a/public/components/data_connections/components/manage_datasource_description.tsx b/public/components/data_connections/components/manage_datasource_description.tsx new file mode 100644 index 000000000..f05fb01e2 --- /dev/null +++ b/public/components/data_connections/components/manage_datasource_description.tsx @@ -0,0 +1,24 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { EuiSpacer, EuiText, EuiTitle, EuiHorizontalRule } from '@elastic/eui'; +import _ from 'lodash'; +import React from 'react'; + +export function DataConnectionsDescription() { + return ( +
+ +

Manage existing data connections

+
+ + + + Manage already created data source connections. + + +
+ ); +} diff --git a/public/components/data_connections/components/manage_datasource_table.tsx b/public/components/data_connections/components/manage_datasource_table.tsx new file mode 100644 index 000000000..2fd3e01b3 --- /dev/null +++ b/public/components/data_connections/components/manage_datasource_table.tsx @@ -0,0 +1,159 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { + EuiFlexGroup, + EuiFlexItem, + EuiIcon, + EuiInMemoryTable, + EuiLink, + EuiPage, + EuiPageBody, + EuiPageContent, + EuiTableFieldDataColumnType, + EuiText, +} from '@elastic/eui'; +import _ from 'lodash'; +import React, { useEffect, useState } from 'react'; +import { DataConnectionsHeader } from './datasources_header'; +import { HomeProps } from '../home'; +import { DataConnectionsDescription } from './manage_datasource_description'; +import { DATASOURCES_BASE } from '../../../../common/constants/shared'; + +interface DataConnection { + connectionType: 'OPENSEARCH' | 'SPARK'; + name: string; +} + +export function ManageDatasourcesTable(props: HomeProps) { + const { http, chrome, pplService } = props; + + const [data, setData] = useState([]); + + useEffect(() => { + chrome.setBreadcrumbs([ + { + text: 'Datasources', + href: '#/', + }, + ]); + handleDataRequest(); + }, []); + + async function handleDataRequest() { + http.get(`${DATASOURCES_BASE}`).then((datasources) => + setData( + datasources.map((x: any) => { + return { name: x.name, connectionType: x.connector }; + }) + ) + ); + } + + const icon = (record: DataConnection) => { + switch (record.connectionType) { + case 'OPENSEARCH': + return ; + default: + return <>; + } + }; + + const tableColumns = [ + { + field: 'name', + name: 'Name', + sortable: true, + truncateText: true, + render: (value, record: DataConnection) => ( + + {icon(record)} + + + {_.truncate(record.name, { length: 100 })} + + + + ), + }, + { + field: 'connectionStatus', + name: 'Connection Status', + sortable: true, + truncateText: true, + render: (value, record) => ( + + {_.truncate(record.creationDate, { length: 100 })} + + ), + }, + { + field: 'actions', + name: 'Actions', + sortable: true, + truncateText: true, + render: (value, record) => ( + { + /* Delete Datasource*/ + }} + /> + ), + }, + ] as Array>; + + const search = { + box: { + incremental: true, + }, + filters: [ + { + type: 'field_value_selection', + field: 'templateName', + name: 'Type', + multiSelect: false, + options: [].map((i) => ({ + value: i, + name: i, + view: i, + })), + }, + ], + }; + + const entries = data.map((dataconnection: DataConnection) => { + const name = dataconnection.name; + const connectionType = dataconnection.connectionType; + return { connectionType, name, data: { name, connectionType } }; + }); + + return ( + + + + + + + + + + ); +} diff --git a/public/components/data_connections/home.tsx b/public/components/data_connections/home.tsx new file mode 100644 index 000000000..88ad367c5 --- /dev/null +++ b/public/components/data_connections/home.tsx @@ -0,0 +1,52 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import React from 'react'; +import { HashRouter, Route, RouteComponentProps, Switch } from 'react-router-dom'; +import { ChromeBreadcrumb, ChromeStart, HttpStart } from '../../../../../src/core/public'; +import { DataSource } from './components/datasource'; +import { ManageDatasourcesTable } from './components/manage_datasource_table'; + +export interface HomeProps extends RouteComponentProps { + pplService: any; + parentBreadcrumb: ChromeBreadcrumb; + http: HttpStart; + chrome: ChromeStart; +} + +export const Home = (props: HomeProps) => { + const { http, chrome, pplService } = props; + + const commonProps = { + http, + chrome, + pplService, + }; + + return ( +
+ + + ( + + )} + /> + + } + /> + + +
+ ); +}; diff --git a/public/components/integrations/components/available_integration_overview_page.tsx b/public/components/integrations/components/available_integration_overview_page.tsx index e858daa54..360bf0db4 100644 --- a/public/components/integrations/components/available_integration_overview_page.tsx +++ b/public/components/integrations/components/available_integration_overview_page.tsx @@ -117,8 +117,7 @@ export function AvailableIntegrationOverviewPage(props: AvailableIntegrationOver http.get(`${INTEGRATIONS_BASE}/repository`).then((exists) => { setData(exists.data); - let newItems = exists.data.hits - .flatMap((hit: { labels?: string[] }) => hit.labels ?? []); + let newItems = exists.data.hits.flatMap((hit: { labels?: string[] }) => hit.labels ?? []); newItems = [...new Set(newItems)].sort().map((newItem) => { return { name: newItem, diff --git a/public/plugin.ts b/public/plugin.ts index 021a9f56a..6d553f63c 100644 --- a/public/plugin.ts +++ b/public/plugin.ts @@ -39,6 +39,9 @@ import { observabilityIntegrationsTitle, observabilityIntegrationsPluginOrder, observabilityPluginOrder, + observabilityDatasourcesID, + observabilityDatasourcesTitle, + observabilityDatasourcesPluginOrder, } from '../common/constants/shared'; import { QueryManager } from '../common/query_manager'; import { VISUALIZATION_SAVED_OBJECT } from '../common/types/observability_saved_object_attributes'; @@ -197,6 +200,23 @@ export class ObservabilityPlugin mount: appMountWithStartPage('integrations'), }); + core.application.register({ + id: observabilityDatasourcesID, + title: observabilityDatasourcesTitle, + category: DEFAULT_APP_CATEGORIES.management, + order: observabilityDatasourcesPluginOrder, + mount: appMountWithStartPage('datasources'), + }); + + setupDeps.managementOverview?.register({ + id: observabilityDatasourcesID, + title: observabilityDatasourcesTitle, + order: 9070, + description: i18n.translate('observability.datasourcesDescription', { + defaultMessage: 'Manage compatible data sources and compute with OpenSearch Dashboards.', + }), + }); + const embeddableFactory = new ObservabilityEmbeddableFactoryDefinition(async () => ({ getAttributeService: (await core.getStartServices())[1].dashboard.getAttributeService, savedObjectsClient: (await core.getStartServices())[0].savedObjects.client, diff --git a/public/types.ts b/public/types.ts index 48f0ad9de..75afb133b 100644 --- a/public/types.ts +++ b/public/types.ts @@ -7,6 +7,7 @@ import { SavedObjectsClient } from '../../../src/core/server'; import { DashboardStart } from '../../../src/plugins/dashboard/public'; import { DataPublicPluginSetup } from '../../../src/plugins/data/public'; import { EmbeddableSetup, EmbeddableStart } from '../../../src/plugins/embeddable/public'; +import { ManagementOverViewPluginSetup } from '../../../src/plugins/management_overview/public'; import { NavigationPublicPluginStart } from '../../../src/plugins/navigation/public'; import { UiActionsStart } from '../../../src/plugins/ui_actions/public'; import { VisualizationsSetup } from '../../../src/plugins/visualizations/public'; @@ -23,6 +24,7 @@ export interface SetupDependencies { visualizations: VisualizationsSetup; data: DataPublicPluginSetup; uiActions: UiActionsStart; + managementOverview?: ManagementOverViewPluginSetup; } // eslint-disable-next-line @typescript-eslint/no-empty-interface diff --git a/server/adaptors/opensearch_observability_plugin.ts b/server/adaptors/opensearch_observability_plugin.ts index fbdbac72b..10137b33c 100644 --- a/server/adaptors/opensearch_observability_plugin.ts +++ b/server/adaptors/opensearch_observability_plugin.ts @@ -3,7 +3,7 @@ * SPDX-License-Identifier: Apache-2.0 */ -import { OPENSEARCH_PANELS_API } from '../../common/constants/shared'; +import { OPENSEARCH_DATASOURCES_API, OPENSEARCH_PANELS_API } from '../../common/constants/shared'; export function OpenSearchObservabilityPlugin(Client: any, config: any, components: any) { const clientAction = components.clientAction.factory; diff --git a/server/adaptors/ppl_plugin.ts b/server/adaptors/ppl_plugin.ts index 304d196e3..e4714c9d0 100644 --- a/server/adaptors/ppl_plugin.ts +++ b/server/adaptors/ppl_plugin.ts @@ -3,7 +3,11 @@ * SPDX-License-Identifier: Apache-2.0 */ -import { PPL_ENDPOINT, SQL_ENDPOINT } from '../../common/constants/shared'; +import { + OPENSEARCH_DATASOURCES_API, + PPL_ENDPOINT, + SQL_ENDPOINT, +} from '../../common/constants/shared'; export const PPLPlugin = function (Client, config, components) { const ca = components.clientAction.factory; @@ -37,4 +41,24 @@ export const PPLPlugin = function (Client, config, components) { needBody: true, method: 'POST', }); + + ppl.getDatasourceById = ca({ + url: { + fmt: `${OPENSEARCH_DATASOURCES_API.DATASOURCE}/<%=datasource%>`, + req: { + datasource: { + type: 'string', + required: true, + }, + }, + }, + method: 'GET', + }); + + ppl.getDatasources = ca({ + url: { + fmt: `${OPENSEARCH_DATASOURCES_API.DATASOURCE}`, + }, + method: 'GET', + }); }; diff --git a/server/routes/datasources/datasources_router.ts b/server/routes/datasources/datasources_router.ts new file mode 100644 index 000000000..187be8da1 --- /dev/null +++ b/server/routes/datasources/datasources_router.ts @@ -0,0 +1,62 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { schema } from '@osd/config-schema'; +import { IRouter } from '../../../../../src/core/server'; +import { DATASOURCES_BASE } from '../../../common/constants/shared'; + +export function registerDatasourcesRoute(router: IRouter) { + router.get( + { + path: `${DATASOURCES_BASE}/{name}`, + validate: { + params: schema.object({ + name: schema.string(), + }), + }, + }, + async (context, request, response): Promise => { + try { + const dataSourcesresponse = await context.observability_plugin.observabilityClient + .asScoped(request) + .callAsCurrentUser('ppl.getDatasourceById', { + datasource: request.params.name, + }); + return response.ok({ + body: dataSourcesresponse, + }); + } catch (error: any) { + console.error('Issue in fetching datasource:', error); + return response.custom({ + statusCode: error.statusCode || 500, + body: error.message, + }); + } + } + ); + + router.get( + { + path: `${DATASOURCES_BASE}`, + validate: false, + }, + async (context, request, response): Promise => { + try { + const dataSourcesresponse = await context.observability_plugin.observabilityClient + .asScoped(request) + .callAsCurrentUser('ppl.getDatasources'); + return response.ok({ + body: dataSourcesresponse, + }); + } catch (error: any) { + console.error('Issue in fetching datasources:', error); + return response.custom({ + statusCode: error.statusCode || 500, + body: error.message, + }); + } + } + ); +} diff --git a/server/routes/index.ts b/server/routes/index.ts index 11912d813..6601127a5 100644 --- a/server/routes/index.ts +++ b/server/routes/index.ts @@ -21,6 +21,7 @@ import { registerEventAnalyticsRouter } from './event_analytics/event_analytics_ import { registerAppAnalyticsRouter } from './application_analytics/app_analytics_router'; import { registerMetricsRoute } from './metrics/metrics_rounter'; import { registerIntegrationsRoute } from './integrations/integrations_router'; +import { registerDatasourcesRoute } from './datasources/datasources_router'; export function setupRoutes({ router, client }: { router: IRouter; client: ILegacyClusterClient }) { PanelsRouter(router); @@ -42,4 +43,5 @@ export function setupRoutes({ router, client }: { router: IRouter; client: ILega registerMetricsRoute(router); registerIntegrationsRoute(router); + registerDatasourcesRoute(router); } From 6e42a2b19af205dad0e85a3ee02daf4f560d7483 Mon Sep 17 00:00:00 2001 From: Shenoy Pratik Date: Mon, 11 Sep 2023 17:30:04 -0400 Subject: [PATCH 02/22] Add acceleration management UI (#989) * add acceleration management UI skeleton Signed-off-by: Shenoy Pratik * Create new documentation link for acc Signed-off-by: Shenoy Pratik * fix typos and minor bugs Signed-off-by: Shenoy Pratik * update snapshot Signed-off-by: Shenoy Pratik * update window location to hash Signed-off-by: Shenoy Pratik * remove unused headers Signed-off-by: Shenoy Pratik --------- Signed-off-by: Shenoy Pratik --- common/constants/data_connections.ts | 3 + opensearch_dashboards.json | 6 +- ...anage_datasource_description.test.tsx.snap | 4 +- .../acceleration_ui/acceleration_header.tsx | 37 ++++++ .../acceleration_ui/acceleration_home.tsx | 23 ++++ .../acceleration_ui/acceleration_indices.tsx | 39 ++++++ .../management/acceleration_management.tsx | 50 ++++++++ .../management/management_table.tsx | 115 ++++++++++++++++++ .../management/source_selector.tsx | 88 ++++++++++++++ .../components/datasource.tsx | 6 +- .../components/datasources_header.tsx | 4 +- .../manage_datasource_description.tsx | 4 +- .../components/manage_datasource_table.tsx | 8 +- public/components/data_connections/home.tsx | 48 ++++---- public/framework/core_refs.ts | 3 +- public/plugin.ts | 1 + 16 files changed, 401 insertions(+), 38 deletions(-) create mode 100644 public/components/data_connections/components/acceleration_ui/acceleration_header.tsx create mode 100644 public/components/data_connections/components/acceleration_ui/acceleration_home.tsx create mode 100644 public/components/data_connections/components/acceleration_ui/acceleration_indices.tsx create mode 100644 public/components/data_connections/components/acceleration_ui/management/acceleration_management.tsx create mode 100644 public/components/data_connections/components/acceleration_ui/management/management_table.tsx create mode 100644 public/components/data_connections/components/acceleration_ui/management/source_selector.tsx diff --git a/common/constants/data_connections.ts b/common/constants/data_connections.ts index ce031cb6e..354d797de 100644 --- a/common/constants/data_connections.ts +++ b/common/constants/data_connections.ts @@ -5,3 +5,6 @@ export const OPENSEARCH_DOCUMENTATION_URL = 'https://opensearch.org/docs/latest/data-connections/index'; + +export const OPENSEARCH_ACC_DOCUMENTATION_URL = + 'https://opensearch.org/docs/latest/data-acceleration/index'; diff --git a/opensearch_dashboards.json b/opensearch_dashboards.json index 7abafdabd..08b79d1a5 100644 --- a/opensearch_dashboards.json +++ b/opensearch_dashboards.json @@ -18,7 +18,5 @@ "urlForwarding", "visualizations" ], - "optionalPlugins": [ - "managementOverview" - ] -} \ No newline at end of file + "optionalPlugins": ["managementOverview"] +} diff --git a/public/components/data_connections/components/__tests__/__snapshots__/manage_datasource_description.test.tsx.snap b/public/components/data_connections/components/__tests__/__snapshots__/manage_datasource_description.test.tsx.snap index b9ab1040b..4dbd5ddf8 100644 --- a/public/components/data_connections/components/__tests__/__snapshots__/manage_datasource_description.test.tsx.snap +++ b/public/components/data_connections/components/__tests__/__snapshots__/manage_datasource_description.test.tsx.snap @@ -1,7 +1,7 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`Manage Datasource Description test Renders manage datasource description 1`] = ` - +
-
+ `; diff --git a/public/components/data_connections/components/acceleration_ui/acceleration_header.tsx b/public/components/data_connections/components/acceleration_ui/acceleration_header.tsx new file mode 100644 index 000000000..548b45059 --- /dev/null +++ b/public/components/data_connections/components/acceleration_ui/acceleration_header.tsx @@ -0,0 +1,37 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { + EuiLink, + EuiPageHeader, + EuiPageHeaderSection, + EuiSpacer, + EuiText, + EuiTitle, +} from '@elastic/eui'; +import React from 'react'; +import { OPENSEARCH_ACC_DOCUMENTATION_URL } from '../../../../../common/constants/data_connections'; + +export const AccelerationHeader = () => { + return ( +
+ + + +

Acceleration Indices

+
+
+
+ + + Manage acceleration indices from external data connections.{' '} + + Learn more + + + +
+ ); +}; diff --git a/public/components/data_connections/components/acceleration_ui/acceleration_home.tsx b/public/components/data_connections/components/acceleration_ui/acceleration_home.tsx new file mode 100644 index 000000000..f1565d820 --- /dev/null +++ b/public/components/data_connections/components/acceleration_ui/acceleration_home.tsx @@ -0,0 +1,23 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import React from 'react'; +import { HashRouter, Route, Switch } from 'react-router-dom'; +import { AccelerationIndices } from './acceleration_indices'; + +export const AccelerationHome = () => { + return ( + + + ( + + )} + /> + + + ); +}; diff --git a/public/components/data_connections/components/acceleration_ui/acceleration_indices.tsx b/public/components/data_connections/components/acceleration_ui/acceleration_indices.tsx new file mode 100644 index 000000000..2d98c2d28 --- /dev/null +++ b/public/components/data_connections/components/acceleration_ui/acceleration_indices.tsx @@ -0,0 +1,39 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import React, { useEffect } from 'react'; +import { EuiPage, EuiPageBody, EuiPageContent } from '@elastic/eui'; +import { coreRefs } from '../../../../framework/core_refs'; +import { AccelerationHeader } from './acceleration_header'; +import { AccelerationManagement } from './management/acceleration_management'; + +interface AccelerationIndicesProps { + dataSource: string; +} + +export const AccelerationIndices = ({ dataSource }: AccelerationIndicesProps) => { + useEffect(() => { + coreRefs.chrome?.setBreadcrumbs([ + { + text: 'Datasources', + href: '#/', + }, + { + text: 'Acceleration', + href: '#/manage/acceleration/' + { dataSource }, + }, + ]); + }, [dataSource]); + return ( + + + + + + + + + ); +}; diff --git a/public/components/data_connections/components/acceleration_ui/management/acceleration_management.tsx b/public/components/data_connections/components/acceleration_ui/management/acceleration_management.tsx new file mode 100644 index 000000000..7a8236600 --- /dev/null +++ b/public/components/data_connections/components/acceleration_ui/management/acceleration_management.tsx @@ -0,0 +1,50 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import React from 'react'; +import { + EuiButton, + EuiFlexGroup, + EuiFlexItem, + EuiHorizontalRule, + EuiSpacer, + EuiText, +} from '@elastic/eui'; +import { ManagementTable } from './management_table'; +import { AccelerationDataSourceSelector } from './source_selector'; + +export const AccelerationManagement = () => { + return ( + <> + + + + +

Manage existing acceleration indices

+
+ + + View and Edit acceleration indices{' '} + +
+ + + + + Delete + + + + Accelerate Table + + + + +
+ + + + ); +}; diff --git a/public/components/data_connections/components/acceleration_ui/management/management_table.tsx b/public/components/data_connections/components/acceleration_ui/management/management_table.tsx new file mode 100644 index 000000000..6c40230a4 --- /dev/null +++ b/public/components/data_connections/components/acceleration_ui/management/management_table.tsx @@ -0,0 +1,115 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import React, { useEffect, useState } from 'react'; +import { + EuiIcon, + EuiInMemoryTable, + EuiSpacer, + EuiTableFieldDataColumnType, + EuiText, +} from '@elastic/eui'; +import _ from 'lodash'; + +interface AccelerationIndicesRecordType { + indexName: string; + accelerationType: string; +} + +export const ManagementTable = () => { + const [accelerationIndicesRecords, setAccelerationIndicesRecords] = useState< + AccelerationIndicesRecordType[] + >([]); + + useEffect(() => { + setAccelerationIndicesRecords([ + { + indexName: 'Sample-skipping-index', + accelerationType: 'Skipping Index', + }, + { + indexName: 'Sample-covering-index', + accelerationType: 'covering Index', + }, + { + indexName: 'Sample-materialized-view', + accelerationType: 'Materialized View', + }, + ]); + }, []); + + const tableColumns: Array> = [ + { + field: 'indexName', + name: 'Index Name', + sortable: true, + truncateText: true, + render: (value, record: AccelerationIndicesRecordType) => ( + {_.truncate(record.indexName, { length: 100 })} + ), + }, + { + field: 'accelerationType', + name: 'Acceleration type', + sortable: true, + truncateText: true, + render: (value, record) => ( + {_.truncate(record.accelerationType, { length: 100 })} + ), + }, + { + field: 'actions', + name: 'Actions', + sortable: true, + truncateText: true, + render: (value, record) => ( + { + /* Delete Datasource*/ + }} + /> + ), + }, + ]; + + const search = { + box: { + incremental: true, + }, + filters: [ + { + type: 'field_value_selection', + field: 'accelerationType', + name: 'Type', + multiSelect: 'or', + options: accelerationIndicesRecords.map((AccelerationIndexRecord) => ({ + value: AccelerationIndexRecord.accelerationType, + name: AccelerationIndexRecord.accelerationType, + view: AccelerationIndexRecord.accelerationType, + })), + }, + ], + }; + + return ( + <> + + + + ); +}; diff --git a/public/components/data_connections/components/acceleration_ui/management/source_selector.tsx b/public/components/data_connections/components/acceleration_ui/management/source_selector.tsx new file mode 100644 index 000000000..fddb537c1 --- /dev/null +++ b/public/components/data_connections/components/acceleration_ui/management/source_selector.tsx @@ -0,0 +1,88 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { EuiComboBox, EuiFormRow, EuiSpacer, EuiText } from '@elastic/eui'; +import React, { useState } from 'react'; +import { useEffect } from 'react'; + +interface DataSourceTypes { + label: string; +} + +export const AccelerationDataSourceSelector = () => { + const [dataConnections, setDataConnections] = useState([]); + const [selectedDataConnection, setSelectedDataConnection] = useState([]); + const [tables, setTables] = useState([]); + const [selectedTable, setSelectedTable] = useState([]); + + useEffect(() => { + setDataConnections([ + { + label: 'spark1', + }, + { + label: 'spark2', + }, + ]); + }, []); + + useEffect(() => { + setTables([ + { + label: 'Table1', + }, + { + label: 'Table1', + }, + ]); + }, [dataConnections]); + + const onChangeDataConnection = ( + dataConnectionOptions: React.SetStateAction + ) => { + setSelectedDataConnection(dataConnectionOptions); + }; + const onChangeTable = (tableOptions: React.SetStateAction) => { + setSelectedTable(tableOptions); + }; + + return ( + <> + +

Select data connection

+
+ + + Select data connection where the data you want to accelerate resides.{' '} + + + + + + + + + + + ); +}; diff --git a/public/components/data_connections/components/datasource.tsx b/public/components/data_connections/components/datasource.tsx index 19c6b9fbe..0964a16a8 100644 --- a/public/components/data_connections/components/datasource.tsx +++ b/public/components/data_connections/components/datasource.tsx @@ -29,7 +29,7 @@ interface DatasourceDetails { cluster: string; } -export function DataSource(props: any) { +export const DataSource = (props: any) => { const { dataSource, pplService, http } = props; const [datasourceDetails, setDatasourceDetails] = useState({ allowedRoles: [], @@ -164,7 +164,7 @@ export function DataSource(props: any) { icon={} title={'Accelerate performance'} description="Accelerate performance through OpenSearch indexing." - onClick={() => {}} + onClick={() => (window.location.hash = `/acceleration/${dataSource}`)} /> @@ -175,4 +175,4 @@ export function DataSource(props: any) { ); -} +}; diff --git a/public/components/data_connections/components/datasources_header.tsx b/public/components/data_connections/components/datasources_header.tsx index 8c0ceb724..045d1cbc8 100644 --- a/public/components/data_connections/components/datasources_header.tsx +++ b/public/components/data_connections/components/datasources_header.tsx @@ -15,7 +15,7 @@ import _ from 'lodash'; import React from 'react'; import { OPENSEARCH_DOCUMENTATION_URL } from '../../../../common/constants/data_connections'; -export function DataConnectionsHeader() { +export const DataConnectionsHeader = () => { return (
@@ -35,4 +35,4 @@ export function DataConnectionsHeader() {
); -} +}; diff --git a/public/components/data_connections/components/manage_datasource_description.tsx b/public/components/data_connections/components/manage_datasource_description.tsx index f05fb01e2..9c97d5758 100644 --- a/public/components/data_connections/components/manage_datasource_description.tsx +++ b/public/components/data_connections/components/manage_datasource_description.tsx @@ -7,7 +7,7 @@ import { EuiSpacer, EuiText, EuiTitle, EuiHorizontalRule } from '@elastic/eui'; import _ from 'lodash'; import React from 'react'; -export function DataConnectionsDescription() { +export const DataConnectionsDescription = () => { return (
@@ -21,4 +21,4 @@ export function DataConnectionsDescription() {
); -} +}; diff --git a/public/components/data_connections/components/manage_datasource_table.tsx b/public/components/data_connections/components/manage_datasource_table.tsx index 2fd3e01b3..c5650d308 100644 --- a/public/components/data_connections/components/manage_datasource_table.tsx +++ b/public/components/data_connections/components/manage_datasource_table.tsx @@ -21,13 +21,15 @@ import { DataConnectionsHeader } from './datasources_header'; import { HomeProps } from '../home'; import { DataConnectionsDescription } from './manage_datasource_description'; import { DATASOURCES_BASE } from '../../../../common/constants/shared'; +import { ChromeStart } from '../../../../../../src/core/public'; interface DataConnection { connectionType: 'OPENSEARCH' | 'SPARK'; name: string; + chrome: ChromeStart; } -export function ManageDatasourcesTable(props: HomeProps) { +export const ManageDatasourcesTable = (props: HomeProps) => { const { http, chrome, pplService } = props; const [data, setData] = useState([]); @@ -40,7 +42,7 @@ export function ManageDatasourcesTable(props: HomeProps) { }, ]); handleDataRequest(); - }, []); + }, [chrome]); async function handleDataRequest() { http.get(`${DATASOURCES_BASE}`).then((datasources) => @@ -156,4 +158,4 @@ export function ManageDatasourcesTable(props: HomeProps) { ); -} +}; diff --git a/public/components/data_connections/home.tsx b/public/components/data_connections/home.tsx index 88ad367c5..c59a0afd8 100644 --- a/public/components/data_connections/home.tsx +++ b/public/components/data_connections/home.tsx @@ -8,6 +8,7 @@ import { HashRouter, Route, RouteComponentProps, Switch } from 'react-router-dom import { ChromeBreadcrumb, ChromeStart, HttpStart } from '../../../../../src/core/public'; import { DataSource } from './components/datasource'; import { ManageDatasourcesTable } from './components/manage_datasource_table'; +import { AccelerationIndices } from './components/acceleration_ui/acceleration_indices'; export interface HomeProps extends RouteComponentProps { pplService: any; @@ -26,27 +27,32 @@ export const Home = (props: HomeProps) => { }; return ( -
- - - ( - - )} - /> + + + ( + + )} + /> - } - /> - - -
+ } + /> + + ( + + )} + /> + + ); }; diff --git a/public/framework/core_refs.ts b/public/framework/core_refs.ts index 68cf51547..5b3791f95 100644 --- a/public/framework/core_refs.ts +++ b/public/framework/core_refs.ts @@ -3,7 +3,7 @@ * SPDX-License-Identifier: Apache-2.0 */ -import { HttpStart, IToasts } from '../../../../src/core/public'; +import { ChromeStart, HttpStart, IToasts } from '../../../../src/core/public'; import { SavedObjectsClientContract } from '../../../../src/core/public'; import PPLService from '../services/requests/ppl'; @@ -14,6 +14,7 @@ class CoreRefs { public savedObjectsClient?: SavedObjectsClientContract; public pplService?: PPLService; public toasts?: IToasts; + public chrome?: ChromeStart; private constructor() { // ... } diff --git a/public/plugin.ts b/public/plugin.ts index 6d553f63c..81da89b80 100644 --- a/public/plugin.ts +++ b/public/plugin.ts @@ -262,6 +262,7 @@ export class ObservabilityPlugin coreRefs.savedObjectsClient = core.savedObjects.client; coreRefs.pplService = pplService; coreRefs.toasts = core.notifications.toasts; + coreRefs.chrome = core.chrome; return {}; } From 24cdd19632fb0c20154583b5dea10473c5a4b12b Mon Sep 17 00:00:00 2001 From: Derek Ho Date: Fri, 15 Sep 2023 10:46:10 -0400 Subject: [PATCH 03/22] Rename data sources to data connections (#1004) * rename data sources to data connections Signed-off-by: Derek Ho * final cleanup Signed-off-by: Derek Ho * update acceleration breadcrumb Signed-off-by: Derek Ho * fix API call for data connection page Signed-off-by: Derek Ho * fix integ test and data test subj and snapshot Signed-off-by: Derek Ho --------- Signed-off-by: Derek Ho --- .cypress/integration/10_datasources.spec.js | 4 +-- common/constants/shared.ts | 16 ++++++------ public/components/app.tsx | 4 +-- ...tsx.snap => data_connection.test.tsx.snap} | 2 +- ...ata_connections_description.test.tsx.snap} | 4 +-- ...nage_data_connections_table.test.tsx.snap} | 16 ++++++------ ...urce.test.tsx => data_connection.test.tsx} | 18 ++++++------- ...age_data_connections_description.test.tsx} | 6 ++--- ...=> manage_data_connections_table.test.tsx} | 12 ++++----- .../components/__tests__/testing_constants.ts | 4 +-- .../acceleration_ui/acceleration_indices.tsx | 10 +++---- .../{datasource.tsx => data_connection.tsx} | 6 ++--- ...header.tsx => data_connections_header.tsx} | 4 +-- ...> manage_data_connections_description.tsx} | 3 +-- ....tsx => manage_data_connections_table.tsx} | 16 ++++++------ public/components/data_connections/home.tsx | 10 +++---- public/plugin.ts | 22 ++++++++-------- server/adaptors/ppl_plugin.ts | 12 ++++----- .../data_connections_router.ts} | 26 +++++++++---------- server/routes/index.ts | 4 +-- 20 files changed, 99 insertions(+), 100 deletions(-) rename public/components/data_connections/components/__tests__/__snapshots__/{datasource.test.tsx.snap => data_connection.test.tsx.snap} (99%) rename public/components/data_connections/components/__tests__/__snapshots__/{manage_datasource_description.test.tsx.snap => manage_data_connections_description.test.tsx.snap} (85%) rename public/components/data_connections/components/__tests__/__snapshots__/{manage_datasource_table.test.tsx.snap => manage_data_connections_table.test.tsx.snap} (97%) rename public/components/data_connections/components/__tests__/{datasource.test.tsx => data_connection.test.tsx} (52%) rename public/components/data_connections/components/__tests__/{manage_datasource_description.test.tsx => manage_data_connections_description.test.tsx} (67%) rename public/components/data_connections/components/__tests__/{manage_datasource_table.test.tsx => manage_data_connections_table.test.tsx} (60%) rename public/components/data_connections/components/{datasource.tsx => data_connection.tsx} (96%) rename public/components/data_connections/components/{datasources_header.tsx => data_connections_header.tsx} (83%) rename public/components/data_connections/components/{manage_datasource_description.tsx => manage_data_connections_description.tsx} (86%) rename public/components/data_connections/components/{manage_datasource_table.tsx => manage_data_connections_table.tsx} (87%) rename server/routes/{datasources/datasources_router.ts => data_connections/data_connections_router.ts} (55%) diff --git a/.cypress/integration/10_datasources.spec.js b/.cypress/integration/10_datasources.spec.js index c4ef7618f..8468c58bd 100644 --- a/.cypress/integration/10_datasources.spec.js +++ b/.cypress/integration/10_datasources.spec.js @@ -6,13 +6,13 @@ /// const moveToDatasourcesHome = () => { - cy.visit(`${Cypress.env('opensearchDashboards')}/app/datasources`); + cy.visit(`${Cypress.env('opensearchDashboards')}/app/dataconnections`); }; describe('Basic sanity test for datasources plugin', () => { it('Navigates to datasources plugin and expects the correct header', () => { moveToDatasourcesHome(); - cy.get('[data-test-subj="datasources-header"]').should('exist'); + cy.get('[data-test-subj="dataconnections-header"]').should('exist'); }); }); diff --git a/common/constants/shared.ts b/common/constants/shared.ts index f69456221..f26a59820 100644 --- a/common/constants/shared.ts +++ b/common/constants/shared.ts @@ -14,7 +14,7 @@ export const DSL_CAT = '/cat.indices'; export const DSL_MAPPING = '/indices.getFieldMapping'; export const OBSERVABILITY_BASE = '/api/observability'; export const INTEGRATIONS_BASE = '/api/integrations'; -export const DATASOURCES_BASE = '/api/datasources'; +export const DATACONNECTIONS_BASE = '/api/dataconnections'; export const EVENT_ANALYTICS = '/event_analytics'; export const SAVED_OBJECTS = '/saved_objects'; export const SAVED_QUERY = '/query'; @@ -24,7 +24,7 @@ export const SAVED_VISUALIZATION = '/vis'; export const PPL_ENDPOINT = '/_plugins/_ppl'; export const SQL_ENDPOINT = '/_plugins/_sql'; export const DSL_ENDPOINT = '/_plugins/_dsl'; -export const DATASOURCES_ENDPOINT = '/_plugins/_query/_datasources'; +export const DATACONNECTIONS_ENDPOINT = '/_plugins/_query/_datasources'; export const observabilityID = 'observability-logs'; export const observabilityTitle = 'Observability'; @@ -58,9 +58,9 @@ export const observabilityIntegrationsID = 'integrations'; export const observabilityIntegrationsTitle = 'Integrations'; export const observabilityIntegrationsPluginOrder = 9020; -export const observabilityDatasourcesID = 'datasources'; -export const observabilityDatasourcesTitle = 'Datasources'; -export const observabilityDatasourcesPluginOrder = 9030; +export const observabilityDataConnectionsID = 'dataconnections'; +export const observabilityDataConnectionsTitle = 'Data Connections'; +export const observabilityDataConnectionsPluginOrder = 9030; // Shared Constants export const SQL_DOCUMENTATION_URL = 'https://opensearch.org/docs/latest/search-plugins/sql/index/'; @@ -80,12 +80,12 @@ export const PPL_NEWLINE_REGEX = /[\n\r]+/g; // Observability plugin URI const BASE_OBSERVABILITY_URI = '/_plugins/_observability'; -const BASE_DATASOURCES_URI = '/_plugins/_query/_datasources'; +const BASE_DATACONNECTIONS_URI = '/_plugins/_query/_datasources'; export const OPENSEARCH_PANELS_API = { OBJECT: `${BASE_OBSERVABILITY_URI}/object`, }; -export const OPENSEARCH_DATASOURCES_API = { - DATASOURCE: `${BASE_DATASOURCES_URI}`, +export const OPENSEARCH_DATACONNECTIONS_API = { + DATACONNECTION: `${BASE_DATACONNECTIONS_URI}`, }; // Saved Objects diff --git a/public/components/app.tsx b/public/components/app.tsx index cb7ba34e4..7ace523b4 100644 --- a/public/components/app.tsx +++ b/public/components/app.tsx @@ -19,7 +19,7 @@ import { EventAnalytics } from './event_analytics'; import { Home as MetricsHome } from './metrics/index'; import { Main as NotebooksHome } from './notebooks/components/main'; import { Home as TraceAnalyticsHome } from './trace_analytics/home'; -import { Home as DatasourcesHome } from './data_connections/home'; +import { Home as DataConnectionsHome } from './data_connections/home'; interface ObservabilityAppDeps { CoreStartProp: CoreStart; @@ -45,7 +45,7 @@ const pages = { notebooks: NotebooksHome, dashboards: CustomPanelsHome, integrations: IntegrationsHome, - datasources: DatasourcesHome, + dataconnections: DataConnectionsHome, }; export const App = ({ diff --git a/public/components/data_connections/components/__tests__/__snapshots__/datasource.test.tsx.snap b/public/components/data_connections/components/__tests__/__snapshots__/data_connection.test.tsx.snap similarity index 99% rename from public/components/data_connections/components/__tests__/__snapshots__/datasource.test.tsx.snap rename to public/components/data_connections/components/__tests__/__snapshots__/data_connection.test.tsx.snap index 793dde104..6b0a6e92c 100644 --- a/public/components/data_connections/components/__tests__/__snapshots__/datasource.test.tsx.snap +++ b/public/components/data_connections/components/__tests__/__snapshots__/data_connection.test.tsx.snap @@ -1,6 +1,6 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`Datasource Page test Renders datasource page with data 1`] = ` +exports[`Data Connection Page test Renders data connection page with data 1`] = `
- Manage already created data source connections. + Manage already created data connections.
diff --git a/public/components/data_connections/components/__tests__/__snapshots__/manage_datasource_table.test.tsx.snap b/public/components/data_connections/components/__tests__/__snapshots__/manage_data_connections_table.test.tsx.snap similarity index 97% rename from public/components/data_connections/components/__tests__/__snapshots__/manage_datasource_table.test.tsx.snap rename to public/components/data_connections/components/__tests__/__snapshots__/manage_data_connections_table.test.tsx.snap index 8206d792b..e61640bef 100644 --- a/public/components/data_connections/components/__tests__/__snapshots__/manage_datasource_table.test.tsx.snap +++ b/public/components/data_connections/components/__tests__/__snapshots__/manage_data_connections_table.test.tsx.snap @@ -1,6 +1,6 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`Manage Datasource Table test Renders manage datasource table with data 1`] = ` +exports[`Manage Data Connections Table test Renders manage data connections table with data 1`] = `

Data connections

@@ -32,7 +32,7 @@ exports[`Manage Datasource Table test Renders manage datasource table with data
- Connect and manage compatible OpenSearch Dashboard data sources and compute. + Connect and manage compatible OpenSearch and OpenSearch Dashboard data connections. - Manage already created data source connections. + Manage already created data connections.

@@ -384,7 +384,7 @@ exports[`Manage Datasource Table test Renders manage datasource table with data >
@@ -460,7 +460,7 @@ exports[`Manage Datasource Table test Renders manage datasource table with data >
@@ -536,7 +536,7 @@ exports[`Manage Datasource Table test Renders manage datasource table with data >
diff --git a/public/components/data_connections/components/__tests__/datasource.test.tsx b/public/components/data_connections/components/__tests__/data_connection.test.tsx similarity index 52% rename from public/components/data_connections/components/__tests__/datasource.test.tsx rename to public/components/data_connections/components/__tests__/data_connection.test.tsx index 8294e0598..9e16fcda8 100644 --- a/public/components/data_connections/components/__tests__/datasource.test.tsx +++ b/public/components/data_connections/components/__tests__/data_connection.test.tsx @@ -7,18 +7,16 @@ import { configure, mount } from 'enzyme'; import Adapter from 'enzyme-adapter-react-16'; import { act, waitFor } from '@testing-library/react'; import React from 'react'; -import { DataConnectionsDescription } from '../manage_datasource_description'; -import { ManageDatasourcesTable } from '../manage_datasource_table'; -import { describeDatasource, showDatasourceData } from './testing_constants'; -import { DataSource } from '../datasource'; +import { describeDataConnection } from './testing_constants'; +import { DataConnection } from '../data_connection'; import ReactDOM from 'react-dom'; -describe('Datasource Page test', () => { +describe('Data Connection Page test', () => { configure({ adapter: new Adapter() }); - it('Renders datasource page with data', async () => { + it('Renders data connection page with data', async () => { const http = { - get: jest.fn().mockResolvedValue(describeDatasource), + get: jest.fn().mockResolvedValue(describeDataConnection), }; const pplService = { fetch: jest.fn(), @@ -26,11 +24,13 @@ describe('Datasource Page test', () => { const mockChrome = { setBreadcrumbs: jest.fn(), }; - const wrapper = mount(); + const wrapper = mount( + + ); const container = document.createElement('div'); await act(() => { ReactDOM.render( - , + , container ); }); diff --git a/public/components/data_connections/components/__tests__/manage_datasource_description.test.tsx b/public/components/data_connections/components/__tests__/manage_data_connections_description.test.tsx similarity index 67% rename from public/components/data_connections/components/__tests__/manage_datasource_description.test.tsx rename to public/components/data_connections/components/__tests__/manage_data_connections_description.test.tsx index e6380b0d5..686230683 100644 --- a/public/components/data_connections/components/__tests__/manage_datasource_description.test.tsx +++ b/public/components/data_connections/components/__tests__/manage_data_connections_description.test.tsx @@ -7,12 +7,12 @@ import { configure, mount } from 'enzyme'; import Adapter from 'enzyme-adapter-react-16'; import { waitFor } from '@testing-library/react'; import React from 'react'; -import { DataConnectionsDescription } from '../manage_datasource_description'; +import { DataConnectionsDescription } from '../manage_data_connections_description'; -describe('Manage Datasource Description test', () => { +describe('Manage Data Connections Description test', () => { configure({ adapter: new Adapter() }); - it('Renders manage datasource description', async () => { + it('Renders manage data connections description', async () => { const wrapper = mount(); await waitFor(() => { diff --git a/public/components/data_connections/components/__tests__/manage_datasource_table.test.tsx b/public/components/data_connections/components/__tests__/manage_data_connections_table.test.tsx similarity index 60% rename from public/components/data_connections/components/__tests__/manage_datasource_table.test.tsx rename to public/components/data_connections/components/__tests__/manage_data_connections_table.test.tsx index 599a7a235..380fcf392 100644 --- a/public/components/data_connections/components/__tests__/manage_datasource_table.test.tsx +++ b/public/components/data_connections/components/__tests__/manage_data_connections_table.test.tsx @@ -7,16 +7,16 @@ import { configure } from 'enzyme'; import Adapter from 'enzyme-adapter-react-16'; import { act } from '@testing-library/react'; import React from 'react'; -import { ManageDatasourcesTable } from '../manage_datasource_table'; -import { showDatasourceData } from './testing_constants'; +import { ManageDataConnectionsTable } from '../manage_data_connections_table'; +import { showDataConnectionsData } from './testing_constants'; import ReactDOM from 'react-dom'; -describe('Manage Datasource Table test', () => { +describe('Manage Data Connections Table test', () => { configure({ adapter: new Adapter() }); - it('Renders manage datasource table with data', async () => { + it('Renders manage data connections table with data', async () => { const http = { - get: jest.fn().mockResolvedValue(showDatasourceData), + get: jest.fn().mockResolvedValue(showDataConnectionsData), }; const pplService = { fetch: jest.fn(), @@ -27,7 +27,7 @@ describe('Manage Datasource Table test', () => { const container = document.createElement('div'); await act(() => { ReactDOM.render( - , + , container ); }); diff --git a/public/components/data_connections/components/__tests__/testing_constants.ts b/public/components/data_connections/components/__tests__/testing_constants.ts index 5cad33957..995e149fe 100644 --- a/public/components/data_connections/components/__tests__/testing_constants.ts +++ b/public/components/data_connections/components/__tests__/testing_constants.ts @@ -3,7 +3,7 @@ * SPDX-License-Identifier: Apache-2.0 */ -export const showDatasourceData = [ +export const showDataConnectionsData = [ { name: 'my_spark3', connector: 'SPARK', @@ -59,7 +59,7 @@ export const showDatasourceData = [ }, ]; -export const describeDatasource = { +export const describeDataConnection = { name: 'my_spark3', connector: 'SPARK', allowedRoles: [], diff --git a/public/components/data_connections/components/acceleration_ui/acceleration_indices.tsx b/public/components/data_connections/components/acceleration_ui/acceleration_indices.tsx index 2d98c2d28..03520416d 100644 --- a/public/components/data_connections/components/acceleration_ui/acceleration_indices.tsx +++ b/public/components/data_connections/components/acceleration_ui/acceleration_indices.tsx @@ -10,22 +10,22 @@ import { AccelerationHeader } from './acceleration_header'; import { AccelerationManagement } from './management/acceleration_management'; interface AccelerationIndicesProps { - dataSource: string; + dataConnection: string; } -export const AccelerationIndices = ({ dataSource }: AccelerationIndicesProps) => { +export const AccelerationIndices = ({ dataConnection }: AccelerationIndicesProps) => { useEffect(() => { coreRefs.chrome?.setBreadcrumbs([ { - text: 'Datasources', + text: 'Data Connections', href: '#/', }, { text: 'Acceleration', - href: '#/manage/acceleration/' + { dataSource }, + href: '#/manage/acceleration/' + { dataConnection }, }, ]); - }, [dataSource]); + }, [dataConnection]); return ( diff --git a/public/components/data_connections/components/datasource.tsx b/public/components/data_connections/components/data_connection.tsx similarity index 96% rename from public/components/data_connections/components/datasource.tsx rename to public/components/data_connections/components/data_connection.tsx index 0964a16a8..e36aeacf9 100644 --- a/public/components/data_connections/components/datasource.tsx +++ b/public/components/data_connections/components/data_connection.tsx @@ -21,7 +21,7 @@ import { EuiTabs, } from '@elastic/eui'; import React, { useEffect, useState } from 'react'; -import { DATASOURCES_BASE } from '../../../../common/constants/shared'; +import { DATACONNECTIONS_BASE } from '../../../../common/constants/shared'; interface DatasourceDetails { allowedRoles: string[]; @@ -29,7 +29,7 @@ interface DatasourceDetails { cluster: string; } -export const DataSource = (props: any) => { +export const DataConnection = (props: any) => { const { dataSource, pplService, http } = props; const [datasourceDetails, setDatasourceDetails] = useState({ allowedRoles: [], @@ -38,7 +38,7 @@ export const DataSource = (props: any) => { }); useEffect(() => { - http.get(`${DATASOURCES_BASE}/${dataSource}`).then((data) => + http.get(`${DATACONNECTIONS_BASE}/${dataSource}`).then((data) => setDatasourceDetails({ allowedRoles: data.allowedRoles, name: data.name, diff --git a/public/components/data_connections/components/datasources_header.tsx b/public/components/data_connections/components/data_connections_header.tsx similarity index 83% rename from public/components/data_connections/components/datasources_header.tsx rename to public/components/data_connections/components/data_connections_header.tsx index 045d1cbc8..7f071683b 100644 --- a/public/components/data_connections/components/datasources_header.tsx +++ b/public/components/data_connections/components/data_connections_header.tsx @@ -20,14 +20,14 @@ export const DataConnectionsHeader = () => {
- +

Data connections

- Connect and manage compatible OpenSearch Dashboard data sources and compute.{' '} + Connect and manage compatible OpenSearch and OpenSearch Dashboard data connections.{' '} Learn more diff --git a/public/components/data_connections/components/manage_datasource_description.tsx b/public/components/data_connections/components/manage_data_connections_description.tsx similarity index 86% rename from public/components/data_connections/components/manage_datasource_description.tsx rename to public/components/data_connections/components/manage_data_connections_description.tsx index 9c97d5758..26cfa90cc 100644 --- a/public/components/data_connections/components/manage_datasource_description.tsx +++ b/public/components/data_connections/components/manage_data_connections_description.tsx @@ -4,7 +4,6 @@ */ import { EuiSpacer, EuiText, EuiTitle, EuiHorizontalRule } from '@elastic/eui'; -import _ from 'lodash'; import React from 'react'; export const DataConnectionsDescription = () => { @@ -16,7 +15,7 @@ export const DataConnectionsDescription = () => { - Manage already created data source connections. + Manage already created data connections.
diff --git a/public/components/data_connections/components/manage_datasource_table.tsx b/public/components/data_connections/components/manage_data_connections_table.tsx similarity index 87% rename from public/components/data_connections/components/manage_datasource_table.tsx rename to public/components/data_connections/components/manage_data_connections_table.tsx index c5650d308..02751bcb5 100644 --- a/public/components/data_connections/components/manage_datasource_table.tsx +++ b/public/components/data_connections/components/manage_data_connections_table.tsx @@ -17,10 +17,10 @@ import { } from '@elastic/eui'; import _ from 'lodash'; import React, { useEffect, useState } from 'react'; -import { DataConnectionsHeader } from './datasources_header'; +import { DataConnectionsHeader } from './data_connections_header'; import { HomeProps } from '../home'; -import { DataConnectionsDescription } from './manage_datasource_description'; -import { DATASOURCES_BASE } from '../../../../common/constants/shared'; +import { DataConnectionsDescription } from './manage_data_connections_description'; +import { DATACONNECTIONS_BASE } from '../../../../common/constants/shared'; import { ChromeStart } from '../../../../../../src/core/public'; interface DataConnection { @@ -29,7 +29,7 @@ interface DataConnection { chrome: ChromeStart; } -export const ManageDatasourcesTable = (props: HomeProps) => { +export const ManageDataConnectionsTable = (props: HomeProps) => { const { http, chrome, pplService } = props; const [data, setData] = useState([]); @@ -37,7 +37,7 @@ export const ManageDatasourcesTable = (props: HomeProps) => { useEffect(() => { chrome.setBreadcrumbs([ { - text: 'Datasources', + text: 'Data Connections', href: '#/', }, ]); @@ -45,9 +45,9 @@ export const ManageDatasourcesTable = (props: HomeProps) => { }, [chrome]); async function handleDataRequest() { - http.get(`${DATASOURCES_BASE}`).then((datasources) => + http.get(`${DATACONNECTIONS_BASE}`).then((dataconnections) => setData( - datasources.map((x: any) => { + dataconnections.map((x: any) => { return { name: x.name, connectionType: x.connector }; }) ) @@ -89,7 +89,7 @@ export const ManageDatasourcesTable = (props: HomeProps) => { sortable: true, truncateText: true, render: (value, record) => ( - + {_.truncate(record.creationDate, { length: 100 })} ), diff --git a/public/components/data_connections/home.tsx b/public/components/data_connections/home.tsx index c59a0afd8..534a71815 100644 --- a/public/components/data_connections/home.tsx +++ b/public/components/data_connections/home.tsx @@ -6,8 +6,8 @@ import React from 'react'; import { HashRouter, Route, RouteComponentProps, Switch } from 'react-router-dom'; import { ChromeBreadcrumb, ChromeStart, HttpStart } from '../../../../../src/core/public'; -import { DataSource } from './components/datasource'; -import { ManageDatasourcesTable } from './components/manage_datasource_table'; +import { DataConnection } from './components/data_connection'; +import { ManageDataConnectionsTable } from './components/manage_data_connections_table'; import { AccelerationIndices } from './components/acceleration_ui/acceleration_indices'; export interface HomeProps extends RouteComponentProps { @@ -33,7 +33,7 @@ export const Home = (props: HomeProps) => { exact path={'/manage/:id+'} render={(routerProps) => ( - @@ -43,13 +43,13 @@ export const Home = (props: HomeProps) => { } + render={(routerProps) => } /> ( - + )} /> diff --git a/public/plugin.ts b/public/plugin.ts index 81da89b80..e3215ce02 100644 --- a/public/plugin.ts +++ b/public/plugin.ts @@ -39,9 +39,9 @@ import { observabilityIntegrationsTitle, observabilityIntegrationsPluginOrder, observabilityPluginOrder, - observabilityDatasourcesID, - observabilityDatasourcesTitle, - observabilityDatasourcesPluginOrder, + observabilityDataConnectionsID, + observabilityDataConnectionsPluginOrder, + observabilityDataConnectionsTitle, } from '../common/constants/shared'; import { QueryManager } from '../common/query_manager'; import { VISUALIZATION_SAVED_OBJECT } from '../common/types/observability_saved_object_attributes'; @@ -201,19 +201,19 @@ export class ObservabilityPlugin }); core.application.register({ - id: observabilityDatasourcesID, - title: observabilityDatasourcesTitle, + id: observabilityDataConnectionsID, + title: observabilityDataConnectionsTitle, category: DEFAULT_APP_CATEGORIES.management, - order: observabilityDatasourcesPluginOrder, - mount: appMountWithStartPage('datasources'), + order: observabilityDataConnectionsPluginOrder, + mount: appMountWithStartPage('dataconnections'), }); setupDeps.managementOverview?.register({ - id: observabilityDatasourcesID, - title: observabilityDatasourcesTitle, + id: observabilityDataConnectionsID, + title: observabilityDataConnectionsTitle, order: 9070, - description: i18n.translate('observability.datasourcesDescription', { - defaultMessage: 'Manage compatible data sources and compute with OpenSearch Dashboards.', + description: i18n.translate('observability.dataconnectionsDescription', { + defaultMessage: 'Manage compatible data connections with OpenSearch Dashboards.', }), }); diff --git a/server/adaptors/ppl_plugin.ts b/server/adaptors/ppl_plugin.ts index e4714c9d0..71dbcb569 100644 --- a/server/adaptors/ppl_plugin.ts +++ b/server/adaptors/ppl_plugin.ts @@ -4,7 +4,7 @@ */ import { - OPENSEARCH_DATASOURCES_API, + OPENSEARCH_DATACONNECTIONS_API, PPL_ENDPOINT, SQL_ENDPOINT, } from '../../common/constants/shared'; @@ -42,11 +42,11 @@ export const PPLPlugin = function (Client, config, components) { method: 'POST', }); - ppl.getDatasourceById = ca({ + ppl.getDataConnectionById = ca({ url: { - fmt: `${OPENSEARCH_DATASOURCES_API.DATASOURCE}/<%=datasource%>`, + fmt: `${OPENSEARCH_DATACONNECTIONS_API.DATACONNECTION}/<%=dataconnection%>`, req: { - datasource: { + dataconnection: { type: 'string', required: true, }, @@ -55,9 +55,9 @@ export const PPLPlugin = function (Client, config, components) { method: 'GET', }); - ppl.getDatasources = ca({ + ppl.getDataConnections = ca({ url: { - fmt: `${OPENSEARCH_DATASOURCES_API.DATASOURCE}`, + fmt: `${OPENSEARCH_DATACONNECTIONS_API.DATACONNECTION}`, }, method: 'GET', }); diff --git a/server/routes/datasources/datasources_router.ts b/server/routes/data_connections/data_connections_router.ts similarity index 55% rename from server/routes/datasources/datasources_router.ts rename to server/routes/data_connections/data_connections_router.ts index 187be8da1..ff276db80 100644 --- a/server/routes/datasources/datasources_router.ts +++ b/server/routes/data_connections/data_connections_router.ts @@ -5,12 +5,12 @@ import { schema } from '@osd/config-schema'; import { IRouter } from '../../../../../src/core/server'; -import { DATASOURCES_BASE } from '../../../common/constants/shared'; +import { DATACONNECTIONS_BASE } from '../../../common/constants/shared'; -export function registerDatasourcesRoute(router: IRouter) { +export function registerDataConnectionsRoute(router: IRouter) { router.get( { - path: `${DATASOURCES_BASE}/{name}`, + path: `${DATACONNECTIONS_BASE}/{name}`, validate: { params: schema.object({ name: schema.string(), @@ -19,16 +19,16 @@ export function registerDatasourcesRoute(router: IRouter) { }, async (context, request, response): Promise => { try { - const dataSourcesresponse = await context.observability_plugin.observabilityClient + const dataConnectionsresponse = await context.observability_plugin.observabilityClient .asScoped(request) - .callAsCurrentUser('ppl.getDatasourceById', { - datasource: request.params.name, + .callAsCurrentUser('ppl.getDataConnectionById', { + dataconnection: request.params.name, }); return response.ok({ - body: dataSourcesresponse, + body: dataConnectionsresponse, }); } catch (error: any) { - console.error('Issue in fetching datasource:', error); + console.error('Issue in fetching data connection:', error); return response.custom({ statusCode: error.statusCode || 500, body: error.message, @@ -39,19 +39,19 @@ export function registerDatasourcesRoute(router: IRouter) { router.get( { - path: `${DATASOURCES_BASE}`, + path: `${DATACONNECTIONS_BASE}`, validate: false, }, async (context, request, response): Promise => { try { - const dataSourcesresponse = await context.observability_plugin.observabilityClient + const dataConnectionsresponse = await context.observability_plugin.observabilityClient .asScoped(request) - .callAsCurrentUser('ppl.getDatasources'); + .callAsCurrentUser('ppl.getDataConnections'); return response.ok({ - body: dataSourcesresponse, + body: dataConnectionsresponse, }); } catch (error: any) { - console.error('Issue in fetching datasources:', error); + console.error('Issue in fetching data connections:', error); return response.custom({ statusCode: error.statusCode || 500, body: error.message, diff --git a/server/routes/index.ts b/server/routes/index.ts index 6601127a5..4c278fa45 100644 --- a/server/routes/index.ts +++ b/server/routes/index.ts @@ -21,7 +21,7 @@ import { registerEventAnalyticsRouter } from './event_analytics/event_analytics_ import { registerAppAnalyticsRouter } from './application_analytics/app_analytics_router'; import { registerMetricsRoute } from './metrics/metrics_rounter'; import { registerIntegrationsRoute } from './integrations/integrations_router'; -import { registerDatasourcesRoute } from './datasources/datasources_router'; +import { registerDataConnectionsRoute } from './data_connections/data_connections_router'; export function setupRoutes({ router, client }: { router: IRouter; client: ILegacyClusterClient }) { PanelsRouter(router); @@ -43,5 +43,5 @@ export function setupRoutes({ router, client }: { router: IRouter; client: ILega registerMetricsRoute(router); registerIntegrationsRoute(router); - registerDatasourcesRoute(router); + registerDataConnectionsRoute(router); } From dfd5bd8f9071f201e255b66c634242ed705b79ad Mon Sep 17 00:00:00 2001 From: Derek Ho Date: Fri, 15 Sep 2023 16:06:38 -0400 Subject: [PATCH 04/22] Add fallback to show if user does not have datasource API permissions (#1008) * add fallback ui for manage and view datasources Signed-off-by: Derek Ho * always show datasources via pplservice Signed-off-by: Derek Ho --------- Signed-off-by: Derek Ho --- .../components/data_connection.tsx | 31 +++++++++++---- .../manage_data_connections_table.tsx | 9 +++-- .../data_connections/components/no_access.tsx | 38 +++++++++++++++++++ 3 files changed, 66 insertions(+), 12 deletions(-) create mode 100644 public/components/data_connections/components/no_access.tsx diff --git a/public/components/data_connections/components/data_connection.tsx b/public/components/data_connections/components/data_connection.tsx index e36aeacf9..1913e0eb0 100644 --- a/public/components/data_connections/components/data_connection.tsx +++ b/public/components/data_connections/components/data_connection.tsx @@ -21,7 +21,9 @@ import { EuiTabs, } from '@elastic/eui'; import React, { useEffect, useState } from 'react'; +import { NoAccess } from './no_access'; import { DATACONNECTIONS_BASE } from '../../../../common/constants/shared'; +import { coreRefs } from '../../../../public/framework/core_refs'; interface DatasourceDetails { allowedRoles: string[]; @@ -30,21 +32,30 @@ interface DatasourceDetails { } export const DataConnection = (props: any) => { - const { dataSource, pplService, http } = props; + const { dataSource } = props; const [datasourceDetails, setDatasourceDetails] = useState({ allowedRoles: [], name: '', cluster: '', }); + const [hasAccess, setHasAccess] = useState(true); + const { http } = coreRefs; useEffect(() => { - http.get(`${DATACONNECTIONS_BASE}/${dataSource}`).then((data) => - setDatasourceDetails({ - allowedRoles: data.allowedRoles, - name: data.name, - cluster: data.properties['emr.cluster'], - }) - ); + http + .get(`${DATACONNECTIONS_BASE}/${dataSource}`) + .then((data) => + setDatasourceDetails({ + allowedRoles: data.allowedRoles, + name: data.name, + cluster: data.properties['emr.cluster'], + }) + ) + .catch((err) => { + if (err.body.statusCode === 403) { + setHasAccess(false); + } + }); }, []); const tabs = [ @@ -128,6 +139,10 @@ export const DataConnection = (props: any) => { ); }; + if (!hasAccess) { + return ; + } + return ( diff --git a/public/components/data_connections/components/manage_data_connections_table.tsx b/public/components/data_connections/components/manage_data_connections_table.tsx index 02751bcb5..3f352d2b9 100644 --- a/public/components/data_connections/components/manage_data_connections_table.tsx +++ b/public/components/data_connections/components/manage_data_connections_table.tsx @@ -20,7 +20,6 @@ import React, { useEffect, useState } from 'react'; import { DataConnectionsHeader } from './data_connections_header'; import { HomeProps } from '../home'; import { DataConnectionsDescription } from './manage_data_connections_description'; -import { DATACONNECTIONS_BASE } from '../../../../common/constants/shared'; import { ChromeStart } from '../../../../../../src/core/public'; interface DataConnection { @@ -33,6 +32,7 @@ export const ManageDataConnectionsTable = (props: HomeProps) => { const { http, chrome, pplService } = props; const [data, setData] = useState([]); + const [hasAccess, setHasAccess] = useState(true); useEffect(() => { chrome.setBreadcrumbs([ @@ -45,10 +45,10 @@ export const ManageDataConnectionsTable = (props: HomeProps) => { }, [chrome]); async function handleDataRequest() { - http.get(`${DATACONNECTIONS_BASE}`).then((dataconnections) => + pplService!.fetch({ query: 'show datasources', format: 'jdbc' }).then((dataconnections) => setData( - dataconnections.map((x: any) => { - return { name: x.name, connectionType: x.connector }; + dataconnections.jsonData.map((x: any) => { + return { name: x.DATASOURCE_NAME, connectionType: x.CONNECTOR_TYPE }; }) ) ); @@ -141,6 +141,7 @@ export const ManageDataConnectionsTable = (props: HomeProps) => { + { + return ( + + + Data connections not set up} + body={ + + { + 'You do not have the permissions to view and edit data connections. Please reach out to your administrator for access.' + } + + } + actions={ + window.open(OPENSEARCH_DOCUMENTATION_URL, '_blank')} + > + Learn more + + } + /> + + + ); +}; From 28201e913a10439b2f37f7fca7d83fec6f8f1d77 Mon Sep 17 00:00:00 2001 From: Derek Ho Date: Mon, 18 Sep 2023 16:42:19 -0400 Subject: [PATCH 05/22] Add access control tab content (#992) * basic rendering for the access control tab Signed-off-by: Derek Ho * hook up basic radio groups and euicombo boxes for query and acceleration permissions Signed-off-by: Derek Ho * refactor and clean up unuseed inports Signed-off-by: Derek Ho * remove unused import Signed-off-by: Derek Ho * fix import and snapshot Signed-off-by: Derek Ho * fix test Signed-off-by: Derek Ho * Address PR comments Signed-off-by: Derek Ho * Address PR comments Signed-off-by: Derek Ho * Remove unused files and variables Signed-off-by: Derek Ho --------- Signed-off-by: Derek Ho --- common/constants/data_connections.ts | 3 + common/types/data_connections.ts | 10 ++ .../data_connection.test.tsx.snap | 85 +++++----- .../__tests__/data_connection.test.tsx | 26 +-- .../manage_data_connections_table.test.tsx | 14 +- .../components/__tests__/testing_constants.ts | 84 ++++------ .../components/access_control_callout.tsx | 16 ++ .../components/access_control_tab.tsx | 153 ++++++++++++++++++ .../components/data_connection.tsx | 55 ++++--- .../data_connections/components/no_access.tsx | 41 ++--- .../components/query_permissions.tsx | 87 ++++++++++ server/adaptors/ppl_plugin.ts | 8 + .../data_connections_router.ts | 37 +++++ 13 files changed, 470 insertions(+), 149 deletions(-) create mode 100644 common/types/data_connections.ts create mode 100644 public/components/data_connections/components/access_control_callout.tsx create mode 100644 public/components/data_connections/components/access_control_tab.tsx create mode 100644 public/components/data_connections/components/query_permissions.tsx diff --git a/common/constants/data_connections.ts b/common/constants/data_connections.ts index 354d797de..2c06e935e 100644 --- a/common/constants/data_connections.ts +++ b/common/constants/data_connections.ts @@ -8,3 +8,6 @@ export const OPENSEARCH_DOCUMENTATION_URL = export const OPENSEARCH_ACC_DOCUMENTATION_URL = 'https://opensearch.org/docs/latest/data-acceleration/index'; + +export const QUERY_RESTRICTED = 'query-restricted'; +export const QUERY_ALL = 'query-all'; diff --git a/common/types/data_connections.ts b/common/types/data_connections.ts new file mode 100644 index 000000000..9fd0527d9 --- /dev/null +++ b/common/types/data_connections.ts @@ -0,0 +1,10 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +export interface PermissionsConfigurationProps { + roles: Array<{ label: string }>; + selectedRoles: Array<{ label: string }>; + setSelectedRoles: React.Dispatch>>; +} diff --git a/public/components/data_connections/components/__tests__/__snapshots__/data_connection.test.tsx.snap b/public/components/data_connections/components/__tests__/__snapshots__/data_connection.test.tsx.snap index 6b0a6e92c..adf1595cf 100644 --- a/public/components/data_connections/components/__tests__/__snapshots__/data_connection.test.tsx.snap +++ b/public/components/data_connections/components/__tests__/__snapshots__/data_connection.test.tsx.snap @@ -259,46 +259,59 @@ exports[`Data Connection Page test Renders data connection page with data 1`] =
-
- - + - + + + Connection configuration + + +
+
({ + coreRefs: { + chrome: { + setBreadcrumbs: jest.fn(), + }, + http: { + get: jest.fn().mockResolvedValue(describeDataConnection), + }, + }, +})); + describe('Data Connection Page test', () => { configure({ adapter: new Adapter() }); it('Renders data connection page with data', async () => { - const http = { - get: jest.fn().mockResolvedValue(describeDataConnection), - }; const pplService = { fetch: jest.fn(), }; - const mockChrome = { - setBreadcrumbs: jest.fn(), - }; - const wrapper = mount( - - ); + const wrapper = mount(); const container = document.createElement('div'); await act(() => { - ReactDOM.render( - , - container - ); + ReactDOM.render(, container); }); expect(container).toMatchSnapshot(); }); diff --git a/public/components/data_connections/components/__tests__/manage_data_connections_table.test.tsx b/public/components/data_connections/components/__tests__/manage_data_connections_table.test.tsx index 380fcf392..fe7369426 100644 --- a/public/components/data_connections/components/__tests__/manage_data_connections_table.test.tsx +++ b/public/components/data_connections/components/__tests__/manage_data_connections_table.test.tsx @@ -10,6 +10,18 @@ import React from 'react'; import { ManageDataConnectionsTable } from '../manage_data_connections_table'; import { showDataConnectionsData } from './testing_constants'; import ReactDOM from 'react-dom'; +import { coreRefs } from '../../../../../public/framework/core_refs'; + +jest.mock('../../../../../public/framework/core_refs', () => ({ + coreRefs: { + chrome: { + setBreadcrumbs: jest.fn(), + }, + http: { + get: jest.fn().mockResolvedValue(showDataConnectionsData), + }, + }, +})); describe('Manage Data Connections Table test', () => { configure({ adapter: new Adapter() }); @@ -19,7 +31,7 @@ describe('Manage Data Connections Table test', () => { get: jest.fn().mockResolvedValue(showDataConnectionsData), }; const pplService = { - fetch: jest.fn(), + fetch: jest.fn().mockResolvedValue(showDataConnectionsData), }; const mockChrome = { setBreadcrumbs: jest.fn(), diff --git a/public/components/data_connections/components/__tests__/testing_constants.ts b/public/components/data_connections/components/__tests__/testing_constants.ts index 995e149fe..65258fb27 100644 --- a/public/components/data_connections/components/__tests__/testing_constants.ts +++ b/public/components/data_connections/components/__tests__/testing_constants.ts @@ -3,61 +3,43 @@ * SPDX-License-Identifier: Apache-2.0 */ -export const showDataConnectionsData = [ - { - name: 'my_spark3', - connector: 'SPARK', - allowedRoles: [], - properties: { - 'spark.connector': 'emr', - 'spark.datasource.flint.host': '0.0.0.0', - 'spark.datasource.flint.integration': - 'https://aws.oss.sonatype.org/content/repositories/snapshots/org/opensearch/opensearch-spark-standalone_2.12/0.1.0-SNAPSHOT/opensearch-spark-standalone_2.12-0.1.0-20230731.182705-3.jar', - 'spark.datasource.flint.port': '9200', - 'spark.datasource.flint.scheme': 'http', - 'emr.cluster': 'j-3UNQLT1MPBGLG', +export const showDataConnectionsData = { + schema: [ + { + name: 'DATASOURCE_NAME', + type: 'string', }, - }, - { - name: 'my_spark4', - connector: 'SPARK', - allowedRoles: [], - properties: { - 'spark.connector': 'emr', - 'spark.datasource.flint.host': '15.248.1.68', - 'spark.datasource.flint.integration': - 'https://aws.oss.sonatype.org/content/repositories/snapshots/org/opensearch/opensearch-spark-standalone_2.12/0.1.0-SNAPSHOT/opensearch-spark-standalone_2.12-0.1.0-20230731.182705-3.jar', - 'spark.datasource.flint.port': '9200', - 'spark.datasource.flint.scheme': 'http', - 'emr.cluster': 'j-3UNQLT1MPBGLG', + { + name: 'CONNECTOR_TYPE', + type: 'string', }, - }, - { - name: 'my_spark', - connector: 'SPARK', - allowedRoles: [], - properties: { - 'spark.connector': 'emr', - 'spark.datasource.flint.host': '0.0.0.0', - 'spark.datasource.flint.port': '9200', - 'spark.datasource.flint.scheme': 'http', - 'spark.datasource.flint.region': 'xxx', - 'emr.cluster': 'xxx', + ], + datarows: [ + ['my_spark_actual', 'SPARK'], + ['@opensearch', 'OPENSEARCH'], + ['my_spark', 'SPARK'], + ], + total: 3, + size: 3, + jsonData: [ + { + DATASOURCE_NAME: 'my_spark3', + CONNECTOR_TYPE: 'SPARK', }, - }, - { - name: 'my_spark2', - connector: 'SPARK', - allowedRoles: [], - properties: { - 'spark.connector': 'emr', - 'spark.datasource.flint.host': '0.0.0.0', - 'spark.datasource.flint.port': '9200', - 'spark.datasource.flint.scheme': 'http', - 'emr.cluster': 'j-3UNQLT1MPBGLG', + { + DATASOURCE_NAME: 'my_spark4', + CONNECTOR_TYPE: 'SPARK', }, - }, -]; + { + DATASOURCE_NAME: 'my_spark', + CONNECTOR_TYPE: 'SPARK', + }, + { + DATASOURCE_NAME: 'my_spark2', + CONNECTOR_TYPE: 'SPARK', + }, + ], +}; export const describeDataConnection = { name: 'my_spark3', diff --git a/public/components/data_connections/components/access_control_callout.tsx b/public/components/data_connections/components/access_control_callout.tsx new file mode 100644 index 000000000..f675673ff --- /dev/null +++ b/public/components/data_connections/components/access_control_callout.tsx @@ -0,0 +1,16 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { EuiCallOut } from '@elastic/eui'; +import React from 'react'; + +export const AccessControlCallout = () => { + return ( + + Access to data can be managed in other systems outside of OpenSearch. Check with your + administrator for additional configurations. + + ); +}; diff --git a/public/components/data_connections/components/access_control_tab.tsx b/public/components/data_connections/components/access_control_tab.tsx new file mode 100644 index 000000000..15c8491b9 --- /dev/null +++ b/public/components/data_connections/components/access_control_tab.tsx @@ -0,0 +1,153 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { + EuiButton, + EuiFlexGroup, + EuiFlexItem, + EuiSpacer, + EuiText, + EuiHorizontalRule, + EuiBottomBar, + EuiButtonEmpty, +} from '@elastic/eui'; +import React, { useEffect, useState } from 'react'; +import { EuiPanel } from '@elastic/eui'; +import { QUERY_ALL, QUERY_RESTRICT } from '../../../../common/constants/data_connections'; +import { AccessControlCallout } from './access_control_callout'; +import { coreRefs } from '../../../../public/framework/core_refs'; +import { QueryPermissionsConfiguration } from './query_permissions'; +import { DATACONNECTIONS_BASE } from '../../../../common/constants/shared'; + +interface AccessControlTabProps { + dataConnection: string; + connector: string; + properties: unknown; +} + +export const AccessControlTab = (props: AccessControlTabProps) => { + const [mode, setMode] = useState<'view' | 'edit'>('view'); + const [roles, setRoles] = useState>([]); + const [selectedQueryPermissionRoles, setSelectedQueryPermissionRoles] = useState< + Array<{ label: string }> + >([]); + const { http } = coreRefs; + + useEffect(() => { + http!.get('/api/v1/configuration/roles').then((data) => + setRoles( + Object.keys(data.data).map((key) => { + return { label: key }; + }) + ) + ); + }, []); + + const AccessControlDetails = () => { + return ( + + + + + Query access + + {[].length ? `Restricted` : '-'} + + + + + + ); + }; + + const EditAccessControlDetails = () => { + return ( + + + + ); + }; + + const saveChanges = () => { + http!.put(`${DATACONNECTIONS_BASE}`, { + body: JSON.stringify({ + name: props.dataConnection, + allowedRoles: selectedQueryPermissionRoles.map((role) => role.label), + connector: props.connector, + properties: props.properties, + }), + }); + setMode('view'); + }; + + const AccessControlHeader = () => { + return ( + + + +

Access Control

+ Control which OpenSearch users have access to this data source. +
+
+ + + setMode(mode === 'view' ? 'edit' : 'view')} + fill={mode === 'view' ? true : false} + > + {mode === 'view' ? 'Edit' : 'Cancel'} + + +
+ ); + }; + + const SaveOrCancel = () => { + return ( + + + + { + setMode('view'); + }} + color="ghost" + size="s" + iconType="cross" + > + Discard change(s) + + + + + Save + + + + + ); + }; + + return ( + <> + + + + + + + {mode === 'view' ? : } + + + {mode === 'edit' && } + + + ); +}; diff --git a/public/components/data_connections/components/data_connection.tsx b/public/components/data_connections/components/data_connection.tsx index 1913e0eb0..0df41e30f 100644 --- a/public/components/data_connections/components/data_connection.tsx +++ b/public/components/data_connections/components/data_connection.tsx @@ -18,9 +18,10 @@ import { EuiIcon, EuiCard, EuiTab, - EuiTabs, + EuiTabbedContent, } from '@elastic/eui'; import React, { useEffect, useState } from 'react'; +import { AccessControlTab } from './access_control_tab'; import { NoAccess } from './no_access'; import { DATACONNECTIONS_BASE } from '../../../../common/constants/shared'; import { coreRefs } from '../../../../public/framework/core_refs'; @@ -29,6 +30,8 @@ interface DatasourceDetails { allowedRoles: string[]; name: string; cluster: string; + connector: string; + properties: unknown; } export const DataConnection = (props: any) => { @@ -37,18 +40,32 @@ export const DataConnection = (props: any) => { allowedRoles: [], name: '', cluster: '', + connector: '', + properties: {}, }); const [hasAccess, setHasAccess] = useState(true); - const { http } = coreRefs; + const { http, chrome } = coreRefs; useEffect(() => { - http + chrome!.setBreadcrumbs([ + { + text: 'Data Connections', + href: '#/', + }, + { + text: `${dataSource}`, + href: `#/manage/${dataSource}`, + }, + ]); + http! .get(`${DATACONNECTIONS_BASE}/${dataSource}`) .then((data) => setDatasourceDetails({ allowedRoles: data.allowedRoles, name: data.name, cluster: data.properties['emr.cluster'], + connector: data.connector, + properties: data.properties, }) ) .catch((err) => { @@ -56,45 +73,35 @@ export const DataConnection = (props: any) => { setHasAccess(false); } }); - }, []); + }, [chrome, http]); const tabs = [ { id: 'data', name: 'Data', disabled: false, + content: <>, }, { id: 'access_control', name: 'Access control', disabled: false, + content: ( + + ), }, { id: 'connection_configuration', name: 'Connection configuration', disabled: false, + content: <>, }, ]; - const [selectedTabId, setSelectedTabId] = useState('data'); - - const onSelectedTabChanged = (id) => { - setSelectedTabId(id); - }; - - const renderTabs = () => { - return tabs.map((tab, index) => ( - onSelectedTabChanged(tab.id)} - isSelected={tab.id === selectedTabId} - disabled={tab.disabled} - key={index} - > - {tab.name} - - )); - }; - const renderOverview = () => { return ( @@ -184,7 +191,7 @@ export const DataConnection = (props: any) => { - {renderTabs()} + diff --git a/public/components/data_connections/components/no_access.tsx b/public/components/data_connections/components/no_access.tsx index 0bb0bae2f..5c07b2893 100644 --- a/public/components/data_connections/components/no_access.tsx +++ b/public/components/data_connections/components/no_access.tsx @@ -3,36 +3,29 @@ * SPDX-License-Identifier: Apache-2.0 */ -import { EuiButton, EuiEmptyPrompt, EuiPage, EuiPanel, EuiText } from '@elastic/eui'; +import { EuiButton, EuiEmptyPrompt, EuiPage, EuiText } from '@elastic/eui'; import _ from 'lodash'; import React from 'react'; -import { OPENSEARCH_DOCUMENTATION_URL } from '../../../../common/constants/data_connections'; export const NoAccess = () => { return ( - - Data connections not set up} - body={ - - { - 'You do not have the permissions to view and edit data connections. Please reach out to your administrator for access.' - } - - } - actions={ - window.open(OPENSEARCH_DOCUMENTATION_URL, '_blank')} - > - Learn more - - } - /> - + {'No permissions to access'}} + body={ + + { + 'Missing permissions to view connection details. Contact your administrator for permissions.' + } + + } + actions={ + (window.location.hash = '')}> + Return to data connections + + } + /> ); }; diff --git a/public/components/data_connections/components/query_permissions.tsx b/public/components/data_connections/components/query_permissions.tsx new file mode 100644 index 000000000..d983015fe --- /dev/null +++ b/public/components/data_connections/components/query_permissions.tsx @@ -0,0 +1,87 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { + EuiComboBox, + EuiFlexGroup, + EuiFlexItem, + EuiLink, + EuiRadioGroup, + EuiSpacer, + EuiText, +} from '@elastic/eui'; +import React, { useState } from 'react'; +import { + OPENSEARCH_DOCUMENTATION_URL, + QUERY_ALL, + QUERY_RESTRICTED, +} from '../../../../common/constants/data_connections'; +import { PermissionsConfigurationProps } from '../../../../common/types/data_connections'; + +export const QueryPermissionsConfiguration = (props: PermissionsConfigurationProps) => { + const { roles, selectedRoles, setSelectedRoles } = props; + + const [selectedRadio, setSelectedRadio] = useState( + selectedRoles.length ? QUERY_RESTRICTED : QUERY_ALL + ); + const radios = [ + { + id: QUERY_RESTRICTED, + label: 'Restricted - accessible by users with specific OpenSearch roles', + }, + { + id: QUERY_ALL, + label: 'Everyone - accessible by all users on this cluster', + }, + ]; + + const ConfigureRoles = () => { + return ( +
+ + OpenSearch Roles + + Select one or more OpenSearch roles that can query this data connection. + + +
+ ); + }; + + return ( + + + + Query Permissions + + Control which OpenSearch roles have query permissions on this data source.{' '} + + Learn more + + + + + setSelectedRadio(id)} + name="query-radio-group" + legend={{ + children: Access level, + }} + /> + {selectedRadio === QUERY_RESTRICTED && } + + + + ); +}; diff --git a/server/adaptors/ppl_plugin.ts b/server/adaptors/ppl_plugin.ts index 71dbcb569..ddc2a2ccf 100644 --- a/server/adaptors/ppl_plugin.ts +++ b/server/adaptors/ppl_plugin.ts @@ -55,6 +55,14 @@ export const PPLPlugin = function (Client, config, components) { method: 'GET', }); + ppl.modifyDataConnection = ca({ + url: { + fmt: `${OPENSEARCH_DATACONNECTIONS_API.DATACONNECTION}`, + }, + needBody: true, + method: 'PUT', + }); + ppl.getDataConnections = ca({ url: { fmt: `${OPENSEARCH_DATACONNECTIONS_API.DATACONNECTION}`, diff --git a/server/routes/data_connections/data_connections_router.ts b/server/routes/data_connections/data_connections_router.ts index ff276db80..b0f2b2bad 100644 --- a/server/routes/data_connections/data_connections_router.ts +++ b/server/routes/data_connections/data_connections_router.ts @@ -37,6 +37,43 @@ export function registerDataConnectionsRoute(router: IRouter) { } ); + router.put( + { + path: `${DATACONNECTIONS_BASE}`, + validate: { + body: schema.object({ + name: schema.string(), + connector: schema.string(), + allowedRoles: schema.arrayOf(schema.string()), + properties: schema.any(), + }), + }, + }, + async (context, request, response): Promise => { + try { + const dataConnectionsresponse = await context.observability_plugin.observabilityClient + .asScoped(request) + .callAsCurrentUser('ppl.modifyDataConnection', { + body: { + name: request.body.name, + connector: request.body.connector, + allowedRoles: request.body.allowedRoles, + properties: request.body.properties, + }, + }); + return response.ok({ + body: dataConnectionsresponse, + }); + } catch (error: any) { + console.error('Issue in modifying data connection:', error); + return response.custom({ + statusCode: error.statusCode || 500, + body: error.message, + }); + } + } + ); + router.get( { path: `${DATACONNECTIONS_BASE}`, From 89eafa207c22e36849b86ba773f1765b3aa1a49d Mon Sep 17 00:00:00 2001 From: Derek Ho Date: Wed, 20 Sep 2023 17:07:54 -0400 Subject: [PATCH 06/22] Delete datasource and Connection Configuration Tab (#1024) * Address previous PR comments and implement rudimentary delete Signed-off-by: Derek Ho * Implement modal and instant delete showing up in list Signed-off-by: Derek Ho * Refactor save or cancel to a shared component, implement hard coded datasource configurations tab Signed-off-by: Derek Ho * Update test with mock role data Signed-off-by: Derek Ho * Add most functionality of edit connectiondetails Signed-off-by: Derek Ho * Address PR comments Signed-off-by: Derek Ho --------- Signed-off-by: Derek Ho --- .../data_connection.test.tsx.snap | 165 +++- ...anage_data_connections_table.test.tsx.snap | 87 +- .../__tests__/data_connection.test.tsx | 9 +- .../manage_data_connections_table.test.tsx | 14 +- .../components/__tests__/testing_constants.ts | 57 -- .../components/access_control_tab.tsx | 43 +- .../components/connection_configuration.tsx | 139 ++++ .../components/connection_details.tsx | 159 ++++ ....tsx => connection_management_callout.tsx} | 2 +- .../components/data_connection.tsx | 51 +- .../manage_data_connections_table.tsx | 61 +- .../data_connections/components/no_access.tsx | 3 +- .../components/query_permissions.tsx | 12 +- .../components/save_or_cancel.tsx | 32 + server/adaptors/ppl_plugin.ts | 13 + .../data_connections_router.ts | 29 + test/datasources.ts | 781 ++++++++++++++++++ 17 files changed, 1396 insertions(+), 261 deletions(-) delete mode 100644 public/components/data_connections/components/__tests__/testing_constants.ts create mode 100644 public/components/data_connections/components/connection_configuration.tsx create mode 100644 public/components/data_connections/components/connection_details.tsx rename public/components/data_connections/components/{access_control_callout.tsx => connection_management_callout.tsx} (89%) create mode 100644 public/components/data_connections/components/save_or_cancel.tsx create mode 100644 test/datasources.ts diff --git a/public/components/data_connections/components/__tests__/__snapshots__/data_connection.test.tsx.snap b/public/components/data_connections/components/__tests__/__snapshots__/data_connection.test.tsx.snap index adf1595cf..a4c2f2572 100644 --- a/public/components/data_connections/components/__tests__/__snapshots__/data_connection.test.tsx.snap +++ b/public/components/data_connections/components/__tests__/__snapshots__/data_connection.test.tsx.snap @@ -62,7 +62,7 @@ exports[`Data Connection Page test Renders data connection page with data 1`] =
- Access control + Authentication method
- Connection description + Data source description
- my_spark3 + - +
+
+
+
+ Query permissions +
+
+ Everyone
+
+
+
+
- Connection status + Spark data location
- j-3UNQLT1MPBGLG + -
@@ -268,20 +290,6 @@ exports[`Data Connection Page test Renders data connection page with data 1`] = aria-controls="random_html_id" aria-selected="true" class="euiTab euiTab-isSelected" - id="data" - role="tab" - type="button" - > - - Data - - -
+ > +
+
+
+ + + Configurations may be managed elsewhere. + +
+
+
+ Access to data can be managed in other systems outside of OpenSearch. Check with your administrator for additional configurations. +
+
+
+
+
+
+
+
+

+ Access Control +

+ Control which OpenSearch users have access to this data source. +
+
+
+ +
+
+
+
+
+
+
+
+ Query access +
+
+ - +
+
+
+
+
+
+
+
+
- - - Connection Status - - - - @@ -295,23 +278,6 @@ exports[`Manage Data Connections Table test Renders manage data connections tabl
- -
- Connection Status -
-
-
-
- @@ -371,23 +337,6 @@ exports[`Manage Data Connections Table test Renders manage data connections tabl
- -
- Connection Status -
-
-
-
- @@ -447,23 +396,6 @@ exports[`Manage Data Connections Table test Renders manage data connections tabl
- -
- Connection Status -
-
-
-
- @@ -523,23 +455,6 @@ exports[`Manage Data Connections Table test Renders manage data connections tabl
- -
- Connection Status -
-
-
-
- diff --git a/public/components/data_connections/components/__tests__/data_connection.test.tsx b/public/components/data_connections/components/__tests__/data_connection.test.tsx index 3146b747f..995719810 100644 --- a/public/components/data_connections/components/__tests__/data_connection.test.tsx +++ b/public/components/data_connections/components/__tests__/data_connection.test.tsx @@ -3,11 +3,11 @@ * SPDX-License-Identifier: Apache-2.0 */ -import { configure, mount } from 'enzyme'; +import { configure } from 'enzyme'; import Adapter from 'enzyme-adapter-react-16'; -import { act, waitFor } from '@testing-library/react'; +import { act } from '@testing-library/react'; import React from 'react'; -import { describeDataConnection } from './testing_constants'; +import { describeDataConnection, mockRoleData } from '../../../../../test/datasources'; import { DataConnection } from '../data_connection'; import ReactDOM from 'react-dom'; @@ -17,7 +17,7 @@ jest.mock('../../../../../public/framework/core_refs', () => ({ setBreadcrumbs: jest.fn(), }, http: { - get: jest.fn().mockResolvedValue(describeDataConnection), + get: jest.fn().mockResolvedValueOnce(mockRoleData).mockResolvedValue(describeDataConnection), }, }, })); @@ -29,7 +29,6 @@ describe('Data Connection Page test', () => { const pplService = { fetch: jest.fn(), }; - const wrapper = mount(); const container = document.createElement('div'); await act(() => { ReactDOM.render(, container); diff --git a/public/components/data_connections/components/__tests__/manage_data_connections_table.test.tsx b/public/components/data_connections/components/__tests__/manage_data_connections_table.test.tsx index fe7369426..cd5509f1b 100644 --- a/public/components/data_connections/components/__tests__/manage_data_connections_table.test.tsx +++ b/public/components/data_connections/components/__tests__/manage_data_connections_table.test.tsx @@ -8,20 +8,8 @@ import Adapter from 'enzyme-adapter-react-16'; import { act } from '@testing-library/react'; import React from 'react'; import { ManageDataConnectionsTable } from '../manage_data_connections_table'; -import { showDataConnectionsData } from './testing_constants'; +import { showDataConnectionsData } from '../../../../../test/datasources'; import ReactDOM from 'react-dom'; -import { coreRefs } from '../../../../../public/framework/core_refs'; - -jest.mock('../../../../../public/framework/core_refs', () => ({ - coreRefs: { - chrome: { - setBreadcrumbs: jest.fn(), - }, - http: { - get: jest.fn().mockResolvedValue(showDataConnectionsData), - }, - }, -})); describe('Manage Data Connections Table test', () => { configure({ adapter: new Adapter() }); diff --git a/public/components/data_connections/components/__tests__/testing_constants.ts b/public/components/data_connections/components/__tests__/testing_constants.ts deleted file mode 100644 index 65258fb27..000000000 --- a/public/components/data_connections/components/__tests__/testing_constants.ts +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright OpenSearch Contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -export const showDataConnectionsData = { - schema: [ - { - name: 'DATASOURCE_NAME', - type: 'string', - }, - { - name: 'CONNECTOR_TYPE', - type: 'string', - }, - ], - datarows: [ - ['my_spark_actual', 'SPARK'], - ['@opensearch', 'OPENSEARCH'], - ['my_spark', 'SPARK'], - ], - total: 3, - size: 3, - jsonData: [ - { - DATASOURCE_NAME: 'my_spark3', - CONNECTOR_TYPE: 'SPARK', - }, - { - DATASOURCE_NAME: 'my_spark4', - CONNECTOR_TYPE: 'SPARK', - }, - { - DATASOURCE_NAME: 'my_spark', - CONNECTOR_TYPE: 'SPARK', - }, - { - DATASOURCE_NAME: 'my_spark2', - CONNECTOR_TYPE: 'SPARK', - }, - ], -}; - -export const describeDataConnection = { - name: 'my_spark3', - connector: 'SPARK', - allowedRoles: [], - properties: { - 'spark.connector': 'emr', - 'spark.datasource.flint.host': '0.0.0.0', - 'spark.datasource.flint.integration': - 'https://aws.oss.sonatype.org/content/repositories/snapshots/org/opensearch/opensearch-spark-standalone_2.12/0.1.0-SNAPSHOT/opensearch-spark-standalone_2.12-0.1.0-20230731.182705-3.jar', - 'spark.datasource.flint.port': '9200', - 'spark.datasource.flint.scheme': 'http', - 'emr.cluster': 'j-3UNQLT1MPBGLG', - }, -}; diff --git a/public/components/data_connections/components/access_control_tab.tsx b/public/components/data_connections/components/access_control_tab.tsx index 15c8491b9..58fdffde3 100644 --- a/public/components/data_connections/components/access_control_tab.tsx +++ b/public/components/data_connections/components/access_control_tab.tsx @@ -10,16 +10,14 @@ import { EuiSpacer, EuiText, EuiHorizontalRule, - EuiBottomBar, - EuiButtonEmpty, } from '@elastic/eui'; import React, { useEffect, useState } from 'react'; import { EuiPanel } from '@elastic/eui'; -import { QUERY_ALL, QUERY_RESTRICT } from '../../../../common/constants/data_connections'; -import { AccessControlCallout } from './access_control_callout'; +import { ConnectionManagementCallout } from './connection_management_callout'; import { coreRefs } from '../../../../public/framework/core_refs'; import { QueryPermissionsConfiguration } from './query_permissions'; import { DATACONNECTIONS_BASE } from '../../../../common/constants/shared'; +import { SaveOrCancel } from './save_or_cancel'; interface AccessControlTabProps { dataConnection: string; @@ -109,36 +107,10 @@ export const AccessControlTab = (props: AccessControlTabProps) => { ); }; - const SaveOrCancel = () => { - return ( - - - - { - setMode('view'); - }} - color="ghost" - size="s" - iconType="cross" - > - Discard change(s) - - - - - Save - - - - - ); - }; - return ( <> - + @@ -146,7 +118,14 @@ export const AccessControlTab = (props: AccessControlTabProps) => { {mode === 'view' ? : } - {mode === 'edit' && } + {mode === 'edit' && ( + { + setMode('view'); + }} + onSave={saveChanges} + /> + )} ); diff --git a/public/components/data_connections/components/connection_configuration.tsx b/public/components/data_connections/components/connection_configuration.tsx new file mode 100644 index 000000000..8ce2bd7be --- /dev/null +++ b/public/components/data_connections/components/connection_configuration.tsx @@ -0,0 +1,139 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { + EuiFieldPassword, + EuiFieldText, + EuiFlexGroup, + EuiFlexItem, + EuiFormRow, + EuiSelect, + EuiSpacer, + EuiText, + EuiTextArea, +} from '@elastic/eui'; +import { EuiSelectOption } from '@elastic/eui/src/components/form/select'; +import React, { useState } from 'react'; + +interface ConnectionConfigurationProps { + connectionName: string; + connectionDetails: string; + onConnectionDetailsChange: (e: any) => void; + authenticationOptions: EuiSelectOption[]; + setSelectedAuthenticationMethod: (authenticationMethod: EuiSelectOption) => void; + selectedAuthenticationMethod: string; +} + +export const ConnectionConfiguration = (props: ConnectionConfigurationProps) => { + const { + connectionName, + connectionDetails, + onConnectionDetailsChange, + authenticationOptions, + selectedAuthenticationMethod, + setSelectedAuthenticationMethod, + } = props; + const [details, setDetails] = useState(connectionDetails); + + const [password, setPassword] = useState(''); + const [dual, setDual] = useState(true); + + const NameRow = () => { + return ( + + + Data source name + + This is the name of the data source and how it will be referenced in OpenSearch + Dashboards. + + + + + + + + + ); + }; + + const SparkEndpointRow = () => { + return ( + + + Spark endpoint URL + + { + "The URL for your Spark cluster and where your data is. This is what OpenSearch will connect to. The endpoint URL can't be changed. If you'd like to use another endpoint create a new data source." + } + + + + + + + + + ); + }; + + return ( + + + + + + Description - optional + + Text that can help identify the data source or share additional details + + + + + { + setDetails(e.target.value); + }} + onBlur={onConnectionDetailsChange} + /> + + + + + + + + + Authentication details + + This is information used to authenticate and create a data source with Spark. + + + + + setSelectedAuthenticationMethod(e)} + /> + + + + + + setPassword(e.target.value)} + /> + + + + + ); +}; diff --git a/public/components/data_connections/components/connection_details.tsx b/public/components/data_connections/components/connection_details.tsx new file mode 100644 index 000000000..44cd206f4 --- /dev/null +++ b/public/components/data_connections/components/connection_details.tsx @@ -0,0 +1,159 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { + EuiButton, + EuiFlexGroup, + EuiFlexItem, + EuiSpacer, + EuiText, + EuiHorizontalRule, +} from '@elastic/eui'; +import React, { useState } from 'react'; +import { EuiPanel } from '@elastic/eui'; +import { ConnectionManagementCallout } from './connection_management_callout'; +import { coreRefs } from '../../../../public/framework/core_refs'; +import { DATACONNECTIONS_BASE } from '../../../../common/constants/shared'; +import { SaveOrCancel } from './save_or_cancel'; +import { ConnectionConfiguration } from './connection_configuration'; + +interface ConnectionDetailProps { + dataConnection: string; + connector: string; + allowedRoles: string[]; + properties: unknown; +} + +export const ConnectionDetails = (props: ConnectionDetailProps) => { + const [mode, setMode] = useState<'view' | 'edit'>('view'); + const { http } = coreRefs; + + const { dataConnection, connector, allowedRoles, properties } = props; + const [connectionDetails, setConnectionDetails] = useState(''); + const onChange = (e) => { + setConnectionDetails(e.target.value); + }; + const authenticationOptions = [{ value: 'option_one', text: 'Username & Password' }]; + + const [selectedAuthenticationMethod, setSelectedAuthenticationMethod] = useState( + authenticationOptions[0].value + ); + + const onAuthenticationMethodChange = (e) => { + setSelectedAuthenticationMethod(e.target.value); + }; + + const ConnectionConfigurationView = () => { + return ( + + + + + Data source name + + {dataConnection} + + + + Spark endpoint URL + + {'-'} + + + + + + + + Description + + {'-'} + + + + Authentication method + + {'-'} + + + + + + ); + }; + + const EditConnectionConfiguration = () => { + return ( + + + + ); + }; + + const saveChanges = () => { + http!.put(`${DATACONNECTIONS_BASE}`, { + body: JSON.stringify({ + name: props.dataConnection, + allowedRoles: props.allowedRoles, + connector: props.connector, + properties: props.properties, + }), + }); + setMode('view'); + }; + + const ConnectionConfigurationHeader = () => { + return ( + + + +

Data source configurations

+ Control configurations for your data source. +
+
+ + + setMode(mode === 'view' ? 'edit' : 'view')} + fill={mode === 'view' ? true : false} + > + {mode === 'view' ? 'Edit' : 'Cancel'} + + +
+ ); + }; + + return ( + <> + + + + + + + {mode === 'view' ? : } + + + {mode === 'edit' && ( + { + setMode('view'); + }} + onSave={saveChanges} + /> + )} + + + ); +}; diff --git a/public/components/data_connections/components/access_control_callout.tsx b/public/components/data_connections/components/connection_management_callout.tsx similarity index 89% rename from public/components/data_connections/components/access_control_callout.tsx rename to public/components/data_connections/components/connection_management_callout.tsx index f675673ff..b78872287 100644 --- a/public/components/data_connections/components/access_control_callout.tsx +++ b/public/components/data_connections/components/connection_management_callout.tsx @@ -6,7 +6,7 @@ import { EuiCallOut } from '@elastic/eui'; import React from 'react'; -export const AccessControlCallout = () => { +export const ConnectionManagementCallout = () => { return ( Access to data can be managed in other systems outside of OpenSearch. Check with your diff --git a/public/components/data_connections/components/data_connection.tsx b/public/components/data_connections/components/data_connection.tsx index 0df41e30f..0529d8529 100644 --- a/public/components/data_connections/components/data_connection.tsx +++ b/public/components/data_connections/components/data_connection.tsx @@ -17,7 +17,6 @@ import { EuiAccordion, EuiIcon, EuiCard, - EuiTab, EuiTabbedContent, } from '@elastic/eui'; import React, { useEffect, useState } from 'react'; @@ -25,6 +24,7 @@ import { AccessControlTab } from './access_control_tab'; import { NoAccess } from './no_access'; import { DATACONNECTIONS_BASE } from '../../../../common/constants/shared'; import { coreRefs } from '../../../../public/framework/core_refs'; +import { ConnectionDetails } from './connection_details'; interface DatasourceDetails { allowedRoles: string[]; @@ -69,19 +69,11 @@ export const DataConnection = (props: any) => { }) ) .catch((err) => { - if (err.body.statusCode === 403) { - setHasAccess(false); - } + setHasAccess(false); }); }, [chrome, http]); const tabs = [ - { - id: 'data', - name: 'Data', - disabled: false, - content: <>, - }, { id: 'access_control', name: 'Access control', @@ -98,11 +90,18 @@ export const DataConnection = (props: any) => { id: 'connection_configuration', name: 'Connection configuration', disabled: false, - content: <>, + content: ( + + ), }, ]; - const renderOverview = () => { + const DatasourceOverview = () => { return ( @@ -115,11 +114,9 @@ export const DataConnection = (props: any) => { - Access control + Authentication method - {datasourceDetails.allowedRoles && datasourceDetails.allowedRoles.length - ? datasourceDetails.allowedRoles - : '-'} + {'-'} @@ -127,15 +124,27 @@ export const DataConnection = (props: any) => { - Connection description + Data source description - {datasourceDetails.name || '-'} + {'-'} + + + + Query permissions + + {datasourceDetails.allowedRoles && datasourceDetails.allowedRoles.length + ? 'Restricted' + : 'Everyone'} + + + + - Connection status + Spark data location - {datasourceDetails.cluster || '-'} + {'-'} @@ -165,7 +174,7 @@ export const DataConnection = (props: any) => { - {renderOverview()} + { const { http, chrome, pplService } = props; - const [data, setData] = useState([]); - const [hasAccess, setHasAccess] = useState(true); + const { setToast } = useToast(); + + const [data, setData] = useState([]); + const [isModalVisible, setIsModalVisible] = useState(false); + const [modalLayout, setModalLayout] = useState(); + + const deleteConnection = (connectionName: string) => { + http! + .delete(`${DATACONNECTIONS_BASE}/${connectionName}`) + .then(() => { + setToast(`Data connection ${connectionName} deleted successfully`); + setData( + data.filter((connection) => { + return !(connection.name === connectionName); + }) + ); + }) + .catch((err) => { + setToast(`Data connection $${connectionName} not deleted. See output for more details.`); + }); + }; useEffect(() => { chrome.setBreadcrumbs([ @@ -54,6 +74,23 @@ export const ManageDataConnectionsTable = (props: HomeProps) => { ); } + 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 icon = (record: DataConnection) => { switch (record.connectionType) { case 'OPENSEARCH': @@ -83,17 +120,6 @@ export const ManageDataConnectionsTable = (props: HomeProps) => { ), }, - { - field: 'connectionStatus', - name: 'Connection Status', - sortable: true, - truncateText: true, - render: (value, record) => ( - - {_.truncate(record.creationDate, { length: 100 })} - - ), - }, { field: 'actions', name: 'Actions', @@ -103,7 +129,7 @@ export const ManageDataConnectionsTable = (props: HomeProps) => { { - /* Delete Datasource*/ + displayDeleteModal(record.name); }} /> ), @@ -156,6 +182,7 @@ export const ManageDataConnectionsTable = (props: HomeProps) => { isSelectable={true} /> + {isModalVisible && modalLayout} ); diff --git a/public/components/data_connections/components/no_access.tsx b/public/components/data_connections/components/no_access.tsx index 5c07b2893..1766f7fe1 100644 --- a/public/components/data_connections/components/no_access.tsx +++ b/public/components/data_connections/components/no_access.tsx @@ -4,7 +4,6 @@ */ import { EuiButton, EuiEmptyPrompt, EuiPage, EuiText } from '@elastic/eui'; -import _ from 'lodash'; import React from 'react'; export const NoAccess = () => { @@ -16,7 +15,7 @@ export const NoAccess = () => { body={ { - 'Missing permissions to view connection details. Contact your administrator for permissions.' + 'You are missing permissions to view connection details. Contact your administrator for permissions.' } } diff --git a/public/components/data_connections/components/query_permissions.tsx b/public/components/data_connections/components/query_permissions.tsx index d983015fe..eee8312a8 100644 --- a/public/components/data_connections/components/query_permissions.tsx +++ b/public/components/data_connections/components/query_permissions.tsx @@ -23,10 +23,10 @@ import { PermissionsConfigurationProps } from '../../../../common/types/data_con export const QueryPermissionsConfiguration = (props: PermissionsConfigurationProps) => { const { roles, selectedRoles, setSelectedRoles } = props; - const [selectedRadio, setSelectedRadio] = useState( + const [selectedAccessLevel, setSelectedAccessLevel] = useState( selectedRoles.length ? QUERY_RESTRICTED : QUERY_ALL ); - const radios = [ + const accessLevelOptions = [ { id: QUERY_RESTRICTED, label: 'Restricted - accessible by users with specific OpenSearch roles', @@ -71,15 +71,15 @@ export const QueryPermissionsConfiguration = (props: PermissionsConfigurationPro setSelectedRadio(id)} + options={accessLevelOptions} + idSelected={selectedAccessLevel} + onChange={(id) => setSelectedAccessLevel(id)} name="query-radio-group" legend={{ children: Access level, }} /> - {selectedRadio === QUERY_RESTRICTED && } + {selectedAccessLevel === QUERY_RESTRICTED && } diff --git a/public/components/data_connections/components/save_or_cancel.tsx b/public/components/data_connections/components/save_or_cancel.tsx new file mode 100644 index 000000000..ccb966210 --- /dev/null +++ b/public/components/data_connections/components/save_or_cancel.tsx @@ -0,0 +1,32 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { EuiBottomBar, EuiButton, EuiButtonEmpty, EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; +import React from 'react'; + +interface SaveOrCancelProps { + onSave: () => void; + onCancel: () => void; +} + +export const SaveOrCancel = (props: SaveOrCancelProps) => { + const { onSave, onCancel } = props; + return ( + + + + + Discard change(s) + + + + + Save + + + + + ); +}; diff --git a/server/adaptors/ppl_plugin.ts b/server/adaptors/ppl_plugin.ts index ddc2a2ccf..563c43672 100644 --- a/server/adaptors/ppl_plugin.ts +++ b/server/adaptors/ppl_plugin.ts @@ -55,6 +55,19 @@ export const PPLPlugin = function (Client, config, components) { method: 'GET', }); + ppl.deleteDataConnection = ca({ + url: { + fmt: `${OPENSEARCH_DATACONNECTIONS_API.DATACONNECTION}/<%=dataconnection%>`, + req: { + dataconnection: { + type: 'string', + required: true, + }, + }, + }, + method: 'DELETE', + }); + ppl.modifyDataConnection = ca({ url: { fmt: `${OPENSEARCH_DATACONNECTIONS_API.DATACONNECTION}`, diff --git a/server/routes/data_connections/data_connections_router.ts b/server/routes/data_connections/data_connections_router.ts index b0f2b2bad..a65660ba4 100644 --- a/server/routes/data_connections/data_connections_router.ts +++ b/server/routes/data_connections/data_connections_router.ts @@ -37,6 +37,35 @@ export function registerDataConnectionsRoute(router: IRouter) { } ); + router.delete( + { + path: `${DATACONNECTIONS_BASE}/{name}`, + validate: { + params: schema.object({ + name: schema.string(), + }), + }, + }, + async (context, request, response): Promise => { + try { + const dataConnectionsresponse = await context.observability_plugin.observabilityClient + .asScoped(request) + .callAsCurrentUser('ppl.deleteDataConnection', { + dataconnection: request.params.name, + }); + return response.ok({ + body: dataConnectionsresponse, + }); + } catch (error: any) { + console.error('Issue in deleting data connection:', error); + return response.custom({ + statusCode: error.statusCode || 500, + body: error.message, + }); + } + } + ); + router.put( { path: `${DATACONNECTIONS_BASE}`, diff --git a/test/datasources.ts b/test/datasources.ts new file mode 100644 index 000000000..1bdf6e25b --- /dev/null +++ b/test/datasources.ts @@ -0,0 +1,781 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +export const showDataConnectionsData = { + schema: [ + { + name: 'DATASOURCE_NAME', + type: 'string', + }, + { + name: 'CONNECTOR_TYPE', + type: 'string', + }, + ], + datarows: [ + ['my_spark_actual', 'SPARK'], + ['@opensearch', 'OPENSEARCH'], + ['my_spark', 'SPARK'], + ], + total: 3, + size: 3, + jsonData: [ + { + DATASOURCE_NAME: 'my_spark3', + CONNECTOR_TYPE: 'SPARK', + }, + { + DATASOURCE_NAME: 'my_spark4', + CONNECTOR_TYPE: 'SPARK', + }, + { + DATASOURCE_NAME: 'my_spark', + CONNECTOR_TYPE: 'SPARK', + }, + { + DATASOURCE_NAME: 'my_spark2', + CONNECTOR_TYPE: 'SPARK', + }, + ], +}; + +export const describeDataConnection = { + name: 'my_spark3', + connector: 'SPARK', + allowedRoles: [], + properties: { + 'spark.connector': 'emr', + 'spark.datasource.flint.host': '0.0.0.0', + 'spark.datasource.flint.integration': + 'https://aws.oss.sonatype.org/content/repositories/snapshots/org/opensearch/opensearch-spark-standalone_2.12/0.1.0-SNAPSHOT/opensearch-spark-standalone_2.12-0.1.0-20230731.182705-3.jar', + 'spark.datasource.flint.port': '9200', + 'spark.datasource.flint.scheme': 'http', + 'emr.cluster': 'j-3UNQLT1MPBGLG', + }, +}; + +export const mockRoleData = { + total: 44, + data: { + security_analytics_ack_alerts: { + reserved: true, + hidden: false, + cluster_permissions: ['cluster:admin/opensearch/securityanalytics/alerts/*'], + index_permissions: [], + tenant_permissions: [], + static: false, + }, + observability_read_access: { + reserved: true, + hidden: false, + cluster_permissions: ['cluster:admin/opensearch/observability/get'], + index_permissions: [], + tenant_permissions: [], + static: false, + }, + kibana_user: { + reserved: true, + hidden: false, + description: 'Provide the minimum permissions for a kibana user', + cluster_permissions: ['cluster_composite_ops'], + index_permissions: [ + { + index_patterns: [ + '.kibana', + '.kibana-6', + '.kibana_*', + '.opensearch_dashboards', + '.opensearch_dashboards-6', + '.opensearch_dashboards_*', + ], + fls: [], + masked_fields: [], + allowed_actions: ['delete', 'index', 'manage', 'read'], + }, + { + index_patterns: ['.tasks', '.management-beats', '*:.tasks', '*:.management-beats'], + fls: [], + masked_fields: [], + allowed_actions: ['indices_all'], + }, + ], + tenant_permissions: [], + static: true, + }, + own_index: { + reserved: true, + hidden: false, + description: 'Allow all for indices named like the current user', + cluster_permissions: ['cluster_composite_ops'], + index_permissions: [ + { + index_patterns: ['${user_name}'], + fls: [], + masked_fields: [], + allowed_actions: ['indices_all'], + }, + ], + tenant_permissions: [], + static: true, + }, + alerting_full_access: { + reserved: true, + hidden: false, + cluster_permissions: [ + 'cluster:admin/opendistro/alerting/*', + 'cluster:admin/opensearch/alerting/*', + 'cluster:admin/opensearch/notifications/feature/publish', + 'cluster_monitor', + ], + index_permissions: [ + { + index_patterns: ['*'], + fls: [], + masked_fields: [], + allowed_actions: [ + 'indices:admin/aliases/get', + 'indices:admin/mappings/get', + 'indices_monitor', + ], + }, + ], + tenant_permissions: [], + static: false, + }, + snapshot_management_read_access: { + reserved: true, + hidden: false, + cluster_permissions: [ + 'cluster:admin/opensearch/snapshot_management/policy/explain', + 'cluster:admin/opensearch/snapshot_management/policy/get', + 'cluster:admin/opensearch/snapshot_management/policy/search', + 'cluster:admin/repository/get', + 'cluster:admin/snapshot/get', + ], + index_permissions: [], + tenant_permissions: [], + static: false, + }, + all_access: { + reserved: true, + hidden: false, + description: 'Allow full access to all indices and all cluster APIs', + cluster_permissions: ['*'], + index_permissions: [ + { + index_patterns: ['*'], + fls: [], + masked_fields: [], + allowed_actions: ['*'], + }, + ], + tenant_permissions: [ + { + tenant_patterns: ['*'], + allowed_actions: ['kibana_all_write'], + }, + ], + static: true, + }, + alerting_read_access: { + reserved: true, + hidden: false, + cluster_permissions: [ + 'cluster:admin/opendistro/alerting/alerts/get', + 'cluster:admin/opendistro/alerting/destination/get', + 'cluster:admin/opendistro/alerting/monitor/get', + 'cluster:admin/opendistro/alerting/monitor/search', + 'cluster:admin/opensearch/alerting/findings/get', + 'cluster:admin/opensearch/alerting/workflow/get', + 'cluster:admin/opensearch/alerting/workflow_alerts/get', + ], + index_permissions: [], + tenant_permissions: [], + static: false, + }, + cross_cluster_replication_follower_full_access: { + reserved: true, + hidden: false, + cluster_permissions: ['cluster:admin/plugins/replication/autofollow/update'], + index_permissions: [ + { + index_patterns: ['*'], + fls: [], + masked_fields: [], + allowed_actions: [ + 'indices:admin/plugins/replication/index/pause', + 'indices:admin/plugins/replication/index/resume', + 'indices:admin/plugins/replication/index/setup/validate', + 'indices:admin/plugins/replication/index/start', + 'indices:admin/plugins/replication/index/status_check', + 'indices:admin/plugins/replication/index/stop', + 'indices:admin/plugins/replication/index/update', + 'indices:data/write/plugins/replication/changes', + ], + }, + ], + tenant_permissions: [], + static: false, + }, + manage_snapshots: { + reserved: true, + hidden: false, + description: 'Provide the minimum permissions for managing snapshots', + cluster_permissions: ['manage_snapshots'], + index_permissions: [ + { + index_patterns: ['*'], + fls: [], + masked_fields: [], + allowed_actions: ['indices:admin/create', 'indices:data/write/index'], + }, + ], + tenant_permissions: [], + static: true, + }, + logstash: { + reserved: true, + hidden: false, + description: 'Provide the minimum permissions for logstash and beats', + cluster_permissions: [ + 'cluster:admin/ingest/pipeline/get', + 'cluster:admin/ingest/pipeline/put', + 'cluster_composite_ops', + 'cluster_monitor', + 'indices:admin/template/get', + 'indices:admin/template/put', + ], + index_permissions: [ + { + index_patterns: ['logstash-*'], + fls: [], + masked_fields: [], + allowed_actions: ['create_index', 'crud'], + }, + { + index_patterns: ['*beat*'], + fls: [], + masked_fields: [], + allowed_actions: ['crud', 'create_index'], + }, + ], + tenant_permissions: [], + static: true, + }, + observability_full_access: { + reserved: true, + hidden: false, + cluster_permissions: [ + 'cluster:admin/opensearch/observability/create', + 'cluster:admin/opensearch/observability/delete', + 'cluster:admin/opensearch/observability/get', + 'cluster:admin/opensearch/observability/update', + ], + index_permissions: [], + tenant_permissions: [], + static: false, + }, + point_in_time_full_access: { + reserved: true, + hidden: false, + cluster_permissions: [], + index_permissions: [ + { + index_patterns: ['*'], + fls: [], + masked_fields: [], + allowed_actions: ['manage_point_in_time'], + }, + ], + tenant_permissions: [], + static: false, + }, + notifications_full_access: { + reserved: true, + hidden: false, + cluster_permissions: ['cluster:admin/opensearch/notifications/*'], + index_permissions: [], + tenant_permissions: [], + static: false, + }, + notifications_read_access: { + reserved: true, + hidden: false, + cluster_permissions: [ + 'cluster:admin/opensearch/notifications/channels/get', + 'cluster:admin/opensearch/notifications/configs/get', + 'cluster:admin/opensearch/notifications/features', + ], + index_permissions: [], + tenant_permissions: [], + static: false, + }, + cross_cluster_replication_leader_full_access: { + reserved: true, + hidden: false, + cluster_permissions: [], + index_permissions: [ + { + index_patterns: ['*'], + fls: [], + masked_fields: [], + allowed_actions: [ + 'indices:admin/plugins/replication/index/setup/validate', + 'indices:data/read/plugins/replication/changes', + 'indices:data/read/plugins/replication/file_chunk', + ], + }, + ], + tenant_permissions: [], + static: false, + }, + knn_read_access: { + reserved: true, + hidden: false, + cluster_permissions: [ + 'cluster:admin/knn_get_model_action', + 'cluster:admin/knn_search_model_action', + 'cluster:admin/knn_stats_action', + ], + index_permissions: [], + tenant_permissions: [], + static: false, + }, + ppl_full_access: { + reserved: true, + hidden: false, + cluster_permissions: ['cluster:admin/opensearch/ppl'], + index_permissions: [ + { + index_patterns: ['*'], + fls: [], + masked_fields: [], + allowed_actions: [ + 'indices:admin/mappings/get', + 'indices:data/read/search*', + 'indices:monitor/settings/get', + ], + }, + ], + tenant_permissions: [], + static: false, + }, + security_analytics_read_access: { + reserved: true, + hidden: false, + cluster_permissions: [ + 'cluster:admin/opensearch/securityanalytics/alerts/get', + 'cluster:admin/opensearch/securityanalytics/correlations/findings', + 'cluster:admin/opensearch/securityanalytics/correlations/list', + 'cluster:admin/opensearch/securityanalytics/detector/get', + 'cluster:admin/opensearch/securityanalytics/detector/search', + 'cluster:admin/opensearch/securityanalytics/findings/get', + 'cluster:admin/opensearch/securityanalytics/mapping/get', + 'cluster:admin/opensearch/securityanalytics/mapping/view/get', + 'cluster:admin/opensearch/securityanalytics/rule/get', + 'cluster:admin/opensearch/securityanalytics/rule/search', + ], + index_permissions: [], + tenant_permissions: [], + static: false, + }, + security_analytics_full_access: { + reserved: true, + hidden: false, + cluster_permissions: [ + 'cluster:admin/opensearch/securityanalytics/alerts/*', + 'cluster:admin/opensearch/securityanalytics/correlations/*', + 'cluster:admin/opensearch/securityanalytics/detector/*', + 'cluster:admin/opensearch/securityanalytics/findings/*', + 'cluster:admin/opensearch/securityanalytics/mapping/*', + 'cluster:admin/opensearch/securityanalytics/rule/*', + ], + index_permissions: [ + { + index_patterns: ['*'], + fls: [], + masked_fields: [], + allowed_actions: ['indices:admin/mapping/put', 'indices:admin/mappings/get'], + }, + ], + tenant_permissions: [], + static: false, + }, + knn_full_access: { + reserved: true, + hidden: false, + cluster_permissions: [ + 'cluster:admin/knn_delete_model_action', + 'cluster:admin/knn_get_model_action', + 'cluster:admin/knn_remove_model_from_cache_action', + 'cluster:admin/knn_search_model_action', + 'cluster:admin/knn_stats_action', + 'cluster:admin/knn_training_job_route_decision_info_action', + 'cluster:admin/knn_training_job_router_action', + 'cluster:admin/knn_training_model_action', + 'cluster:admin/knn_update_model_graveyard_action', + 'cluster:admin/knn_warmup_action', + ], + index_permissions: [], + tenant_permissions: [], + static: false, + }, + asynchronous_search_read_access: { + reserved: true, + hidden: false, + cluster_permissions: ['cluster:admin/opendistro/asynchronous_search/get'], + index_permissions: [], + tenant_permissions: [], + static: false, + }, + index_management_full_access: { + reserved: true, + hidden: false, + cluster_permissions: [ + 'cluster:admin/opendistro/ism/*', + 'cluster:admin/opendistro/rollup/*', + 'cluster:admin/opendistro/transform/*', + 'cluster:admin/opensearch/controlcenter/lron/*', + 'cluster:admin/opensearch/notifications/channels/get', + 'cluster:admin/opensearch/notifications/feature/publish', + ], + index_permissions: [ + { + index_patterns: ['*'], + fls: [], + masked_fields: [], + allowed_actions: ['indices:admin/opensearch/ism/*'], + }, + ], + tenant_permissions: [], + static: false, + }, + readall_and_monitor: { + reserved: true, + hidden: false, + description: 'Provide the minimum permissions for to readall indices and monitor the cluster', + cluster_permissions: ['cluster_composite_ops_ro', 'cluster_monitor'], + index_permissions: [ + { + index_patterns: ['*'], + fls: [], + masked_fields: [], + allowed_actions: ['read'], + }, + ], + tenant_permissions: [], + static: true, + }, + ml_read_access: { + reserved: true, + hidden: false, + cluster_permissions: [ + 'cluster:admin/opensearch/ml/connectors/get', + 'cluster:admin/opensearch/ml/connectors/search', + 'cluster:admin/opensearch/ml/model_groups/search', + 'cluster:admin/opensearch/ml/models/get', + 'cluster:admin/opensearch/ml/models/search', + 'cluster:admin/opensearch/ml/tasks/get', + 'cluster:admin/opensearch/ml/tasks/search', + ], + index_permissions: [], + tenant_permissions: [], + static: false, + }, + security_rest_api_full_access: { + reserved: true, + hidden: false, + cluster_permissions: [ + 'restapi:admin/actiongroups', + 'restapi:admin/allowlist', + 'restapi:admin/internalusers', + 'restapi:admin/nodesdn', + 'restapi:admin/roles', + 'restapi:admin/rolesmapping', + 'restapi:admin/ssl/certs/info', + 'restapi:admin/ssl/certs/reload', + 'restapi:admin/tenants', + ], + index_permissions: [], + tenant_permissions: [], + static: false, + }, + kibana_read_only: { + reserved: true, + hidden: false, + cluster_permissions: [], + index_permissions: [], + tenant_permissions: [], + static: false, + }, + cross_cluster_search_remote_full_access: { + reserved: true, + hidden: false, + cluster_permissions: [], + index_permissions: [ + { + index_patterns: ['*'], + fls: [], + masked_fields: [], + allowed_actions: ['indices:admin/shards/search_shards', 'indices:data/read/search'], + }, + ], + tenant_permissions: [], + static: false, + }, + reports_read_access: { + reserved: true, + hidden: false, + cluster_permissions: [ + 'cluster:admin/opendistro/reports/definition/get', + 'cluster:admin/opendistro/reports/definition/list', + 'cluster:admin/opendistro/reports/instance/get', + 'cluster:admin/opendistro/reports/instance/list', + 'cluster:admin/opendistro/reports/menu/download', + ], + index_permissions: [], + tenant_permissions: [], + static: false, + }, + anomaly_read_access: { + reserved: true, + hidden: false, + cluster_permissions: [ + 'cluster:admin/opendistro/ad/detector/info', + 'cluster:admin/opendistro/ad/detector/search', + 'cluster:admin/opendistro/ad/detector/validate', + 'cluster:admin/opendistro/ad/detectors/get', + 'cluster:admin/opendistro/ad/result/search', + 'cluster:admin/opendistro/ad/result/topAnomalies', + 'cluster:admin/opendistro/ad/tasks/search', + ], + index_permissions: [], + tenant_permissions: [], + static: false, + }, + anomaly_full_access: { + reserved: true, + hidden: false, + cluster_permissions: ['cluster:admin/opendistro/ad/*', 'cluster_monitor'], + index_permissions: [ + { + index_patterns: ['*'], + fls: [], + masked_fields: [], + allowed_actions: [ + 'indices:admin/aliases/get', + 'indices:admin/mappings/get', + 'indices_monitor', + ], + }, + ], + tenant_permissions: [], + static: false, + }, + reports_instances_read_access: { + reserved: true, + hidden: false, + cluster_permissions: [ + 'cluster:admin/opendistro/reports/instance/get', + 'cluster:admin/opendistro/reports/instance/list', + 'cluster:admin/opendistro/reports/menu/download', + ], + index_permissions: [], + tenant_permissions: [], + static: false, + }, + snapshot_management_full_access: { + reserved: true, + hidden: false, + cluster_permissions: [ + 'cluster:admin/opensearch/notifications/feature/publish', + 'cluster:admin/opensearch/snapshot_management/*', + 'cluster:admin/repository/*', + 'cluster:admin/snapshot/*', + ], + index_permissions: [], + tenant_permissions: [], + static: false, + }, + readall: { + reserved: true, + hidden: false, + description: 'Provide the minimum permissions for to readall indices', + cluster_permissions: ['cluster_composite_ops_ro'], + index_permissions: [ + { + index_patterns: ['*'], + fls: [], + masked_fields: [], + allowed_actions: ['read'], + }, + ], + tenant_permissions: [], + static: true, + }, + asynchronous_search_full_access: { + reserved: true, + hidden: false, + cluster_permissions: ['cluster:admin/opendistro/asynchronous_search/*'], + index_permissions: [ + { + index_patterns: ['*'], + fls: [], + masked_fields: [], + allowed_actions: ['indices:data/read/search*'], + }, + ], + tenant_permissions: [], + static: false, + }, + ml_full_access: { + reserved: true, + hidden: false, + cluster_permissions: ['cluster:admin/opensearch/ml/*', 'cluster_monitor'], + index_permissions: [ + { + index_patterns: ['*'], + fls: [], + masked_fields: [], + allowed_actions: ['indices_monitor'], + }, + ], + tenant_permissions: [], + static: false, + }, + reports_full_access: { + reserved: true, + hidden: false, + cluster_permissions: [ + 'cluster:admin/opendistro/reports/definition/create', + 'cluster:admin/opendistro/reports/definition/delete', + 'cluster:admin/opendistro/reports/definition/get', + 'cluster:admin/opendistro/reports/definition/list', + 'cluster:admin/opendistro/reports/definition/on_demand', + 'cluster:admin/opendistro/reports/definition/update', + 'cluster:admin/opendistro/reports/instance/get', + 'cluster:admin/opendistro/reports/instance/list', + 'cluster:admin/opendistro/reports/menu/download', + ], + index_permissions: [], + tenant_permissions: [], + static: false, + }, + security_rest_api_access: { + reserved: true, + hidden: false, + cluster_permissions: [], + index_permissions: [], + tenant_permissions: [], + static: false, + }, + ip2geo_datasource_read_access: { + reserved: true, + hidden: false, + cluster_permissions: ['cluster:admin/geospatial/datasource/get'], + index_permissions: [], + tenant_permissions: [], + static: false, + }, + alerting_ack_alerts: { + reserved: true, + hidden: false, + cluster_permissions: [ + 'cluster:admin/opendistro/alerting/alerts/*', + 'cluster:admin/opendistro/alerting/chained_alerts/*', + 'cluster:admin/opendistro/alerting/workflow_alerts/*', + ], + index_permissions: [], + tenant_permissions: [], + static: false, + }, + ip2geo_datasource_full_access: { + reserved: true, + hidden: false, + cluster_permissions: ['cluster:admin/geospatial/datasource/*'], + index_permissions: [], + tenant_permissions: [], + static: false, + }, + kibana_server: { + reserved: true, + hidden: false, + description: 'Provide the minimum permissions for the Kibana server', + cluster_permissions: [ + 'cluster_composite_ops', + 'cluster_monitor', + 'indices:admin/index_template*', + 'indices:admin/template*', + 'indices:data/read/scroll*', + 'manage_point_in_time', + ], + index_permissions: [ + { + index_patterns: ['.kibana', '.opensearch_dashboards'], + fls: [], + masked_fields: [], + allowed_actions: ['indices_all'], + }, + { + index_patterns: ['.kibana-6', '.opensearch_dashboards-6'], + fls: [], + masked_fields: [], + allowed_actions: ['indices_all'], + }, + { + index_patterns: ['.kibana_*', '.opensearch_dashboards_*'], + fls: [], + masked_fields: [], + allowed_actions: ['indices_all'], + }, + { + index_patterns: ['.tasks'], + fls: [], + masked_fields: [], + allowed_actions: ['indices_all'], + }, + { + index_patterns: ['.management-beats*'], + fls: [], + masked_fields: [], + allowed_actions: ['indices_all'], + }, + { + index_patterns: ['*'], + fls: [], + masked_fields: [], + allowed_actions: ['indices:admin/aliases*'], + }, + ], + tenant_permissions: [], + static: true, + }, + notebooks_read_access: { + reserved: true, + hidden: false, + cluster_permissions: [ + 'cluster:admin/opendistro/notebooks/get', + 'cluster:admin/opendistro/notebooks/list', + ], + index_permissions: [], + tenant_permissions: [], + static: false, + }, + notebooks_full_access: { + reserved: true, + hidden: false, + cluster_permissions: [ + 'cluster:admin/opendistro/notebooks/create', + 'cluster:admin/opendistro/notebooks/delete', + 'cluster:admin/opendistro/notebooks/get', + 'cluster:admin/opendistro/notebooks/list', + 'cluster:admin/opendistro/notebooks/update', + ], + index_permissions: [], + tenant_permissions: [], + static: false, + }, + }, +}; From 1efd1917ad9233771eb423c97d953e38803be6c1 Mon Sep 17 00:00:00 2001 From: Derek Ho Date: Fri, 22 Sep 2023 15:37:18 -0400 Subject: [PATCH 07/22] Get most of the workflow working for configure datasource Signed-off-by: Derek Ho --- .../components/configure_datasource.tsx | 117 ++++++++++++++++++ .../components/data_connections_header.tsx | 45 ++++++- .../manage_data_connections_table.tsx | 2 +- .../components/new_datasource.tsx | 84 +++++++++++++ .../components/new_datasource_card_view.tsx | 116 +++++++++++++++++ .../components/new_datasource_description.tsx | 24 ++++ public/components/data_connections/home.tsx | 11 ++ .../icons/apache_spark-icon.svg | 1 + 8 files changed, 396 insertions(+), 4 deletions(-) create mode 100644 public/components/data_connections/components/configure_datasource.tsx create mode 100644 public/components/data_connections/components/new_datasource.tsx create mode 100644 public/components/data_connections/components/new_datasource_card_view.tsx create mode 100644 public/components/data_connections/components/new_datasource_description.tsx create mode 100644 public/components/data_connections/icons/apache_spark-icon.svg diff --git a/public/components/data_connections/components/configure_datasource.tsx b/public/components/data_connections/components/configure_datasource.tsx new file mode 100644 index 000000000..3cd30dece --- /dev/null +++ b/public/components/data_connections/components/configure_datasource.tsx @@ -0,0 +1,117 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { + EuiFlexGroup, + EuiFlexItem, + EuiPage, + EuiPageBody, + EuiSpacer, + EuiTitle, + EuiText, + EuiLink, + EuiButton, + EuiSteps, + EuiPageSideBar, + EuiPanel, + EuiFormRow, + EuiFieldText, + EuiBottomBar, + EuiButtonEmpty, +} from '@elastic/eui'; +import React from 'react'; +import { OPENSEARCH_DOCUMENTATION_URL } from '../../../../common/constants/data_connections'; + +interface ConfigureDatasourceProps { + type: string; +} + +export function Configure(props: ConfigureDatasourceProps) { + const { type } = props; + const ConfigureDatasourceSteps = [ + { + title: 'Step 1', + children: ( + +

Configure Connection

+
+ ), + }, + { + title: 'Step 2', + children: ( + +

Review Configuration

+
+ ), + }, + ]; + + const ConfigureDatasource = (configurationProps: { datasourceType: string }) => { + const { datasourceType } = configurationProps; + return ( +
+ + +

{`Configure ${datasourceType} Connection`}

+
+ + + {`Connect to ${datasourceType} with OpenSearch and OpenSearch Dashboards `} + + Learn more + + + + +

Connection Details

+
+ + + + + + + + + + + +
+
+ ); + }; + + return ( + + + + + + + + + + + + {}} color="ghost" size="s" iconType="cross"> + Cancel + + + + {}} color="ghost" size="s" iconType="arrowLeft"> + Previous + + + + {}} size="s" iconType="arrowRight" fill> + Review Configuration + + + + + + ); +} diff --git a/public/components/data_connections/components/data_connections_header.tsx b/public/components/data_connections/components/data_connections_header.tsx index 7f071683b..85f204dd9 100644 --- a/public/components/data_connections/components/data_connections_header.tsx +++ b/public/components/data_connections/components/data_connections_header.tsx @@ -8,31 +8,70 @@ import { EuiPageHeader, EuiPageHeaderSection, EuiSpacer, + EuiTab, + EuiTabs, EuiText, EuiTitle, } from '@elastic/eui'; import _ from 'lodash'; -import React from 'react'; +import React, { useState } from 'react'; import { OPENSEARCH_DOCUMENTATION_URL } from '../../../../common/constants/data_connections'; export const DataConnectionsHeader = () => { + const tabs = [ + { + id: 'manage', + name: 'Manage data source', + disabled: false, + }, + { + id: 'new', + name: 'New data source', + disabled: false, + }, + ]; + + const [selectedTabId, setSelectedTabId] = useState( + window.location.hash.substring(2) ? window.location.hash.substring(2) : 'manage' + ); + + const onSelectedTabChanged = (id) => { + setSelectedTabId(id); + window.location.hash = id; + }; + + const renderTabs = () => { + return tabs.map((tab, index) => ( + onSelectedTabChanged(tab.id)} + isSelected={tab.id === selectedTabId} + disabled={tab.disabled} + key={index} + > + {tab.name} + + )); + }; + return (
-

Data connections

+

Data sources

- Connect and manage compatible OpenSearch and OpenSearch Dashboard data connections.{' '} + Connect and manage compatible OpenSearch and OpenSearch Dashboard data sources.{' '} Learn more + {renderTabs()} +
); }; diff --git a/public/components/data_connections/components/manage_data_connections_table.tsx b/public/components/data_connections/components/manage_data_connections_table.tsx index e1950e704..a1b241031 100644 --- a/public/components/data_connections/components/manage_data_connections_table.tsx +++ b/public/components/data_connections/components/manage_data_connections_table.tsx @@ -57,7 +57,7 @@ export const ManageDataConnectionsTable = (props: HomeProps) => { useEffect(() => { chrome.setBreadcrumbs([ { - text: 'Data Connections', + text: 'Data sources', href: '#/', }, ]); diff --git a/public/components/data_connections/components/new_datasource.tsx b/public/components/data_connections/components/new_datasource.tsx new file mode 100644 index 000000000..186749ba5 --- /dev/null +++ b/public/components/data_connections/components/new_datasource.tsx @@ -0,0 +1,84 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { + EuiFieldSearch, + EuiFilterButton, + EuiFilterGroup, + EuiFilterSelectItem, + EuiFlexGroup, + EuiFlexItem, + EuiIcon, + EuiInMemoryTable, + EuiLink, + EuiOverlayMask, + EuiPage, + EuiPageBody, + EuiPageContent, + EuiPopover, + EuiPopoverTitle, + EuiTableFieldDataColumnType, +} from '@elastic/eui'; +import _ from 'lodash'; +import React, { useEffect, useState } from 'react'; +import { DataConnectionsHeader } from './data_connections_header'; +import { HomeProps } from '../home'; +import { DataConnectionsDescription } from './manage_data_connections_description'; +import { DATACONNECTIONS_BASE, INTEGRATIONS_BASE } from '../../../../common/constants/shared'; +import { useToast } from '../../../../public/components/common/toast'; +import { DeleteModal } from '../../../../public/components/common/helpers/delete_modal'; +import { AvailableIntegrationsList } from '../../../../public/components/integrations/components/available_integration_overview_page'; +import { IntegrationHeader } from '../../../../public/components/integrations/components/integration_header'; +import { AvailableIntegrationsCardView } from '../../../../public/components/integrations/components/available_integration_card_view'; +import { AvailableIntegrationsTable } from '../../../../public/components/integrations/components/available_integration_table'; +import { NewDatasourceCardView } from './new_datasource_card_view'; + +interface DataConnection { + connectionType: 'OPENSEARCH' | 'SPARK'; + name: string; +} + +export const NewDatasource = (props: HomeProps) => { + const { chrome, http } = props; + + const [query, setQuery] = useState(''); + const [isCardView, setCardView] = useState(true); + const [data, setData] = useState({ hits: [] }); + + const [isPopoverOpen, setIsPopoverOpen] = useState(false); + + const onButtonClick = () => { + setIsPopoverOpen(!isPopoverOpen); + }; + + const closePopover = () => { + setIsPopoverOpen(false); + }; + + const [items, setItems] = useState([] as Array<{ name: string; checked: boolean }>); + + useEffect(() => { + chrome.setBreadcrumbs([ + { + text: 'Data sources', + href: '#/', + }, + ]); + }, []); + + // TODO: implement table view + const NewDatasourceTableView = () => { + return null; + }; + + return ( + + + + {isCardView ? : } + + + ); +}; diff --git a/public/components/data_connections/components/new_datasource_card_view.tsx b/public/components/data_connections/components/new_datasource_card_view.tsx new file mode 100644 index 000000000..0981b4d26 --- /dev/null +++ b/public/components/data_connections/components/new_datasource_card_view.tsx @@ -0,0 +1,116 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { + EuiPanel, + EuiCard, + EuiFlexGroup, + EuiFlexItem, + EuiSpacer, + EuiFieldSearch, + EuiButtonGroup, + EuiIcon, +} from '@elastic/eui'; +import _ from 'lodash'; +import React, { useState } from 'react'; +import { INTEGRATIONS_BASE } from '../../../../common/constants/shared'; +import { NewDatasourceDescription } from './new_datasource_description'; +import { coreRefs } from '../../../../public/framework/core_refs'; +import { MANAGEMENT_APP_ID } from '../../../../../../src/plugins/management/public'; +import sparkSvg from '../icons/apache_spark-icon.svg'; + +export interface DatasourceType { + name: string; + description: string; + displayIcon: JSX.Element; +} + +const Datasources: DatasourceType[] = [ + { + name: 'OpenSearch', + description: 'Connect to self managed OpenSearch clusters', + displayIcon: , + }, + { + name: 'Spark', + description: 'Connect to a self managed instance of Apache Spark', + displayIcon: , + }, +]; + +export function NewDatasourceCardView() { + const { http } = coreRefs; + const [toggleIconIdSelected, setToggleIconIdSelected] = useState('1'); + + const toggleButtonsIcons = [ + { + id: '0', + label: 'list', + iconType: 'list', + }, + { + id: '1', + label: 'grid', + iconType: 'grid', + }, + ]; + + const onChangeIcons = (optionId: string) => { + setToggleIconIdSelected(optionId); + }; + + const renderRows = (datasources: DatasourceType[]) => { + return ( + <> + + {datasources.map((i, v) => { + return ( + + (window.location.hash = `#/configure/${i.name}`)} + /> + + ); + })} + + + + ); + }; + + return ( + + + + + {}} + /> + + + onChangeIcons(id)} + isIconOnly + /> + + + + {renderRows(Datasources)} + + ); +} diff --git a/public/components/data_connections/components/new_datasource_description.tsx b/public/components/data_connections/components/new_datasource_description.tsx new file mode 100644 index 000000000..91f13c666 --- /dev/null +++ b/public/components/data_connections/components/new_datasource_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/public/components/data_connections/home.tsx b/public/components/data_connections/home.tsx index 534a71815..0ee1d5c9d 100644 --- a/public/components/data_connections/home.tsx +++ b/public/components/data_connections/home.tsx @@ -9,6 +9,8 @@ import { ChromeBreadcrumb, ChromeStart, HttpStart } from '../../../../../src/cor import { DataConnection } from './components/data_connection'; import { ManageDataConnectionsTable } from './components/manage_data_connections_table'; import { AccelerationIndices } from './components/acceleration_ui/acceleration_indices'; +import { NewDatasource } from './components/new_datasource'; +import { Configure } from './components/configure_datasource'; export interface HomeProps extends RouteComponentProps { pplService: any; @@ -45,6 +47,15 @@ export const Home = (props: HomeProps) => { path={['/', '/manage']} render={(routerProps) => } /> + } /> + + ( + + )} + /> \ No newline at end of file From ad153edbe3de01c5d439500214ed24d7236d747e Mon Sep 17 00:00:00 2001 From: Shenoy Pratik Date: Fri, 22 Sep 2023 12:41:04 -0700 Subject: [PATCH 08/22] remove acceleration components Signed-off-by: Shenoy Pratik --- common/constants/data_connections.ts | 3 - .../acceleration_ui/acceleration_header.tsx | 37 ------ .../acceleration_ui/acceleration_home.tsx | 23 ---- .../acceleration_ui/acceleration_indices.tsx | 39 ------ .../management/acceleration_management.tsx | 50 -------- .../management/management_table.tsx | 115 ------------------ .../management/source_selector.tsx | 88 -------------- .../components/data_connection.tsx | 2 +- public/components/data_connections/home.tsx | 8 -- 9 files changed, 1 insertion(+), 364 deletions(-) delete mode 100644 public/components/data_connections/components/acceleration_ui/acceleration_header.tsx delete mode 100644 public/components/data_connections/components/acceleration_ui/acceleration_home.tsx delete mode 100644 public/components/data_connections/components/acceleration_ui/acceleration_indices.tsx delete mode 100644 public/components/data_connections/components/acceleration_ui/management/acceleration_management.tsx delete mode 100644 public/components/data_connections/components/acceleration_ui/management/management_table.tsx delete mode 100644 public/components/data_connections/components/acceleration_ui/management/source_selector.tsx diff --git a/common/constants/data_connections.ts b/common/constants/data_connections.ts index 2c06e935e..3e56f6ec3 100644 --- a/common/constants/data_connections.ts +++ b/common/constants/data_connections.ts @@ -6,8 +6,5 @@ export const OPENSEARCH_DOCUMENTATION_URL = 'https://opensearch.org/docs/latest/data-connections/index'; -export const OPENSEARCH_ACC_DOCUMENTATION_URL = - 'https://opensearch.org/docs/latest/data-acceleration/index'; - export const QUERY_RESTRICTED = 'query-restricted'; export const QUERY_ALL = 'query-all'; diff --git a/public/components/data_connections/components/acceleration_ui/acceleration_header.tsx b/public/components/data_connections/components/acceleration_ui/acceleration_header.tsx deleted file mode 100644 index 548b45059..000000000 --- a/public/components/data_connections/components/acceleration_ui/acceleration_header.tsx +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright OpenSearch Contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import { - EuiLink, - EuiPageHeader, - EuiPageHeaderSection, - EuiSpacer, - EuiText, - EuiTitle, -} from '@elastic/eui'; -import React from 'react'; -import { OPENSEARCH_ACC_DOCUMENTATION_URL } from '../../../../../common/constants/data_connections'; - -export const AccelerationHeader = () => { - return ( -
- - - -

Acceleration Indices

-
-
-
- - - Manage acceleration indices from external data connections.{' '} - - Learn more - - - -
- ); -}; diff --git a/public/components/data_connections/components/acceleration_ui/acceleration_home.tsx b/public/components/data_connections/components/acceleration_ui/acceleration_home.tsx deleted file mode 100644 index f1565d820..000000000 --- a/public/components/data_connections/components/acceleration_ui/acceleration_home.tsx +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Copyright OpenSearch Contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import React from 'react'; -import { HashRouter, Route, Switch } from 'react-router-dom'; -import { AccelerationIndices } from './acceleration_indices'; - -export const AccelerationHome = () => { - return ( - - - ( - - )} - /> - - - ); -}; diff --git a/public/components/data_connections/components/acceleration_ui/acceleration_indices.tsx b/public/components/data_connections/components/acceleration_ui/acceleration_indices.tsx deleted file mode 100644 index 03520416d..000000000 --- a/public/components/data_connections/components/acceleration_ui/acceleration_indices.tsx +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright OpenSearch Contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import React, { useEffect } from 'react'; -import { EuiPage, EuiPageBody, EuiPageContent } from '@elastic/eui'; -import { coreRefs } from '../../../../framework/core_refs'; -import { AccelerationHeader } from './acceleration_header'; -import { AccelerationManagement } from './management/acceleration_management'; - -interface AccelerationIndicesProps { - dataConnection: string; -} - -export const AccelerationIndices = ({ dataConnection }: AccelerationIndicesProps) => { - useEffect(() => { - coreRefs.chrome?.setBreadcrumbs([ - { - text: 'Data Connections', - href: '#/', - }, - { - text: 'Acceleration', - href: '#/manage/acceleration/' + { dataConnection }, - }, - ]); - }, [dataConnection]); - return ( - - - - - - - - - ); -}; diff --git a/public/components/data_connections/components/acceleration_ui/management/acceleration_management.tsx b/public/components/data_connections/components/acceleration_ui/management/acceleration_management.tsx deleted file mode 100644 index 7a8236600..000000000 --- a/public/components/data_connections/components/acceleration_ui/management/acceleration_management.tsx +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright OpenSearch Contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import React from 'react'; -import { - EuiButton, - EuiFlexGroup, - EuiFlexItem, - EuiHorizontalRule, - EuiSpacer, - EuiText, -} from '@elastic/eui'; -import { ManagementTable } from './management_table'; -import { AccelerationDataSourceSelector } from './source_selector'; - -export const AccelerationManagement = () => { - return ( - <> - - - - -

Manage existing acceleration indices

-
- - - View and Edit acceleration indices{' '} - -
- - - - - Delete - - - - Accelerate Table - - - - -
- - - - ); -}; diff --git a/public/components/data_connections/components/acceleration_ui/management/management_table.tsx b/public/components/data_connections/components/acceleration_ui/management/management_table.tsx deleted file mode 100644 index 6c40230a4..000000000 --- a/public/components/data_connections/components/acceleration_ui/management/management_table.tsx +++ /dev/null @@ -1,115 +0,0 @@ -/* - * Copyright OpenSearch Contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import React, { useEffect, useState } from 'react'; -import { - EuiIcon, - EuiInMemoryTable, - EuiSpacer, - EuiTableFieldDataColumnType, - EuiText, -} from '@elastic/eui'; -import _ from 'lodash'; - -interface AccelerationIndicesRecordType { - indexName: string; - accelerationType: string; -} - -export const ManagementTable = () => { - const [accelerationIndicesRecords, setAccelerationIndicesRecords] = useState< - AccelerationIndicesRecordType[] - >([]); - - useEffect(() => { - setAccelerationIndicesRecords([ - { - indexName: 'Sample-skipping-index', - accelerationType: 'Skipping Index', - }, - { - indexName: 'Sample-covering-index', - accelerationType: 'covering Index', - }, - { - indexName: 'Sample-materialized-view', - accelerationType: 'Materialized View', - }, - ]); - }, []); - - const tableColumns: Array> = [ - { - field: 'indexName', - name: 'Index Name', - sortable: true, - truncateText: true, - render: (value, record: AccelerationIndicesRecordType) => ( - {_.truncate(record.indexName, { length: 100 })} - ), - }, - { - field: 'accelerationType', - name: 'Acceleration type', - sortable: true, - truncateText: true, - render: (value, record) => ( - {_.truncate(record.accelerationType, { length: 100 })} - ), - }, - { - field: 'actions', - name: 'Actions', - sortable: true, - truncateText: true, - render: (value, record) => ( - { - /* Delete Datasource*/ - }} - /> - ), - }, - ]; - - const search = { - box: { - incremental: true, - }, - filters: [ - { - type: 'field_value_selection', - field: 'accelerationType', - name: 'Type', - multiSelect: 'or', - options: accelerationIndicesRecords.map((AccelerationIndexRecord) => ({ - value: AccelerationIndexRecord.accelerationType, - name: AccelerationIndexRecord.accelerationType, - view: AccelerationIndexRecord.accelerationType, - })), - }, - ], - }; - - return ( - <> - - - - ); -}; diff --git a/public/components/data_connections/components/acceleration_ui/management/source_selector.tsx b/public/components/data_connections/components/acceleration_ui/management/source_selector.tsx deleted file mode 100644 index fddb537c1..000000000 --- a/public/components/data_connections/components/acceleration_ui/management/source_selector.tsx +++ /dev/null @@ -1,88 +0,0 @@ -/* - * Copyright OpenSearch Contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import { EuiComboBox, EuiFormRow, EuiSpacer, EuiText } from '@elastic/eui'; -import React, { useState } from 'react'; -import { useEffect } from 'react'; - -interface DataSourceTypes { - label: string; -} - -export const AccelerationDataSourceSelector = () => { - const [dataConnections, setDataConnections] = useState([]); - const [selectedDataConnection, setSelectedDataConnection] = useState([]); - const [tables, setTables] = useState([]); - const [selectedTable, setSelectedTable] = useState([]); - - useEffect(() => { - setDataConnections([ - { - label: 'spark1', - }, - { - label: 'spark2', - }, - ]); - }, []); - - useEffect(() => { - setTables([ - { - label: 'Table1', - }, - { - label: 'Table1', - }, - ]); - }, [dataConnections]); - - const onChangeDataConnection = ( - dataConnectionOptions: React.SetStateAction - ) => { - setSelectedDataConnection(dataConnectionOptions); - }; - const onChangeTable = (tableOptions: React.SetStateAction) => { - setSelectedTable(tableOptions); - }; - - return ( - <> - -

Select data connection

-
- - - Select data connection where the data you want to accelerate resides.{' '} - - - - - - - - - - - ); -}; diff --git a/public/components/data_connections/components/data_connection.tsx b/public/components/data_connections/components/data_connection.tsx index 0529d8529..d4c87ef49 100644 --- a/public/components/data_connections/components/data_connection.tsx +++ b/public/components/data_connections/components/data_connection.tsx @@ -195,7 +195,7 @@ export const DataConnection = (props: any) => { icon={} title={'Accelerate performance'} description="Accelerate performance through OpenSearch indexing." - onClick={() => (window.location.hash = `/acceleration/${dataSource}`)} + onClick={() => {}} /> diff --git a/public/components/data_connections/home.tsx b/public/components/data_connections/home.tsx index 534a71815..29d5e83bd 100644 --- a/public/components/data_connections/home.tsx +++ b/public/components/data_connections/home.tsx @@ -8,7 +8,6 @@ import { HashRouter, Route, RouteComponentProps, Switch } from 'react-router-dom import { ChromeBreadcrumb, ChromeStart, HttpStart } from '../../../../../src/core/public'; import { DataConnection } from './components/data_connection'; import { ManageDataConnectionsTable } from './components/manage_data_connections_table'; -import { AccelerationIndices } from './components/acceleration_ui/acceleration_indices'; export interface HomeProps extends RouteComponentProps { pplService: any; @@ -45,13 +44,6 @@ export const Home = (props: HomeProps) => { path={['/', '/manage']} render={(routerProps) => } /> - - ( - - )} - /> ); From 93ad0dda60fd0155463c756bc711e4b42bd57634 Mon Sep 17 00:00:00 2001 From: Derek Ho Date: Fri, 22 Sep 2023 15:44:43 -0400 Subject: [PATCH 09/22] Update data connection to datasources in a few more places and update tests Signed-off-by: Derek Ho --- common/constants/shared.ts | 4 +- ...data_connections_description.test.tsx.snap | 4 +- ...anage_data_connections_table.test.tsx.snap | 40 +++++++++++++++++-- .../manage_data_connections_description.tsx | 4 +- 4 files changed, 42 insertions(+), 10 deletions(-) diff --git a/common/constants/shared.ts b/common/constants/shared.ts index f26a59820..b3a08da21 100644 --- a/common/constants/shared.ts +++ b/common/constants/shared.ts @@ -58,8 +58,8 @@ export const observabilityIntegrationsID = 'integrations'; export const observabilityIntegrationsTitle = 'Integrations'; export const observabilityIntegrationsPluginOrder = 9020; -export const observabilityDataConnectionsID = 'dataconnections'; -export const observabilityDataConnectionsTitle = 'Data Connections'; +export const observabilityDataConnectionsID = 'datasources'; +export const observabilityDataConnectionsTitle = 'Data Sources'; export const observabilityDataConnectionsPluginOrder = 9030; // Shared Constants diff --git a/public/components/data_connections/components/__tests__/__snapshots__/manage_data_connections_description.test.tsx.snap b/public/components/data_connections/components/__tests__/__snapshots__/manage_data_connections_description.test.tsx.snap index 2cc84b45b..10c1b2484 100644 --- a/public/components/data_connections/components/__tests__/__snapshots__/manage_data_connections_description.test.tsx.snap +++ b/public/components/data_connections/components/__tests__/__snapshots__/manage_data_connections_description.test.tsx.snap @@ -9,7 +9,7 @@ exports[`Manage Data Connections Description test Renders manage data connection

- Manage existing data connections + Manage existing data sources

- Manage already created data connections. + Manage already created data sources.
diff --git a/public/components/data_connections/components/__tests__/__snapshots__/manage_data_connections_table.test.tsx.snap b/public/components/data_connections/components/__tests__/__snapshots__/manage_data_connections_table.test.tsx.snap index 20c847340..6cd9a84f9 100644 --- a/public/components/data_connections/components/__tests__/__snapshots__/manage_data_connections_table.test.tsx.snap +++ b/public/components/data_connections/components/__tests__/__snapshots__/manage_data_connections_table.test.tsx.snap @@ -19,7 +19,7 @@ exports[`Manage Data Connections Table test Renders manage data connections tabl class="euiTitle euiTitle--large" data-test-subj="dataconnections-header" > - Data connections + Data sources
@@ -32,7 +32,7 @@ exports[`Manage Data Connections Table test Renders manage data connections tabl
- Connect and manage compatible OpenSearch and OpenSearch Dashboard data connections. + Connect and manage compatible OpenSearch and OpenSearch Dashboard data sources. +
+ + +
+
- Manage existing data connections + Manage existing data sources
- Manage already created data connections. + Manage already created data sources.

{ return (
-

Manage existing data connections

+

Manage existing data sources

- Manage already created data connections. + Manage already created data sources.
From 2bd8c2711e353b920da463e27b0a51bbbf1fc0f7 Mon Sep 17 00:00:00 2001 From: Derek Ho Date: Fri, 22 Sep 2023 16:08:27 -0400 Subject: [PATCH 10/22] Rename and re-organize in folders Signed-off-by: Derek Ho --- public/components/app.tsx | 2 +- .../components/new_datasource.tsx | 84 ------------------- .../data_connection.test.tsx.snap | 0 ...data_connections_description.test.tsx.snap | 0 ...anage_data_connections_table.test.tsx.snap | 0 .../__tests__/data_connection.test.tsx | 2 +- ...nage_data_connections_description.test.tsx | 2 +- .../manage_data_connections_table.test.tsx | 0 .../components/data_connections_header.tsx | 0 .../components/manage}/access_control_tab.tsx | 6 +- .../components/manage}/connection_details.tsx | 8 +- .../manage}/connection_management_callout.tsx | 0 .../components/manage}/data_connection.tsx | 8 +- .../manage_data_connections_description.tsx | 0 .../manage}/manage_data_connections_table.tsx | 4 +- .../components/manage}/query_permissions.tsx | 4 +- .../components/new}/configure_datasource.tsx | 31 +++++-- .../new}/connection_configuration.tsx | 0 .../components/new/new_datasource.tsx | 48 +++++++++++ .../new}/new_datasource_card_view.tsx | 6 +- .../new}/new_datasource_description.tsx | 0 .../components/no_access.tsx | 0 .../components/save_or_cancel.tsx | 0 .../home.tsx | 6 +- .../icons/apache_spark-icon.svg | 0 25 files changed, 96 insertions(+), 115 deletions(-) delete mode 100644 public/components/data_connections/components/new_datasource.tsx rename public/components/{data_connections => datasources}/components/__tests__/__snapshots__/data_connection.test.tsx.snap (100%) rename public/components/{data_connections => datasources}/components/__tests__/__snapshots__/manage_data_connections_description.test.tsx.snap (100%) rename public/components/{data_connections => datasources}/components/__tests__/__snapshots__/manage_data_connections_table.test.tsx.snap (100%) rename public/components/{data_connections => datasources}/components/__tests__/data_connection.test.tsx (94%) rename public/components/{data_connections => datasources}/components/__tests__/manage_data_connections_description.test.tsx (86%) rename public/components/{data_connections => datasources}/components/__tests__/manage_data_connections_table.test.tsx (100%) rename public/components/{data_connections => datasources}/components/data_connections_header.tsx (100%) rename public/components/{data_connections/components => datasources/components/manage}/access_control_tab.tsx (94%) rename public/components/{data_connections/components => datasources/components/manage}/connection_details.tsx (94%) rename public/components/{data_connections/components => datasources/components/manage}/connection_management_callout.tsx (100%) rename public/components/{data_connections/components => datasources/components/manage}/data_connection.tsx (96%) rename public/components/{data_connections/components => datasources/components/manage}/manage_data_connections_description.tsx (100%) rename public/components/{data_connections/components => datasources/components/manage}/manage_data_connections_table.tsx (96%) rename public/components/{data_connections/components => datasources/components/manage}/query_permissions.tsx (94%) rename public/components/{data_connections/components => datasources/components/new}/configure_datasource.tsx (71%) rename public/components/{data_connections/components => datasources/components/new}/connection_configuration.tsx (100%) create mode 100644 public/components/datasources/components/new/new_datasource.tsx rename public/components/{data_connections/components => datasources/components/new}/new_datasource_card_view.tsx (90%) rename public/components/{data_connections/components => datasources/components/new}/new_datasource_description.tsx (100%) rename public/components/{data_connections => datasources}/components/no_access.tsx (100%) rename public/components/{data_connections => datasources}/components/save_or_cancel.tsx (100%) rename public/components/{data_connections => datasources}/home.tsx (88%) rename public/components/{data_connections => datasources}/icons/apache_spark-icon.svg (100%) diff --git a/public/components/app.tsx b/public/components/app.tsx index 7ace523b4..805ebc2e0 100644 --- a/public/components/app.tsx +++ b/public/components/app.tsx @@ -19,7 +19,7 @@ import { EventAnalytics } from './event_analytics'; import { Home as MetricsHome } from './metrics/index'; import { Main as NotebooksHome } from './notebooks/components/main'; import { Home as TraceAnalyticsHome } from './trace_analytics/home'; -import { Home as DataConnectionsHome } from './data_connections/home'; +import { Home as DataConnectionsHome } from './datasources/home'; interface ObservabilityAppDeps { CoreStartProp: CoreStart; diff --git a/public/components/data_connections/components/new_datasource.tsx b/public/components/data_connections/components/new_datasource.tsx deleted file mode 100644 index 186749ba5..000000000 --- a/public/components/data_connections/components/new_datasource.tsx +++ /dev/null @@ -1,84 +0,0 @@ -/* - * Copyright OpenSearch Contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import { - EuiFieldSearch, - EuiFilterButton, - EuiFilterGroup, - EuiFilterSelectItem, - EuiFlexGroup, - EuiFlexItem, - EuiIcon, - EuiInMemoryTable, - EuiLink, - EuiOverlayMask, - EuiPage, - EuiPageBody, - EuiPageContent, - EuiPopover, - EuiPopoverTitle, - EuiTableFieldDataColumnType, -} from '@elastic/eui'; -import _ from 'lodash'; -import React, { useEffect, useState } from 'react'; -import { DataConnectionsHeader } from './data_connections_header'; -import { HomeProps } from '../home'; -import { DataConnectionsDescription } from './manage_data_connections_description'; -import { DATACONNECTIONS_BASE, INTEGRATIONS_BASE } from '../../../../common/constants/shared'; -import { useToast } from '../../../../public/components/common/toast'; -import { DeleteModal } from '../../../../public/components/common/helpers/delete_modal'; -import { AvailableIntegrationsList } from '../../../../public/components/integrations/components/available_integration_overview_page'; -import { IntegrationHeader } from '../../../../public/components/integrations/components/integration_header'; -import { AvailableIntegrationsCardView } from '../../../../public/components/integrations/components/available_integration_card_view'; -import { AvailableIntegrationsTable } from '../../../../public/components/integrations/components/available_integration_table'; -import { NewDatasourceCardView } from './new_datasource_card_view'; - -interface DataConnection { - connectionType: 'OPENSEARCH' | 'SPARK'; - name: string; -} - -export const NewDatasource = (props: HomeProps) => { - const { chrome, http } = props; - - const [query, setQuery] = useState(''); - const [isCardView, setCardView] = useState(true); - const [data, setData] = useState({ hits: [] }); - - const [isPopoverOpen, setIsPopoverOpen] = useState(false); - - const onButtonClick = () => { - setIsPopoverOpen(!isPopoverOpen); - }; - - const closePopover = () => { - setIsPopoverOpen(false); - }; - - const [items, setItems] = useState([] as Array<{ name: string; checked: boolean }>); - - useEffect(() => { - chrome.setBreadcrumbs([ - { - text: 'Data sources', - href: '#/', - }, - ]); - }, []); - - // TODO: implement table view - const NewDatasourceTableView = () => { - return null; - }; - - return ( - - - - {isCardView ? : } - - - ); -}; diff --git a/public/components/data_connections/components/__tests__/__snapshots__/data_connection.test.tsx.snap b/public/components/datasources/components/__tests__/__snapshots__/data_connection.test.tsx.snap similarity index 100% rename from public/components/data_connections/components/__tests__/__snapshots__/data_connection.test.tsx.snap rename to public/components/datasources/components/__tests__/__snapshots__/data_connection.test.tsx.snap diff --git a/public/components/data_connections/components/__tests__/__snapshots__/manage_data_connections_description.test.tsx.snap b/public/components/datasources/components/__tests__/__snapshots__/manage_data_connections_description.test.tsx.snap similarity index 100% rename from public/components/data_connections/components/__tests__/__snapshots__/manage_data_connections_description.test.tsx.snap rename to public/components/datasources/components/__tests__/__snapshots__/manage_data_connections_description.test.tsx.snap diff --git a/public/components/data_connections/components/__tests__/__snapshots__/manage_data_connections_table.test.tsx.snap b/public/components/datasources/components/__tests__/__snapshots__/manage_data_connections_table.test.tsx.snap similarity index 100% rename from public/components/data_connections/components/__tests__/__snapshots__/manage_data_connections_table.test.tsx.snap rename to public/components/datasources/components/__tests__/__snapshots__/manage_data_connections_table.test.tsx.snap diff --git a/public/components/data_connections/components/__tests__/data_connection.test.tsx b/public/components/datasources/components/__tests__/data_connection.test.tsx similarity index 94% rename from public/components/data_connections/components/__tests__/data_connection.test.tsx rename to public/components/datasources/components/__tests__/data_connection.test.tsx index 995719810..04c1278c2 100644 --- a/public/components/data_connections/components/__tests__/data_connection.test.tsx +++ b/public/components/datasources/components/__tests__/data_connection.test.tsx @@ -8,7 +8,7 @@ import Adapter from 'enzyme-adapter-react-16'; import { act } from '@testing-library/react'; import React from 'react'; import { describeDataConnection, mockRoleData } from '../../../../../test/datasources'; -import { DataConnection } from '../data_connection'; +import { DataConnection } from '../manage/data_connection'; import ReactDOM from 'react-dom'; jest.mock('../../../../../public/framework/core_refs', () => ({ diff --git a/public/components/data_connections/components/__tests__/manage_data_connections_description.test.tsx b/public/components/datasources/components/__tests__/manage_data_connections_description.test.tsx similarity index 86% rename from public/components/data_connections/components/__tests__/manage_data_connections_description.test.tsx rename to public/components/datasources/components/__tests__/manage_data_connections_description.test.tsx index 686230683..3bbfa820e 100644 --- a/public/components/data_connections/components/__tests__/manage_data_connections_description.test.tsx +++ b/public/components/datasources/components/__tests__/manage_data_connections_description.test.tsx @@ -7,7 +7,7 @@ import { configure, mount } from 'enzyme'; import Adapter from 'enzyme-adapter-react-16'; import { waitFor } from '@testing-library/react'; import React from 'react'; -import { DataConnectionsDescription } from '../manage_data_connections_description'; +import { DataConnectionsDescription } from '../manage/manage_data_connections_description'; describe('Manage Data Connections Description test', () => { configure({ adapter: new Adapter() }); diff --git a/public/components/data_connections/components/__tests__/manage_data_connections_table.test.tsx b/public/components/datasources/components/__tests__/manage_data_connections_table.test.tsx similarity index 100% rename from public/components/data_connections/components/__tests__/manage_data_connections_table.test.tsx rename to public/components/datasources/components/__tests__/manage_data_connections_table.test.tsx diff --git a/public/components/data_connections/components/data_connections_header.tsx b/public/components/datasources/components/data_connections_header.tsx similarity index 100% rename from public/components/data_connections/components/data_connections_header.tsx rename to public/components/datasources/components/data_connections_header.tsx diff --git a/public/components/data_connections/components/access_control_tab.tsx b/public/components/datasources/components/manage/access_control_tab.tsx similarity index 94% rename from public/components/data_connections/components/access_control_tab.tsx rename to public/components/datasources/components/manage/access_control_tab.tsx index 58fdffde3..3f588b23b 100644 --- a/public/components/data_connections/components/access_control_tab.tsx +++ b/public/components/datasources/components/manage/access_control_tab.tsx @@ -14,10 +14,10 @@ import { import React, { useEffect, useState } from 'react'; import { EuiPanel } from '@elastic/eui'; import { ConnectionManagementCallout } from './connection_management_callout'; -import { coreRefs } from '../../../../public/framework/core_refs'; +import { coreRefs } from '../../../../framework/core_refs'; import { QueryPermissionsConfiguration } from './query_permissions'; -import { DATACONNECTIONS_BASE } from '../../../../common/constants/shared'; -import { SaveOrCancel } from './save_or_cancel'; +import { DATACONNECTIONS_BASE } from '../../../../../common/constants/shared'; +import { SaveOrCancel } from '../save_or_cancel'; interface AccessControlTabProps { dataConnection: string; diff --git a/public/components/data_connections/components/connection_details.tsx b/public/components/datasources/components/manage/connection_details.tsx similarity index 94% rename from public/components/data_connections/components/connection_details.tsx rename to public/components/datasources/components/manage/connection_details.tsx index 44cd206f4..0ad4eb1b5 100644 --- a/public/components/data_connections/components/connection_details.tsx +++ b/public/components/datasources/components/manage/connection_details.tsx @@ -14,10 +14,10 @@ import { import React, { useState } from 'react'; import { EuiPanel } from '@elastic/eui'; import { ConnectionManagementCallout } from './connection_management_callout'; -import { coreRefs } from '../../../../public/framework/core_refs'; -import { DATACONNECTIONS_BASE } from '../../../../common/constants/shared'; -import { SaveOrCancel } from './save_or_cancel'; -import { ConnectionConfiguration } from './connection_configuration'; +import { coreRefs } from '../../../../framework/core_refs'; +import { DATACONNECTIONS_BASE } from '../../../../../common/constants/shared'; +import { SaveOrCancel } from '../save_or_cancel'; +import { ConnectionConfiguration } from '../new/connection_configuration'; interface ConnectionDetailProps { dataConnection: string; diff --git a/public/components/data_connections/components/connection_management_callout.tsx b/public/components/datasources/components/manage/connection_management_callout.tsx similarity index 100% rename from public/components/data_connections/components/connection_management_callout.tsx rename to public/components/datasources/components/manage/connection_management_callout.tsx diff --git a/public/components/data_connections/components/data_connection.tsx b/public/components/datasources/components/manage/data_connection.tsx similarity index 96% rename from public/components/data_connections/components/data_connection.tsx rename to public/components/datasources/components/manage/data_connection.tsx index d4c87ef49..c8cf014ac 100644 --- a/public/components/data_connections/components/data_connection.tsx +++ b/public/components/datasources/components/manage/data_connection.tsx @@ -21,9 +21,9 @@ import { } from '@elastic/eui'; import React, { useEffect, useState } from 'react'; import { AccessControlTab } from './access_control_tab'; -import { NoAccess } from './no_access'; -import { DATACONNECTIONS_BASE } from '../../../../common/constants/shared'; -import { coreRefs } from '../../../../public/framework/core_refs'; +import { NoAccess } from '../no_access'; +import { DATACONNECTIONS_BASE } from '../../../../../common/constants/shared'; +import { coreRefs } from '../../../../framework/core_refs'; import { ConnectionDetails } from './connection_details'; interface DatasourceDetails { @@ -49,7 +49,7 @@ export const DataConnection = (props: any) => { useEffect(() => { chrome!.setBreadcrumbs([ { - text: 'Data Connections', + text: 'Data sources', href: '#/', }, { diff --git a/public/components/data_connections/components/manage_data_connections_description.tsx b/public/components/datasources/components/manage/manage_data_connections_description.tsx similarity index 100% rename from public/components/data_connections/components/manage_data_connections_description.tsx rename to public/components/datasources/components/manage/manage_data_connections_description.tsx diff --git a/public/components/data_connections/components/manage_data_connections_table.tsx b/public/components/datasources/components/manage/manage_data_connections_table.tsx similarity index 96% rename from public/components/data_connections/components/manage_data_connections_table.tsx rename to public/components/datasources/components/manage/manage_data_connections_table.tsx index a1b241031..2ad6882ef 100644 --- a/public/components/data_connections/components/manage_data_connections_table.tsx +++ b/public/components/datasources/components/manage/manage_data_connections_table.tsx @@ -21,8 +21,8 @@ import { DataConnectionsHeader } from './data_connections_header'; import { HomeProps } from '../home'; import { DataConnectionsDescription } from './manage_data_connections_description'; import { DATACONNECTIONS_BASE } from '../../../../common/constants/shared'; -import { useToast } from '../../../../public/components/common/toast'; -import { DeleteModal } from '../../../../public/components/common/helpers/delete_modal'; +import { useToast } from '../../common/toast'; +import { DeleteModal } from '../../common/helpers/delete_modal'; interface DataConnection { connectionType: 'OPENSEARCH' | 'SPARK'; diff --git a/public/components/data_connections/components/query_permissions.tsx b/public/components/datasources/components/manage/query_permissions.tsx similarity index 94% rename from public/components/data_connections/components/query_permissions.tsx rename to public/components/datasources/components/manage/query_permissions.tsx index eee8312a8..25f43ffac 100644 --- a/public/components/data_connections/components/query_permissions.tsx +++ b/public/components/datasources/components/manage/query_permissions.tsx @@ -17,8 +17,8 @@ import { OPENSEARCH_DOCUMENTATION_URL, QUERY_ALL, QUERY_RESTRICTED, -} from '../../../../common/constants/data_connections'; -import { PermissionsConfigurationProps } from '../../../../common/types/data_connections'; +} from '../../../../../common/constants/data_connections'; +import { PermissionsConfigurationProps } from '../../../../../common/types/data_connections'; export const QueryPermissionsConfiguration = (props: PermissionsConfigurationProps) => { const { roles, selectedRoles, setSelectedRoles } = props; diff --git a/public/components/data_connections/components/configure_datasource.tsx b/public/components/datasources/components/new/configure_datasource.tsx similarity index 71% rename from public/components/data_connections/components/configure_datasource.tsx rename to public/components/datasources/components/new/configure_datasource.tsx index 3cd30dece..82ffe3532 100644 --- a/public/components/data_connections/components/configure_datasource.tsx +++ b/public/components/datasources/components/new/configure_datasource.tsx @@ -20,9 +20,10 @@ import { EuiFieldText, EuiBottomBar, EuiButtonEmpty, + EuiTextArea, } from '@elastic/eui'; -import React from 'react'; -import { OPENSEARCH_DOCUMENTATION_URL } from '../../../../common/constants/data_connections'; +import React, { useState } from 'react'; +import { OPENSEARCH_DOCUMENTATION_URL } from '../../../../../common/constants/data_connections'; interface ConfigureDatasourceProps { type: string; @@ -30,6 +31,9 @@ interface ConfigureDatasourceProps { export function Configure(props: ConfigureDatasourceProps) { const { type } = props; + + const [name, setName] = useState(''); + const [details, setDetails] = useState(''); const ConfigureDatasourceSteps = [ { title: 'Step 1', @@ -66,18 +70,33 @@ export function Configure(props: ConfigureDatasourceProps) { -

Connection Details

+

Data source details

- + - + + Description - optional + + Text that can help identify the data source or share additional details + + + + { + setDetails(e.target.value); + }} + /> + + - +
diff --git a/public/components/data_connections/components/connection_configuration.tsx b/public/components/datasources/components/new/connection_configuration.tsx similarity index 100% rename from public/components/data_connections/components/connection_configuration.tsx rename to public/components/datasources/components/new/connection_configuration.tsx diff --git a/public/components/datasources/components/new/new_datasource.tsx b/public/components/datasources/components/new/new_datasource.tsx new file mode 100644 index 000000000..c504a2c10 --- /dev/null +++ b/public/components/datasources/components/new/new_datasource.tsx @@ -0,0 +1,48 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { EuiPage, EuiPageBody } from '@elastic/eui'; +import _ from 'lodash'; +import React, { useEffect, useState } from 'react'; +import { DataConnectionsHeader } from '../data_connections_header'; +import { HomeProps } from '../../home'; +import { AvailableIntegrationsList } from '../../../integrations/components/available_integration_overview_page'; +import { NewDatasourceCardView } from './new_datasource_card_view'; + +interface DataConnection { + connectionType: 'OPENSEARCH' | 'SPARK'; + name: string; +} + +export const NewDatasource = (props: HomeProps) => { + const { chrome, http } = props; + + // TODO: implement searching the card view with this + const [query, setQuery] = useState(''); + const [isCardView, setCardView] = useState(true); + + useEffect(() => { + chrome.setBreadcrumbs([ + { + text: 'Data sources', + href: '#/', + }, + ]); + }, []); + + // TODO: implement table view + const NewDatasourceTableView = () => { + return null; + }; + + return ( + + + + {isCardView ? : } + + + ); +}; diff --git a/public/components/data_connections/components/new_datasource_card_view.tsx b/public/components/datasources/components/new/new_datasource_card_view.tsx similarity index 90% rename from public/components/data_connections/components/new_datasource_card_view.tsx rename to public/components/datasources/components/new/new_datasource_card_view.tsx index 0981b4d26..7526aca49 100644 --- a/public/components/data_connections/components/new_datasource_card_view.tsx +++ b/public/components/datasources/components/new/new_datasource_card_view.tsx @@ -15,11 +15,9 @@ import { } from '@elastic/eui'; import _ from 'lodash'; import React, { useState } from 'react'; -import { INTEGRATIONS_BASE } from '../../../../common/constants/shared'; import { NewDatasourceDescription } from './new_datasource_description'; -import { coreRefs } from '../../../../public/framework/core_refs'; -import { MANAGEMENT_APP_ID } from '../../../../../../src/plugins/management/public'; -import sparkSvg from '../icons/apache_spark-icon.svg'; +import { coreRefs } from '../../../../framework/core_refs'; +import sparkSvg from '../../icons/apache_spark-icon.svg'; export interface DatasourceType { name: string; diff --git a/public/components/data_connections/components/new_datasource_description.tsx b/public/components/datasources/components/new/new_datasource_description.tsx similarity index 100% rename from public/components/data_connections/components/new_datasource_description.tsx rename to public/components/datasources/components/new/new_datasource_description.tsx diff --git a/public/components/data_connections/components/no_access.tsx b/public/components/datasources/components/no_access.tsx similarity index 100% rename from public/components/data_connections/components/no_access.tsx rename to public/components/datasources/components/no_access.tsx diff --git a/public/components/data_connections/components/save_or_cancel.tsx b/public/components/datasources/components/save_or_cancel.tsx similarity index 100% rename from public/components/data_connections/components/save_or_cancel.tsx rename to public/components/datasources/components/save_or_cancel.tsx diff --git a/public/components/data_connections/home.tsx b/public/components/datasources/home.tsx similarity index 88% rename from public/components/data_connections/home.tsx rename to public/components/datasources/home.tsx index daa7aff6e..e66301627 100644 --- a/public/components/data_connections/home.tsx +++ b/public/components/datasources/home.tsx @@ -6,10 +6,10 @@ import React from 'react'; import { HashRouter, Route, RouteComponentProps, Switch } from 'react-router-dom'; import { ChromeBreadcrumb, ChromeStart, HttpStart } from '../../../../../src/core/public'; -import { DataConnection } from './components/data_connection'; +import { DataConnection } from './components/manage/data_connection'; import { ManageDataConnectionsTable } from './components/manage_data_connections_table'; -import { NewDatasource } from './components/new_datasource'; -import { Configure } from './components/configure_datasource'; +import { NewDatasource } from './components/new/new_datasource'; +import { Configure } from './components/new/configure_datasource'; export interface HomeProps extends RouteComponentProps { pplService: any; diff --git a/public/components/data_connections/icons/apache_spark-icon.svg b/public/components/datasources/icons/apache_spark-icon.svg similarity index 100% rename from public/components/data_connections/icons/apache_spark-icon.svg rename to public/components/datasources/icons/apache_spark-icon.svg From cc7b1a2e9ee6579d4428c7e43843cdcb16a6c255 Mon Sep 17 00:00:00 2001 From: Derek Ho Date: Fri, 22 Sep 2023 16:26:25 -0400 Subject: [PATCH 11/22] Fix import path in testing file Signed-off-by: Derek Ho --- common/constants/shared.ts | 2 +- .../__tests__/manage_data_connections_table.test.tsx | 2 +- .../{new => manage}/connection_configuration.tsx | 0 .../components/manage/connection_details.tsx | 2 +- .../manage/manage_data_connections_table.tsx | 10 +++++----- public/components/datasources/home.tsx | 2 +- 6 files changed, 9 insertions(+), 9 deletions(-) rename public/components/datasources/components/{new => manage}/connection_configuration.tsx (100%) diff --git a/common/constants/shared.ts b/common/constants/shared.ts index b3a08da21..9bda5d3be 100644 --- a/common/constants/shared.ts +++ b/common/constants/shared.ts @@ -59,7 +59,7 @@ export const observabilityIntegrationsTitle = 'Integrations'; export const observabilityIntegrationsPluginOrder = 9020; export const observabilityDataConnectionsID = 'datasources'; -export const observabilityDataConnectionsTitle = 'Data Sources'; +export const observabilityDataConnectionsTitle = 'Data sources'; export const observabilityDataConnectionsPluginOrder = 9030; // Shared Constants diff --git a/public/components/datasources/components/__tests__/manage_data_connections_table.test.tsx b/public/components/datasources/components/__tests__/manage_data_connections_table.test.tsx index cd5509f1b..dfdb65d85 100644 --- a/public/components/datasources/components/__tests__/manage_data_connections_table.test.tsx +++ b/public/components/datasources/components/__tests__/manage_data_connections_table.test.tsx @@ -7,7 +7,7 @@ import { configure } from 'enzyme'; import Adapter from 'enzyme-adapter-react-16'; import { act } from '@testing-library/react'; import React from 'react'; -import { ManageDataConnectionsTable } from '../manage_data_connections_table'; +import { ManageDataConnectionsTable } from '../manage/manage_data_connections_table'; import { showDataConnectionsData } from '../../../../../test/datasources'; import ReactDOM from 'react-dom'; diff --git a/public/components/datasources/components/new/connection_configuration.tsx b/public/components/datasources/components/manage/connection_configuration.tsx similarity index 100% rename from public/components/datasources/components/new/connection_configuration.tsx rename to public/components/datasources/components/manage/connection_configuration.tsx diff --git a/public/components/datasources/components/manage/connection_details.tsx b/public/components/datasources/components/manage/connection_details.tsx index 0ad4eb1b5..533071960 100644 --- a/public/components/datasources/components/manage/connection_details.tsx +++ b/public/components/datasources/components/manage/connection_details.tsx @@ -17,7 +17,7 @@ import { ConnectionManagementCallout } from './connection_management_callout'; import { coreRefs } from '../../../../framework/core_refs'; import { DATACONNECTIONS_BASE } from '../../../../../common/constants/shared'; import { SaveOrCancel } from '../save_or_cancel'; -import { ConnectionConfiguration } from '../new/connection_configuration'; +import { ConnectionConfiguration } from './connection_configuration'; interface ConnectionDetailProps { dataConnection: string; diff --git a/public/components/datasources/components/manage/manage_data_connections_table.tsx b/public/components/datasources/components/manage/manage_data_connections_table.tsx index 2ad6882ef..5f223ae03 100644 --- a/public/components/datasources/components/manage/manage_data_connections_table.tsx +++ b/public/components/datasources/components/manage/manage_data_connections_table.tsx @@ -17,12 +17,12 @@ import { } from '@elastic/eui'; import _ from 'lodash'; import React, { useEffect, useState } from 'react'; -import { DataConnectionsHeader } from './data_connections_header'; -import { HomeProps } from '../home'; +import { DataConnectionsHeader } from '../data_connections_header'; +import { HomeProps } from '../../home'; import { DataConnectionsDescription } from './manage_data_connections_description'; -import { DATACONNECTIONS_BASE } from '../../../../common/constants/shared'; -import { useToast } from '../../common/toast'; -import { DeleteModal } from '../../common/helpers/delete_modal'; +import { DATACONNECTIONS_BASE } from '../../../../../common/constants/shared'; +import { useToast } from '../../../common/toast'; +import { DeleteModal } from '../../../common/helpers/delete_modal'; interface DataConnection { connectionType: 'OPENSEARCH' | 'SPARK'; diff --git a/public/components/datasources/home.tsx b/public/components/datasources/home.tsx index e66301627..fef07a780 100644 --- a/public/components/datasources/home.tsx +++ b/public/components/datasources/home.tsx @@ -7,7 +7,7 @@ import React from 'react'; import { HashRouter, Route, RouteComponentProps, Switch } from 'react-router-dom'; import { ChromeBreadcrumb, ChromeStart, HttpStart } from '../../../../../src/core/public'; import { DataConnection } from './components/manage/data_connection'; -import { ManageDataConnectionsTable } from './components/manage_data_connections_table'; +import { ManageDataConnectionsTable } from './components/manage/manage_data_connections_table'; import { NewDatasource } from './components/new/new_datasource'; import { Configure } from './components/new/configure_datasource'; From ed8cfc1d69ab1814e41115ff1d652de7a6627494 Mon Sep 17 00:00:00 2001 From: Derek Ho Date: Mon, 25 Sep 2023 10:32:39 -0400 Subject: [PATCH 12/22] Get Initial S3 configuration working Signed-off-by: Derek Ho --- .../components/new/configure_datasource.tsx | 61 +++--------- .../new/configure_s3_datasource.tsx | 92 +++++++++++++++++++ .../new/new_datasource_card_view.tsx | 7 +- .../components/datasources/icons/s3-logo.svg | 7 ++ 4 files changed, 117 insertions(+), 50 deletions(-) create mode 100644 public/components/datasources/components/new/configure_s3_datasource.tsx create mode 100644 public/components/datasources/icons/s3-logo.svg diff --git a/public/components/datasources/components/new/configure_datasource.tsx b/public/components/datasources/components/new/configure_datasource.tsx index 82ffe3532..61cbf5f85 100644 --- a/public/components/datasources/components/new/configure_datasource.tsx +++ b/public/components/datasources/components/new/configure_datasource.tsx @@ -23,7 +23,7 @@ import { EuiTextArea, } from '@elastic/eui'; import React, { useState } from 'react'; -import { OPENSEARCH_DOCUMENTATION_URL } from '../../../../../common/constants/data_connections'; +import { ConfigureS3Datasource } from './configure_s3_datasource'; interface ConfigureDatasourceProps { type: string; @@ -55,52 +55,19 @@ export function Configure(props: ConfigureDatasourceProps) { const ConfigureDatasource = (configurationProps: { datasourceType: string }) => { const { datasourceType } = configurationProps; - return ( -
- - -

{`Configure ${datasourceType} Connection`}

-
- - - {`Connect to ${datasourceType} with OpenSearch and OpenSearch Dashboards `} - - Learn more - - - - -

Data source details

-
- - - - - - - Description - optional - - Text that can help identify the data source or share additional details - - - - { - setDetails(e.target.value); - }} - /> - - - - - - - -
-
- ); + switch (datasourceType) { + case 'S3': + return ( + + ); + default: + return <>; + } }; return ( diff --git a/public/components/datasources/components/new/configure_s3_datasource.tsx b/public/components/datasources/components/new/configure_s3_datasource.tsx new file mode 100644 index 000000000..11d6b7588 --- /dev/null +++ b/public/components/datasources/components/new/configure_s3_datasource.tsx @@ -0,0 +1,92 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { + EuiPanel, + EuiTitle, + EuiSpacer, + EuiText, + EuiLink, + EuiFormRow, + EuiFieldText, + EuiTextArea, +} from '@elastic/eui'; +import React, { useState } from 'react'; +import { OPENSEARCH_DOCUMENTATION_URL } from '../../../../../common/constants/data_connections'; + +interface ConfigureS3DatasourceProps { + currentName: string; + currentDetails: string; + setNameForRequest: React.Dispatch>; + setDetailsForRequest: React.Dispatch>; +} + +export const ConfigureS3Datasource = (props: ConfigureS3DatasourceProps) => { + const { setNameForRequest, setDetailsForRequest, currentName, currentDetails } = props; + + const [name, setName] = useState(currentName); + const [details, setDetails] = useState(currentDetails); + + return ( +
+ + +

{`Configure S3 Data Source`}

+
+ + + {`Connect to S3with OpenSearch and OpenSearch Dashboards `} + + Learn more + + + + +

Data source details

+
+ + + <> + +

+ This is the name the connection will be referenced by in OpenSearch Dashboards. It + is recommended to make this short yet descriptive to help users when selecting a + connection. +

+
+ { + setName(e.target.value); + }} + onBlur={(e) => { + setNameForRequest(e.target.value); + }} + /> + +
+ + { + setDetailsForRequest(e.target.value); + }} + onChange={(e) => { + setDetails(e.target.value); + }} + /> + + + + +

Glue authentication details

+
+
+
+ ); +}; diff --git a/public/components/datasources/components/new/new_datasource_card_view.tsx b/public/components/datasources/components/new/new_datasource_card_view.tsx index 7526aca49..727975a5c 100644 --- a/public/components/datasources/components/new/new_datasource_card_view.tsx +++ b/public/components/datasources/components/new/new_datasource_card_view.tsx @@ -18,6 +18,7 @@ import React, { useState } from 'react'; import { NewDatasourceDescription } from './new_datasource_description'; import { coreRefs } from '../../../../framework/core_refs'; import sparkSvg from '../../icons/apache_spark-icon.svg'; +import s3Svg from '../../icons/s3-logo.svg'; export interface DatasourceType { name: string; @@ -32,9 +33,9 @@ const Datasources: DatasourceType[] = [ displayIcon: , }, { - name: 'Spark', - description: 'Connect to a self managed instance of Apache Spark', - displayIcon: , + name: 'S3', + description: 'Connect to Amazon S3 via Amazon Glue', + displayIcon: , }, ]; diff --git a/public/components/datasources/icons/s3-logo.svg b/public/components/datasources/icons/s3-logo.svg new file mode 100644 index 000000000..39b0fc099 --- /dev/null +++ b/public/components/datasources/icons/s3-logo.svg @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file From 0b84fab3f00fe95a5b8efdacf523dc176f6072b2 Mon Sep 17 00:00:00 2001 From: Derek Ho Date: Mon, 25 Sep 2023 13:05:51 -0400 Subject: [PATCH 13/22] Configure S3 Data Source Working Signed-off-by: Derek Ho --- .../components/manage/access_control_tab.tsx | 9 +- .../components/manage/data_connection.tsx | 10 +- .../components/new/configure_datasource.tsx | 134 ++++++++++++++++-- .../new/configure_s3_datasource.tsx | 114 ++++++++++++++- .../review_s3_datasource_configuration.tsx | 103 ++++++++++++++ server/adaptors/ppl_plugin.ts | 8 ++ .../data_connections_router.ts | 37 +++++ 7 files changed, 395 insertions(+), 20 deletions(-) create mode 100644 public/components/datasources/components/new/review_s3_datasource_configuration.tsx diff --git a/public/components/datasources/components/manage/access_control_tab.tsx b/public/components/datasources/components/manage/access_control_tab.tsx index 3f588b23b..d35f3876f 100644 --- a/public/components/datasources/components/manage/access_control_tab.tsx +++ b/public/components/datasources/components/manage/access_control_tab.tsx @@ -23,6 +23,7 @@ interface AccessControlTabProps { dataConnection: string; connector: string; properties: unknown; + allowedRoles: string[]; } export const AccessControlTab = (props: AccessControlTabProps) => { @@ -30,7 +31,11 @@ export const AccessControlTab = (props: AccessControlTabProps) => { const [roles, setRoles] = useState>([]); const [selectedQueryPermissionRoles, setSelectedQueryPermissionRoles] = useState< Array<{ label: string }> - >([]); + >( + props.allowedRoles.map((role) => { + return { label: role }; + }) + ); const { http } = coreRefs; useEffect(() => { @@ -51,7 +56,7 @@ export const AccessControlTab = (props: AccessControlTabProps) => { Query access - {[].length ? `Restricted` : '-'} + {selectedQueryPermissionRoles.length ? `Restricted` : '-'} diff --git a/public/components/datasources/components/manage/data_connection.tsx b/public/components/datasources/components/manage/data_connection.tsx index c8cf014ac..a0527e7bc 100644 --- a/public/components/datasources/components/manage/data_connection.tsx +++ b/public/components/datasources/components/manage/data_connection.tsx @@ -59,15 +59,15 @@ export const DataConnection = (props: any) => { ]); http! .get(`${DATACONNECTIONS_BASE}/${dataSource}`) - .then((data) => + .then((data) => { setDatasourceDetails({ allowedRoles: data.allowedRoles, name: data.name, cluster: data.properties['emr.cluster'], connector: data.connector, properties: data.properties, - }) - ) + }); + }) .catch((err) => { setHasAccess(false); }); @@ -80,9 +80,11 @@ export const DataConnection = (props: any) => { disabled: false, content: ( ), }, @@ -200,7 +202,7 @@ export const DataConnection = (props: any) => { - + diff --git a/public/components/datasources/components/new/configure_datasource.tsx b/public/components/datasources/components/new/configure_datasource.tsx index 61cbf5f85..ed44498c8 100644 --- a/public/components/datasources/components/new/configure_datasource.tsx +++ b/public/components/datasources/components/new/configure_datasource.tsx @@ -22,8 +22,12 @@ import { EuiButtonEmpty, EuiTextArea, } from '@elastic/eui'; -import React, { useState } from 'react'; +import React, { useCallback, useEffect, useState } from 'react'; import { ConfigureS3Datasource } from './configure_s3_datasource'; +import { coreRefs } from '../../../../../public/framework/core_refs'; +import { DATACONNECTIONS_BASE } from '../../../../../common/constants/shared'; +import { ReviewS3Datasource } from './review_s3_datasource_configuration'; +import { useToast } from '../../../../../public/components/common/toast'; interface ConfigureDatasourceProps { type: string; @@ -31,9 +35,18 @@ interface ConfigureDatasourceProps { export function Configure(props: ConfigureDatasourceProps) { const { type } = props; + const { http } = coreRefs; + const { setToast } = useToast(); const [name, setName] = useState(''); const [details, setDetails] = useState(''); + const [arn, setArn] = useState(''); + const [store, setStore] = useState(''); + const [roles, setRoles] = useState>([]); + const [selectedQueryPermissionRoles, setSelectedQueryPermissionRoles] = useState< + Array<{ label: string }> + >([]); + const [page, setPage] = useState<'configure' | 'review'>('configure'); const ConfigureDatasourceSteps = [ { title: 'Step 1', @@ -53,6 +66,16 @@ export function Configure(props: ConfigureDatasourceProps) { }, ]; + useEffect(() => { + http!.get('/api/v1/configuration/roles').then((data) => + setRoles( + Object.keys(data.data).map((key) => { + return { label: key }; + }) + ) + ); + }, []); + const ConfigureDatasource = (configurationProps: { datasourceType: string }) => { const { datasourceType } = configurationProps; switch (datasourceType) { @@ -63,6 +86,13 @@ export function Configure(props: ConfigureDatasourceProps) { currentDetails={details} setNameForRequest={setName} setDetailsForRequest={setDetails} + currentArn={arn} + setArnForRequest={setArn} + currentStore={store} + setStoreForRequest={setStore} + roles={roles} + selectedQueryPermissionRoles={selectedQueryPermissionRoles} + setSelectedQueryPermissionRoles={setSelectedQueryPermissionRoles} /> ); default: @@ -70,34 +100,112 @@ export function Configure(props: ConfigureDatasourceProps) { } }; - return ( - - - - - - - + const ReviewDatasourceConfiguration = (configurationProps: { datasourceType: string }) => { + const { datasourceType } = configurationProps; + switch (datasourceType) { + case 'S3': + return ( + + ); + default: + return <>; + } + }; + const ReviewSaveOrCancel = useCallback(() => { + return ( - {}} color="ghost" size="s" iconType="cross"> + { + window.location.hash = '#/new'; + }} + color="ghost" + size="s" + iconType="cross" + > Cancel - {}} color="ghost" size="s" iconType="arrowLeft"> + setPage('configure') : () => {}} + color="ghost" + size="s" + iconType="arrowLeft" + > Previous - {}} size="s" iconType="arrowRight" fill> - Review Configuration + createDatasource() + : () => { + setPage('review'); + } + } + size="s" + iconType="arrowRight" + fill + > + {page === 'configure' ? `Review Configuration` : `Connect to ${type}`} + ); + }, [page]); + + const createDatasource = () => { + http! + .post(`${DATACONNECTIONS_BASE}`, { + body: JSON.stringify({ + name, + allowedRoles: selectedQueryPermissionRoles.map((role) => role.label), + connector: 's3glue', + properties: { + 'glue.auth.type': 'iam_role', + 'glue.auth.role_arn': arn, + 'glue.indexstore.opensearch.uri': store, + 'glue.indexstore.opensearch.auth': false, + 'glue.indexstore.opensearch.region': 'us-west-2', + }, + }), + }) + .then(() => { + setToast(`Data source ${name} created successfully!`); + window.location.hash = '#/manage'; + }) + .catch((err) => { + setToast(`Data source ${name} created successfully!`); + window.location.hash = '#/manage'; + }); + }; + + return ( + + + + + + {page === 'configure' ? ( + + ) : ( + + )} + + + + ); } diff --git a/public/components/datasources/components/new/configure_s3_datasource.tsx b/public/components/datasources/components/new/configure_s3_datasource.tsx index 11d6b7588..155d29d40 100644 --- a/public/components/datasources/components/new/configure_s3_datasource.tsx +++ b/public/components/datasources/components/new/configure_s3_datasource.tsx @@ -12,22 +12,45 @@ import { EuiFormRow, EuiFieldText, EuiTextArea, + EuiButton, } from '@elastic/eui'; import React, { useState } from 'react'; import { OPENSEARCH_DOCUMENTATION_URL } from '../../../../../common/constants/data_connections'; +import { QueryPermissionsConfiguration } from '../manage/query_permissions'; interface ConfigureS3DatasourceProps { + roles: Array<{ label: string }>; + selectedQueryPermissionRoles: Array<{ label: string }>; + setSelectedQueryPermissionRoles: React.Dispatch>>; currentName: string; currentDetails: string; + currentArn: string; + currentStore: string; + setStoreForRequest: React.Dispatch>; setNameForRequest: React.Dispatch>; setDetailsForRequest: React.Dispatch>; + setArnForRequest: React.Dispatch>; } export const ConfigureS3Datasource = (props: ConfigureS3DatasourceProps) => { - const { setNameForRequest, setDetailsForRequest, currentName, currentDetails } = props; + const { + setNameForRequest, + setDetailsForRequest, + setArnForRequest, + setStoreForRequest, + currentStore, + currentName, + currentDetails, + currentArn, + roles, + selectedQueryPermissionRoles, + setSelectedQueryPermissionRoles, + } = props; const [name, setName] = useState(currentName); const [details, setDetails] = useState(currentDetails); + const [arn, setArn] = useState(currentArn); + const [store, setStore] = useState(currentStore); return (
@@ -86,6 +109,95 @@ export const ConfigureS3Datasource = (props: ConfigureS3DatasourceProps) => {

Glue authentication details

+ + + + <> + +

+ This parameters provides the authentication type information required for execution + engine to connect to glue. +

+
+ + +
+ + + <> + +

This should be the IAM role ARN

+
+ { + setArn(e.target.value); + }} + onBlur={(e) => { + setArnForRequest(e.target.value); + }} + /> + +
+ + + + +

Glue index store details

+
+ + + + <> + +

+ This parameters provides the OpenSearch cluster host information for glue. This + OpenSearch instance is used for writing index data back. +

+
+ { + setStore(e.target.value); + }} + onBlur={(e) => { + setStoreForRequest(e.target.value); + }} + /> + +
+ + + <> + +

Lorem ipsum.

+
+ + +
+ + + <> + +

Lorem ipsum.

+
+ + +
+ + Test connection + + + +
); diff --git a/public/components/datasources/components/new/review_s3_datasource_configuration.tsx b/public/components/datasources/components/new/review_s3_datasource_configuration.tsx new file mode 100644 index 000000000..ede85f204 --- /dev/null +++ b/public/components/datasources/components/new/review_s3_datasource_configuration.tsx @@ -0,0 +1,103 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { + EuiPanel, + EuiTitle, + EuiSpacer, + EuiText, + EuiLink, + EuiFormRow, + EuiFieldText, + EuiTextArea, + EuiButton, + EuiFlexGroup, + EuiHorizontalRule, + EuiFlexItem, +} from '@elastic/eui'; +import React, { useState } from 'react'; +import { OPENSEARCH_DOCUMENTATION_URL } from '../../../../../common/constants/data_connections'; +import { QueryPermissionsConfiguration } from '../manage/query_permissions'; + +interface ConfigureS3DatasourceProps { + selectedQueryPermissionRoles: Array<{ label: string }>; + currentName: string; + currentDetails: string; + currentArn: string; + currentStore: string; +} + +export const ReviewS3Datasource = (props: ConfigureS3DatasourceProps) => { + const { + currentStore, + currentName, + currentDetails, + currentArn, + selectedQueryPermissionRoles, + } = props; + + return ( +
+ + +

{`Review S3 Data Source Configuration`}

+
+ + + +

Data source configuration

+
+ + + + + + + Data source name + + {currentName} + + + + Description + + {currentDetails} + + + + + + + + Glue authentication ARN + + {currentArn} + + + + Glue index store URI + + {currentStore} + + + + + + + + Query Permissions + + {selectedQueryPermissionRoles + ? `Restricted - ${JSON.stringify(selectedQueryPermissionRoles)}` + : 'Everyone'} + + + + + +
+
+ ); +}; diff --git a/server/adaptors/ppl_plugin.ts b/server/adaptors/ppl_plugin.ts index 563c43672..6007f913f 100644 --- a/server/adaptors/ppl_plugin.ts +++ b/server/adaptors/ppl_plugin.ts @@ -68,6 +68,14 @@ export const PPLPlugin = function (Client, config, components) { method: 'DELETE', }); + ppl.createDataSource = ca({ + url: { + fmt: `${OPENSEARCH_DATACONNECTIONS_API.DATACONNECTION}`, + }, + needBody: true, + method: 'POST', + }); + ppl.modifyDataConnection = ca({ url: { fmt: `${OPENSEARCH_DATACONNECTIONS_API.DATACONNECTION}`, diff --git a/server/routes/data_connections/data_connections_router.ts b/server/routes/data_connections/data_connections_router.ts index a65660ba4..2c996ddcc 100644 --- a/server/routes/data_connections/data_connections_router.ts +++ b/server/routes/data_connections/data_connections_router.ts @@ -103,6 +103,43 @@ export function registerDataConnectionsRoute(router: IRouter) { } ); + router.post( + { + path: `${DATACONNECTIONS_BASE}`, + validate: { + body: schema.object({ + name: schema.string(), + connector: schema.string(), + allowedRoles: schema.arrayOf(schema.string()), + properties: schema.any(), + }), + }, + }, + async (context, request, response): Promise => { + try { + const dataConnectionsresponse = await context.observability_plugin.observabilityClient + .asScoped(request) + .callAsCurrentUser('ppl.createDataSource', { + body: { + name: request.body.name, + connector: request.body.connector, + allowedRoles: request.body.allowedRoles, + properties: request.body.properties, + }, + }); + return response.ok({ + body: dataConnectionsresponse, + }); + } catch (error: any) { + console.error('Issue in creating data source:', error); + return response.custom({ + statusCode: error.statusCode || 500, + body: error.message, + }); + } + } + ); + router.get( { path: `${DATACONNECTIONS_BASE}`, From 6d8a98f79e222c5c809a0dbaf6e14094791d28b8 Mon Sep 17 00:00:00 2001 From: Derek Ho Date: Mon, 25 Sep 2023 13:40:55 -0400 Subject: [PATCH 14/22] Fix query permissions display Signed-off-by: Derek Ho --- .../new/review_s3_datasource_configuration.tsx | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/public/components/datasources/components/new/review_s3_datasource_configuration.tsx b/public/components/datasources/components/new/review_s3_datasource_configuration.tsx index ede85f204..bffe519ba 100644 --- a/public/components/datasources/components/new/review_s3_datasource_configuration.tsx +++ b/public/components/datasources/components/new/review_s3_datasource_configuration.tsx @@ -8,18 +8,11 @@ import { EuiTitle, EuiSpacer, EuiText, - EuiLink, - EuiFormRow, - EuiFieldText, - EuiTextArea, - EuiButton, EuiFlexGroup, EuiHorizontalRule, EuiFlexItem, } from '@elastic/eui'; -import React, { useState } from 'react'; -import { OPENSEARCH_DOCUMENTATION_URL } from '../../../../../common/constants/data_connections'; -import { QueryPermissionsConfiguration } from '../manage/query_permissions'; +import React from 'react'; interface ConfigureS3DatasourceProps { selectedQueryPermissionRoles: Array<{ label: string }>; @@ -90,7 +83,9 @@ export const ReviewS3Datasource = (props: ConfigureS3DatasourceProps) => { Query Permissions {selectedQueryPermissionRoles - ? `Restricted - ${JSON.stringify(selectedQueryPermissionRoles)}` + ? `Restricted - ${selectedQueryPermissionRoles + .map((role) => role.label) + .join(',')}` : 'Everyone'} From 7a3f085219d0afeab05e99543c51d7710d368be2 Mon Sep 17 00:00:00 2001 From: Derek Ho Date: Mon, 25 Sep 2023 14:17:31 -0400 Subject: [PATCH 15/22] Fix merge conflict Signed-off-by: Derek Ho --- .../data_connection.test.tsx.snap | 445 ------------- ...data_connections_description.test.tsx.snap | 50 -- ...anage_data_connections_table.test.tsx.snap | 610 ------------------ .../__tests__/data_connection.test.tsx | 38 -- ...nage_data_connections_description.test.tsx | 22 - .../manage_data_connections_table.test.tsx | 36 -- .../components/access_control_tab.tsx | 132 ---- .../components/connection_configuration.tsx | 139 ---- .../components/connection_details.tsx | 159 ----- .../connection_management_callout.tsx | 16 - .../components/data_connection.tsx | 209 ------ .../components/data_connections_header.tsx | 38 -- .../manage_data_connections_description.tsx | 23 - .../manage_data_connections_table.tsx | 189 ------ .../data_connections/components/no_access.tsx | 30 - .../components/query_permissions.tsx | 87 --- .../components/save_or_cancel.tsx | 32 - public/components/data_connections/home.tsx | 50 -- 18 files changed, 2305 deletions(-) delete mode 100644 public/components/data_connections/components/__tests__/__snapshots__/data_connection.test.tsx.snap delete mode 100644 public/components/data_connections/components/__tests__/__snapshots__/manage_data_connections_description.test.tsx.snap delete mode 100644 public/components/data_connections/components/__tests__/__snapshots__/manage_data_connections_table.test.tsx.snap delete mode 100644 public/components/data_connections/components/__tests__/data_connection.test.tsx delete mode 100644 public/components/data_connections/components/__tests__/manage_data_connections_description.test.tsx delete mode 100644 public/components/data_connections/components/__tests__/manage_data_connections_table.test.tsx delete mode 100644 public/components/data_connections/components/access_control_tab.tsx delete mode 100644 public/components/data_connections/components/connection_configuration.tsx delete mode 100644 public/components/data_connections/components/connection_details.tsx delete mode 100644 public/components/data_connections/components/connection_management_callout.tsx delete mode 100644 public/components/data_connections/components/data_connection.tsx delete mode 100644 public/components/data_connections/components/data_connections_header.tsx delete mode 100644 public/components/data_connections/components/manage_data_connections_description.tsx delete mode 100644 public/components/data_connections/components/manage_data_connections_table.tsx delete mode 100644 public/components/data_connections/components/no_access.tsx delete mode 100644 public/components/data_connections/components/query_permissions.tsx delete mode 100644 public/components/data_connections/components/save_or_cancel.tsx delete mode 100644 public/components/data_connections/home.tsx diff --git a/public/components/data_connections/components/__tests__/__snapshots__/data_connection.test.tsx.snap b/public/components/data_connections/components/__tests__/__snapshots__/data_connection.test.tsx.snap deleted file mode 100644 index a4c2f2572..000000000 --- a/public/components/data_connections/components/__tests__/__snapshots__/data_connection.test.tsx.snap +++ /dev/null @@ -1,445 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`Data Connection Page test Renders data connection page with data 1`] = ` -
-
-
-
-
-
-
-

-

-
-
-
-
-
-
-
-
-
- Connection title -
-
- my_spark3 -
-
-
-
- Authentication method -
-
- - -
-
-
-
-
-
-
-
- Data source description -
-
- - -
-
-
-
- Query permissions -
-
- Everyone -
-
-
-
-
-
-
-
- Spark data location -
-
- - -
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
- -
-
- - - -
-

- Query your data in Data Explorer or Observability Logs. -

-
-
-
-
-
-
-
- -
-
- - - -
-

- Accelerate performance through OpenSearch indexing. -

-
-
-
-
-
-
-
-
-
-
-
- - -
-
-
-
-
- - - Configurations may be managed elsewhere. - -
-
-
- Access to data can be managed in other systems outside of OpenSearch. Check with your administrator for additional configurations. -
-
-
-
-
-
-
-
-

- Access Control -

- Control which OpenSearch users have access to this data source. -
-
-
- -
-
-
-
-
-
-
-
- Query access -
-
- - -
-
-
-
-
-
-
-
-
-
-
-
-
-
-`; diff --git a/public/components/data_connections/components/__tests__/__snapshots__/manage_data_connections_description.test.tsx.snap b/public/components/data_connections/components/__tests__/__snapshots__/manage_data_connections_description.test.tsx.snap deleted file mode 100644 index 2cc84b45b..000000000 --- a/public/components/data_connections/components/__tests__/__snapshots__/manage_data_connections_description.test.tsx.snap +++ /dev/null @@ -1,50 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`Manage Data Connections Description test Renders manage data connections description 1`] = ` - -
- -

- Manage existing data connections -

-
- -
- - -
- -
- Manage already created data connections. -
-
-
-
- -
-
-
- -`; diff --git a/public/components/data_connections/components/__tests__/__snapshots__/manage_data_connections_table.test.tsx.snap b/public/components/data_connections/components/__tests__/__snapshots__/manage_data_connections_table.test.tsx.snap deleted file mode 100644 index 20c847340..000000000 --- a/public/components/data_connections/components/__tests__/__snapshots__/manage_data_connections_table.test.tsx.snap +++ /dev/null @@ -1,610 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`Manage Data Connections Table test Renders manage data connections table with data 1`] = ` -
-
-
-
-
-
-

- Data connections -

-
-
-
-
-
- Connect and manage compatible OpenSearch and OpenSearch Dashboard data connections. - - - Learn more - - -
-
-
-
-
-
-

- Manage existing data connections -

-
-
-
- Manage already created data connections. -
-
-
-
-
-
-
-
-
- -
- - - -
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
-
- - - - - - - - - - - - - - - - - - - - - - - - - -
-
- - - Name - - - - - - Actions - - -
-
- Name -
-
-
- -
-
-
- Actions -
-
- -
-
-
- Name -
-
-
- -
-
-
- Actions -
-
- -
-
-
- Name -
-
-
- -
-
-
- Actions -
-
- -
-
-
- Name -
-
-
- -
-
-
- Actions -
-
- -
-
-
-
-
-
-
-
-
- -
-
-
-
- -
-
-
-
-
-
-
-
-
-`; diff --git a/public/components/data_connections/components/__tests__/data_connection.test.tsx b/public/components/data_connections/components/__tests__/data_connection.test.tsx deleted file mode 100644 index 995719810..000000000 --- a/public/components/data_connections/components/__tests__/data_connection.test.tsx +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright OpenSearch Contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import { configure } from 'enzyme'; -import Adapter from 'enzyme-adapter-react-16'; -import { act } from '@testing-library/react'; -import React from 'react'; -import { describeDataConnection, mockRoleData } from '../../../../../test/datasources'; -import { DataConnection } from '../data_connection'; -import ReactDOM from 'react-dom'; - -jest.mock('../../../../../public/framework/core_refs', () => ({ - coreRefs: { - chrome: { - setBreadcrumbs: jest.fn(), - }, - http: { - get: jest.fn().mockResolvedValueOnce(mockRoleData).mockResolvedValue(describeDataConnection), - }, - }, -})); - -describe('Data Connection Page test', () => { - configure({ adapter: new Adapter() }); - - it('Renders data connection page with data', async () => { - const pplService = { - fetch: jest.fn(), - }; - const container = document.createElement('div'); - await act(() => { - ReactDOM.render(, container); - }); - expect(container).toMatchSnapshot(); - }); -}); diff --git a/public/components/data_connections/components/__tests__/manage_data_connections_description.test.tsx b/public/components/data_connections/components/__tests__/manage_data_connections_description.test.tsx deleted file mode 100644 index 686230683..000000000 --- a/public/components/data_connections/components/__tests__/manage_data_connections_description.test.tsx +++ /dev/null @@ -1,22 +0,0 @@ -/* - * Copyright OpenSearch Contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import { configure, mount } from 'enzyme'; -import Adapter from 'enzyme-adapter-react-16'; -import { waitFor } from '@testing-library/react'; -import React from 'react'; -import { DataConnectionsDescription } from '../manage_data_connections_description'; - -describe('Manage Data Connections Description test', () => { - configure({ adapter: new Adapter() }); - - it('Renders manage data connections description', async () => { - const wrapper = mount(); - - await waitFor(() => { - expect(wrapper).toMatchSnapshot(); - }); - }); -}); diff --git a/public/components/data_connections/components/__tests__/manage_data_connections_table.test.tsx b/public/components/data_connections/components/__tests__/manage_data_connections_table.test.tsx deleted file mode 100644 index cd5509f1b..000000000 --- a/public/components/data_connections/components/__tests__/manage_data_connections_table.test.tsx +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright OpenSearch Contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import { configure } from 'enzyme'; -import Adapter from 'enzyme-adapter-react-16'; -import { act } from '@testing-library/react'; -import React from 'react'; -import { ManageDataConnectionsTable } from '../manage_data_connections_table'; -import { showDataConnectionsData } from '../../../../../test/datasources'; -import ReactDOM from 'react-dom'; - -describe('Manage Data Connections Table test', () => { - configure({ adapter: new Adapter() }); - - it('Renders manage data connections table with data', async () => { - const http = { - get: jest.fn().mockResolvedValue(showDataConnectionsData), - }; - const pplService = { - fetch: jest.fn().mockResolvedValue(showDataConnectionsData), - }; - const mockChrome = { - setBreadcrumbs: jest.fn(), - }; - const container = document.createElement('div'); - await act(() => { - ReactDOM.render( - , - container - ); - }); - expect(container).toMatchSnapshot(); - }); -}); diff --git a/public/components/data_connections/components/access_control_tab.tsx b/public/components/data_connections/components/access_control_tab.tsx deleted file mode 100644 index 58fdffde3..000000000 --- a/public/components/data_connections/components/access_control_tab.tsx +++ /dev/null @@ -1,132 +0,0 @@ -/* - * Copyright OpenSearch Contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import { - EuiButton, - EuiFlexGroup, - EuiFlexItem, - EuiSpacer, - EuiText, - EuiHorizontalRule, -} from '@elastic/eui'; -import React, { useEffect, useState } from 'react'; -import { EuiPanel } from '@elastic/eui'; -import { ConnectionManagementCallout } from './connection_management_callout'; -import { coreRefs } from '../../../../public/framework/core_refs'; -import { QueryPermissionsConfiguration } from './query_permissions'; -import { DATACONNECTIONS_BASE } from '../../../../common/constants/shared'; -import { SaveOrCancel } from './save_or_cancel'; - -interface AccessControlTabProps { - dataConnection: string; - connector: string; - properties: unknown; -} - -export const AccessControlTab = (props: AccessControlTabProps) => { - const [mode, setMode] = useState<'view' | 'edit'>('view'); - const [roles, setRoles] = useState>([]); - const [selectedQueryPermissionRoles, setSelectedQueryPermissionRoles] = useState< - Array<{ label: string }> - >([]); - const { http } = coreRefs; - - useEffect(() => { - http!.get('/api/v1/configuration/roles').then((data) => - setRoles( - Object.keys(data.data).map((key) => { - return { label: key }; - }) - ) - ); - }, []); - - const AccessControlDetails = () => { - return ( - - - - - Query access - - {[].length ? `Restricted` : '-'} - - - - - - ); - }; - - const EditAccessControlDetails = () => { - return ( - - - - ); - }; - - const saveChanges = () => { - http!.put(`${DATACONNECTIONS_BASE}`, { - body: JSON.stringify({ - name: props.dataConnection, - allowedRoles: selectedQueryPermissionRoles.map((role) => role.label), - connector: props.connector, - properties: props.properties, - }), - }); - setMode('view'); - }; - - const AccessControlHeader = () => { - return ( - - - -

Access Control

- Control which OpenSearch users have access to this data source. -
-
- - - setMode(mode === 'view' ? 'edit' : 'view')} - fill={mode === 'view' ? true : false} - > - {mode === 'view' ? 'Edit' : 'Cancel'} - - -
- ); - }; - - return ( - <> - - - - - - - {mode === 'view' ? : } - - - {mode === 'edit' && ( - { - setMode('view'); - }} - onSave={saveChanges} - /> - )} - - - ); -}; diff --git a/public/components/data_connections/components/connection_configuration.tsx b/public/components/data_connections/components/connection_configuration.tsx deleted file mode 100644 index 8ce2bd7be..000000000 --- a/public/components/data_connections/components/connection_configuration.tsx +++ /dev/null @@ -1,139 +0,0 @@ -/* - * Copyright OpenSearch Contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import { - EuiFieldPassword, - EuiFieldText, - EuiFlexGroup, - EuiFlexItem, - EuiFormRow, - EuiSelect, - EuiSpacer, - EuiText, - EuiTextArea, -} from '@elastic/eui'; -import { EuiSelectOption } from '@elastic/eui/src/components/form/select'; -import React, { useState } from 'react'; - -interface ConnectionConfigurationProps { - connectionName: string; - connectionDetails: string; - onConnectionDetailsChange: (e: any) => void; - authenticationOptions: EuiSelectOption[]; - setSelectedAuthenticationMethod: (authenticationMethod: EuiSelectOption) => void; - selectedAuthenticationMethod: string; -} - -export const ConnectionConfiguration = (props: ConnectionConfigurationProps) => { - const { - connectionName, - connectionDetails, - onConnectionDetailsChange, - authenticationOptions, - selectedAuthenticationMethod, - setSelectedAuthenticationMethod, - } = props; - const [details, setDetails] = useState(connectionDetails); - - const [password, setPassword] = useState(''); - const [dual, setDual] = useState(true); - - const NameRow = () => { - return ( - - - Data source name - - This is the name of the data source and how it will be referenced in OpenSearch - Dashboards. - - - - - - - - - ); - }; - - const SparkEndpointRow = () => { - return ( - - - Spark endpoint URL - - { - "The URL for your Spark cluster and where your data is. This is what OpenSearch will connect to. The endpoint URL can't be changed. If you'd like to use another endpoint create a new data source." - } - - - - - - - - - ); - }; - - return ( - - - - - - Description - optional - - Text that can help identify the data source or share additional details - - - - - { - setDetails(e.target.value); - }} - onBlur={onConnectionDetailsChange} - /> - - - - - - - - - Authentication details - - This is information used to authenticate and create a data source with Spark. - - - - - setSelectedAuthenticationMethod(e)} - /> - - - - - - setPassword(e.target.value)} - /> - - - - - ); -}; diff --git a/public/components/data_connections/components/connection_details.tsx b/public/components/data_connections/components/connection_details.tsx deleted file mode 100644 index 44cd206f4..000000000 --- a/public/components/data_connections/components/connection_details.tsx +++ /dev/null @@ -1,159 +0,0 @@ -/* - * Copyright OpenSearch Contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import { - EuiButton, - EuiFlexGroup, - EuiFlexItem, - EuiSpacer, - EuiText, - EuiHorizontalRule, -} from '@elastic/eui'; -import React, { useState } from 'react'; -import { EuiPanel } from '@elastic/eui'; -import { ConnectionManagementCallout } from './connection_management_callout'; -import { coreRefs } from '../../../../public/framework/core_refs'; -import { DATACONNECTIONS_BASE } from '../../../../common/constants/shared'; -import { SaveOrCancel } from './save_or_cancel'; -import { ConnectionConfiguration } from './connection_configuration'; - -interface ConnectionDetailProps { - dataConnection: string; - connector: string; - allowedRoles: string[]; - properties: unknown; -} - -export const ConnectionDetails = (props: ConnectionDetailProps) => { - const [mode, setMode] = useState<'view' | 'edit'>('view'); - const { http } = coreRefs; - - const { dataConnection, connector, allowedRoles, properties } = props; - const [connectionDetails, setConnectionDetails] = useState(''); - const onChange = (e) => { - setConnectionDetails(e.target.value); - }; - const authenticationOptions = [{ value: 'option_one', text: 'Username & Password' }]; - - const [selectedAuthenticationMethod, setSelectedAuthenticationMethod] = useState( - authenticationOptions[0].value - ); - - const onAuthenticationMethodChange = (e) => { - setSelectedAuthenticationMethod(e.target.value); - }; - - const ConnectionConfigurationView = () => { - return ( - - - - - Data source name - - {dataConnection} - - - - Spark endpoint URL - - {'-'} - - - - - - - - Description - - {'-'} - - - - Authentication method - - {'-'} - - - - - - ); - }; - - const EditConnectionConfiguration = () => { - return ( - - - - ); - }; - - const saveChanges = () => { - http!.put(`${DATACONNECTIONS_BASE}`, { - body: JSON.stringify({ - name: props.dataConnection, - allowedRoles: props.allowedRoles, - connector: props.connector, - properties: props.properties, - }), - }); - setMode('view'); - }; - - const ConnectionConfigurationHeader = () => { - return ( - - - -

Data source configurations

- Control configurations for your data source. -
-
- - - setMode(mode === 'view' ? 'edit' : 'view')} - fill={mode === 'view' ? true : false} - > - {mode === 'view' ? 'Edit' : 'Cancel'} - - -
- ); - }; - - return ( - <> - - - - - - - {mode === 'view' ? : } - - - {mode === 'edit' && ( - { - setMode('view'); - }} - onSave={saveChanges} - /> - )} - - - ); -}; diff --git a/public/components/data_connections/components/connection_management_callout.tsx b/public/components/data_connections/components/connection_management_callout.tsx deleted file mode 100644 index b78872287..000000000 --- a/public/components/data_connections/components/connection_management_callout.tsx +++ /dev/null @@ -1,16 +0,0 @@ -/* - * Copyright OpenSearch Contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import { EuiCallOut } from '@elastic/eui'; -import React from 'react'; - -export const ConnectionManagementCallout = () => { - return ( - - Access to data can be managed in other systems outside of OpenSearch. Check with your - administrator for additional configurations. - - ); -}; diff --git a/public/components/data_connections/components/data_connection.tsx b/public/components/data_connections/components/data_connection.tsx deleted file mode 100644 index d4c87ef49..000000000 --- a/public/components/data_connections/components/data_connection.tsx +++ /dev/null @@ -1,209 +0,0 @@ -/* - * Copyright OpenSearch Contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import { - EuiFlexGroup, - EuiFlexItem, - EuiPage, - EuiPageBody, - EuiSpacer, - EuiTitle, - EuiText, - EuiPanel, - EuiPageHeader, - EuiPageHeaderSection, - EuiAccordion, - EuiIcon, - EuiCard, - EuiTabbedContent, -} from '@elastic/eui'; -import React, { useEffect, useState } from 'react'; -import { AccessControlTab } from './access_control_tab'; -import { NoAccess } from './no_access'; -import { DATACONNECTIONS_BASE } from '../../../../common/constants/shared'; -import { coreRefs } from '../../../../public/framework/core_refs'; -import { ConnectionDetails } from './connection_details'; - -interface DatasourceDetails { - allowedRoles: string[]; - name: string; - cluster: string; - connector: string; - properties: unknown; -} - -export const DataConnection = (props: any) => { - const { dataSource } = props; - const [datasourceDetails, setDatasourceDetails] = useState({ - allowedRoles: [], - name: '', - cluster: '', - connector: '', - properties: {}, - }); - const [hasAccess, setHasAccess] = useState(true); - const { http, chrome } = coreRefs; - - useEffect(() => { - chrome!.setBreadcrumbs([ - { - text: 'Data Connections', - href: '#/', - }, - { - text: `${dataSource}`, - href: `#/manage/${dataSource}`, - }, - ]); - http! - .get(`${DATACONNECTIONS_BASE}/${dataSource}`) - .then((data) => - setDatasourceDetails({ - allowedRoles: data.allowedRoles, - name: data.name, - cluster: data.properties['emr.cluster'], - connector: data.connector, - properties: data.properties, - }) - ) - .catch((err) => { - setHasAccess(false); - }); - }, [chrome, http]); - - const tabs = [ - { - id: 'access_control', - name: 'Access control', - disabled: false, - content: ( - - ), - }, - { - id: 'connection_configuration', - name: 'Connection configuration', - disabled: false, - content: ( - - ), - }, - ]; - - const DatasourceOverview = () => { - return ( - - - - - - Connection title - - {datasourceDetails.name || '-'} - - - - Authentication method - - {'-'} - - - - - - - - Data source description - - {'-'} - - - - Query permissions - - {datasourceDetails.allowedRoles && datasourceDetails.allowedRoles.length - ? 'Restricted' - : 'Everyone'} - - - - - - - - Spark data location - - {'-'} - - - - - - - - ); - }; - - if (!hasAccess) { - return ; - } - - return ( - - - - - - - -

{dataSource}

-
-
-
-
-
- - - - - - - } - title={'Query data'} - description="Query your data in Data Explorer or Observability Logs." - onClick={() => {}} - /> - - - } - title={'Accelerate performance'} - description="Accelerate performance through OpenSearch indexing." - onClick={() => {}} - /> - - - - - - -
-
- ); -}; diff --git a/public/components/data_connections/components/data_connections_header.tsx b/public/components/data_connections/components/data_connections_header.tsx deleted file mode 100644 index 7f071683b..000000000 --- a/public/components/data_connections/components/data_connections_header.tsx +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright OpenSearch Contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import { - EuiLink, - EuiPageHeader, - EuiPageHeaderSection, - EuiSpacer, - EuiText, - EuiTitle, -} from '@elastic/eui'; -import _ from 'lodash'; -import React from 'react'; -import { OPENSEARCH_DOCUMENTATION_URL } from '../../../../common/constants/data_connections'; - -export const DataConnectionsHeader = () => { - return ( -
- - - -

Data connections

-
-
-
- - - Connect and manage compatible OpenSearch and OpenSearch Dashboard data connections.{' '} - - Learn more - - - -
- ); -}; diff --git a/public/components/data_connections/components/manage_data_connections_description.tsx b/public/components/data_connections/components/manage_data_connections_description.tsx deleted file mode 100644 index 26cfa90cc..000000000 --- a/public/components/data_connections/components/manage_data_connections_description.tsx +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Copyright OpenSearch Contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import { EuiSpacer, EuiText, EuiTitle, EuiHorizontalRule } from '@elastic/eui'; -import React from 'react'; - -export const DataConnectionsDescription = () => { - return ( -
- -

Manage existing data connections

-
- - - - Manage already created data connections. - - -
- ); -}; diff --git a/public/components/data_connections/components/manage_data_connections_table.tsx b/public/components/data_connections/components/manage_data_connections_table.tsx deleted file mode 100644 index e1950e704..000000000 --- a/public/components/data_connections/components/manage_data_connections_table.tsx +++ /dev/null @@ -1,189 +0,0 @@ -/* - * Copyright OpenSearch Contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import { - EuiFlexGroup, - EuiFlexItem, - EuiIcon, - EuiInMemoryTable, - EuiLink, - EuiOverlayMask, - EuiPage, - EuiPageBody, - EuiPageContent, - EuiTableFieldDataColumnType, -} from '@elastic/eui'; -import _ from 'lodash'; -import React, { useEffect, useState } from 'react'; -import { DataConnectionsHeader } from './data_connections_header'; -import { HomeProps } from '../home'; -import { DataConnectionsDescription } from './manage_data_connections_description'; -import { DATACONNECTIONS_BASE } from '../../../../common/constants/shared'; -import { useToast } from '../../../../public/components/common/toast'; -import { DeleteModal } from '../../../../public/components/common/helpers/delete_modal'; - -interface DataConnection { - connectionType: 'OPENSEARCH' | 'SPARK'; - name: string; -} - -export const ManageDataConnectionsTable = (props: HomeProps) => { - const { http, chrome, pplService } = props; - - const { setToast } = useToast(); - - const [data, setData] = useState([]); - const [isModalVisible, setIsModalVisible] = useState(false); - const [modalLayout, setModalLayout] = useState(); - - const deleteConnection = (connectionName: string) => { - http! - .delete(`${DATACONNECTIONS_BASE}/${connectionName}`) - .then(() => { - setToast(`Data connection ${connectionName} deleted successfully`); - setData( - data.filter((connection) => { - return !(connection.name === connectionName); - }) - ); - }) - .catch((err) => { - setToast(`Data connection $${connectionName} not deleted. See output for more details.`); - }); - }; - - useEffect(() => { - chrome.setBreadcrumbs([ - { - text: 'Data Connections', - href: '#/', - }, - ]); - handleDataRequest(); - }, [chrome]); - - async function handleDataRequest() { - pplService!.fetch({ query: 'show datasources', format: 'jdbc' }).then((dataconnections) => - setData( - dataconnections.jsonData.map((x: any) => { - return { name: x.DATASOURCE_NAME, connectionType: x.CONNECTOR_TYPE }; - }) - ) - ); - } - - 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 icon = (record: DataConnection) => { - switch (record.connectionType) { - case 'OPENSEARCH': - return ; - default: - return <>; - } - }; - - const tableColumns = [ - { - field: 'name', - name: 'Name', - sortable: true, - truncateText: true, - render: (value, record: DataConnection) => ( - - {icon(record)} - - - {_.truncate(record.name, { length: 100 })} - - - - ), - }, - { - field: 'actions', - name: 'Actions', - sortable: true, - truncateText: true, - render: (value, record) => ( - { - displayDeleteModal(record.name); - }} - /> - ), - }, - ] as Array>; - - const search = { - box: { - incremental: true, - }, - filters: [ - { - type: 'field_value_selection', - field: 'templateName', - name: 'Type', - multiSelect: false, - options: [].map((i) => ({ - value: i, - name: i, - view: i, - })), - }, - ], - }; - - const entries = data.map((dataconnection: DataConnection) => { - const name = dataconnection.name; - const connectionType = dataconnection.connectionType; - return { connectionType, name, data: { name, connectionType } }; - }); - - return ( - - - - - - - - - {isModalVisible && modalLayout} - - - ); -}; diff --git a/public/components/data_connections/components/no_access.tsx b/public/components/data_connections/components/no_access.tsx deleted file mode 100644 index 1766f7fe1..000000000 --- a/public/components/data_connections/components/no_access.tsx +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright OpenSearch Contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import { EuiButton, EuiEmptyPrompt, EuiPage, EuiText } from '@elastic/eui'; -import React from 'react'; - -export const NoAccess = () => { - return ( - - {'No permissions to access'}} - body={ - - { - 'You are missing permissions to view connection details. Contact your administrator for permissions.' - } - - } - actions={ - (window.location.hash = '')}> - Return to data connections - - } - /> - - ); -}; diff --git a/public/components/data_connections/components/query_permissions.tsx b/public/components/data_connections/components/query_permissions.tsx deleted file mode 100644 index eee8312a8..000000000 --- a/public/components/data_connections/components/query_permissions.tsx +++ /dev/null @@ -1,87 +0,0 @@ -/* - * Copyright OpenSearch Contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import { - EuiComboBox, - EuiFlexGroup, - EuiFlexItem, - EuiLink, - EuiRadioGroup, - EuiSpacer, - EuiText, -} from '@elastic/eui'; -import React, { useState } from 'react'; -import { - OPENSEARCH_DOCUMENTATION_URL, - QUERY_ALL, - QUERY_RESTRICTED, -} from '../../../../common/constants/data_connections'; -import { PermissionsConfigurationProps } from '../../../../common/types/data_connections'; - -export const QueryPermissionsConfiguration = (props: PermissionsConfigurationProps) => { - const { roles, selectedRoles, setSelectedRoles } = props; - - const [selectedAccessLevel, setSelectedAccessLevel] = useState( - selectedRoles.length ? QUERY_RESTRICTED : QUERY_ALL - ); - const accessLevelOptions = [ - { - id: QUERY_RESTRICTED, - label: 'Restricted - accessible by users with specific OpenSearch roles', - }, - { - id: QUERY_ALL, - label: 'Everyone - accessible by all users on this cluster', - }, - ]; - - const ConfigureRoles = () => { - return ( -
- - OpenSearch Roles - - Select one or more OpenSearch roles that can query this data connection. - - -
- ); - }; - - return ( - - - - Query Permissions - - Control which OpenSearch roles have query permissions on this data source.{' '} - - Learn more - - - - - setSelectedAccessLevel(id)} - name="query-radio-group" - legend={{ - children: Access level, - }} - /> - {selectedAccessLevel === QUERY_RESTRICTED && } - - - - ); -}; diff --git a/public/components/data_connections/components/save_or_cancel.tsx b/public/components/data_connections/components/save_or_cancel.tsx deleted file mode 100644 index ccb966210..000000000 --- a/public/components/data_connections/components/save_or_cancel.tsx +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright OpenSearch Contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import { EuiBottomBar, EuiButton, EuiButtonEmpty, EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; -import React from 'react'; - -interface SaveOrCancelProps { - onSave: () => void; - onCancel: () => void; -} - -export const SaveOrCancel = (props: SaveOrCancelProps) => { - const { onSave, onCancel } = props; - return ( - - - - - Discard change(s) - - - - - Save - - - - - ); -}; diff --git a/public/components/data_connections/home.tsx b/public/components/data_connections/home.tsx deleted file mode 100644 index 29d5e83bd..000000000 --- a/public/components/data_connections/home.tsx +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright OpenSearch Contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import React from 'react'; -import { HashRouter, Route, RouteComponentProps, Switch } from 'react-router-dom'; -import { ChromeBreadcrumb, ChromeStart, HttpStart } from '../../../../../src/core/public'; -import { DataConnection } from './components/data_connection'; -import { ManageDataConnectionsTable } from './components/manage_data_connections_table'; - -export interface HomeProps extends RouteComponentProps { - pplService: any; - parentBreadcrumb: ChromeBreadcrumb; - http: HttpStart; - chrome: ChromeStart; -} - -export const Home = (props: HomeProps) => { - const { http, chrome, pplService } = props; - - const commonProps = { - http, - chrome, - pplService, - }; - - return ( - - - ( - - )} - /> - - } - /> - - - ); -}; From 1ffdfb0cb445684a9bc55942a1c516da987d6299 Mon Sep 17 00:00:00 2001 From: Derek Ho Date: Mon, 25 Sep 2023 14:42:45 -0400 Subject: [PATCH 16/22] Clean up PR Signed-off-by: Derek Ho --- .../datasources/components/data_connections_header.tsx | 1 - .../datasources/components/new/configure_datasource.tsx | 6 ------ .../datasources/components/new/new_datasource.tsx | 4 +--- .../datasources/components/new/new_datasource_card_view.tsx | 4 ---- public/components/datasources/icons/apache_spark-icon.svg | 1 - 5 files changed, 1 insertion(+), 15 deletions(-) delete mode 100644 public/components/datasources/icons/apache_spark-icon.svg diff --git a/public/components/datasources/components/data_connections_header.tsx b/public/components/datasources/components/data_connections_header.tsx index 85f204dd9..38f623f1a 100644 --- a/public/components/datasources/components/data_connections_header.tsx +++ b/public/components/datasources/components/data_connections_header.tsx @@ -13,7 +13,6 @@ import { EuiText, EuiTitle, } from '@elastic/eui'; -import _ from 'lodash'; import React, { useState } from 'react'; import { OPENSEARCH_DOCUMENTATION_URL } from '../../../../common/constants/data_connections'; diff --git a/public/components/datasources/components/new/configure_datasource.tsx b/public/components/datasources/components/new/configure_datasource.tsx index ed44498c8..fd7b01756 100644 --- a/public/components/datasources/components/new/configure_datasource.tsx +++ b/public/components/datasources/components/new/configure_datasource.tsx @@ -9,18 +9,12 @@ import { EuiPage, EuiPageBody, EuiSpacer, - EuiTitle, EuiText, - EuiLink, EuiButton, EuiSteps, EuiPageSideBar, - EuiPanel, - EuiFormRow, - EuiFieldText, EuiBottomBar, EuiButtonEmpty, - EuiTextArea, } from '@elastic/eui'; import React, { useCallback, useEffect, useState } from 'react'; import { ConfigureS3Datasource } from './configure_s3_datasource'; diff --git a/public/components/datasources/components/new/new_datasource.tsx b/public/components/datasources/components/new/new_datasource.tsx index c504a2c10..ab17c4a00 100644 --- a/public/components/datasources/components/new/new_datasource.tsx +++ b/public/components/datasources/components/new/new_datasource.tsx @@ -4,11 +4,9 @@ */ import { EuiPage, EuiPageBody } from '@elastic/eui'; -import _ from 'lodash'; import React, { useEffect, useState } from 'react'; import { DataConnectionsHeader } from '../data_connections_header'; import { HomeProps } from '../../home'; -import { AvailableIntegrationsList } from '../../../integrations/components/available_integration_overview_page'; import { NewDatasourceCardView } from './new_datasource_card_view'; interface DataConnection { @@ -17,7 +15,7 @@ interface DataConnection { } export const NewDatasource = (props: HomeProps) => { - const { chrome, http } = props; + const { chrome } = props; // TODO: implement searching the card view with this const [query, setQuery] = useState(''); diff --git a/public/components/datasources/components/new/new_datasource_card_view.tsx b/public/components/datasources/components/new/new_datasource_card_view.tsx index 727975a5c..e4e4291ed 100644 --- a/public/components/datasources/components/new/new_datasource_card_view.tsx +++ b/public/components/datasources/components/new/new_datasource_card_view.tsx @@ -13,11 +13,8 @@ import { EuiButtonGroup, EuiIcon, } from '@elastic/eui'; -import _ from 'lodash'; import React, { useState } from 'react'; import { NewDatasourceDescription } from './new_datasource_description'; -import { coreRefs } from '../../../../framework/core_refs'; -import sparkSvg from '../../icons/apache_spark-icon.svg'; import s3Svg from '../../icons/s3-logo.svg'; export interface DatasourceType { @@ -40,7 +37,6 @@ const Datasources: DatasourceType[] = [ ]; export function NewDatasourceCardView() { - const { http } = coreRefs; const [toggleIconIdSelected, setToggleIconIdSelected] = useState('1'); const toggleButtonsIcons = [ diff --git a/public/components/datasources/icons/apache_spark-icon.svg b/public/components/datasources/icons/apache_spark-icon.svg deleted file mode 100644 index 30ba2b182..000000000 --- a/public/components/datasources/icons/apache_spark-icon.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file From 7a333bfb9774cd1b926b1d75a7299845b6dbb876 Mon Sep 17 00:00:00 2001 From: Derek Ho Date: Mon, 25 Sep 2023 14:45:05 -0400 Subject: [PATCH 17/22] Add s3 logo in manage table Signed-off-by: Derek Ho --- .../components/manage/manage_data_connections_table.tsx | 5 +++-- .../components/datasources/components/new/new_datasource.tsx | 5 ----- 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/public/components/datasources/components/manage/manage_data_connections_table.tsx b/public/components/datasources/components/manage/manage_data_connections_table.tsx index 5f223ae03..5ee19f62c 100644 --- a/public/components/datasources/components/manage/manage_data_connections_table.tsx +++ b/public/components/datasources/components/manage/manage_data_connections_table.tsx @@ -23,9 +23,10 @@ import { DataConnectionsDescription } from './manage_data_connections_descriptio import { DATACONNECTIONS_BASE } from '../../../../../common/constants/shared'; import { useToast } from '../../../common/toast'; import { DeleteModal } from '../../../common/helpers/delete_modal'; +import S3Logo from '../../icons/s3-logo.svg'; interface DataConnection { - connectionType: 'OPENSEARCH' | 'SPARK'; + connectionType: 'OPENSEARCH' | 'SPARK' | 'S3'; name: string; } @@ -96,7 +97,7 @@ export const ManageDataConnectionsTable = (props: HomeProps) => { case 'OPENSEARCH': return ; default: - return <>; + return ; } }; diff --git a/public/components/datasources/components/new/new_datasource.tsx b/public/components/datasources/components/new/new_datasource.tsx index ab17c4a00..669d0705e 100644 --- a/public/components/datasources/components/new/new_datasource.tsx +++ b/public/components/datasources/components/new/new_datasource.tsx @@ -9,11 +9,6 @@ import { DataConnectionsHeader } from '../data_connections_header'; import { HomeProps } from '../../home'; import { NewDatasourceCardView } from './new_datasource_card_view'; -interface DataConnection { - connectionType: 'OPENSEARCH' | 'SPARK'; - name: string; -} - export const NewDatasource = (props: HomeProps) => { const { chrome } = props; From c5f1eaeed98aec1ae47d63b3dad3f31bb75d7562 Mon Sep 17 00:00:00 2001 From: Derek Ho Date: Mon, 25 Sep 2023 15:56:18 -0400 Subject: [PATCH 18/22] Fix up PR according to UX feedback Signed-off-by: Derek Ho --- common/types/data_connections.ts | 1 + ...anage_data_connections_table.test.tsx.snap | 32 ++++++++++++++++--- .../components/manage/access_control_tab.tsx | 1 + .../manage/manage_data_connections_table.tsx | 6 ++-- .../components/manage/query_permissions.tsx | 4 +-- .../components/new/configure_datasource.tsx | 21 ++++-------- .../new/configure_s3_datasource.tsx | 27 ++++++++++++---- .../review_s3_datasource_configuration.tsx | 18 ++++++++--- 8 files changed, 77 insertions(+), 33 deletions(-) diff --git a/common/types/data_connections.ts b/common/types/data_connections.ts index 9fd0527d9..f9701ec32 100644 --- a/common/types/data_connections.ts +++ b/common/types/data_connections.ts @@ -7,4 +7,5 @@ export interface PermissionsConfigurationProps { roles: Array<{ label: string }>; selectedRoles: Array<{ label: string }>; setSelectedRoles: React.Dispatch>>; + layout: 'horizontal' | 'vertical'; } diff --git a/public/components/datasources/components/__tests__/__snapshots__/manage_data_connections_table.test.tsx.snap b/public/components/datasources/components/__tests__/__snapshots__/manage_data_connections_table.test.tsx.snap index 6cd9a84f9..31554b3e4 100644 --- a/public/components/datasources/components/__tests__/__snapshots__/manage_data_connections_table.test.tsx.snap +++ b/public/components/datasources/components/__tests__/__snapshots__/manage_data_connections_table.test.tsx.snap @@ -294,7 +294,13 @@ exports[`Manage Data Connections Table test Renders manage data connections tabl >
+ > + +
@@ -353,7 +359,13 @@ exports[`Manage Data Connections Table test Renders manage data connections tabl >
+ > + +
@@ -412,7 +424,13 @@ exports[`Manage Data Connections Table test Renders manage data connections tabl >
+ > + +
@@ -471,7 +489,13 @@ exports[`Manage Data Connections Table test Renders manage data connections tabl >
+ > + +
diff --git a/public/components/datasources/components/manage/access_control_tab.tsx b/public/components/datasources/components/manage/access_control_tab.tsx index d35f3876f..cdcec0d2a 100644 --- a/public/components/datasources/components/manage/access_control_tab.tsx +++ b/public/components/datasources/components/manage/access_control_tab.tsx @@ -72,6 +72,7 @@ export const AccessControlTab = (props: AccessControlTabProps) => { roles={roles} selectedRoles={selectedQueryPermissionRoles} setSelectedRoles={setSelectedQueryPermissionRoles} + layout={'vertical'} /> ); diff --git a/public/components/datasources/components/manage/manage_data_connections_table.tsx b/public/components/datasources/components/manage/manage_data_connections_table.tsx index 5ee19f62c..76ea44429 100644 --- a/public/components/datasources/components/manage/manage_data_connections_table.tsx +++ b/public/components/datasources/components/manage/manage_data_connections_table.tsx @@ -26,7 +26,7 @@ import { DeleteModal } from '../../../common/helpers/delete_modal'; import S3Logo from '../../icons/s3-logo.svg'; interface DataConnection { - connectionType: 'OPENSEARCH' | 'SPARK' | 'S3'; + connectionType: 'OPENSEARCH' | 'SPARK' | 'S3GLUE'; name: string; } @@ -96,8 +96,10 @@ export const ManageDataConnectionsTable = (props: HomeProps) => { switch (record.connectionType) { case 'OPENSEARCH': return ; - default: + case 'S3GLUE': return ; + default: + return <>; } }; diff --git a/public/components/datasources/components/manage/query_permissions.tsx b/public/components/datasources/components/manage/query_permissions.tsx index 25f43ffac..92ae3ae95 100644 --- a/public/components/datasources/components/manage/query_permissions.tsx +++ b/public/components/datasources/components/manage/query_permissions.tsx @@ -21,7 +21,7 @@ import { import { PermissionsConfigurationProps } from '../../../../../common/types/data_connections'; export const QueryPermissionsConfiguration = (props: PermissionsConfigurationProps) => { - const { roles, selectedRoles, setSelectedRoles } = props; + const { roles, selectedRoles, setSelectedRoles, layout } = props; const [selectedAccessLevel, setSelectedAccessLevel] = useState( selectedRoles.length ? QUERY_RESTRICTED : QUERY_ALL @@ -59,7 +59,7 @@ export const QueryPermissionsConfiguration = (props: PermissionsConfigurationPro return ( - + Query Permissions diff --git a/public/components/datasources/components/new/configure_datasource.tsx b/public/components/datasources/components/new/configure_datasource.tsx index fd7b01756..35daec098 100644 --- a/public/components/datasources/components/new/configure_datasource.tsx +++ b/public/components/datasources/components/new/configure_datasource.tsx @@ -43,20 +43,12 @@ export function Configure(props: ConfigureDatasourceProps) { const [page, setPage] = useState<'configure' | 'review'>('configure'); const ConfigureDatasourceSteps = [ { - title: 'Step 1', - children: ( - -

Configure Connection

-
- ), + title: 'Configure Data Source', + children: null, }, { - title: 'Step 2', - children: ( - -

Review Configuration

-
- ), + title: 'Review Configuration', + children: null, }, ]; @@ -105,6 +97,7 @@ export function Configure(props: ConfigureDatasourceProps) { currentArn={arn} currentStore={store} selectedQueryPermissionRoles={selectedQueryPermissionRoles} + goBack={() => setPage('configure')} /> ); default: @@ -176,11 +169,11 @@ export function Configure(props: ConfigureDatasourceProps) { }), }) .then(() => { - setToast(`Data source ${name} created successfully!`); + setToast(`Data source ${name} created successfully!`, 'success'); window.location.hash = '#/manage'; }) .catch((err) => { - setToast(`Data source ${name} created successfully!`); + setToast(`Data source ${name} created successfully!`, 'success'); window.location.hash = '#/manage'; }); }; diff --git a/public/components/datasources/components/new/configure_s3_datasource.tsx b/public/components/datasources/components/new/configure_s3_datasource.tsx index 155d29d40..3bbe65902 100644 --- a/public/components/datasources/components/new/configure_s3_datasource.tsx +++ b/public/components/datasources/components/new/configure_s3_datasource.tsx @@ -13,6 +13,7 @@ import { EuiFieldText, EuiTextArea, EuiButton, + EuiSelect, } from '@elastic/eui'; import React, { useState } from 'react'; import { OPENSEARCH_DOCUMENTATION_URL } from '../../../../../common/constants/data_connections'; @@ -51,6 +52,12 @@ export const ConfigureS3Datasource = (props: ConfigureS3DatasourceProps) => { const [details, setDetails] = useState(currentDetails); const [arn, setArn] = useState(currentArn); const [store, setStore] = useState(currentStore); + const authOptions = [ + { value: 'option_one', text: 'No authentication' }, + { value: 'option_two', text: 'SIGV4' }, + { value: 'option_three', text: 'Basic Auth' }, + ]; + const [selectedAuthOption, setSelectedAuthOption] = useState(authOptions[0].value); return (
@@ -119,7 +126,7 @@ export const ConfigureS3Datasource = (props: ConfigureS3DatasourceProps) => { engine to connect to glue.

- + @@ -174,29 +181,35 @@ export const ConfigureS3Datasource = (props: ConfigureS3DatasourceProps) => { <> -

Lorem ipsum.

+

Authentication settings to access the index store.

- + { + setSelectedAuthOption(e.target.value); + }} + />
<> -

Lorem ipsum.

+

The region where the index store is.

- +
- Test connection -
diff --git a/public/components/datasources/components/new/review_s3_datasource_configuration.tsx b/public/components/datasources/components/new/review_s3_datasource_configuration.tsx index bffe519ba..1db77e48f 100644 --- a/public/components/datasources/components/new/review_s3_datasource_configuration.tsx +++ b/public/components/datasources/components/new/review_s3_datasource_configuration.tsx @@ -11,6 +11,7 @@ import { EuiFlexGroup, EuiHorizontalRule, EuiFlexItem, + EuiButton, } from '@elastic/eui'; import React from 'react'; @@ -20,6 +21,7 @@ interface ConfigureS3DatasourceProps { currentDetails: string; currentArn: string; currentStore: string; + goBack: () => void; } export const ReviewS3Datasource = (props: ConfigureS3DatasourceProps) => { @@ -29,6 +31,7 @@ export const ReviewS3Datasource = (props: ConfigureS3DatasourceProps) => { currentDetails, currentArn, selectedQueryPermissionRoles, + goBack, } = props; return ( @@ -39,9 +42,16 @@ export const ReviewS3Datasource = (props: ConfigureS3DatasourceProps) => { - -

Data source configuration

-
+ + + +

Data source configuration

+
+
+ + Edit + +
@@ -82,7 +92,7 @@ export const ReviewS3Datasource = (props: ConfigureS3DatasourceProps) => { Query Permissions - {selectedQueryPermissionRoles + {selectedQueryPermissionRoles && selectedQueryPermissionRoles.length ? `Restricted - ${selectedQueryPermissionRoles .map((role) => role.label) .join(',')}` From 23699bc4a7de3c49b8456cfd703debe74ab7b2bd Mon Sep 17 00:00:00 2001 From: Derek Ho Date: Mon, 25 Sep 2023 16:01:42 -0400 Subject: [PATCH 19/22] Remove successfully Signed-off-by: Derek Ho --- .../datasources/components/new/configure_datasource.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/public/components/datasources/components/new/configure_datasource.tsx b/public/components/datasources/components/new/configure_datasource.tsx index 35daec098..a752312e3 100644 --- a/public/components/datasources/components/new/configure_datasource.tsx +++ b/public/components/datasources/components/new/configure_datasource.tsx @@ -169,11 +169,11 @@ export function Configure(props: ConfigureDatasourceProps) { }), }) .then(() => { - setToast(`Data source ${name} created successfully!`, 'success'); + setToast(`Data source ${name} created`, 'success'); window.location.hash = '#/manage'; }) .catch((err) => { - setToast(`Data source ${name} created successfully!`, 'success'); + setToast(`Data source ${name} created`, 'success'); window.location.hash = '#/manage'; }); }; From 51bb5d4a6efb5768582df203b8166d6023c8b813 Mon Sep 17 00:00:00 2001 From: Derek Ho Date: Mon, 25 Sep 2023 16:38:18 -0400 Subject: [PATCH 20/22] Update test Signed-off-by: Derek Ho --- ...anage_data_connections_table.test.tsx.snap | 32 +++---------------- 1 file changed, 4 insertions(+), 28 deletions(-) diff --git a/public/components/datasources/components/__tests__/__snapshots__/manage_data_connections_table.test.tsx.snap b/public/components/datasources/components/__tests__/__snapshots__/manage_data_connections_table.test.tsx.snap index 31554b3e4..6cd9a84f9 100644 --- a/public/components/datasources/components/__tests__/__snapshots__/manage_data_connections_table.test.tsx.snap +++ b/public/components/datasources/components/__tests__/__snapshots__/manage_data_connections_table.test.tsx.snap @@ -294,13 +294,7 @@ exports[`Manage Data Connections Table test Renders manage data connections tabl >
- -
+ />
@@ -359,13 +353,7 @@ exports[`Manage Data Connections Table test Renders manage data connections tabl >
- -
+ />
@@ -424,13 +412,7 @@ exports[`Manage Data Connections Table test Renders manage data connections tabl >
- -
+ />
@@ -489,13 +471,7 @@ exports[`Manage Data Connections Table test Renders manage data connections tabl >
- -
+ />
From 680763b566a24a70d93f79214331182f495ed291 Mon Sep 17 00:00:00 2001 From: Derek Ho Date: Wed, 27 Sep 2023 11:35:23 -0400 Subject: [PATCH 21/22] Address PR comments Signed-off-by: Derek Ho --- common/types/data_connections.ts | 12 +++++-- .../components/data_connections_header.tsx | 31 ++++++++++--------- .../components/manage/access_control_tab.tsx | 7 ++--- .../manage/manage_data_connections_table.tsx | 5 ++- .../components/new/configure_datasource.tsx | 21 +++++-------- .../new/configure_s3_datasource.tsx | 7 +++-- .../new/new_datasource_card_view.tsx | 18 ++++++----- .../review_s3_datasource_configuration.tsx | 2 +- .../data_connections_router.ts | 2 +- 9 files changed, 54 insertions(+), 51 deletions(-) diff --git a/common/types/data_connections.ts b/common/types/data_connections.ts index f9701ec32..b19b1bb7d 100644 --- a/common/types/data_connections.ts +++ b/common/types/data_connections.ts @@ -3,9 +3,15 @@ * SPDX-License-Identifier: Apache-2.0 */ +import { EuiComboBoxOptionOption } from '@elastic/eui'; + export interface PermissionsConfigurationProps { - roles: Array<{ label: string }>; - selectedRoles: Array<{ label: string }>; - setSelectedRoles: React.Dispatch>>; + roles: Role[]; + selectedRoles: Role[]; + setSelectedRoles: React.Dispatch>; layout: 'horizontal' | 'vertical'; } + +export type Role = EuiComboBoxOptionOption; + +export type DatasourceType = 'SPARK' | 'S3GLUE' | 'OPENSEARCH'; diff --git a/public/components/datasources/components/data_connections_header.tsx b/public/components/datasources/components/data_connections_header.tsx index 38f623f1a..6f5c87092 100644 --- a/public/components/datasources/components/data_connections_header.tsx +++ b/public/components/datasources/components/data_connections_header.tsx @@ -14,25 +14,26 @@ import { EuiTitle, } from '@elastic/eui'; import React, { useState } from 'react'; +import { useLocation } from 'react-router-dom'; import { OPENSEARCH_DOCUMENTATION_URL } from '../../../../common/constants/data_connections'; +const tabs = [ + { + id: 'manage', + name: 'Manage data source', + disabled: false, + }, + { + id: 'new', + name: 'New data source', + disabled: false, + }, +]; + export const DataConnectionsHeader = () => { - const tabs = [ - { - id: 'manage', - name: 'Manage data source', - disabled: false, - }, - { - id: 'new', - name: 'New data source', - disabled: false, - }, - ]; + const location = useLocation().pathname.substring(1); - const [selectedTabId, setSelectedTabId] = useState( - window.location.hash.substring(2) ? window.location.hash.substring(2) : 'manage' - ); + const [selectedTabId, setSelectedTabId] = useState(location ? location : 'manage'); const onSelectedTabChanged = (id) => { setSelectedTabId(id); diff --git a/public/components/datasources/components/manage/access_control_tab.tsx b/public/components/datasources/components/manage/access_control_tab.tsx index cdcec0d2a..40e9e8ecd 100644 --- a/public/components/datasources/components/manage/access_control_tab.tsx +++ b/public/components/datasources/components/manage/access_control_tab.tsx @@ -18,6 +18,7 @@ import { coreRefs } from '../../../../framework/core_refs'; import { QueryPermissionsConfiguration } from './query_permissions'; import { DATACONNECTIONS_BASE } from '../../../../../common/constants/shared'; import { SaveOrCancel } from '../save_or_cancel'; +import { Role } from '../../../../../common/types/data_connections'; interface AccessControlTabProps { dataConnection: string; @@ -28,10 +29,8 @@ interface AccessControlTabProps { export const AccessControlTab = (props: AccessControlTabProps) => { const [mode, setMode] = useState<'view' | 'edit'>('view'); - const [roles, setRoles] = useState>([]); - const [selectedQueryPermissionRoles, setSelectedQueryPermissionRoles] = useState< - Array<{ label: string }> - >( + const [roles, setRoles] = useState([]); + const [selectedQueryPermissionRoles, setSelectedQueryPermissionRoles] = useState( props.allowedRoles.map((role) => { return { label: role }; }) diff --git a/public/components/datasources/components/manage/manage_data_connections_table.tsx b/public/components/datasources/components/manage/manage_data_connections_table.tsx index 76ea44429..d2009fb1f 100644 --- a/public/components/datasources/components/manage/manage_data_connections_table.tsx +++ b/public/components/datasources/components/manage/manage_data_connections_table.tsx @@ -24,9 +24,10 @@ import { DATACONNECTIONS_BASE } from '../../../../../common/constants/shared'; import { useToast } from '../../../common/toast'; import { DeleteModal } from '../../../common/helpers/delete_modal'; import S3Logo from '../../icons/s3-logo.svg'; +import { DatasourceType } from '../../../../../common/types/data_connections'; interface DataConnection { - connectionType: 'OPENSEARCH' | 'SPARK' | 'S3GLUE'; + connectionType: DatasourceType; name: string; } @@ -94,8 +95,6 @@ export const ManageDataConnectionsTable = (props: HomeProps) => { const icon = (record: DataConnection) => { switch (record.connectionType) { - case 'OPENSEARCH': - return ; case 'S3GLUE': return ; default: diff --git a/public/components/datasources/components/new/configure_datasource.tsx b/public/components/datasources/components/new/configure_datasource.tsx index a752312e3..004611d34 100644 --- a/public/components/datasources/components/new/configure_datasource.tsx +++ b/public/components/datasources/components/new/configure_datasource.tsx @@ -22,6 +22,7 @@ import { coreRefs } from '../../../../../public/framework/core_refs'; import { DATACONNECTIONS_BASE } from '../../../../../common/constants/shared'; import { ReviewS3Datasource } from './review_s3_datasource_configuration'; import { useToast } from '../../../../../public/components/common/toast'; +import { DatasourceType, Role } from '../../../../../common/types/data_connections'; interface ConfigureDatasourceProps { type: string; @@ -36,10 +37,8 @@ export function Configure(props: ConfigureDatasourceProps) { const [details, setDetails] = useState(''); const [arn, setArn] = useState(''); const [store, setStore] = useState(''); - const [roles, setRoles] = useState>([]); - const [selectedQueryPermissionRoles, setSelectedQueryPermissionRoles] = useState< - Array<{ label: string }> - >([]); + const [roles, setRoles] = useState([]); + const [selectedQueryPermissionRoles, setSelectedQueryPermissionRoles] = useState([]); const [page, setPage] = useState<'configure' | 'review'>('configure'); const ConfigureDatasourceSteps = [ { @@ -62,10 +61,10 @@ export function Configure(props: ConfigureDatasourceProps) { ); }, []); - const ConfigureDatasource = (configurationProps: { datasourceType: string }) => { + const ConfigureDatasource = (configurationProps: { datasourceType: DatasourceType }) => { const { datasourceType } = configurationProps; switch (datasourceType) { - case 'S3': + case 'S3GLUE': return ( setPage('configure') : () => {}} + onClick={() => (page === 'review' ? setPage('configure') : {})} color="ghost" size="s" iconType="arrowLeft" @@ -133,13 +132,7 @@ export function Configure(props: ConfigureDatasourceProps) { createDatasource() - : () => { - setPage('review'); - } - } + onClick={() => (page === 'review' ? createDatasource() : setPage('review'))} size="s" iconType="arrowRight" fill diff --git a/public/components/datasources/components/new/configure_s3_datasource.tsx b/public/components/datasources/components/new/configure_s3_datasource.tsx index 3bbe65902..803249aca 100644 --- a/public/components/datasources/components/new/configure_s3_datasource.tsx +++ b/public/components/datasources/components/new/configure_s3_datasource.tsx @@ -18,11 +18,12 @@ import { import React, { useState } from 'react'; import { OPENSEARCH_DOCUMENTATION_URL } from '../../../../../common/constants/data_connections'; import { QueryPermissionsConfiguration } from '../manage/query_permissions'; +import { Role } from '../../../../../common/types/data_connections'; interface ConfigureS3DatasourceProps { - roles: Array<{ label: string }>; - selectedQueryPermissionRoles: Array<{ label: string }>; - setSelectedQueryPermissionRoles: React.Dispatch>>; + roles: Role[]; + selectedQueryPermissionRoles: Role[]; + setSelectedQueryPermissionRoles: React.Dispatch>; currentName: string; currentDetails: string; currentArn: string; diff --git a/public/components/datasources/components/new/new_datasource_card_view.tsx b/public/components/datasources/components/new/new_datasource_card_view.tsx index e4e4291ed..04ede43aa 100644 --- a/public/components/datasources/components/new/new_datasource_card_view.tsx +++ b/public/components/datasources/components/new/new_datasource_card_view.tsx @@ -16,21 +16,25 @@ import { import React, { useState } from 'react'; import { NewDatasourceDescription } from './new_datasource_description'; import s3Svg from '../../icons/s3-logo.svg'; +import { DatasourceType } from '../../../../../common/types/data_connections'; -export interface DatasourceType { - name: string; +export interface DatasourceCard { + name: DatasourceType; + displayName: string; description: string; displayIcon: JSX.Element; } -const Datasources: DatasourceType[] = [ +const Datasources: DatasourceCard[] = [ { - name: 'OpenSearch', + name: 'OPENSEARCH', + displayName: 'OpenSearch', description: 'Connect to self managed OpenSearch clusters', displayIcon: , }, { - name: 'S3', + name: 'S3GLUE', + displayName: 'S3', description: 'Connect to Amazon S3 via Amazon Glue', displayIcon: , }, @@ -56,7 +60,7 @@ export function NewDatasourceCardView() { setToggleIconIdSelected(optionId); }; - const renderRows = (datasources: DatasourceType[]) => { + const renderRows = (datasources: DatasourceCard[]) => { return ( <> @@ -65,7 +69,7 @@ export function NewDatasourceCardView() { ; + selectedQueryPermissionRoles: Role[]; currentName: string; currentDetails: string; currentArn: string; diff --git a/server/routes/data_connections/data_connections_router.ts b/server/routes/data_connections/data_connections_router.ts index 2c996ddcc..52dc1c284 100644 --- a/server/routes/data_connections/data_connections_router.ts +++ b/server/routes/data_connections/data_connections_router.ts @@ -115,7 +115,7 @@ export function registerDataConnectionsRoute(router: IRouter) { }), }, }, - async (context, request, response): Promise => { + async (context, request, response) => { try { const dataConnectionsresponse = await context.observability_plugin.observabilityClient .asScoped(request) From 4d19eb4ec384f39086aa7531182cf76d8836fbe7 Mon Sep 17 00:00:00 2001 From: Derek Ho Date: Wed, 27 Sep 2023 11:41:44 -0400 Subject: [PATCH 22/22] Update test in accordance to useLocation Signed-off-by: Derek Ho --- .../__tests__/manage_data_connections_table.test.tsx | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/public/components/datasources/components/__tests__/manage_data_connections_table.test.tsx b/public/components/datasources/components/__tests__/manage_data_connections_table.test.tsx index dfdb65d85..9c4979cff 100644 --- a/public/components/datasources/components/__tests__/manage_data_connections_table.test.tsx +++ b/public/components/datasources/components/__tests__/manage_data_connections_table.test.tsx @@ -11,6 +11,13 @@ import { ManageDataConnectionsTable } from '../manage/manage_data_connections_ta import { showDataConnectionsData } from '../../../../../test/datasources'; import ReactDOM from 'react-dom'; +jest.mock('react-router-dom', () => ({ + ...jest.requireActual('react-router-dom'), + useLocation: () => ({ + pathname: '/manage', + }), +})); + describe('Manage Data Connections Table test', () => { configure({ adapter: new Adapter() });