From eb05d7de991e7c015085f743156e01f820356fe3 Mon Sep 17 00:00:00 2001 From: sumukhswamy Date: Wed, 11 Oct 2023 19:31:48 -0700 Subject: [PATCH 1/8] made the tree persistant, added changes for loading screen Signed-off-by: sumukhswamy --- common/constants/index.ts | 4 + common/types/index.ts | 10 +- public/components/SQLPage/TableView.tsx | 250 ++++++++++++++---------- 3 files changed, 164 insertions(+), 100 deletions(-) diff --git a/common/constants/index.ts b/common/constants/index.ts index c7ed1d43..9cfda206 100644 --- a/common/constants/index.ts +++ b/common/constants/index.ts @@ -9,6 +9,10 @@ export const OPENSEARCH_ACC_DOCUMENTATION_URL = 'https://opensearch.org/docs/lat export const ACC_INDEX_TYPE_DOCUMENTATION_URL = 'https://opensearch.org/docs/latest'; export const SKIPPING_INDEX = `skipping_index`; +export const COVERING_INDEX = `covering_index`; +export const DATABASE = `database`; +export const TABLE = `table`; +export const INDICIES = `indicies` export const ON_LOAD_QUERY = `SHOW tables LIKE '%';`; export const SKIPPING_INDEX_QUERY = `CREATE SKIPPING INDEX ON myS3.logs_db.http_logs (status VALUE_SET) diff --git a/common/types/index.ts b/common/types/index.ts index c96bb147..2c63b344 100644 --- a/common/types/index.ts +++ b/common/types/index.ts @@ -77,4 +77,12 @@ export interface CreateAccelerationForm { formErrors: FormErrorsType; } -export type AsyncQueryLoadingStatus = "SUCCESS" | "FAILED" | "RUNNING" | "SCHEDULED" | "CANCELED" \ No newline at end of file +export type AsyncQueryLoadingStatus = "SUCCESS" | "FAILED" | "RUNNING" | "SCHEDULED" | "CANCELED" +export type Tree = "covering_index" | "skipping_index" | "table" | "database" | "materialized_view" + +export interface TreeItem{ + name: string; + type: Tree + isExpanded: boolean; + values?: TreeItem []; +} \ No newline at end of file diff --git a/public/components/SQLPage/TableView.tsx b/public/components/SQLPage/TableView.tsx index 017fbf19..b9b2e233 100644 --- a/public/components/SQLPage/TableView.tsx +++ b/public/components/SQLPage/TableView.tsx @@ -14,10 +14,17 @@ import { EuiToolTip, EuiTreeView, } from '@elastic/eui'; +import { Tree, TreeItem } from 'common/types'; import _ from 'lodash'; import React, { useEffect, useState } from 'react'; import { CoreStart } from '../../../../../src/core/public'; -import { ON_LOAD_QUERY, SKIPPING_INDEX } from '../../../common/constants'; +import { + COVERING_INDEX, + DATABASE, + ON_LOAD_QUERY, + SKIPPING_INDEX, + TABLE, +} from '../../../common/constants'; import { AccelerationIndexFlyout } from './acceleration_index_flyout'; import { getJobId, pollQueryStatus } from './utils'; @@ -28,17 +35,16 @@ interface CustomView { } export const TableView = ({ http, selectedItems, updateSQLQueries }: CustomView) => { - const [tablenames, setTablenames] = useState([]); - const [selectedNode, setSelectedNode] = useState(null); - const [childData, setChildData] = useState([]); - const [selectedChildNode, setSelectedChildNode] = useState(null); - const [indexData, setIndexedData] = useState([]); + const [tableNames, setTableNames] = useState([]); + const [selectedDatabase, setSelectedDatabase] = useState(''); + const [selectedTable, setSelectedTable] = useState(null); const [isLoading, setIsLoading] = useState(false); const [indexFlyout, setIndexFlyout] = useState(<>); const [childLoadingStates, setChildLoadingStates] = useState<{ [key: string]: boolean }>({}); const [tableLoadingStates, setTableLoadingStates] = useState<{ [key: string]: boolean }>({}); + const [treeData, setTreeData] = useState([]); - let indiciesData: string[] = []; + let indicesData: string[] = []; const resetFlyout = () => { setIndexFlyout(<>); @@ -62,13 +68,38 @@ export const TableView = ({ http, selectedItems, updateSQLQueries }: CustomView) ); }; + function mapToTreeItem(elements: string[], type: Tree): TreeItem[] { + return elements.map((element) => { + const treeItem: TreeItem = { + name: element, + type: type, + isExpanded: true, + }; + + if (type === DATABASE) { + treeItem.values = []; + treeItem.isExpanded = true; + } else if (type === TABLE) { + treeItem.values = []; + treeItem.isExpanded = true; + } else if (type === SKIPPING_INDEX) { + treeItem.values = []; + treeItem.type = SKIPPING_INDEX; + } else { + treeItem.type = COVERING_INDEX; + } + + return treeItem; + }); + } + const get_async_query_results = (id, http, callback) => { pollQueryStatus(id, http, callback); }; const getSidebarContent = () => { if (selectedItems[0].label === 'OpenSearch') { - setTablenames([]); + setTableNames([]); const query = { query: ON_LOAD_QUERY }; http .post(`/api/sql_console/sqlquery`, { @@ -76,18 +107,18 @@ export const TableView = ({ http, selectedItems, updateSQLQueries }: CustomView) }) .then((res) => { const responseObj = res.data.resp ? JSON.parse(res.data.resp) : ''; - const datarows: any[][] = _.get(responseObj, 'datarows'); - const fields = datarows.map((data) => { + const dataRows: any[][] = _.get(responseObj, 'datarows'); + const fields = dataRows.map((data) => { return data[2]; }); - setTablenames(fields); + setTableNames(fields); }) .catch((err) => { console.error(err); }); } else { setIsLoading(true); - setTablenames([]); + setTableNames([]); const query = { lang: 'sql', query: `SHOW SCHEMAS IN ${selectedItems[0]['label']}`, @@ -95,7 +126,8 @@ export const TableView = ({ http, selectedItems, updateSQLQueries }: CustomView) }; getJobId(query, http, (id) => { get_async_query_results(id, http, (data) => { - setTablenames(data); + data = [].concat(...data); + setTreeData(mapToTreeItem(data, DATABASE)); setIsLoading(false); }); }); @@ -107,71 +139,78 @@ export const TableView = ({ http, selectedItems, updateSQLQueries }: CustomView) getSidebarContent(); }, [selectedItems]); - const handleNodeClick = (nodeLabel: string) => { - setSelectedNode(nodeLabel); + const handleDatabaseClick = (databaseName: string) => { + setSelectedDatabase(databaseName); const query = { lang: 'sql', - query: `SHOW TABLES IN ${selectedItems[0]['label']}.${nodeLabel}`, + query: `SHOW TABLES IN ${selectedItems[0]['label']}.${databaseName}`, datasource: selectedItems[0]['label'], }; - setTableLoadingStates((prevState) => ({ - ...prevState, - [nodeLabel]: true, - })); getJobId(query, http, (id) => { get_async_query_results(id, http, (data) => { data = data.map((subArray) => subArray[1]); - setChildData(data); - - setTableLoadingStates((prevState) => ({ - ...prevState, - [nodeLabel]: false, - })); + const values = mapToTreeItem(data, TABLE); + treeData.map((database) => { + if (database.name === databaseName) { + database.values = values; + } + }); + setIsLoading(false); }); }); }; - const callCoverQuery = (nodeLabel1: string) => { + const callCoverQuery = (tableName: string) => { const coverQuery = { lang: 'sql', - query: `SHOW INDEX ON ${selectedItems[0]['label']}.${selectedNode}.${nodeLabel1}`, + query: `SHOW INDEX ON ${selectedItems[0]['label']}.${selectedDatabase}.${tableName}`, datasource: selectedItems[0]['label'], }; getJobId(coverQuery, http, (id) => { get_async_query_results(id, http, (data) => { const res = [].concat(data); - const final = indiciesData.concat(...res); - setIndexedData(final); - setChildLoadingStates((prevState) => ({ - ...prevState, - [nodeLabel1]: false, - })); + let coverIndexObj = mapToTreeItem(res, COVERING_INDEX); + const final = indicesData.concat(...res); + treeData.map((database) => { + if (database.name === selectedDatabase) { + database.values.map((table) => { + if (table.name === tableName) { + table.values = table.values.concat(...coverIndexObj); + } + }); + } + }); + setIsLoading(false); }); }); }; - const handleChildClick = (nodeLabel1: string) => { - setSelectedChildNode(nodeLabel1); + + const handleTableClick = (tableName: string) => { + setSelectedTable(tableName); const skipQuery = { lang: 'sql', - query: `DESC SKIPPING INDEX ON ${selectedItems[0]['label']}.${selectedNode}.${nodeLabel1}`, + query: `DESC SKIPPING INDEX ON ${selectedItems[0]['label']}.${selectedDatabase}.${tableName}`, datasource: selectedItems[0]['label'], }; - setChildLoadingStates((prevState) => ({ - ...prevState, - [nodeLabel1]: true, - })); - getJobId(skipQuery, http, (id) => { get_async_query_results(id, http, (data) => { if (data.length > 0) { - indiciesData.push(SKIPPING_INDEX); + treeData.map((database) => { + if (database.name === selectedDatabase) { + database.values.map((table) => { + if (table.name === tableName) { + table.values = mapToTreeItem([SKIPPING_INDEX], SKIPPING_INDEX); + } + }); + } + }); } - callCoverQuery(nodeLabel1); + callCoverQuery(tableName); }); }); }; - const treeData = tablenames.map((database, index) => ({ + const treeDataOpenSearch = tableNames.map((database, index) => ({ label: (
@@ -182,73 +221,86 @@ export const TableView = ({ http, selectedItems, updateSQLQueries }: CustomView) ), icon: , id: 'element_' + index, + })); + + const treeDataDatabases = treeData.map((database, index) => ({ + label: ( +
+ + {_.truncate(database.name, { length: 50 })} + {' '} +
+ ), + icon: , + id: 'element_' + index, callback: () => { - setChildData([]); - selectedItems[0].label !== 'OpenSearch' && handleNodeClick(database); + if (database.values.length === 0 && selectedItems[0].label !== 'OpenSearch') { + handleDatabaseClick(database.name); + setIsLoading(true); + } }, isSelectable: true, - isExpanded: true, - children: - selectedNode === database - ? childData.map((table) => ({ - label: ( -
- - {_.truncate(table, { length: 50 })} - {' '} - {childLoadingStates[table] && } -
- ), - id: `${database}_${table}`, - icon: , - callback: () => { - setIndexedData([]); - handleChildClick(table); - setChildLoadingStates((prevState) => ({ - ...prevState, - [selectedChildNode]: false, - })); - }, - sSelectable: true, - isExpanded: true, - children: - selectedChildNode === table - ? indexData.map((indexChild) => ({ - label: ( -
- - {_.truncate(indexChild, { length: 50 })} - -
- ), - id: `${table}_${indexChild}`, - icon: , - callback: () => - handleAccelerationIndexClick( - selectedItems[0].label, - database, - table, - indexChild - ), - })) - : undefined, - })) - : undefined, + isExpanded: false, + children: database.values.map((table) => ({ + label: ( +
+ + {_.truncate(table.name, { length: 50 })} + {' '} +
+ ), + id: `${database.name}_${table.name}`, + icon: , + callback: () => { + if (table.values.length === 0) { + handleTableClick(table.name); + setIsLoading(true); + } + }, + isSelectable: true, + isExpanded: false, + children: table.values.map((indexChild) => ({ + label: ( +
+ + {_.truncate(indexChild.name, { length: 50 })} + +
+ ), + id: `${table.name}_${indexChild.name}`, + icon: , + callback: () => + handleAccelerationIndexClick( + selectedItems[0].label, + database.name, + table.name, + indexChild.name + ), + })), + })), })); return ( <> {isLoading ? ( - - Loading databases + - + + + Loading databases + + Loading can take more than 30s. Queries can be made after the data has loaded. Any + queries run before the data is loaded will be queued - ) : treeData.length > 0 ? ( + ) : treeDataOpenSearch.length > 0 || treeDataDatabases.length > 0 ? ( - + {selectedItems[0].label === 'OpenSearch' ? ( + + ) : ( + + )} ) : ( From 568d267306c69864120be35a6db34d9c2dd7ef3c Mon Sep 17 00:00:00 2001 From: sumukhswamy Date: Wed, 11 Oct 2023 20:02:08 -0700 Subject: [PATCH 2/8] changes for the text displayed during loading screen Signed-off-by: sumukhswamy --- public/components/SQLPage/TableView.tsx | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/public/components/SQLPage/TableView.tsx b/public/components/SQLPage/TableView.tsx index b9b2e233..e52ff9e9 100644 --- a/public/components/SQLPage/TableView.tsx +++ b/public/components/SQLPage/TableView.tsx @@ -240,7 +240,7 @@ export const TableView = ({ http, selectedItems, updateSQLQueries }: CustomView) } }, isSelectable: true, - isExpanded: false, + isExpanded: true, children: database.values.map((table) => ({ label: (
@@ -258,7 +258,7 @@ export const TableView = ({ http, selectedItems, updateSQLQueries }: CustomView) } }, isSelectable: true, - isExpanded: false, + isExpanded: true, children: table.values.map((indexChild) => ({ label: (
@@ -290,8 +290,10 @@ export const TableView = ({ http, selectedItems, updateSQLQueries }: CustomView) Loading databases - Loading can take more than 30s. Queries can be made after the data has loaded. Any - queries run before the data is loaded will be queued + + Loading can take more than 30s. Queries can be made after the data has loaded. Any + queries run before the data is loaded will be queued + ) : treeDataOpenSearch.length > 0 || treeDataDatabases.length > 0 ? ( From ed657223de2faf80ab8c892eeea5f42934e87a67 Mon Sep 17 00:00:00 2001 From: sumukhswamy Date: Fri, 13 Oct 2023 11:36:42 -0700 Subject: [PATCH 3/8] addressed pr comments Signed-off-by: sumukhswamy --- common/constants/index.ts | 14 ++-- common/types/index.ts | 12 +-- public/components/SQLPage/TableView.tsx | 104 +++++++++--------------- 3 files changed, 54 insertions(+), 76 deletions(-) diff --git a/common/constants/index.ts b/common/constants/index.ts index 9cfda206..c3a4b278 100644 --- a/common/constants/index.ts +++ b/common/constants/index.ts @@ -8,12 +8,12 @@ export const PLUGIN_NAME = 'Query Workbench'; export const OPENSEARCH_ACC_DOCUMENTATION_URL = 'https://opensearch.org/docs/latest'; export const ACC_INDEX_TYPE_DOCUMENTATION_URL = 'https://opensearch.org/docs/latest'; -export const SKIPPING_INDEX = `skipping_index`; -export const COVERING_INDEX = `covering_index`; -export const DATABASE = `database`; -export const TABLE = `table`; -export const INDICIES = `indicies` -export const ON_LOAD_QUERY = `SHOW tables LIKE '%';`; +export const SKIPPING_INDEX_NAME = `skipping_index`; +export const COVERING_INDEX_NAME = `covering_index`; +export const DATABASE_NAME = `database`; +export const TABLE_NAME = `table`; +export const INDICIES_NAME = `indicies` +export const LOAD_OPENSEARCH_INDICES_QUERY = `SHOW tables LIKE '%';`; export const SKIPPING_INDEX_QUERY = `CREATE SKIPPING INDEX ON myS3.logs_db.http_logs (status VALUE_SET) WITH ( @@ -86,3 +86,5 @@ export const ACCELERATION_INDEX_NAME_INFO = `All OpenSearch acceleration indices `; export const SIDEBAR_POLL_INTERVAL_MS = 5000; + +export const FETCH_OPENSEARCH_INDICES_PATH = '/api/sql_console/sqlquery' \ No newline at end of file diff --git a/common/types/index.ts b/common/types/index.ts index 2c63b344..8133863c 100644 --- a/common/types/index.ts +++ b/common/types/index.ts @@ -77,12 +77,12 @@ export interface CreateAccelerationForm { formErrors: FormErrorsType; } -export type AsyncQueryLoadingStatus = "SUCCESS" | "FAILED" | "RUNNING" | "SCHEDULED" | "CANCELED" -export type Tree = "covering_index" | "skipping_index" | "table" | "database" | "materialized_view" +export type AsyncQueryLoadingStatus = 'SUCCESS' | 'FAILED' | 'RUNNING' | 'SCHEDULED' | 'CANCELED'; +export type Tree = 'covering_index' | 'skipping_index' | 'table' | 'database' | 'materialized_view'; -export interface TreeItem{ +export interface TreeItem { name: string; - type: Tree + type: Tree; isExpanded: boolean; - values?: TreeItem []; -} \ No newline at end of file + values?: TreeItem[]; +} diff --git a/public/components/SQLPage/TableView.tsx b/public/components/SQLPage/TableView.tsx index e52ff9e9..f09f2fc1 100644 --- a/public/components/SQLPage/TableView.tsx +++ b/public/components/SQLPage/TableView.tsx @@ -19,11 +19,12 @@ import _ from 'lodash'; import React, { useEffect, useState } from 'react'; import { CoreStart } from '../../../../../src/core/public'; import { - COVERING_INDEX, - DATABASE, - ON_LOAD_QUERY, - SKIPPING_INDEX, - TABLE, + COVERING_INDEX_NAME, + DATABASE_NAME, + FETCH_OPENSEARCH_INDICES_PATH, + LOAD_OPENSEARCH_INDICES_QUERY, + SKIPPING_INDEX_NAME, + TABLE_NAME, } from '../../../common/constants'; import { AccelerationIndexFlyout } from './acceleration_index_flyout'; import { getJobId, pollQueryStatus } from './utils'; @@ -40,12 +41,8 @@ export const TableView = ({ http, selectedItems, updateSQLQueries }: CustomView) const [selectedTable, setSelectedTable] = useState(null); const [isLoading, setIsLoading] = useState(false); const [indexFlyout, setIndexFlyout] = useState(<>); - const [childLoadingStates, setChildLoadingStates] = useState<{ [key: string]: boolean }>({}); - const [tableLoadingStates, setTableLoadingStates] = useState<{ [key: string]: boolean }>({}); const [treeData, setTreeData] = useState([]); - let indicesData: string[] = []; - const resetFlyout = () => { setIndexFlyout(<>); }; @@ -68,25 +65,21 @@ export const TableView = ({ http, selectedItems, updateSQLQueries }: CustomView) ); }; - function mapToTreeItem(elements: string[], type: Tree): TreeItem[] { + function loadTreeItem(elements: string[], type: Tree): TreeItem[] { return elements.map((element) => { - const treeItem: TreeItem = { + let treeItem: TreeItem = { name: element, type: type, isExpanded: true, }; - if (type === DATABASE) { - treeItem.values = []; - treeItem.isExpanded = true; - } else if (type === TABLE) { + if (type === DATABASE_NAME || type === TABLE_NAME) { treeItem.values = []; treeItem.isExpanded = true; - } else if (type === SKIPPING_INDEX) { - treeItem.values = []; - treeItem.type = SKIPPING_INDEX; + } else if (type === SKIPPING_INDEX_NAME) { + treeItem.type = SKIPPING_INDEX_NAME; } else { - treeItem.type = COVERING_INDEX; + treeItem.type = COVERING_INDEX_NAME; } return treeItem; @@ -100,13 +93,13 @@ export const TableView = ({ http, selectedItems, updateSQLQueries }: CustomView) const getSidebarContent = () => { if (selectedItems[0].label === 'OpenSearch') { setTableNames([]); - const query = { query: ON_LOAD_QUERY }; + const query = { query: LOAD_OPENSEARCH_INDICES_QUERY }; http - .post(`/api/sql_console/sqlquery`, { + .post(FETCH_OPENSEARCH_INDICES_PATH, { body: JSON.stringify(query), }) .then((res) => { - const responseObj = res.data.resp ? JSON.parse(res.data.resp) : ''; + const responseObj = res.data.resp ? JSON.parse(res.data.resp) : {}; const dataRows: any[][] = _.get(responseObj, 'datarows'); const fields = dataRows.map((data) => { return data[2]; @@ -127,7 +120,7 @@ export const TableView = ({ http, selectedItems, updateSQLQueries }: CustomView) getJobId(query, http, (id) => { get_async_query_results(id, http, (data) => { data = [].concat(...data); - setTreeData(mapToTreeItem(data, DATABASE)); + setTreeData(loadTreeItem(data, DATABASE_NAME)); setIsLoading(false); }); }); @@ -141,6 +134,7 @@ export const TableView = ({ http, selectedItems, updateSQLQueries }: CustomView) const handleDatabaseClick = (databaseName: string) => { setSelectedDatabase(databaseName); + setIsLoading(true); const query = { lang: 'sql', query: `SHOW TABLES IN ${selectedItems[0]['label']}.${databaseName}`, @@ -149,7 +143,7 @@ export const TableView = ({ http, selectedItems, updateSQLQueries }: CustomView) getJobId(query, http, (id) => { get_async_query_results(id, http, (data) => { data = data.map((subArray) => subArray[1]); - const values = mapToTreeItem(data, TABLE); + const values = loadTreeItem(data, TABLE_NAME); treeData.map((database) => { if (database.name === databaseName) { database.values = values; @@ -160,7 +154,7 @@ export const TableView = ({ http, selectedItems, updateSQLQueries }: CustomView) }); }; - const callCoverQuery = (tableName: string) => { + const loadCoveringIndex = (tableName: string) => { const coverQuery = { lang: 'sql', query: `SHOW INDEX ON ${selectedItems[0]['label']}.${selectedDatabase}.${tableName}`, @@ -169,8 +163,7 @@ export const TableView = ({ http, selectedItems, updateSQLQueries }: CustomView) getJobId(coverQuery, http, (id) => { get_async_query_results(id, http, (data) => { const res = [].concat(data); - let coverIndexObj = mapToTreeItem(res, COVERING_INDEX); - const final = indicesData.concat(...res); + let coverIndexObj = loadTreeItem(res, COVERING_INDEX_NAME); treeData.map((database) => { if (database.name === selectedDatabase) { database.values.map((table) => { @@ -187,6 +180,7 @@ export const TableView = ({ http, selectedItems, updateSQLQueries }: CustomView) const handleTableClick = (tableName: string) => { setSelectedTable(tableName); + setIsLoading(true); const skipQuery = { lang: 'sql', query: `DESC SKIPPING INDEX ON ${selectedItems[0]['label']}.${selectedDatabase}.${tableName}`, @@ -199,75 +193,57 @@ export const TableView = ({ http, selectedItems, updateSQLQueries }: CustomView) if (database.name === selectedDatabase) { database.values.map((table) => { if (table.name === tableName) { - table.values = mapToTreeItem([SKIPPING_INDEX], SKIPPING_INDEX); + table.values = loadTreeItem([SKIPPING_INDEX_NAME], SKIPPING_INDEX_NAME); } }); } }); } - callCoverQuery(tableName); + loadCoveringIndex(tableName); }); }); }; - - const treeDataOpenSearch = tableNames.map((database, index) => ({ - label: ( -
- - {_.truncate(database, { length: 50 })} + const labelCreation = (name: string) => { + return ( +
+ + {_.truncate(name, { length: 50 })} {' '} - {tableLoadingStates[database] && }
- ), + ); + }; + + const OpenSearchIndicesTree = tableNames.map((database, index) => ({ + label: labelCreation(database), icon: , id: 'element_' + index, })); const treeDataDatabases = treeData.map((database, index) => ({ - label: ( -
- - {_.truncate(database.name, { length: 50 })} - {' '} -
- ), + label: labelCreation(database.name), icon: , id: 'element_' + index, callback: () => { if (database.values.length === 0 && selectedItems[0].label !== 'OpenSearch') { handleDatabaseClick(database.name); - setIsLoading(true); } }, isSelectable: true, isExpanded: true, children: database.values.map((table) => ({ - label: ( -
- - {_.truncate(table.name, { length: 50 })} - {' '} -
- ), + label: labelCreation(table.name), id: `${database.name}_${table.name}`, icon: , callback: () => { if (table.values.length === 0) { handleTableClick(table.name); - setIsLoading(true); } }, isSelectable: true, isExpanded: true, children: table.values.map((indexChild) => ({ - label: ( -
- - {_.truncate(indexChild.name, { length: 50 })} - -
- ), - id: `${table.name}_${indexChild.name}`, + label: labelCreation(indexChild.name), + id: `${database.name}_${table.name}_${indexChild.name}`, icon: , callback: () => handleAccelerationIndexClick( @@ -290,16 +266,16 @@ export const TableView = ({ http, selectedItems, updateSQLQueries }: CustomView) Loading databases - + Loading can take more than 30s. Queries can be made after the data has loaded. Any queries run before the data is loaded will be queued - ) : treeDataOpenSearch.length > 0 || treeDataDatabases.length > 0 ? ( + ) : OpenSearchIndicesTree.length > 0 || treeDataDatabases.length > 0 ? ( {selectedItems[0].label === 'OpenSearch' ? ( - + ) : ( )} From a4c8c72aa00018a942d337b94d831e524b41096d Mon Sep 17 00:00:00 2001 From: sumukhswamy Date: Tue, 17 Oct 2023 00:30:25 -0700 Subject: [PATCH 4/8] addressed pr comments, added code for reload button Signed-off-by: sumukhswamy --- common/constants/index.ts | 9 +- common/types/index.ts | 4 +- public/components/Main/main.tsx | 27 +++++- public/components/SQLPage/TableView.tsx | 111 ++++++++++++++---------- 4 files changed, 95 insertions(+), 56 deletions(-) diff --git a/common/constants/index.ts b/common/constants/index.ts index c3a4b278..434b0710 100644 --- a/common/constants/index.ts +++ b/common/constants/index.ts @@ -8,11 +8,10 @@ export const PLUGIN_NAME = 'Query Workbench'; export const OPENSEARCH_ACC_DOCUMENTATION_URL = 'https://opensearch.org/docs/latest'; export const ACC_INDEX_TYPE_DOCUMENTATION_URL = 'https://opensearch.org/docs/latest'; -export const SKIPPING_INDEX_NAME = `skipping_index`; -export const COVERING_INDEX_NAME = `covering_index`; -export const DATABASE_NAME = `database`; -export const TABLE_NAME = `table`; -export const INDICIES_NAME = `indicies` +export const TREE_ITEM_SKIPPING_INDEX_DEFAULT_NAME = `skipping_index`; +export const TREE_ITEM_COVERING_INDEX_DEFAULT_NAME = `covering_index`; +export const TREE_ITEM_DATABASE_NAME_DEFAULT_NAME = `database`; +export const TREE_ITEM_TABLE_NAME_DEFAULT_NAME = `table`; export const LOAD_OPENSEARCH_INDICES_QUERY = `SHOW tables LIKE '%';`; export const SKIPPING_INDEX_QUERY = `CREATE SKIPPING INDEX ON myS3.logs_db.http_logs (status VALUE_SET) diff --git a/common/types/index.ts b/common/types/index.ts index 8133863c..3725021f 100644 --- a/common/types/index.ts +++ b/common/types/index.ts @@ -78,11 +78,11 @@ export interface CreateAccelerationForm { } export type AsyncQueryLoadingStatus = 'SUCCESS' | 'FAILED' | 'RUNNING' | 'SCHEDULED' | 'CANCELED'; -export type Tree = 'covering_index' | 'skipping_index' | 'table' | 'database' | 'materialized_view'; +export type TreeItemType = 'covering_index' | 'skipping_index' | 'table' | 'database' | 'materialized_view'; export interface TreeItem { name: string; - type: Tree; + type: TreeItemType; isExpanded: boolean; values?: TreeItem[]; } diff --git a/public/components/Main/main.tsx b/public/components/Main/main.tsx index 86f24463..02dd323c 100644 --- a/public/components/Main/main.tsx +++ b/public/components/Main/main.tsx @@ -109,6 +109,7 @@ interface MainState { asyncLoading: boolean; asyncLoadingStatus: AsyncQueryLoadingStatus; asyncJobId: string; + refreshTree: boolean; } const SUCCESS_MESSAGE = 'Success'; @@ -246,6 +247,7 @@ export class Main extends React.Component { asyncLoading: false, asyncLoadingStatus: 'SUCCESS', asyncJobId: '', + refreshTree: false, }; this.httpClient = this.props.httpClient; this.updateSQLQueries = _.debounce(this.updateSQLQueries, 250).bind(this); @@ -798,6 +800,12 @@ export class Main extends React.Component { }); }; + handleReloadTree = () => { + this.setState({ + refreshTree: !this.state.refreshTree, + }); + }; + render() { let page; let link; @@ -920,16 +928,27 @@ export class Main extends React.Component { - + + + + + + + + diff --git a/public/components/SQLPage/TableView.tsx b/public/components/SQLPage/TableView.tsx index f09f2fc1..961d8766 100644 --- a/public/components/SQLPage/TableView.tsx +++ b/public/components/SQLPage/TableView.tsx @@ -12,19 +12,19 @@ import { EuiLoadingSpinner, EuiText, EuiToolTip, - EuiTreeView, + EuiTreeView } from '@elastic/eui'; -import { Tree, TreeItem } from 'common/types'; +import { TreeItem, TreeItemType } from 'common/types'; import _ from 'lodash'; import React, { useEffect, useState } from 'react'; import { CoreStart } from '../../../../../src/core/public'; import { - COVERING_INDEX_NAME, - DATABASE_NAME, FETCH_OPENSEARCH_INDICES_PATH, LOAD_OPENSEARCH_INDICES_QUERY, - SKIPPING_INDEX_NAME, - TABLE_NAME, + TREE_ITEM_COVERING_INDEX_DEFAULT_NAME, + TREE_ITEM_DATABASE_NAME_DEFAULT_NAME, + TREE_ITEM_SKIPPING_INDEX_DEFAULT_NAME, + TREE_ITEM_TABLE_NAME_DEFAULT_NAME } from '../../../common/constants'; import { AccelerationIndexFlyout } from './acceleration_index_flyout'; import { getJobId, pollQueryStatus } from './utils'; @@ -33,9 +33,10 @@ interface CustomView { http: CoreStart['http']; selectedItems: EuiComboBoxOptionOption[]; updateSQLQueries: (query: string) => void; + refreshTree: boolean } -export const TableView = ({ http, selectedItems, updateSQLQueries }: CustomView) => { +export const TableView = ({ http, selectedItems, updateSQLQueries, refreshTree }: CustomView) => { const [tableNames, setTableNames] = useState([]); const [selectedDatabase, setSelectedDatabase] = useState(''); const [selectedTable, setSelectedTable] = useState(null); @@ -65,7 +66,7 @@ export const TableView = ({ http, selectedItems, updateSQLQueries }: CustomView) ); }; - function loadTreeItem(elements: string[], type: Tree): TreeItem[] { + function loadTreeItem(elements: string[], type: TreeItemType): TreeItem[] { return elements.map((element) => { let treeItem: TreeItem = { name: element, @@ -73,15 +74,10 @@ export const TableView = ({ http, selectedItems, updateSQLQueries }: CustomView) isExpanded: true, }; - if (type === DATABASE_NAME || type === TABLE_NAME) { + if (type === TREE_ITEM_DATABASE_NAME_DEFAULT_NAME || type === TREE_ITEM_TABLE_NAME_DEFAULT_NAME) { treeItem.values = []; treeItem.isExpanded = true; - } else if (type === SKIPPING_INDEX_NAME) { - treeItem.type = SKIPPING_INDEX_NAME; - } else { - treeItem.type = COVERING_INDEX_NAME; } - return treeItem; }); } @@ -120,7 +116,7 @@ export const TableView = ({ http, selectedItems, updateSQLQueries }: CustomView) getJobId(query, http, (id) => { get_async_query_results(id, http, (data) => { data = [].concat(...data); - setTreeData(loadTreeItem(data, DATABASE_NAME)); + setTreeData(loadTreeItem(data, TREE_ITEM_DATABASE_NAME_DEFAULT_NAME)); setIsLoading(false); }); }); @@ -130,7 +126,7 @@ export const TableView = ({ http, selectedItems, updateSQLQueries }: CustomView) useEffect(() => { setIsLoading(false); getSidebarContent(); - }, [selectedItems]); + }, [selectedItems, refreshTree]); const handleDatabaseClick = (databaseName: string) => { setSelectedDatabase(databaseName); @@ -143,11 +139,14 @@ export const TableView = ({ http, selectedItems, updateSQLQueries }: CustomView) getJobId(query, http, (id) => { get_async_query_results(id, http, (data) => { data = data.map((subArray) => subArray[1]); - const values = loadTreeItem(data, TABLE_NAME); - treeData.map((database) => { - if (database.name === databaseName) { - database.values = values; - } + const values = loadTreeItem(data, TREE_ITEM_TABLE_NAME_DEFAULT_NAME); + setTreeData((prevTreeData) => { + return prevTreeData.map((database) => { + if (database.name === databaseName) { + return { ...database, values: values }; + } + return database; + }); }); setIsLoading(false); }); @@ -163,15 +162,25 @@ export const TableView = ({ http, selectedItems, updateSQLQueries }: CustomView) getJobId(coverQuery, http, (id) => { get_async_query_results(id, http, (data) => { const res = [].concat(data); - let coverIndexObj = loadTreeItem(res, COVERING_INDEX_NAME); - treeData.map((database) => { - if (database.name === selectedDatabase) { - database.values.map((table) => { - if (table.name === tableName) { - table.values = table.values.concat(...coverIndexObj); - } - }); - } + let coverIndexObj = loadTreeItem(res, TREE_ITEM_COVERING_INDEX_DEFAULT_NAME); + setTreeData((prevTreeData) => { + return prevTreeData.map((database) => { + if (database.name === selectedDatabase) { + return { + ...database, + values: database.values.map((table) => { + if (table.name === tableName) { + return { + ...table, + values: table.values.concat(...coverIndexObj), + }; + } + return table; + }), + }; + } + return database; + }); }); setIsLoading(false); }); @@ -189,21 +198,32 @@ export const TableView = ({ http, selectedItems, updateSQLQueries }: CustomView) getJobId(skipQuery, http, (id) => { get_async_query_results(id, http, (data) => { if (data.length > 0) { - treeData.map((database) => { - if (database.name === selectedDatabase) { - database.values.map((table) => { - if (table.name === tableName) { - table.values = loadTreeItem([SKIPPING_INDEX_NAME], SKIPPING_INDEX_NAME); - } - }); - } + setTreeData((prevTreeData) => { + return prevTreeData.map((database) => { + if (database.name === selectedDatabase) { + return { + ...database, + values: database.values.map((table) => { + if (table.name === tableName) { + return { + ...table, + values: loadTreeItem([TREE_ITEM_SKIPPING_INDEX_DEFAULT_NAME], TREE_ITEM_SKIPPING_INDEX_DEFAULT_NAME), + }; + } + return table; + }), + }; + } + return database; + }); }); } loadCoveringIndex(tableName); }); }); }; - const labelCreation = (name: string) => { + + const createLabel = (name: string) => { return (
@@ -214,13 +234,14 @@ export const TableView = ({ http, selectedItems, updateSQLQueries }: CustomView) }; const OpenSearchIndicesTree = tableNames.map((database, index) => ({ - label: labelCreation(database), + label: createLabel(database), icon: , id: 'element_' + index, + isSelectable: false, })); const treeDataDatabases = treeData.map((database, index) => ({ - label: labelCreation(database.name), + label: createLabel(database.name), icon: , id: 'element_' + index, callback: () => { @@ -229,9 +250,9 @@ export const TableView = ({ http, selectedItems, updateSQLQueries }: CustomView) } }, isSelectable: true, - isExpanded: true, + isExpanded: database.isExpanded, children: database.values.map((table) => ({ - label: labelCreation(table.name), + label: createLabel(table.name), id: `${database.name}_${table.name}`, icon: , callback: () => { @@ -240,9 +261,9 @@ export const TableView = ({ http, selectedItems, updateSQLQueries }: CustomView) } }, isSelectable: true, - isExpanded: true, + isExpanded: table.isExpanded, children: table.values.map((indexChild) => ({ - label: labelCreation(indexChild.name), + label: createLabel(indexChild.name), id: `${database.name}_${table.name}_${indexChild.name}`, icon: , callback: () => From 481e4b12e1d293557789adda5ed97687818ba0d8 Mon Sep 17 00:00:00 2001 From: sumukhswamy Date: Wed, 18 Oct 2023 15:26:35 -0700 Subject: [PATCH 5/8] addressed pr comments, added Materialiazed view badges, bug fixes for loading state Signed-off-by: sumukhswamy --- common/constants/index.ts | 3 + common/types/index.ts | 2 +- public/components/Main/main.tsx | 12 +- public/components/SQLPage/TableView.tsx | 149 ++++++++++++++++++------ 4 files changed, 128 insertions(+), 38 deletions(-) diff --git a/common/constants/index.ts b/common/constants/index.ts index 434b0710..828462bc 100644 --- a/common/constants/index.ts +++ b/common/constants/index.ts @@ -10,8 +10,11 @@ export const ACC_INDEX_TYPE_DOCUMENTATION_URL = 'https://opensearch.org/docs/lat export const TREE_ITEM_SKIPPING_INDEX_DEFAULT_NAME = `skipping_index`; export const TREE_ITEM_COVERING_INDEX_DEFAULT_NAME = `covering_index`; +export const TREE_ITEM_MATERIALIZED_VIEW_DEFAULT_NAME = `materialized_view`; export const TREE_ITEM_DATABASE_NAME_DEFAULT_NAME = `database`; export const TREE_ITEM_TABLE_NAME_DEFAULT_NAME = `table`; +export const TREE_ITEM_LOAD_MATERIALIZED_BADGE_NAME = `Load Materialized View`; +export const TREE_ITEM_BADGE_NAME =`badge` export const LOAD_OPENSEARCH_INDICES_QUERY = `SHOW tables LIKE '%';`; export const SKIPPING_INDEX_QUERY = `CREATE SKIPPING INDEX ON myS3.logs_db.http_logs (status VALUE_SET) diff --git a/common/types/index.ts b/common/types/index.ts index 3725021f..7313fc59 100644 --- a/common/types/index.ts +++ b/common/types/index.ts @@ -78,7 +78,7 @@ export interface CreateAccelerationForm { } export type AsyncQueryLoadingStatus = 'SUCCESS' | 'FAILED' | 'RUNNING' | 'SCHEDULED' | 'CANCELED'; -export type TreeItemType = 'covering_index' | 'skipping_index' | 'table' | 'database' | 'materialized_view'; +export type TreeItemType = 'covering_index' | 'skipping_index' | 'table' | 'database' | 'materialized_view' | 'Load Materialized View' | 'badge' export interface TreeItem { name: string; diff --git a/public/components/Main/main.tsx b/public/components/Main/main.tsx index 02dd323c..e1517217 100644 --- a/public/components/Main/main.tsx +++ b/public/components/Main/main.tsx @@ -5,6 +5,7 @@ import { EuiButton, + EuiButtonIcon, EuiComboBoxOptionOption, EuiFlexGroup, EuiFlexItem, @@ -924,14 +925,17 @@ export class Main extends React.Component { {this.state.language === 'SQL' && ( - + - - - + + diff --git a/public/components/SQLPage/TableView.tsx b/public/components/SQLPage/TableView.tsx index 961d8766..d416d70e 100644 --- a/public/components/SQLPage/TableView.tsx +++ b/public/components/SQLPage/TableView.tsx @@ -4,6 +4,7 @@ */ import { + EuiBadge, EuiComboBoxOptionOption, EuiEmptyPrompt, EuiFlexGroup, @@ -21,8 +22,11 @@ import { CoreStart } from '../../../../../src/core/public'; import { FETCH_OPENSEARCH_INDICES_PATH, LOAD_OPENSEARCH_INDICES_QUERY, + TREE_ITEM_BADGE_NAME, TREE_ITEM_COVERING_INDEX_DEFAULT_NAME, TREE_ITEM_DATABASE_NAME_DEFAULT_NAME, + TREE_ITEM_LOAD_MATERIALIZED_BADGE_NAME, + TREE_ITEM_MATERIALIZED_VIEW_DEFAULT_NAME, TREE_ITEM_SKIPPING_INDEX_DEFAULT_NAME, TREE_ITEM_TABLE_NAME_DEFAULT_NAME } from '../../../common/constants'; @@ -33,7 +37,7 @@ interface CustomView { http: CoreStart['http']; selectedItems: EuiComboBoxOptionOption[]; updateSQLQueries: (query: string) => void; - refreshTree: boolean + refreshTree: boolean; } export const TableView = ({ http, selectedItems, updateSQLQueries, refreshTree }: CustomView) => { @@ -74,9 +78,11 @@ export const TableView = ({ http, selectedItems, updateSQLQueries, refreshTree } isExpanded: true, }; - if (type === TREE_ITEM_DATABASE_NAME_DEFAULT_NAME || type === TREE_ITEM_TABLE_NAME_DEFAULT_NAME) { + if ( + type != TREE_ITEM_COVERING_INDEX_DEFAULT_NAME && + type != TREE_ITEM_SKIPPING_INDEX_DEFAULT_NAME + ) { treeItem.values = []; - treeItem.isExpanded = true; } return treeItem; }); @@ -139,7 +145,9 @@ export const TableView = ({ http, selectedItems, updateSQLQueries, refreshTree } getJobId(query, http, (id) => { get_async_query_results(id, http, (data) => { data = data.map((subArray) => subArray[1]); - const values = loadTreeItem(data, TREE_ITEM_TABLE_NAME_DEFAULT_NAME); + let values = loadTreeItem(data, TREE_ITEM_TABLE_NAME_DEFAULT_NAME); + let mvObj = loadTreeItem([TREE_ITEM_LOAD_MATERIALIZED_BADGE_NAME], TREE_ITEM_LOAD_MATERIALIZED_BADGE_NAME); + values = [...values, ...mvObj]; setTreeData((prevTreeData) => { return prevTreeData.map((database) => { if (database.name === databaseName) { @@ -168,11 +176,11 @@ export const TableView = ({ http, selectedItems, updateSQLQueries, refreshTree } if (database.name === selectedDatabase) { return { ...database, - values: database.values.map((table) => { + values: database.values?.map((table) => { if (table.name === tableName) { return { ...table, - values: table.values.concat(...coverIndexObj), + values: table.values?.concat(...coverIndexObj), }; } return table; @@ -187,6 +195,41 @@ export const TableView = ({ http, selectedItems, updateSQLQueries, refreshTree } }); }; + const handleButtonClick = (e: MouseEvent, tableName: string) => { + e.stopPropagation(); + setSelectedTable(tableName); + setIsLoading(true); + const materializedViewQuery = { + lang: 'sql', + query: `SHOW MATERIALIZED VIEW IN ${selectedItems[0]['label']}.${selectedDatabase}`, + datasource: selectedItems[0]['label'], + }; + getJobId(materializedViewQuery, http, (id) => { + get_async_query_results(id, http, (data) => { + console.log(data) + data = data.map((subArray) => subArray[1]); + let values = loadTreeItem(data, TREE_ITEM_MATERIALIZED_VIEW_DEFAULT_NAME); + if(values.length === 0){ + values = [{ name: 'No Materialized View', type: TREE_ITEM_BADGE_NAME, isExpanded: false }] + } + setTreeData((prevTreeData) => { + return prevTreeData.map((database) => { + if (database.name === selectedDatabase) { + const updatedValues = database.values?.filter( + (item) => item.type !== TREE_ITEM_LOAD_MATERIALIZED_BADGE_NAME + ); + return { ...database, values: updatedValues?.concat(...values) }; + } + return database; + }); + }); + setIsLoading(false); + }); + }); + + + }; + const handleTableClick = (tableName: string) => { setSelectedTable(tableName); setIsLoading(true); @@ -203,11 +246,14 @@ export const TableView = ({ http, selectedItems, updateSQLQueries, refreshTree } if (database.name === selectedDatabase) { return { ...database, - values: database.values.map((table) => { + values: database.values?.map((table) => { if (table.name === tableName) { return { ...table, - values: loadTreeItem([TREE_ITEM_SKIPPING_INDEX_DEFAULT_NAME], TREE_ITEM_SKIPPING_INDEX_DEFAULT_NAME), + values: loadTreeItem( + [TREE_ITEM_SKIPPING_INDEX_DEFAULT_NAME], + TREE_ITEM_SKIPPING_INDEX_DEFAULT_NAME + ), }; } return table; @@ -223,56 +269,93 @@ export const TableView = ({ http, selectedItems, updateSQLQueries, refreshTree } }); }; - const createLabel = (name: string) => { - return ( -
- - {_.truncate(name, { length: 50 })} - {' '} -
- ); + const createLabel = (node: TreeItem, parentName: string, index: number) => { + if (node.type === TREE_ITEM_BADGE_NAME) { + return ( +
+ + {_.truncate(node.name, { length: 50 })} + {' '} +
+ ); + }else if(node.type === TREE_ITEM_LOAD_MATERIALIZED_BADGE_NAME) { + return ( +
+ Load Materialized View +
+ ); + } + else { + return ( +
+ + {_.truncate(node.name, { length: 50 })} + {' '} +
+ ); + } }; const OpenSearchIndicesTree = tableNames.map((database, index) => ({ - label: createLabel(database), + label: ( +
+ + {_.truncate(database, { length: 50 })} + {' '} +
+ ), icon: , id: 'element_' + index, isSelectable: false, })); const treeDataDatabases = treeData.map((database, index) => ({ - label: createLabel(database.name), + label: createLabel(database,selectedItems[0].label,index), icon: , id: 'element_' + index, callback: () => { - if (database.values.length === 0 && selectedItems[0].label !== 'OpenSearch') { + if (database.values?.length === 0 && selectedItems[0].label !== 'OpenSearch') { handleDatabaseClick(database.name); } }, isSelectable: true, isExpanded: database.isExpanded, - children: database.values.map((table) => ({ - label: createLabel(table.name), + children: database.values?.map((table, index) => ({ + label: createLabel(table,database.name,index), id: `${database.name}_${table.name}`, - icon: , + icon: + table.type === TREE_ITEM_LOAD_MATERIALIZED_BADGE_NAME ? ( + MV + ) : table.type === TREE_ITEM_BADGE_NAME ? null : ( + + ), callback: () => { - if (table.values.length === 0) { + if ( + table.type !== TREE_ITEM_LOAD_MATERIALIZED_BADGE_NAME && + table.values?.length === 0 + ) { handleTableClick(table.name); } + if (table.values?.length === 0) { + table.values = [{ name: 'No Indicies', type: TREE_ITEM_BADGE_NAME, isExpanded: false }]; + } }, isSelectable: true, isExpanded: table.isExpanded, - children: table.values.map((indexChild) => ({ - label: createLabel(indexChild.name), + children: table.values?.map((indexChild,index) => ({ + label: createLabel(indexChild,table.name,index), id: `${database.name}_${table.name}_${indexChild.name}`, - icon: , - callback: () => - handleAccelerationIndexClick( - selectedItems[0].label, - database.name, - table.name, - indexChild.name - ), + icon: indexChild.type === TREE_ITEM_BADGE_NAME ? null : , + callback: () => { + if (indexChild.type !== TREE_ITEM_BADGE_NAME) { + handleAccelerationIndexClick( + selectedItems[0].label, + database.name, + table.name, + indexChild.name + ); + } + }, })), })), })); From e4d2455113487a2e04b42173df74f2f112935119 Mon Sep 17 00:00:00 2001 From: sumukhswamy Date: Wed, 18 Oct 2023 15:43:43 -0700 Subject: [PATCH 6/8] updated snapshots Signed-off-by: sumukhswamy --- .../Main/__snapshots__/main.test.tsx.snap | 248 +++++++++++++++++- 1 file changed, 234 insertions(+), 14 deletions(-) diff --git a/public/components/Main/__snapshots__/main.test.tsx.snap b/public/components/Main/__snapshots__/main.test.tsx.snap index baa291c8..8e976eff 100644 --- a/public/components/Main/__snapshots__/main.test.tsx.snap +++ b/public/components/Main/__snapshots__/main.test.tsx.snap @@ -193,7 +193,7 @@ exports[`
spec click clear button 1`] = ` >
spec click clear button 1`] = ` >
+ > +
+
+ +
+
+
+
@@ -715,7 +747,7 @@ exports[`
spec click run button, and response causes an error 1`] = ` >
spec click run button, and response causes an error 1`] = ` >
+ > +
+
+ +
+
+
+
@@ -1237,7 +1301,7 @@ exports[`
spec click run button, and response is not ok 1`] = ` >
spec click run button, and response is not ok 1`] = ` >
+ > +
+
+ +
+
+
+
@@ -1759,7 +1855,7 @@ exports[`
spec click run button, and response is ok 1`] = ` >
spec click run button, and response is ok 1`] = ` >
+ > +
+
+ +
+
+
+
@@ -2369,7 +2497,7 @@ exports[`
spec click run button, response fills null and missing values >
spec click run button, response fills null and missing values >
+ > +
+
+ +
+
+
+
@@ -2978,7 +3138,7 @@ exports[`
spec click translation button, and response is ok 1`] = ` >
spec click translation button, and response is ok 1`] = ` >
+ > +
+
+ +
+
+
+
@@ -3491,7 +3683,7 @@ exports[`
spec renders the component 1`] = ` >
spec renders the component 1`] = ` >
+ > +
+
+ +
+
+
+
From b9b1bff10956a99a0291547a25144c568ca1b0f2 Mon Sep 17 00:00:00 2001 From: sumukhswamy Date: Thu, 19 Oct 2023 20:29:32 -0700 Subject: [PATCH 7/8] added tests, addressed pr comments Signed-off-by: sumukhswamy --- .../Main/__snapshots__/main.test.tsx.snap | 8 +- public/components/Main/main.tsx | 2 +- .../__snapshots__/table_view.test.tsx.snap | 1016 +++++++++++++++++ public/components/SQLPage/table_view.test.tsx | 57 + .../SQLPage/{TableView.tsx => table_view.tsx} | 89 +- test/mocks/mockData.ts | 16 + 6 files changed, 1140 insertions(+), 48 deletions(-) create mode 100644 public/components/SQLPage/__snapshots__/table_view.test.tsx.snap create mode 100644 public/components/SQLPage/table_view.test.tsx rename public/components/SQLPage/{TableView.tsx => table_view.tsx} (86%) diff --git a/public/components/Main/__snapshots__/main.test.tsx.snap b/public/components/Main/__snapshots__/main.test.tsx.snap index 8e976eff..55c51e81 100644 --- a/public/components/Main/__snapshots__/main.test.tsx.snap +++ b/public/components/Main/__snapshots__/main.test.tsx.snap @@ -269,7 +269,7 @@ exports[`
spec click clear button 1`] = `

- Error loading Datasources + Error loading data

@@ -823,7 +823,7 @@ exports[`
spec click run button, and response causes an error 1`] = `

- Error loading Datasources + Error loading data

@@ -1377,7 +1377,7 @@ exports[`
spec click run button, and response is not ok 1`] = `

- Error loading Datasources + Error loading data

@@ -3214,7 +3214,7 @@ exports[`
spec click translation button, and response is ok 1`] = `

- Error loading Datasources + Error loading data

diff --git a/public/components/Main/main.tsx b/public/components/Main/main.tsx index e1517217..d77c94c2 100644 --- a/public/components/Main/main.tsx +++ b/public/components/Main/main.tsx @@ -36,7 +36,7 @@ import QueryResults from '../QueryResults/QueryResults'; import { CreateButton } from '../SQLPage/CreateButton'; import { DataSelect } from '../SQLPage/DataSelect'; import { SQLPage } from '../SQLPage/SQLPage'; -import { TableView } from '../SQLPage/TableView'; +import { TableView } from '../SQLPage/table_view'; interface ResponseData { ok: boolean; diff --git a/public/components/SQLPage/__snapshots__/table_view.test.tsx.snap b/public/components/SQLPage/__snapshots__/table_view.test.tsx.snap new file mode 100644 index 00000000..708a9063 --- /dev/null +++ b/public/components/SQLPage/__snapshots__/table_view.test.tsx.snap @@ -0,0 +1,1016 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Render databases in tree fetches and displays database nodes when datasource is s3 1`] = ` +
+
+
+
+ +
+

+ Error loading data +

+
+
+
+
+`; + +exports[`Render databases in tree fetches and displays indicies when datasource is OpenSearch 1`] = ` +
+
+
+
+

+ You can quickly navigate this list using arrow keys. +

+
    +
  • + +
    +
  • +
  • + +
    +
  • +
  • + +
    +
  • +
  • + +
    +
  • +
  • + +
    +
  • +
  • + +
    +
  • +
  • + +
    +
  • +
  • + +
    +
  • +
  • + +
    +
  • +
  • + +
    +
  • +
  • + +
    +
  • +
  • + +
    +
  • +
  • + +
    +
  • +
  • + +
    +
  • +
  • + +
    +
  • +
  • + +
    +
  • +
  • + +
    +
  • +
  • + +
    +
  • +
  • + +
    +
  • +
  • + +
    +
  • +
  • + +
    +
  • +
+
+
+
+
+`; diff --git a/public/components/SQLPage/table_view.test.tsx b/public/components/SQLPage/table_view.test.tsx new file mode 100644 index 00000000..3f602918 --- /dev/null +++ b/public/components/SQLPage/table_view.test.tsx @@ -0,0 +1,57 @@ +import '@testing-library/jest-dom'; +import React from 'react'; +import { httpClientMock } from '../../../test/mocks'; + +import '@testing-library/jest-dom/extend-expect'; +import { render, waitFor } from '@testing-library/react'; +import { HttpResponse } from '../../../../../src/core/public'; +import { mockDatabaseQuery, mockJobId, mockOpenSearchIndicies } from '../../../test/mocks/mockData'; +import { TableView } from './table_view'; + +describe('Render databases in tree', () => { + it('fetches and displays indicies when datasource is OpenSearch', async () => { + const client = httpClientMock; + client.post = jest.fn(() => { + return (Promise.resolve(mockOpenSearchIndicies) as unknown) as HttpResponse; + }); + + const asyncTest = () => { + render( + {}} + refreshTree={false} + /> + ); + }; + await asyncTest(); + expect(document.body.children[0]).toMatchSnapshot(); + }); + it('fetches and displays database nodes when datasource is s3', async () => { + const client = httpClientMock; + client.post = jest.fn(() => { + return (Promise.resolve(mockJobId) as unknown) as HttpResponse; + }); + client.get = jest.fn(() => { + return (Promise.resolve(mockDatabaseQuery) as unknown) as HttpResponse; + }); + + const { getByText } = render( + {}} + refreshTree={false} + /> + ); + await waitFor(() => { + expect( + getByText( + 'Loading can take more than 30s. Queries can be made after the data has loaded. Any queries run before the data is loaded will be queued' + ) + ).toBeInTheDocument(); + }); + expect(document.body.children[0]).toMatchSnapshot(); + }); +}); diff --git a/public/components/SQLPage/TableView.tsx b/public/components/SQLPage/table_view.tsx similarity index 86% rename from public/components/SQLPage/TableView.tsx rename to public/components/SQLPage/table_view.tsx index d416d70e..2519db33 100644 --- a/public/components/SQLPage/TableView.tsx +++ b/public/components/SQLPage/table_view.tsx @@ -13,7 +13,7 @@ import { EuiLoadingSpinner, EuiText, EuiToolTip, - EuiTreeView + EuiTreeView, } from '@elastic/eui'; import { TreeItem, TreeItemType } from 'common/types'; import _ from 'lodash'; @@ -28,7 +28,7 @@ import { TREE_ITEM_LOAD_MATERIALIZED_BADGE_NAME, TREE_ITEM_MATERIALIZED_VIEW_DEFAULT_NAME, TREE_ITEM_SKIPPING_INDEX_DEFAULT_NAME, - TREE_ITEM_TABLE_NAME_DEFAULT_NAME + TREE_ITEM_TABLE_NAME_DEFAULT_NAME, } from '../../../common/constants'; import { AccelerationIndexFlyout } from './acceleration_index_flyout'; import { getJobId, pollQueryStatus } from './utils'; @@ -80,7 +80,7 @@ export const TableView = ({ http, selectedItems, updateSQLQueries, refreshTree } if ( type != TREE_ITEM_COVERING_INDEX_DEFAULT_NAME && - type != TREE_ITEM_SKIPPING_INDEX_DEFAULT_NAME + type != TREE_ITEM_SKIPPING_INDEX_DEFAULT_NAME ) { treeItem.values = []; } @@ -146,7 +146,10 @@ export const TableView = ({ http, selectedItems, updateSQLQueries, refreshTree } get_async_query_results(id, http, (data) => { data = data.map((subArray) => subArray[1]); let values = loadTreeItem(data, TREE_ITEM_TABLE_NAME_DEFAULT_NAME); - let mvObj = loadTreeItem([TREE_ITEM_LOAD_MATERIALIZED_BADGE_NAME], TREE_ITEM_LOAD_MATERIALIZED_BADGE_NAME); + let mvObj = loadTreeItem( + [TREE_ITEM_LOAD_MATERIALIZED_BADGE_NAME], + TREE_ITEM_LOAD_MATERIALIZED_BADGE_NAME + ); values = [...values, ...mvObj]; setTreeData((prevTreeData) => { return prevTreeData.map((database) => { @@ -206,11 +209,12 @@ export const TableView = ({ http, selectedItems, updateSQLQueries, refreshTree } }; getJobId(materializedViewQuery, http, (id) => { get_async_query_results(id, http, (data) => { - console.log(data) data = data.map((subArray) => subArray[1]); let values = loadTreeItem(data, TREE_ITEM_MATERIALIZED_VIEW_DEFAULT_NAME); - if(values.length === 0){ - values = [{ name: 'No Materialized View', type: TREE_ITEM_BADGE_NAME, isExpanded: false }] + if (values.length === 0) { + values = [ + { name: 'No Materialized View', type: TREE_ITEM_BADGE_NAME, isExpanded: false }, + ]; } setTreeData((prevTreeData) => { return prevTreeData.map((database) => { @@ -226,8 +230,6 @@ export const TableView = ({ http, selectedItems, updateSQLQueries, refreshTree } setIsLoading(false); }); }); - - }; const handleTableClick = (tableName: string) => { @@ -270,29 +272,33 @@ export const TableView = ({ http, selectedItems, updateSQLQueries, refreshTree } }; const createLabel = (node: TreeItem, parentName: string, index: number) => { - if (node.type === TREE_ITEM_BADGE_NAME) { - return ( -
- - {_.truncate(node.name, { length: 50 })} - {' '} -
- ); - }else if(node.type === TREE_ITEM_LOAD_MATERIALIZED_BADGE_NAME) { - return ( -
- Load Materialized View -
- ); - } - else { - return ( -
- - {_.truncate(node.name, { length: 50 })} - {' '} -
- ); + switch (node.type) { + case TREE_ITEM_BADGE_NAME: + return ( +
+ + {_.truncate(node.name, { length: 50 })} + {' '} +
+ ); + + case TREE_ITEM_LOAD_MATERIALIZED_BADGE_NAME: + return ( +
+ + Load Materialized View + +
+ ); + + default: + return ( +
+ + {_.truncate(node.name, { length: 50 })} + {' '} +
+ ); } }; @@ -310,7 +316,7 @@ export const TableView = ({ http, selectedItems, updateSQLQueries, refreshTree } })); const treeDataDatabases = treeData.map((database, index) => ({ - label: createLabel(database,selectedItems[0].label,index), + label: createLabel(database, selectedItems[0].label, index), icon: , id: 'element_' + index, callback: () => { @@ -321,19 +327,16 @@ export const TableView = ({ http, selectedItems, updateSQLQueries, refreshTree } isSelectable: true, isExpanded: database.isExpanded, children: database.values?.map((table, index) => ({ - label: createLabel(table,database.name,index), + label: createLabel(table, database.name, index), id: `${database.name}_${table.name}`, icon: table.type === TREE_ITEM_LOAD_MATERIALIZED_BADGE_NAME ? ( - MV + MV ) : table.type === TREE_ITEM_BADGE_NAME ? null : ( ), callback: () => { - if ( - table.type !== TREE_ITEM_LOAD_MATERIALIZED_BADGE_NAME && - table.values?.length === 0 - ) { + if (table.type !== TREE_ITEM_LOAD_MATERIALIZED_BADGE_NAME && table.values?.length === 0) { handleTableClick(table.name); } if (table.values?.length === 0) { @@ -342,8 +345,8 @@ export const TableView = ({ http, selectedItems, updateSQLQueries, refreshTree } }, isSelectable: true, isExpanded: table.isExpanded, - children: table.values?.map((indexChild,index) => ({ - label: createLabel(indexChild,table.name,index), + children: table.values?.map((indexChild, index) => ({ + label: createLabel(indexChild, table.name, index), id: `${database.name}_${table.name}_${indexChild.name}`, icon: indexChild.type === TREE_ITEM_BADGE_NAME ? null : , callback: () => { @@ -368,7 +371,7 @@ export const TableView = ({ http, selectedItems, updateSQLQueries, refreshTree } - Loading databases + Loading data Loading can take more than 30s. Queries can be made after the data has loaded. Any @@ -389,7 +392,7 @@ export const TableView = ({ http, selectedItems, updateSQLQueries, refreshTree } Error loading Datasources} + title={

Error loading data

} />
)} diff --git a/test/mocks/mockData.ts b/test/mocks/mockData.ts index 65904eec..fee838f0 100644 --- a/test/mocks/mockData.ts +++ b/test/mocks/mockData.ts @@ -2349,4 +2349,20 @@ export const mockDatasourcesQuery = } } +export const mockJobId = { + data: { + ok: true, + resp: '{ "queryId": "00fe3fjpnfnn400q" }', + }, +}; + +export const mockOpenSearchIndicies = { + data: { + ok: true, + resp: + '{"schema":[{"name":"TABLE_CAT","type":"keyword"},{"name":"TABLE_SCHEM","type":"keyword"},{"name":"TABLE_NAME","type":"keyword"},{"name":"TABLE_TYPE","type":"keyword"},{"name":"REMARKS","type":"keyword"},{"name":"TYPE_CAT","type":"keyword"},{"name":"TYPE_SCHEM","type":"keyword"},{"name":"TYPE_NAME","type":"keyword"},{"name":"SELF_REFERENCING_COL_NAME","type":"keyword"},{"name":"REF_GENERATION","type":"keyword"}],"datarows":[["opensearch",null,".kibana_1","BASE TABLE",null,null,null,null,null,null],["opensearch",null,".kibana_2","BASE TABLE",null,null,null,null,null,null],["opensearch",null,".kibana_3","BASE TABLE",null,null,null,null,null,null],["opensearch",null,".opendistro-reports-definitions","BASE TABLE",null,null,null,null,null,null],["opensearch",null,".opendistro-reports-instances","BASE TABLE",null,null,null,null,null,null],["opensearch",null,".opensearch-observability","BASE TABLE",null,null,null,null,null,null],["opensearch",null,".plugins-ml-config","BASE TABLE",null,null,null,null,null,null],["opensearch",null,".ql-datasources","BASE TABLE",null,null,null,null,null,null],["opensearch",null,".ql-job-metadata","BASE TABLE",null,null,null,null,null,null],["opensearch",null,".query_execution_result","BASE TABLE",null,null,null,null,null,null],["opensearch",null,"flint_mys3_default_alb_logs_temp_10_test_index","BASE TABLE",null,null,null,null,null,null],["opensearch",null,"flint_mys3_default_alb_logs_temp_5_mys3_default_alb_logs_temp_5_index","BASE TABLE",null,null,null,null,null,null],["opensearch",null,"flint_mys3_default_elb_logs_regex_elb_logs_regex_index_index","BASE TABLE",null,null,null,null,null,null],["opensearch",null,"flint_mys3_default_empty_table_empty_table_index_index","BASE TABLE",null,null,null,null,null,null],["opensearch",null,"flint_mys3_default_http_logs_skipping_index","BASE TABLE",null,null,null,null,null,null],["opensearch",null,"flint_mys3_default_parquet_elb_logs_simple_parquet_index_simple_index","BASE TABLE",null,null,null,null,null,null],["opensearch",null,"opensearch_dashboards_sample_data_flights","BASE TABLE",null,null,null,null,null,null],["opensearch",null,"opensearch_dashboards_sample_data_logs","BASE TABLE",null,null,null,null,null,null],["opensearch",null,"ss4o_traces-elb-test","BASE TABLE",null,null,null,null,null,null],["opensearch",null,".flint-elv-mv","BASE TABLE",null,null,null,null,null,null],["opensearch",null,".kibana","BASE TABLE",null,null,null,null,null,null]],"total":21,"size":21,"status":200}', + }, +}; + + From 49d86e71676a78d6f59add4e14d3c4d11eac0e02 Mon Sep 17 00:00:00 2001 From: sumukhswamy Date: Fri, 20 Oct 2023 11:19:45 -0700 Subject: [PATCH 8/8] added fix for text overflowing Signed-off-by: sumukhswamy --- .../Main/__snapshots__/main.test.tsx.snap | 16 ++++++++-------- .../__snapshots__/table_view.test.tsx.snap | 4 ++-- public/components/SQLPage/table_view.tsx | 4 +++- 3 files changed, 13 insertions(+), 11 deletions(-) diff --git a/public/components/Main/__snapshots__/main.test.tsx.snap b/public/components/Main/__snapshots__/main.test.tsx.snap index 55c51e81..6d65fd66 100644 --- a/public/components/Main/__snapshots__/main.test.tsx.snap +++ b/public/components/Main/__snapshots__/main.test.tsx.snap @@ -266,11 +266,11 @@ exports[`
spec click clear button 1`] = `
-

Error loading data -

+
@@ -820,11 +820,11 @@ exports[`
spec click run button, and response causes an error 1`] = `
-

Error loading data -

+
@@ -1374,11 +1374,11 @@ exports[`
spec click run button, and response is not ok 1`] = `
-

Error loading data -

+
@@ -3211,11 +3211,11 @@ exports[`
spec click translation button, and response is ok 1`] = `
-

Error loading data -

+
diff --git a/public/components/SQLPage/__snapshots__/table_view.test.tsx.snap b/public/components/SQLPage/__snapshots__/table_view.test.tsx.snap index 708a9063..6b8be8c2 100644 --- a/public/components/SQLPage/__snapshots__/table_view.test.tsx.snap +++ b/public/components/SQLPage/__snapshots__/table_view.test.tsx.snap @@ -29,11 +29,11 @@ exports[`Render databases in tree fetches and displays database nodes when datas
-

Error loading data -

+
diff --git a/public/components/SQLPage/table_view.tsx b/public/components/SQLPage/table_view.tsx index 2519db33..eb2a44bf 100644 --- a/public/components/SQLPage/table_view.tsx +++ b/public/components/SQLPage/table_view.tsx @@ -373,10 +373,12 @@ export const TableView = ({ http, selectedItems, updateSQLQueries, refreshTree } Loading data +
Loading can take more than 30s. Queries can be made after the data has loaded. Any queries run before the data is loaded will be queued +
) : OpenSearchIndicesTree.length > 0 || treeDataDatabases.length > 0 ? ( @@ -392,7 +394,7 @@ export const TableView = ({ http, selectedItems, updateSQLQueries, refreshTree } Error loading data} + title={

Error loading data

} /> )}