From 786c7c7a0d42b1e6531d3af8bfe691d60561792f Mon Sep 17 00:00:00 2001 From: "opensearch-trigger-bot[bot]" <98922864+opensearch-trigger-bot[bot]@users.noreply.github.com> Date: Mon, 23 Oct 2023 19:53:58 -0700 Subject: [PATCH] design changes for loading, changed the banner, updated tests (#170) (#172) (cherry picked from commit dcff236853e92907ed36e52f948d68795497e419) Signed-off-by: sumukhswamy Signed-off-by: github-actions[bot] Co-authored-by: github-actions[bot] --- common/types/index.ts | 6 + common/utils/async_query_helpers.ts | 5 +- .../Main/__snapshots__/main.test.tsx.snap | 214 ++++++++------- public/components/Main/main.tsx | 6 +- .../__snapshots__/table_view.test.tsx.snap | 50 ++-- public/components/SQLPage/table_view.test.tsx | 33 +-- public/components/SQLPage/table_view.tsx | 254 ++++++++++++------ test/mocks/mockData.ts | 6 + 8 files changed, 346 insertions(+), 228 deletions(-) diff --git a/common/types/index.ts b/common/types/index.ts index 5ed212c8..17208cc3 100644 --- a/common/types/index.ts +++ b/common/types/index.ts @@ -87,4 +87,10 @@ export interface TreeItem { type: TreeItemType; isExpanded: boolean; values?: TreeItem[]; + isLoading?: boolean +} + +export interface isLoading { + flag: boolean; + status: string; } diff --git a/common/utils/async_query_helpers.ts b/common/utils/async_query_helpers.ts index 689727b3..3731859e 100644 --- a/common/utils/async_query_helpers.ts +++ b/common/utils/async_query_helpers.ts @@ -47,12 +47,13 @@ export const pollQueryStatus = (id: string, http: CoreStart['http'], callback) = status === 'scheduled' || status === 'waiting' ) { + callback({status: status}) setTimeout(() => pollQueryStatus(id, http, callback), POLL_INTERVAL_MS); } else if (status === 'failed') { - callback([]); + callback({ status: 'FAILED', results: [] }); } else if (status === 'success') { const results = _.get(res.data.resp, 'datarows'); - callback(results); + callback({ status: 'SUCCESS', results: results }); } }) .catch((err) => { diff --git a/public/components/Main/__snapshots__/main.test.tsx.snap b/public/components/Main/__snapshots__/main.test.tsx.snap index f34fea4e..3b7c236c 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`] = ` class="euiFlexGroup euiFlexGroup--gutterLarge euiFlexGroup--directionRow euiFlexGroup--responsive" >
-
-

- Error loading data -

+ +
+

+ Error loading data +

+
@@ -746,7 +750,7 @@ exports[`
spec click run button, and response causes an error 1`] = ` >
spec click run button, and response causes an error 1`] = ` class="euiFlexGroup euiFlexGroup--gutterLarge euiFlexGroup--directionRow euiFlexGroup--responsive" >
-
-

- Error loading data -

+ +
+

+ Error loading data +

+
@@ -1299,7 +1307,7 @@ exports[`
spec click run button, and response is not ok 1`] = ` >
spec click run button, and response is not ok 1`] = ` class="euiFlexGroup euiFlexGroup--gutterLarge euiFlexGroup--directionRow euiFlexGroup--responsive" >
-
-

- Error loading data -

+ +
+

+ Error loading data +

