From 79d18df6a4bba28303dccb5ef0bc681309f2715a Mon Sep 17 00:00:00 2001 From: Derek Ho Date: Wed, 27 Sep 2023 11:44:09 -0400 Subject: [PATCH] Configure S3 datasource flow (#1049) * 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 * 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 * 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 * 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 * 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 * 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 * Get most of the workflow working for configure datasource Signed-off-by: Derek Ho * remove acceleration components Signed-off-by: Shenoy Pratik * Update data connection to datasources in a few more places and update tests Signed-off-by: Derek Ho * Rename and re-organize in folders Signed-off-by: Derek Ho * Fix import path in testing file Signed-off-by: Derek Ho * Get Initial S3 configuration working Signed-off-by: Derek Ho * Configure S3 Data Source Working Signed-off-by: Derek Ho * Fix query permissions display Signed-off-by: Derek Ho * Fix merge conflict Signed-off-by: Derek Ho * Clean up PR Signed-off-by: Derek Ho * Add s3 logo in manage table Signed-off-by: Derek Ho * Fix up PR according to UX feedback Signed-off-by: Derek Ho * Remove successfully Signed-off-by: Derek Ho * Update test Signed-off-by: Derek Ho * Address PR comments Signed-off-by: Derek Ho * Update test in accordance to useLocation Signed-off-by: Derek Ho --------- Signed-off-by: Derek Ho Signed-off-by: Shenoy Pratik Co-authored-by: Shenoy Pratik --- common/constants/shared.ts | 4 +- common/types/data_connections.ts | 13 +- public/components/app.tsx | 2 +- .../components/data_connections_header.tsx | 38 --- .../data_connection.test.tsx.snap | 0 ...data_connections_description.test.tsx.snap | 4 +- ...anage_data_connections_table.test.tsx.snap | 40 +++- .../__tests__/data_connection.test.tsx | 2 +- ...nage_data_connections_description.test.tsx | 2 +- .../manage_data_connections_table.test.tsx | 9 +- .../components/data_connections_header.tsx | 77 +++++++ .../components/manage}/access_control_tab.tsx | 21 +- .../manage}/connection_configuration.tsx | 0 .../components/manage}/connection_details.tsx | 6 +- .../manage}/connection_management_callout.tsx | 0 .../components/manage}/data_connection.tsx | 18 +- .../manage_data_connections_description.tsx | 4 +- .../manage}/manage_data_connections_table.tsx | 20 +- .../components/manage}/query_permissions.tsx | 8 +- .../components/new/configure_datasource.tsx | 191 +++++++++++++++ .../new/configure_s3_datasource.tsx | 218 ++++++++++++++++++ .../components/new/new_datasource.tsx | 41 ++++ .../new/new_datasource_card_view.tsx | 115 +++++++++ .../new/new_datasource_description.tsx | 24 ++ .../review_s3_datasource_configuration.tsx | 108 +++++++++ .../components/no_access.tsx | 0 .../components/save_or_cancel.tsx | 0 .../home.tsx | 15 +- .../components/datasources/icons/s3-logo.svg | 7 + server/adaptors/ppl_plugin.ts | 8 + .../data_connections_router.ts | 37 +++ 31 files changed, 943 insertions(+), 89 deletions(-) delete mode 100644 public/components/data_connections/components/data_connections_header.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 (91%) rename public/components/{data_connections => datasources}/components/__tests__/__snapshots__/manage_data_connections_table.test.tsx.snap (96%) 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 (81%) create mode 100644 public/components/datasources/components/data_connections_header.tsx rename public/components/{data_connections/components => datasources/components/manage}/access_control_tab.tsx (85%) rename public/components/{data_connections/components => datasources/components/manage}/connection_configuration.tsx (100%) rename public/components/{data_connections/components => datasources/components/manage}/connection_details.tsx (96%) 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 (93%) rename public/components/{data_connections/components => datasources/components/manage}/manage_data_connections_description.tsx (82%) rename public/components/{data_connections/components => datasources/components/manage}/manage_data_connections_table.tsx (89%) rename public/components/{data_connections/components => datasources/components/manage}/query_permissions.tsx (88%) create mode 100644 public/components/datasources/components/new/configure_datasource.tsx create mode 100644 public/components/datasources/components/new/configure_s3_datasource.tsx create mode 100644 public/components/datasources/components/new/new_datasource.tsx create mode 100644 public/components/datasources/components/new/new_datasource_card_view.tsx create mode 100644 public/components/datasources/components/new/new_datasource_description.tsx create mode 100644 public/components/datasources/components/new/review_s3_datasource_configuration.tsx 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 (64%) create mode 100644 public/components/datasources/icons/s3-logo.svg diff --git a/common/constants/shared.ts b/common/constants/shared.ts index 66b42e8c6..2187f28ce 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/common/types/data_connections.ts b/common/types/data_connections.ts index 9fd0527d9..b19b1bb7d 100644 --- a/common/types/data_connections.ts +++ b/common/types/data_connections.ts @@ -3,8 +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/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/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/__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 91% 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 index 2cc84b45b..10c1b2484 100644 --- 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 @@ -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/datasources/components/__tests__/__snapshots__/manage_data_connections_table.test.tsx.snap similarity index 96% 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 index 20c847340..6cd9a84f9 100644 --- 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 @@ -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.

({ 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 81% 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 index cd5509f1b..9c4979cff 100644 --- 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 @@ -7,10 +7,17 @@ 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'; +jest.mock('react-router-dom', () => ({ + ...jest.requireActual('react-router-dom'), + useLocation: () => ({ + pathname: '/manage', + }), +})); + describe('Manage Data Connections Table test', () => { configure({ adapter: new Adapter() }); diff --git a/public/components/datasources/components/data_connections_header.tsx b/public/components/datasources/components/data_connections_header.tsx new file mode 100644 index 000000000..6f5c87092 --- /dev/null +++ b/public/components/datasources/components/data_connections_header.tsx @@ -0,0 +1,77 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { + EuiLink, + EuiPageHeader, + EuiPageHeaderSection, + EuiSpacer, + EuiTab, + EuiTabs, + EuiText, + 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 location = useLocation().pathname.substring(1); + + const [selectedTabId, setSelectedTabId] = useState(location ? location : '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 sources

+
+
+
+ + + Connect and manage compatible OpenSearch and OpenSearch Dashboard data sources.{' '} + + Learn more + + + + {renderTabs()} + +
+ ); +}; diff --git a/public/components/data_connections/components/access_control_tab.tsx b/public/components/datasources/components/manage/access_control_tab.tsx similarity index 85% rename from public/components/data_connections/components/access_control_tab.tsx rename to public/components/datasources/components/manage/access_control_tab.tsx index 58fdffde3..40e9e8ecd 100644 --- a/public/components/data_connections/components/access_control_tab.tsx +++ b/public/components/datasources/components/manage/access_control_tab.tsx @@ -14,23 +14,27 @@ 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'; +import { Role } from '../../../../../common/types/data_connections'; interface AccessControlTabProps { dataConnection: string; connector: string; properties: unknown; + allowedRoles: string[]; } 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 }; + }) + ); const { http } = coreRefs; useEffect(() => { @@ -51,7 +55,7 @@ export const AccessControlTab = (props: AccessControlTabProps) => { Query access - {[].length ? `Restricted` : '-'} + {selectedQueryPermissionRoles.length ? `Restricted` : '-'} @@ -67,6 +71,7 @@ export const AccessControlTab = (props: AccessControlTabProps) => { roles={roles} selectedRoles={selectedQueryPermissionRoles} setSelectedRoles={setSelectedQueryPermissionRoles} + layout={'vertical'} /> ); diff --git a/public/components/data_connections/components/connection_configuration.tsx b/public/components/datasources/components/manage/connection_configuration.tsx similarity index 100% rename from public/components/data_connections/components/connection_configuration.tsx rename to public/components/datasources/components/manage/connection_configuration.tsx diff --git a/public/components/data_connections/components/connection_details.tsx b/public/components/datasources/components/manage/connection_details.tsx similarity index 96% rename from public/components/data_connections/components/connection_details.tsx rename to public/components/datasources/components/manage/connection_details.tsx index 44cd206f4..533071960 100644 --- a/public/components/data_connections/components/connection_details.tsx +++ b/public/components/datasources/components/manage/connection_details.tsx @@ -14,9 +14,9 @@ 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 { coreRefs } from '../../../../framework/core_refs'; +import { DATACONNECTIONS_BASE } from '../../../../../common/constants/shared'; +import { SaveOrCancel } from '../save_or_cancel'; import { ConnectionConfiguration } from './connection_configuration'; interface ConnectionDetailProps { 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 93% rename from public/components/data_connections/components/data_connection.tsx rename to public/components/datasources/components/manage/data_connection.tsx index d4c87ef49..a0527e7bc 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: '#/', }, { @@ -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/data_connections/components/manage_data_connections_description.tsx b/public/components/datasources/components/manage/manage_data_connections_description.tsx similarity index 82% rename from public/components/data_connections/components/manage_data_connections_description.tsx rename to public/components/datasources/components/manage/manage_data_connections_description.tsx index 26cfa90cc..866ac5ae3 100644 --- a/public/components/data_connections/components/manage_data_connections_description.tsx +++ b/public/components/datasources/components/manage/manage_data_connections_description.tsx @@ -10,12 +10,12 @@ export const DataConnectionsDescription = () => { return (
-

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/manage_data_connections_table.tsx b/public/components/datasources/components/manage/manage_data_connections_table.tsx similarity index 89% 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 e1950e704..d2009fb1f 100644 --- a/public/components/data_connections/components/manage_data_connections_table.tsx +++ b/public/components/datasources/components/manage/manage_data_connections_table.tsx @@ -17,15 +17,17 @@ 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 '../../../../public/components/common/toast'; -import { DeleteModal } from '../../../../public/components/common/helpers/delete_modal'; +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'; + connectionType: DatasourceType; name: string; } @@ -57,7 +59,7 @@ export const ManageDataConnectionsTable = (props: HomeProps) => { useEffect(() => { chrome.setBreadcrumbs([ { - text: 'Data Connections', + text: 'Data sources', href: '#/', }, ]); @@ -93,8 +95,8 @@ export const ManageDataConnectionsTable = (props: HomeProps) => { const icon = (record: DataConnection) => { switch (record.connectionType) { - case 'OPENSEARCH': - return ; + case 'S3GLUE': + return ; default: return <>; } diff --git a/public/components/data_connections/components/query_permissions.tsx b/public/components/datasources/components/manage/query_permissions.tsx similarity index 88% rename from public/components/data_connections/components/query_permissions.tsx rename to public/components/datasources/components/manage/query_permissions.tsx index eee8312a8..92ae3ae95 100644 --- a/public/components/data_connections/components/query_permissions.tsx +++ b/public/components/datasources/components/manage/query_permissions.tsx @@ -17,11 +17,11 @@ 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; + 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 new file mode 100644 index 000000000..004611d34 --- /dev/null +++ b/public/components/datasources/components/new/configure_datasource.tsx @@ -0,0 +1,191 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { + EuiFlexGroup, + EuiFlexItem, + EuiPage, + EuiPageBody, + EuiSpacer, + EuiText, + EuiButton, + EuiSteps, + EuiPageSideBar, + EuiBottomBar, + EuiButtonEmpty, +} from '@elastic/eui'; +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'; +import { DatasourceType, Role } from '../../../../../common/types/data_connections'; + +interface ConfigureDatasourceProps { + type: string; +} + +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([]); + const [page, setPage] = useState<'configure' | 'review'>('configure'); + const ConfigureDatasourceSteps = [ + { + title: 'Configure Data Source', + children: null, + }, + { + title: 'Review Configuration', + children: null, + }, + ]; + + useEffect(() => { + http!.get('/api/v1/configuration/roles').then((data) => + setRoles( + Object.keys(data.data).map((key) => { + return { label: key }; + }) + ) + ); + }, []); + + const ConfigureDatasource = (configurationProps: { datasourceType: DatasourceType }) => { + const { datasourceType } = configurationProps; + switch (datasourceType) { + case 'S3GLUE': + return ( + + ); + default: + return <>; + } + }; + + const ReviewDatasourceConfiguration = (configurationProps: { datasourceType: string }) => { + const { datasourceType } = configurationProps; + switch (datasourceType) { + case 'S3': + return ( + setPage('configure')} + /> + ); + default: + return <>; + } + }; + + const ReviewSaveOrCancel = useCallback(() => { + return ( + + + + { + window.location.hash = '#/new'; + }} + color="ghost" + size="s" + iconType="cross" + > + Cancel + + + + (page === 'review' ? setPage('configure') : {})} + color="ghost" + size="s" + iconType="arrowLeft" + > + Previous + + + + (page === 'review' ? 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`, 'success'); + window.location.hash = '#/manage'; + }) + .catch((err) => { + setToast(`Data source ${name} created`, 'success'); + 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 new file mode 100644 index 000000000..803249aca --- /dev/null +++ b/public/components/datasources/components/new/configure_s3_datasource.tsx @@ -0,0 +1,218 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { + EuiPanel, + EuiTitle, + EuiSpacer, + EuiText, + EuiLink, + EuiFormRow, + EuiFieldText, + EuiTextArea, + EuiButton, + EuiSelect, +} from '@elastic/eui'; +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: Role[]; + selectedQueryPermissionRoles: Role[]; + 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, + 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); + 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 ( +
+ + +

{`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

+
+ + + + <> + +

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

Authentication settings to access the index store.

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

The region where the index store is.

+
+ + +
+ + + + +
+
+ ); +}; 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..669d0705e --- /dev/null +++ b/public/components/datasources/components/new/new_datasource.tsx @@ -0,0 +1,41 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { EuiPage, EuiPageBody } from '@elastic/eui'; +import React, { useEffect, useState } from 'react'; +import { DataConnectionsHeader } from '../data_connections_header'; +import { HomeProps } from '../../home'; +import { NewDatasourceCardView } from './new_datasource_card_view'; + +export const NewDatasource = (props: HomeProps) => { + const { chrome } = 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/datasources/components/new/new_datasource_card_view.tsx b/public/components/datasources/components/new/new_datasource_card_view.tsx new file mode 100644 index 000000000..04ede43aa --- /dev/null +++ b/public/components/datasources/components/new/new_datasource_card_view.tsx @@ -0,0 +1,115 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { + EuiPanel, + EuiCard, + EuiFlexGroup, + EuiFlexItem, + EuiSpacer, + EuiFieldSearch, + EuiButtonGroup, + EuiIcon, +} from '@elastic/eui'; +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 DatasourceCard { + name: DatasourceType; + displayName: string; + description: string; + displayIcon: JSX.Element; +} + +const Datasources: DatasourceCard[] = [ + { + name: 'OPENSEARCH', + displayName: 'OpenSearch', + description: 'Connect to self managed OpenSearch clusters', + displayIcon: , + }, + { + name: 'S3GLUE', + displayName: 'S3', + description: 'Connect to Amazon S3 via Amazon Glue', + displayIcon: , + }, +]; + +export function NewDatasourceCardView() { + 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: DatasourceCard[]) => { + return ( + <> + + {datasources.map((i, v) => { + return ( + + (window.location.hash = `#/configure/${i.name}`)} + /> + + ); + })} + + + + ); + }; + + return ( + + + + + {}} + /> + + + onChangeIcons(id)} + isIconOnly + /> + + + + {renderRows(Datasources)} + + ); +} diff --git a/public/components/datasources/components/new/new_datasource_description.tsx b/public/components/datasources/components/new/new_datasource_description.tsx new file mode 100644 index 000000000..91f13c666 --- /dev/null +++ b/public/components/datasources/components/new/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/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..2a65f8e2b --- /dev/null +++ b/public/components/datasources/components/new/review_s3_datasource_configuration.tsx @@ -0,0 +1,108 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { + EuiPanel, + EuiTitle, + EuiSpacer, + EuiText, + EuiFlexGroup, + EuiHorizontalRule, + EuiFlexItem, + EuiButton, +} from '@elastic/eui'; +import React from 'react'; + +interface ConfigureS3DatasourceProps { + selectedQueryPermissionRoles: Role[]; + currentName: string; + currentDetails: string; + currentArn: string; + currentStore: string; + goBack: () => void; +} + +export const ReviewS3Datasource = (props: ConfigureS3DatasourceProps) => { + const { + currentStore, + currentName, + currentDetails, + currentArn, + selectedQueryPermissionRoles, + goBack, + } = props; + + return ( +
+ + +

{`Review S3 Data Source Configuration`}

+
+ + + + + +

Data source configuration

+
+
+ + Edit + +
+ + + + + + + Data source name + + {currentName} + + + + Description + + {currentDetails} + + + + + + + + Glue authentication ARN + + {currentArn} + + + + Glue index store URI + + {currentStore} + + + + + + + + Query Permissions + + {selectedQueryPermissionRoles && selectedQueryPermissionRoles.length + ? `Restricted - ${selectedQueryPermissionRoles + .map((role) => role.label) + .join(',')}` + : 'Everyone'} + + + + + +
+
+ ); +}; 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 64% rename from public/components/data_connections/home.tsx rename to public/components/datasources/home.tsx index 29d5e83bd..fef07a780 100644 --- a/public/components/data_connections/home.tsx +++ b/public/components/datasources/home.tsx @@ -6,8 +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 { ManageDataConnectionsTable } from './components/manage_data_connections_table'; +import { DataConnection } from './components/manage/data_connection'; +import { ManageDataConnectionsTable } from './components/manage/manage_data_connections_table'; +import { NewDatasource } from './components/new/new_datasource'; +import { Configure } from './components/new/configure_datasource'; export interface HomeProps extends RouteComponentProps { pplService: any; @@ -44,6 +46,15 @@ export const Home = (props: HomeProps) => { path={['/', '/manage']} render={(routerProps) => } /> + } /> + + ( + + )} + /> ); 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 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..52dc1c284 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) => { + 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}`,