From 0330447c91ad9ea6f65a2017888d8e50c6b4740c Mon Sep 17 00:00:00 2001 From: sumukhswamy Date: Tue, 3 Oct 2023 19:11:09 -0700 Subject: [PATCH] =?UTF-8?q?added=20the=20skipping=20index=20queries,=20cov?= =?UTF-8?q?ering=20index=20queries,updates=20the=20=E2=80=A6=20(#134)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * added the skipping index queries, covering index queries,updates the data picker Signed-off-by: sumukhswamy * added the skipping index queries, covering index queries,updates the data picker Signed-off-by: sumukhswamy * reverted updates to yarn Signed-off-by: sumukhswamy * updated tests, snapshots Signed-off-by: sumukhswamy --------- Signed-off-by: sumukhswamy --- .../Main/__snapshots__/main.test.tsx.snap | 268 +++--------------- public/components/Main/main.test.tsx | 54 ++-- public/components/Main/main.tsx | 39 +-- public/components/SQLPage/DataSelect.tsx | 76 +++++ public/components/SQLPage/TableView.tsx | 241 ++++++++++------ public/components/SQLPage/utils.tsx | 44 +++ server/clusters/sql/sqlPlugin.js | 10 +- server/routes/query.ts | 30 +- server/services/QueryService.ts | 30 +- server/services/utils/constants.ts | 2 +- server/utils/constants.ts | 3 +- test/mocks/mockData.ts | 11 +- yarn.lock | 2 +- 13 files changed, 419 insertions(+), 391 deletions(-) create mode 100644 public/components/SQLPage/DataSelect.tsx create mode 100644 public/components/SQLPage/utils.tsx diff --git a/public/components/Main/__snapshots__/main.test.tsx.snap b/public/components/Main/__snapshots__/main.test.tsx.snap index d77c51ba..8b0d7301 100644 --- a/public/components/Main/__snapshots__/main.test.tsx.snap +++ b/public/components/Main/__snapshots__/main.test.tsx.snap @@ -26,23 +26,14 @@ exports[`
spec click clear button 1`] = ` class="euiFormControlLayout__childrenWrapper" >
- - - Opensearch - - + OpenSearch
spec click clear button 1`] = `
-
spec click run button, and response is ok 1`] = ` - 2 +
+ 2 +
spec click run button, response fills null and missing values class="euiFormControlLayout__childrenWrapper" >
- - - Opensearch - - + OpenSearch
spec click run button, response fills null and missing values
-
spec click run button, response fills null and missing values + > +
+
spec click translation button, and response is ok 1`] = ` class="euiFormControlLayout__childrenWrapper" >
- - - Opensearch - - + OpenSearch
spec click translation button, and response is ok 1`] = `
-
spec", () => { - - it("renders the component", async () => { - +describe('
spec', () => { + it('renders the component', async () => { const client = httpClientMock; - client.post = jest.fn().mockResolvedValue(mockHttpQuery) - + client.post = jest.fn().mockResolvedValue(mockHttpQuery); + client.get = jest.fn().mockResolvedValue(mockDatasourcesQuery); const asyncTest = () => { - render( -
- ); + render(
); }; await asyncTest(); expect(document.body.children[0]).toMatchSnapshot(); }); - - it("click run button, and response is ok", async () => { + it('click run button, and response is ok', async () => { const client = httpClientMock; client.post = jest.fn().mockResolvedValue(mockQueryResultJDBCResponse); @@ -51,9 +46,10 @@ describe("
spec", () => { expect(document.body.children[0]).toMatchSnapshot(); }); - it("click run button, response fills null and missing values", async () => { + it('click run button, response fills null and missing values', async () => { const client = httpClientMock; client.post = jest.fn().mockResolvedValue(mockResultWithNull); + client.get = jest.fn().mockResolvedValue(mockDatasourcesQuery); const { getByText } = await render(
@@ -64,11 +60,12 @@ describe("
spec", () => { }; await asyncTest(); expect(document.body.children[0]).toMatchSnapshot(); - }) + }); - it("click run button, and response causes an error", async () => { + it('click run button, and response causes an error', async () => { const client = httpClientMock; client.post = jest.fn().mockRejectedValue('err'); + client.get = jest.fn().mockResolvedValue(mockDatasourcesQuery); const { getByText } = await render(
@@ -81,9 +78,10 @@ describe("
spec", () => { expect(document.body.children[0]).toMatchSnapshot(); }); - it("click run button, and response is not ok", async () => { + it('click run button, and response is not ok', async () => { const client = httpClientMock; client.post = jest.fn().mockResolvedValue(mockNotOkQueryResultResponse); + client.get = jest.fn().mockResolvedValue(mockDatasourcesQuery); const { getByText } = await render(
@@ -96,9 +94,11 @@ describe("
spec", () => { expect(document.body.children[0]).toMatchSnapshot(); }); - it("click translation button, and response is ok", async () => { + it('click translation button, and response is ok', async () => { const client = httpClientMock; client.post = jest.fn().mockResolvedValue(mockQueryTranslationResponse); + client.get = jest.fn().mockResolvedValue(mockDatasourcesQuery); + const { getByText } = await render(
); @@ -110,8 +110,10 @@ describe("
spec", () => { expect(document.body.children[0]).toMatchSnapshot(); }); - it("click clear button", async () => { + it('click clear button', async () => { const client = httpClientMock; + client.get = jest.fn().mockResolvedValue(mockDatasourcesQuery); + const { getByText } = await render(
); diff --git a/public/components/Main/main.tsx b/public/components/Main/main.tsx index 5c7defb0..f79c42db 100644 --- a/public/components/Main/main.tsx +++ b/public/components/Main/main.tsx @@ -5,7 +5,7 @@ import { EuiButton, - EuiComboBox, + EuiComboBoxOptionOption, EuiFlexGroup, EuiFlexItem, EuiPage, @@ -14,12 +14,13 @@ import { EuiPageSideBar, EuiPanel, EuiSpacer, - EuiText, + EuiText } from '@elastic/eui'; import { IHttpResponse } from 'angular'; import _ from 'lodash'; import React from 'react'; import { ChromeBreadcrumb, CoreStart } from '../../../../../src/core/public'; +import { AsyncQueryLoadingStatus } from '../../../common/types'; import { MESSAGE_TAB_LABEL } from '../../utils/constants'; import { Tree, @@ -31,9 +32,9 @@ import { import { PPLPage } from '../PPLPage/PPLPage'; import Switch from '../QueryLanguageSwitch/Switch'; import QueryResults from '../QueryResults/QueryResults'; +import { DataSelect } from '../SQLPage/DataSelect'; import { SQLPage } from '../SQLPage/SQLPage'; import { TableView } from '../SQLPage/TableView'; -import { AsyncQueryLoadingStatus } from '../../../common/types'; interface ResponseData { ok: boolean; @@ -101,7 +102,7 @@ interface MainState { itemIdToExpandedRowMap: ItemIdToExpandedRowMap; messages: Array; isResultFullScreen: boolean; - selectedDatasource: string; + selectedDatasource: EuiComboBoxOptionOption[]; asyncLoading: boolean; asyncLoadingStatus: AsyncQueryLoadingStatus; asyncJobId: string; @@ -238,7 +239,7 @@ export class Main extends React.Component { itemIdToExpandedRowMap: {}, messages: [], isResultFullScreen: false, - selectedDatasource: 'Opensearch', + selectedDatasource: [{ label: 'OpenSearch' }], asyncLoading: false, asyncLoadingStatus: 'SUCCESS', asyncJobId: '', @@ -416,7 +417,7 @@ export class Main extends React.Component { queries.map((query: string) => this.httpClient .post(endpoint, { - body: JSON.stringify({ lang: language, query: query, datasource: 'my_glue' }), // TODO: dynamically datasource when accurate + body: JSON.stringify({ lang: language, query: query, datasource: this.state.selectedDatasource[0].label}), // TODO: dynamically datasource when accurate }) .catch((error: any) => { this.setState({ @@ -781,9 +782,9 @@ export class Main extends React.Component { }); } - handleComboOptionChange = (selectedOption: string) => { + handleDataSelect = (selectedItems: []) => { this.setState({ - selectedDatasource: selectedOption, + selectedDatasource: selectedItems, }); }; @@ -796,7 +797,7 @@ export class Main extends React.Component { page = ( { page = ( { Data Sources - { - const selectedValue = selectedOptions[0] ? selectedOptions[0].value : ''; - this.handleComboOptionChange(selectedValue); - }} - /> + @@ -915,7 +902,7 @@ export class Main extends React.Component { diff --git a/public/components/SQLPage/DataSelect.tsx b/public/components/SQLPage/DataSelect.tsx new file mode 100644 index 00000000..bc63607a --- /dev/null +++ b/public/components/SQLPage/DataSelect.tsx @@ -0,0 +1,76 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { EuiComboBox, EuiComboBoxOptionOption } from '@elastic/eui'; +import React, { useEffect, useState } from 'react'; +import { CoreStart } from '../../../../../src/core/public'; + +interface CustomView { + http: CoreStart['http']; + onSelect: (selectedItems: []) => void; +} + +export const DataSelect = ({ http, onSelect }: CustomView) => { + const [selectedOptions, setSelectedOptions] = useState([{ label: 'OpenSearch' }]); + const [options, setOptions] = useState([]); + + const datasources = () => { + http + .get(`/api/get_datasources`) + .then((res) => { + const data = res.data.resp; + + const connectorGroups = {}; + + data.forEach((item) => { + const connector = item.connector; + const name = item.name; + + if (connector === 'S3GLUE') { + if (!connectorGroups[connector]) { + connectorGroups[connector] = []; + } + + connectorGroups[connector].push(name); + } + }); + options.push({ label: 'OpenSearch' }); + for (const connector in connectorGroups) { + if (connectorGroups.hasOwnProperty(connector)) { + const connectorNames = connectorGroups[connector]; + + options.push({ + label: connector, + options: connectorNames.map((name) => ({ label: name })), + }); + } + } + + setOptions(options); + }) + .catch((err) => { + console.error(err); + }); + }; + + useEffect(() => { + datasources(); + }, []); + + const handleSelectionChange = (selectedItems: any[]) => { + setSelectedOptions(selectedItems); + onSelect(selectedItems); + }; + + return ( + handleSelectionChange(selectedItems)} + /> + ); +}; diff --git a/public/components/SQLPage/TableView.tsx b/public/components/SQLPage/TableView.tsx index 328a4330..3f168ccd 100644 --- a/public/components/SQLPage/TableView.tsx +++ b/public/components/SQLPage/TableView.tsx @@ -3,106 +3,161 @@ * SPDX-License-Identifier: Apache-2.0 */ - -import React, { useState, useEffect } from "react"; -import { EuiEmptyPrompt, EuiIcon, EuiTreeView } from "@elastic/eui"; +import { EuiEmptyPrompt, EuiIcon, EuiTreeView } from '@elastic/eui'; import _ from 'lodash'; +import React, { useEffect, useState } from 'react'; import { CoreStart } from '../../../../../src/core/public'; -import { ON_LOAD_QUERY } from "../../../common/constants"; +import { ON_LOAD_QUERY } from '../../../common/constants'; +import { getJobId, pollQueryStatus } from './utils'; interface CustomView { - http: CoreStart['http'], - dataConnection: string + http: CoreStart['http']; + selectedItems: any[]; } -export const TableView = ({ http, dataConnection }: CustomView) => { - const [tablenames, setTablenames] = useState([]); - const [selectedNode, setSelectedNode] = useState(null); - const [childData, setChildData] = useState([]); - const [selectedChildNode, setSelectedChildNode] = useState(null); - const [indexData, setIndexedData] = useState([]); - - const getSidebarContent = () => { - const query = { query: ON_LOAD_QUERY } - http - .post(`/api/sql_console/sqlquery`, { - body: JSON.stringify(query), - }) - .then((res) => { - const responseObj = res.data.resp - ? JSON.parse(res.data.resp) - : ''; - const datarows: any[][] = _.get(responseObj, 'datarows'); - const fields = datarows.map((data) => { - return data[2] - }) - setTablenames(fields) - }) - .catch((err) => { - console.error(err); - }); +export const TableView = ({ http, selectedItems }: CustomView) => { + const [tablenames, setTablenames] = useState([]); + const [selectedNode, setSelectedNode] = useState(null); + const [childData, setChildData] = useState([]); + const [selectedChildNode, setSelectedChildNode] = useState(null); + const [indexData, setIndexedData] = useState([]); + const [isLoading, setIsLoading] = useState(false); + const [indiciesData, setIndiciesData] = useState([]); + + const get_async_query_results = (id, http, callback) => { + pollQueryStatus(id, http, callback); + }; + + const getSidebarContent = () => { + if (selectedItems[0].label == 'OpenSearch') { + setTablenames([]); + const query = { query: ON_LOAD_QUERY }; + http + .post(`/api/sql_console/sqlquery`, { + body: JSON.stringify(query), + }) + .then((res) => { + const responseObj = res.data.resp ? JSON.parse(res.data.resp) : ''; + const datarows: any[][] = _.get(responseObj, 'datarows'); + const fields = datarows.map((data) => { + return data[2]; + }); + setTablenames(fields); + }) + .catch((err) => { + console.error(err); + }); + } else { + setTablenames([]); + const query = { + lang: 'sql', + query: `SHOW SCHEMAS IN ${selectedItems[0]['label']}`, + datasource: selectedItems[0]['label'], + }; + getJobId(query, http, (id) => { + get_async_query_results(id, http, (data) => { + setTablenames(data); + }); + }); + } + }; + + useEffect(() => { + getSidebarContent(); + }, [selectedItems[0]['label']]); + + const handleNodeClick = (nodeLabel: string) => { + setSelectedNode(nodeLabel); + const query = { + lang: 'sql', + query: `SHOW TABLES IN ${selectedItems[0]['label']}.${nodeLabel}`, + datasource: selectedItems[0]['label'], }; - - useEffect(() => { - - getSidebarContent(); - }, []); - - const handleNodeClick = (nodeLabel: string) => { - - // // will update after new query - - const newData = ["Child 1", "Child 2", "Child 3"]; - setChildData(newData); - setSelectedNode(nodeLabel); + getJobId(query, http, (id) => { + get_async_query_results(id, http, (data) => { + data = data.map((subArray) => subArray[1]); + setChildData(data); + }); + }); + }; + + const callCoverQuery = (nodeLabel1: string) => { + const coverQuery = { + lang: 'sql', + query: `SHOW INDEX ON ${selectedItems[0]['label']}.${selectedNode}.${nodeLabel1}`, + datasource: selectedItems[0]['label'], }; - - const handleChildClick = (nodeLabel1: string) => { - - // will update after new query - - const newData1 = ["Child 4", "Child 5", "Child 6"]; - setIndexedData(newData1); - setSelectedChildNode(nodeLabel1); + getJobId(coverQuery, http, (id) => { + get_async_query_results(id, http, (data) => { + data = [].concat(...data) + indiciesData.push(data) + setIndexedData(indiciesData); + }); + }); + }; + const handleChildClick = (nodeLabel1: string) => { + setSelectedChildNode(nodeLabel1); + const skipQuery = { + lang: 'sql', + query: `DESC SKIPPING INDEX ON ${selectedItems[0]['label']}.${selectedNode}.${nodeLabel1}`, + datasource: selectedItems[0]['label'], }; - - - const treeData = tablenames.map((element, index) => ({ - label: element, - icon: , - id: 'element_' + index, - callback: () => handleNodeClick(element), - isSelectable: true, - isExpanded: true, - children: dataConnection === 'S3' && selectedNode === element ? childData.map(child => ({ - label: child, - id: `${element}_${child}`, - icon: , - callback: () => handleChildClick(child), - sSelectable: true, + getJobId(skipQuery, http, (id) => { + get_async_query_results(id, http, (data) => { + if (data.length > 0) { + indiciesData.push('skip_index'); + callCoverQuery(nodeLabel1); + } + }); + }); + }; + + const treeData = tablenames.map((database, index) => ({ + label:
{database}
, + icon: , + id: 'element_' + index, + callback: () => { + setChildData([]); + setIsLoading(true); + handleNodeClick(database); + }, + isSelectable: true, + isExpanded: true, + children: + selectedNode === database + ? childData.map((table) => ({ + label:
{table}
, + id: `${database}_${table}`, + icon: , + callback: () => { + setIndexedData([]); + handleChildClick(table); + }, + sSelectable: true, isExpanded: true, - children: selectedChildNode === child ? indexData.map(indexChild => ({ - label: indexChild, - id: `${child}_${indexChild}`, - icon: - })):undefined, - })) : undefined, - })); - - return ( - <> - {treeData.length > 0 ? - - : Error loading Datasources} - /> - } - - ) -} - + children: + selectedChildNode === table + ? indexData.map((indexChild) => ({ + label: indexChild, + id: `${table}_${indexChild}`, + icon: , + })) + : undefined, + })) + : undefined, + })); + + return ( + <> + {treeData.length > 0 ? ( + + ) : ( + Error loading Datasources} + /> + )} + + ); +}; diff --git a/public/components/SQLPage/utils.tsx b/public/components/SQLPage/utils.tsx new file mode 100644 index 00000000..48909ab8 --- /dev/null +++ b/public/components/SQLPage/utils.tsx @@ -0,0 +1,44 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ +const POLL_INTERVAL_MS = 5000; +import _ from 'lodash'; +import { CoreStart } from '../../../../../src/core/public'; + + + +export const pollQueryStatus = (id: string, http :CoreStart['http'], callback) => { + http + .get(`/api/spark_sql_console/job/` + id) + .then((res) => { + const status = res.data.resp.status; + if (status === 'PENDING' || status === 'RUNNING' || status === 'SCHEDULED') { + setTimeout(() => pollQueryStatus(id, http, callback), POLL_INTERVAL_MS); + } else if (status === 'FAILED') { + callback([]); + } else if (status === 'SUCCESS') { + const results = _.get(res.data.resp, 'datarows'); + callback(results); + } + }) + .catch((err) => { + console.error(err); + callback([]); + }); +}; + +export const getJobId = (query: {}, http: CoreStart['http'], callback) => { + let id; + http + .post(`/api/spark_sql_console`, { + body: JSON.stringify(query), + }) + .then((res) => { + id = res.data.resp.queryId; + callback(id) + }) + .catch((err) => { + console.error(err); + }); +}; diff --git a/server/clusters/sql/sqlPlugin.js b/server/clusters/sql/sqlPlugin.js index 3f0b210d..e23a068f 100644 --- a/server/clusters/sql/sqlPlugin.js +++ b/server/clusters/sql/sqlPlugin.js @@ -4,7 +4,7 @@ */ -import { SQL_TRANSLATE_ROUTE, SQL_QUERY_ROUTE, PPL_QUERY_ROUTE, PPL_TRANSLATE_ROUTE, FORMAT_CSV, FROMAT_JDBC, FORMAT_JSON, FORMAT_TEXT, SPARK_SQL_QUERY_ROUTE } from '../../services/utils/constants'; +import { SQL_TRANSLATE_ROUTE, SQL_QUERY_ROUTE, PPL_QUERY_ROUTE, PPL_TRANSLATE_ROUTE, FORMAT_CSV, FROMAT_JDBC, FORMAT_JSON, FORMAT_TEXT, SPARK_SQL_QUERY_ROUTE, DATASOURCES_GET_QUERY } from '../../services/utils/constants'; export default function sqlPlugin(Client, config, components) { const ca = components.clientAction.factory; @@ -114,6 +114,14 @@ export default function sqlPlugin(Client, config, components) { method: 'GET', }); + sql.datasourcesGetQuery = ca({ + url: { + fmt: `${DATASOURCES_GET_QUERY}`, + }, + needBody: false, + method: 'GET', + }); + sql.asyncDeleteQuery = ca({ url: { fmt: `${SPARK_SQL_QUERY_ROUTE}/<%=jobId%>`, diff --git a/server/routes/query.ts b/server/routes/query.ts index a4b0b376..95e6b6ba 100644 --- a/server/routes/query.ts +++ b/server/routes/query.ts @@ -8,16 +8,17 @@ import { schema } from '@osd/config-schema'; import { IOpenSearchDashboardsResponse, IRouter, ResponseError } from '../../../../src/core/server'; import QueryService from '../services/QueryService'; import { - ROUTE_PATH_SQL_QUERY, - ROUTE_PATH_PPL_QUERY, - ROUTE_PATH_SQL_CSV, - ROUTE_PATH_SQL_JSON, - ROUTE_PATH_SQL_TEXT, + ROUTE_PATH_GET_DATASOURCES, ROUTE_PATH_PPL_CSV, ROUTE_PATH_PPL_JSON, + ROUTE_PATH_PPL_QUERY, ROUTE_PATH_PPL_TEXT, - ROUTE_PATH_SPARK_SQL_QUERY, ROUTE_PATH_SPARK_SQL_JOB_QUERY, + ROUTE_PATH_SPARK_SQL_QUERY, + ROUTE_PATH_SQL_CSV, + ROUTE_PATH_SQL_JSON, + ROUTE_PATH_SQL_QUERY, + ROUTE_PATH_SQL_TEXT } from '../utils/constants'; export default function query(server: IRouter, service: QueryService) { @@ -189,4 +190,21 @@ export default function query(server: IRouter, service: QueryService) { }); } ) + + server.get( + { + path: ROUTE_PATH_GET_DATASOURCES, + validate: { + + }, + }, + async (context, request, response): Promise> => { + const retVal = await service.describeSyncQueryDataSources(request); + return response.ok({ + body: retVal, + }); + } + ) + + } diff --git a/server/services/QueryService.ts b/server/services/QueryService.ts index 9aa927ce..5d0bb5ad 100644 --- a/server/services/QueryService.ts +++ b/server/services/QueryService.ts @@ -5,8 +5,8 @@ import 'core-js/stable'; -import 'regenerator-runtime/runtime'; import _ from 'lodash'; +import 'regenerator-runtime/runtime'; export default class QueryService { private client: any; @@ -62,6 +62,28 @@ export default class QueryService { } }; + describeQueryGetInternalSync = async (request: any, format: string, responseFormat: string) => { + try { + const queryResponse = await this.client.asScoped(request).callAsCurrentUser(format); + return { + data: { + ok: true, + resp: _.isEqual(responseFormat, 'json') ? JSON.stringify(queryResponse) : queryResponse, + }, + }; + } catch (err) { + console.log(err); + return { + data: { + ok: false, + resp: err.message, + body: err.body + }, + }; + } + }; + + describeSQLQuery = async (request: any) => { return this.describeQueryPostInternal(request, 'sql.sqlQuery', 'json', request.body); }; @@ -101,8 +123,10 @@ export default class QueryService { describeSQLAsyncGetQuery = async (request: any, jobId: string) => { return this.describeQueryJobIdInternal(request, 'sql.sparkSqlGetQuery', jobId, null); }; - + describeSyncQueryDataSources = async (request: any) => { + return this.describeQueryGetInternalSync(request, 'sql.datasourcesGetQuery', null); + }; describeAsyncDeleteQuery = async (request: any, jobId: string) => { return this.describeQueryJobIdInternal(request, 'sql.asyncDeleteQuery', jobId, null); }; -} +} \ No newline at end of file diff --git a/server/services/utils/constants.ts b/server/services/utils/constants.ts index 2d103254..04c9d4d0 100644 --- a/server/services/utils/constants.ts +++ b/server/services/utils/constants.ts @@ -4,7 +4,6 @@ */ -import { ParsedUrlQuery } from 'querystring'; export const SQL_TRANSLATE_ROUTE = `/_plugins/_sql/_explain`; export const PPL_TRANSLATE_ROUTE = `/_plugins/_ppl/_explain`; @@ -14,6 +13,7 @@ export const FORMAT_CSV = `format=csv`; export const FORMAT_JSON = `format=json`; export const FORMAT_TEXT = `format=raw`; export const SPARK_SQL_QUERY_ROUTE = `/_plugins/_async_query`; +export const DATASOURCES_GET_QUERY = `/_plugins/_query/_datasources` export const DEFAULT_HEADERS = { 'Content-Type': 'application/json', diff --git a/server/utils/constants.ts b/server/utils/constants.ts index da6b6522..d6e4d4bf 100644 --- a/server/utils/constants.ts +++ b/server/utils/constants.ts @@ -14,4 +14,5 @@ export const ROUTE_PATH_PPL_JSON = '/api/sql_console/ppljson'; export const ROUTE_PATH_SQL_TEXT = '/api/sql_console/sqltext'; export const ROUTE_PATH_PPL_TEXT = '/api/sql_console/ppltext'; export const ROUTE_PATH_SPARK_SQL_QUERY = '/api/spark_sql_console'; -export const ROUTE_PATH_SPARK_SQL_JOB_QUERY = '/api/spark_sql_console/job'; \ No newline at end of file +export const ROUTE_PATH_SPARK_SQL_JOB_QUERY = '/api/spark_sql_console/job'; +export const ROUTE_PATH_GET_DATASOURCES = '/api/get_datasources' \ No newline at end of file diff --git a/test/mocks/mockData.ts b/test/mocks/mockData.ts index 2daadf9d..65904eec 100644 --- a/test/mocks/mockData.ts +++ b/test/mocks/mockData.ts @@ -2340,4 +2340,13 @@ export const mockHttpQuery = "ok": true, resp: "{\"schema\":[{\"name\":\"TABLE_CAT\",\"type\":\"keyword\"}],\"datarows\":[[\"opensearch\",null,\".kibana_1\",\"BASE TABLE\",null,null,null,null,null,null]]}" } -} \ No newline at end of file +} +export const mockDatasourcesQuery = +{ + "data": { + "ok": true, + resp: "[{ \"name\": \"my_glue\", \"description\": \"\", \"connector\": \"S3GLUE\", \"allowedRoles\": [], \"properties\": { \"glue.indexstore.opensearch.uri\": \"\", \"glue.indexstore.opensearch.region\": \"\" }}]" + } +} + + diff --git a/yarn.lock b/yarn.lock index de41642a..d64b7fcf 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2637,4 +2637,4 @@ yauzl@^2.10.0: yocto-queue@^0.1.0: version "0.1.0" resolved "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz" - integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q== + integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q== \ No newline at end of file