+
@@ -1852,7 +1864,7 @@ exports[`
spec click run button, and response is ok 1`] = ` >
spec click run button, response fills null and missing values >
spec click translation button, and response is ok 1`] = ` >
spec click translation button, and response is ok 1`] = ` class="euiFlexGroup euiFlexGroup--gutterLarge euiFlexGroup--directionRow euiFlexGroup--responsive" >
-
-

- Error loading data -

+ +
+

+ Error loading data +

+
@@ -3677,7 +3693,7 @@ exports[`
spec renders the component 1`] = ` >
{ {this.state.language === 'SQL' && ( - - + + diff --git a/public/components/SQLPage/__snapshots__/table_view.test.tsx.snap b/public/components/SQLPage/__snapshots__/table_view.test.tsx.snap index 6b8be8c2..56a16514 100644 --- a/public/components/SQLPage/__snapshots__/table_view.test.tsx.snap +++ b/public/components/SQLPage/__snapshots__/table_view.test.tsx.snap @@ -6,34 +6,38 @@ exports[`Render databases in tree fetches and displays database nodes when datas class="euiFlexGroup euiFlexGroup--gutterLarge euiFlexGroup--directionRow euiFlexGroup--responsive" >
-
-

- Error loading data -

+ +
+

+ Error loading data +

+
diff --git a/public/components/SQLPage/table_view.test.tsx b/public/components/SQLPage/table_view.test.tsx index 3f602918..976291c9 100644 --- a/public/components/SQLPage/table_view.test.tsx +++ b/public/components/SQLPage/table_view.test.tsx @@ -3,7 +3,8 @@ import React from 'react'; import { httpClientMock } from '../../../test/mocks'; import '@testing-library/jest-dom/extend-expect'; -import { render, waitFor } from '@testing-library/react'; +import { render } from '@testing-library/react'; +import { isLoading } from 'common/types'; import { HttpResponse } from '../../../../../src/core/public'; import { mockDatabaseQuery, mockJobId, mockOpenSearchIndicies } from '../../../test/mocks/mockData'; import { TableView } from './table_view'; @@ -30,6 +31,10 @@ describe('Render databases in tree', () => { }); it('fetches and displays database nodes when datasource is s3', async () => { const client = httpClientMock; + const isLoading: isLoading = { + flag: false, + status: 'Not loading', + } client.post = jest.fn(() => { return (Promise.resolve(mockJobId) as unknown) as HttpResponse; }); @@ -37,21 +42,17 @@ describe('Render databases in tree', () => { 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(); - }); + const asyncTest = () => { + render( + {}} + refreshTree={false} + /> + ); + }; + await asyncTest(); expect(document.body.children[0]).toMatchSnapshot(); }); }); diff --git a/public/components/SQLPage/table_view.tsx b/public/components/SQLPage/table_view.tsx index c1e0fbf6..ab4014ea 100644 --- a/public/components/SQLPage/table_view.tsx +++ b/public/components/SQLPage/table_view.tsx @@ -11,11 +11,12 @@ import { EuiFlexItem, EuiIcon, EuiLoadingSpinner, + EuiSpacer, EuiText, EuiToolTip, EuiTreeView, } from '@elastic/eui'; -import { TreeItem, TreeItemType } from 'common/types'; +import { TreeItem, TreeItemType, isLoading } from 'common/types'; import _ from 'lodash'; import React, { useEffect, useState } from 'react'; import { CoreStart } from '../../../../../src/core/public'; @@ -44,7 +45,10 @@ export const TableView = ({ http, selectedItems, updateSQLQueries, refreshTree } const [tableNames, setTableNames] = useState([]); const [selectedDatabase, setSelectedDatabase] = useState(''); const [selectedTable, setSelectedTable] = useState(null); - const [isLoading, setIsLoading] = useState(false); + const [isLoadingBanner, setIsLoading] = useState({ + flag: false, + status: 'Not loading', + }); const [indexFlyout, setIndexFlyout] = useState(<>); const [treeData, setTreeData] = useState([]); @@ -75,7 +79,7 @@ export const TableView = ({ http, selectedItems, updateSQLQueries, refreshTree } let treeItem: TreeItem = { name: element, type: type, - isExpanded: true, + isExpanded: false, }; if ( @@ -83,6 +87,7 @@ export const TableView = ({ http, selectedItems, updateSQLQueries, refreshTree } type != TREE_ITEM_SKIPPING_INDEX_DEFAULT_NAME ) { treeItem.values = []; + treeItem.isLoading = false; } return treeItem; }); @@ -112,7 +117,6 @@ export const TableView = ({ http, selectedItems, updateSQLQueries, refreshTree } console.error(err); }); } else { - setIsLoading(true); setTableNames([]); const query = { lang: 'sql', @@ -120,23 +124,36 @@ export const TableView = ({ http, selectedItems, updateSQLQueries, refreshTree } datasource: selectedItems[0]['label'], }; getJobId(query, http, (id) => { - get_async_query_results(id, http, (data) => { - data = [].concat(...data); - setTreeData(loadTreeItem(data, TREE_ITEM_DATABASE_NAME_DEFAULT_NAME)); - setIsLoading(false); + pollQueryStatus(id, http, (data) => { + setIsLoading({ flag: true, status: data.status }); + if (data.status === 'SUCCESS') { + const fetchedDatanases = [].concat(...data.results); + setTreeData(loadTreeItem(fetchedDatanases, TREE_ITEM_DATABASE_NAME_DEFAULT_NAME)); + setIsLoading({ flag: false, status: data.status }); + } }); }); } }; useEffect(() => { - setIsLoading(false); + setIsLoading({ + flag: false, + status: 'Not loading', + }); getSidebarContent(); }, [selectedItems, refreshTree]); const handleDatabaseClick = (databaseName: string) => { + setTreeData((prevTreeData) => { + return prevTreeData.map((database) => { + if (database.name === databaseName) { + return { ...database, isExpanded: true, isLoading: true }; + } + return database; + }); + }); setSelectedDatabase(databaseName); - setIsLoading(true); const query = { lang: 'sql', query: `SHOW TABLES IN ${selectedItems[0]['label']}.${databaseName}`, @@ -144,22 +161,23 @@ export const TableView = ({ http, selectedItems, updateSQLQueries, refreshTree } }; getJobId(query, http, (id) => { 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 - ); - values = [...values, ...mvObj]; - setTreeData((prevTreeData) => { - return prevTreeData.map((database) => { - if (database.name === databaseName) { - return { ...database, values: values }; - } - return database; + if (data.status === 'SUCCESS') { + const fetchTables = data.results.map((subArray) => subArray[1]); + let values = loadTreeItem(fetchTables, 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) { + return { ...database, values: values, isExpanded: true, isLoading: false}; + } + return database; + }); }); - }); - setIsLoading(false); + } }); }); }; @@ -172,28 +190,31 @@ export const TableView = ({ http, selectedItems, updateSQLQueries, refreshTree } }; getJobId(coverQuery, http, (id) => { get_async_query_results(id, http, (data) => { - const res = [].concat(data); - 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; + if (data.status === 'SUCCESS') { + const res = [].concat(data.results); + 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), + isLoading: false, + isExpanded: true, + }; + } + return table; + }), + }; + } + return database; + }); }); - }); - setIsLoading(false); + } }); }); }; @@ -201,7 +222,25 @@ export const TableView = ({ http, selectedItems, updateSQLQueries, refreshTree } const handleButtonClick = (e: MouseEvent, tableName: string) => { e.stopPropagation(); setSelectedTable(tableName); - setIsLoading(true); + setTreeData((prevTreeData) => { + return prevTreeData.map((database) => { + if (database.name === selectedDatabase) { + return { + ...database, + values: database.values?.map((table) => { + if (table.name === tableName) { + return { + ...table, + isLoading: true, + }; + } + return table; + }), + }; + } + return database; + }); + }); const materializedViewQuery = { lang: 'sql', query: `SHOW MATERIALIZED VIEW IN ${selectedItems[0]['label']}.${selectedDatabase}`, @@ -209,32 +248,56 @@ export const TableView = ({ http, selectedItems, updateSQLQueries, refreshTree } }; getJobId(materializedViewQuery, http, (id) => { get_async_query_results(id, http, (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; + if (data.status === 'SUCCESS') { + const fetchMaterialzedView = data.results.map((subArray) => subArray[1]); + let values = loadTreeItem(fetchMaterialzedView, TREE_ITEM_MATERIALIZED_VIEW_DEFAULT_NAME); + if (values.length === 0) { + values = [ + { + name: 'No Materialized View', + type: TREE_ITEM_BADGE_NAME, + isExpanded: false, + isLoading: 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), isLoading: false , isExpanded: true}; + } + return database; + }); }); - }); - setIsLoading(false); + } }); }); }; const handleTableClick = (tableName: string) => { setSelectedTable(tableName); - setIsLoading(true); + setTreeData((prevTreeData) => { + return prevTreeData.map((database) => { + if (database.name === selectedDatabase) { + return { + ...database, + values: database.values?.map((table) => { + if (table.name === tableName) { + return { + ...table, + isLoading: true, + }; + } + return table; + }), + }; + } + return database; + }); + }); const skipQuery = { lang: 'sql', query: `DESC SKIPPING INDEX ON ${selectedItems[0]['label']}.${selectedDatabase}.${tableName}`, @@ -242,7 +305,7 @@ export const TableView = ({ http, selectedItems, updateSQLQueries, refreshTree } }; getJobId(skipQuery, http, (id) => { get_async_query_results(id, http, (data) => { - if (data.length > 0) { + if (data.status === 'SUCCESS') { setTreeData((prevTreeData) => { return prevTreeData.map((database) => { if (database.name === selectedDatabase) { @@ -265,8 +328,8 @@ export const TableView = ({ http, selectedItems, updateSQLQueries, refreshTree } return database; }); }); + loadCoveringIndex(tableName); } - loadCoveringIndex(tableName); }); }); }; @@ -288,6 +351,7 @@ export const TableView = ({ http, selectedItems, updateSQLQueries, refreshTree } Load Materialized View + {node.isLoading && }
); @@ -295,8 +359,15 @@ export const TableView = ({ http, selectedItems, updateSQLQueries, refreshTree } return (
- {_.truncate(node.name, { length: 50 })} - {' '} + + + + {_.truncate(node.name, { length: 50 })}{' '} + {node.isLoading && } + + + +
); } @@ -331,7 +402,7 @@ export const TableView = ({ http, selectedItems, updateSQLQueries, refreshTree } id: `${database.name}_${table.name}`, icon: table.type === TREE_ITEM_LOAD_MATERIALIZED_BADGE_NAME ? ( - MV + null ) : table.type === TREE_ITEM_BADGE_NAME ? null : ( ), @@ -339,9 +410,12 @@ export const TableView = ({ http, selectedItems, updateSQLQueries, refreshTree } 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 }]; + else { + if(table.values?.length === 0) { + table.values = [{ name: 'No Indicies', type: TREE_ITEM_BADGE_NAME, isExpanded: false }]; + } } + }, isSelectable: true, isExpanded: table.isExpanded, @@ -366,18 +440,25 @@ export const TableView = ({ http, selectedItems, updateSQLQueries, refreshTree } return ( <> - {isLoading ? ( + {isLoadingBanner.flag ? ( + 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 - + + + Loading may take over 30 seconds + + + + + Status: {isLoadingBanner.status} + +
@@ -390,13 +471,16 @@ export const TableView = ({ http, selectedItems, updateSQLQueries, refreshTree } )} ) : ( - - Error loading data} - /> - + + + Error loading data} + /> + + )} {indexFlyout}
diff --git a/test/mocks/mockData.ts b/test/mocks/mockData.ts index fee838f0..9a01e0fa 100644 --- a/test/mocks/mockData.ts +++ b/test/mocks/mockData.ts @@ -2364,5 +2364,11 @@ export const mockOpenSearchIndicies = { }, }; +export const mockDatabaseQuery = { + data: { + ok: true, + resp: "{ \"schema\": [ { \"name\": \"namespace\", \"type\": \"string\" } ], \"datarows\": [ [ \"default\" ] ], \"total\": 1, \"size\": 1}" + }, +};