diff --git a/.cypress/integration/10_datasources.spec.js b/.cypress/integration/10_datasources.spec.js
new file mode 100644
index 0000000000..c4ef7618f8
--- /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 0000000000..ce031cb6e4
--- /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 2d10c08e2a..f694562214 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 17267478d2..7abafdabd9 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 ac3fa5772c..cb7ba34e43 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 0000000000..793dde1044
--- /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 0000000000..b9ab1040b9
--- /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 0000000000..8206d792b7
--- /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`] = `
+
+
+
+
+
+
+
+
+ Connect and manage compatible OpenSearch Dashboard data sources and compute.
+
+
+ Learn more
+
+
+
+
+
+
+
+
+
+ Manage existing data connections
+
+
+
+
+ Manage already created data source connections.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ |
+
+
+
+ |
+
+
+
+
+
+ |
+
+
+
+
+
+ |
+
+
+
+ |
+
+
+
+
+
+ |
+
+
+
+
+
+ |
+
+
+
+ |
+
+
+
+
+
+ |
+
+
+
+
+
+ |
+
+
+
+ |
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+`;
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 0000000000..8294e05989
--- /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 0000000000..e6380b0d51
--- /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 0000000000..599a7a235e
--- /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 0000000000..5cad339575
--- /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 0000000000..19c6b9fbec
--- /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 0000000000..8c0ceb7242
--- /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 0000000000..f05fb01e25
--- /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 0000000000..2fd3e01b3b
--- /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 0000000000..88ad367c53
--- /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 e858daa549..360bf0db49 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 021a9f56ad..6d553f63cf 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 48f0ad9de6..75afb133bf 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 fbdbac72be..10137b33c7 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 304d196e3f..e4714c9d00 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 0000000000..187be8da1c
--- /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 4830bf58c4..d3d64f5509 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);
}