From 621b82e730e305e82b43895d6f6d1c70127a5ecb Mon Sep 17 00:00:00 2001 From: Shenoy Pratik <sgguruda@amazon.com> Date: Wed, 4 Oct 2023 10:20:32 -0700 Subject: [PATCH] Acceleration related changes and minor fixes (#135) * add acc index flyout Signed-off-by: Shenoy Pratik <sgguruda@amazon.com> * remove [if not exists] from acc creation Signed-off-by: Shenoy Pratik <sgguruda@amazon.com> * merge tableview from main Signed-off-by: Shenoy Pratik <sgguruda@amazon.com> * adding acc index flyout Signed-off-by: Shenoy Pratik <sgguruda@amazon.com> * add hash router Signed-off-by: Shenoy Pratik <sgguruda@amazon.com> * hide materialized view index type Signed-off-by: Shenoy Pratik <sgguruda@amazon.com> * update snapshots Signed-off-by: Shenoy Pratik <sgguruda@amazon.com> * loading combo boxes for acc flyout Signed-off-by: Shenoy Pratik <sgguruda@amazon.com> * adding acceleration backend integ Signed-off-by: Shenoy Pratik <sgguruda@amazon.com> * update jest tests for acc flyout Signed-off-by: Shenoy Pratik <sgguruda@amazon.com> * add redirection support for home page Signed-off-by: Shenoy Pratik <sgguruda@amazon.com> * fix primary shards count and replica validation Signed-off-by: Shenoy Pratik <sgguruda@amazon.com> * remove the caution callout for acc flyout Signed-off-by: Shenoy Pratik <sgguruda@amazon.com> * support acc flyout redirection from data sources Signed-off-by: Shenoy Pratik <sgguruda@amazon.com> --------- Signed-off-by: Shenoy Pratik <sgguruda@amazon.com> --- common/constants/index.ts | 2 +- public/components/Main/main.tsx | 26 +++- public/components/SQLPage/DataSelect.tsx | 23 ++- public/components/SQLPage/SQLPage.tsx | 31 ++-- public/components/SQLPage/TableView.tsx | 49 +++++-- .../__snapshots__/SQLPage.test.tsx.snap | 1 + .../SQLPage/acceleration_index_flyout.tsx | 132 ++++++++++++++++++ .../caution_banner_callout.test.tsx.snap | 39 ------ .../create_acceleration.test.tsx.snap | 77 +--------- .../__tests__/caution_banner_callout.test.tsx | 28 ---- .../__tests__/create_acceleration.test.tsx | 10 +- .../create/__tests__/utils.test.tsx | 4 +- .../create/caution_banner_callout.tsx | 17 --- .../create/create_acceleration.tsx | 17 ++- .../components/acceleration/create/utils.tsx | 2 +- .../index_setting_options.test.tsx.snap | 12 +- .../source_selector.test.tsx.snap | 13 +- .../__tests__/source_selector.test.tsx | 15 ++ .../selectors/index_setting_options.tsx | 8 +- .../selectors/index_type_selector.tsx | 51 ++++++- .../selectors/source_selector.tsx | 132 ++++++++++-------- .../query_visual_editor.test.tsx.snap | 28 ---- .../covering_index_builder.test.tsx.snap | 28 ---- .../covering_index/covering_index_builder.tsx | 3 - .../materialized_view_builder.test.tsx.snap | 28 ---- .../materialized_view/add_column_popover.tsx | 2 +- .../materialized_view_builder.tsx | 4 - .../visual_editors/query_builder.tsx | 8 +- public/components/app.tsx | 70 +++++++--- test/mocks/accelerationMock.ts | 10 +- 30 files changed, 470 insertions(+), 400 deletions(-) create mode 100644 public/components/SQLPage/acceleration_index_flyout.tsx delete mode 100644 public/components/acceleration/create/__tests__/__snapshots__/caution_banner_callout.test.tsx.snap delete mode 100644 public/components/acceleration/create/__tests__/caution_banner_callout.test.tsx delete mode 100644 public/components/acceleration/create/caution_banner_callout.tsx diff --git a/common/constants/index.ts b/common/constants/index.ts index 8533039d..6a796871 100644 --- a/common/constants/index.ts +++ b/common/constants/index.ts @@ -13,7 +13,7 @@ export const ON_LOAD_QUERY = `SHOW tables LIKE '%';`; export const ACCELERATION_INDEX_TYPES = [ { label: 'Skipping Index', value: 'skipping' }, { label: 'Covering Index', value: 'covering' }, - { label: 'Materialized View', value: 'materialized' }, + // { label: 'Materialized View', value: 'materialized' }, Hidden Option -> Until opensearch-spark feature is ready ]; export const ACCELERATION_AGGREGRATION_FUNCTIONS = [ diff --git a/public/components/Main/main.tsx b/public/components/Main/main.tsx index f79c42db..789e8404 100644 --- a/public/components/Main/main.tsx +++ b/public/components/Main/main.tsx @@ -14,7 +14,7 @@ import { EuiPageSideBar, EuiPanel, EuiSpacer, - EuiText + EuiText, } from '@elastic/eui'; import { IHttpResponse } from 'angular'; import _ from 'lodash'; @@ -83,6 +83,8 @@ export type DataRow = { interface MainProps { httpClient: CoreStart['http']; setBreadcrumbs: (newBreadcrumbs: ChromeBreadcrumb[]) => void; + isAccelerationFlyoutOpen: boolean; + urlDataSource: string; } interface MainState { @@ -417,7 +419,11 @@ export class Main extends React.Component<MainProps, MainState> { queries.map((query: string) => this.httpClient .post(endpoint, { - body: JSON.stringify({ lang: language, query: query, datasource: this.state.selectedDatasource[0].label}), // 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({ @@ -796,8 +802,11 @@ export class Main extends React.Component<MainProps, MainState> { if (this.state.language == 'SQL') { page = ( <SQLPage + http={this.httpClient} onRun={ - _.isEqual(this.state.selectedDatasource[0].label, 'OpenSearch') ? this.onRun : this.onRunAsync + _.isEqual(this.state.selectedDatasource[0].label, 'OpenSearch') + ? this.onRun + : this.onRunAsync } onTranslate={this.onTranslate} onClear={this.onClear} @@ -814,7 +823,9 @@ export class Main extends React.Component<MainProps, MainState> { page = ( <PPLPage onRun={ - _.isEqual(this.state.selectedDatasource[0].label, 'OpenSearch') ? this.onRun : this.onRunAsync + _.isEqual(this.state.selectedDatasource[0].label, 'OpenSearch') + ? this.onRun + : this.onRunAsync } onTranslate={this.onTranslate} onClear={this.onClear} @@ -876,7 +887,11 @@ export class Main extends React.Component<MainProps, MainState> { <EuiFlexGroup direction="row" alignItems="center"> <EuiFlexItem> <EuiText>Data Sources</EuiText> - <DataSelect http={this.httpClient} onSelect={this.handleDataSelect} /> + <DataSelect + http={this.httpClient} + onSelect={this.handleDataSelect} + urlDataSource={this.props.urlDataSource} + /> <EuiSpacer /> </EuiFlexItem> <EuiFlexItem grow={false}> @@ -903,6 +918,7 @@ export class Main extends React.Component<MainProps, MainState> { <TableView http={this.httpClient} selectedItems={this.state.selectedDatasource} + updateSQLQueries={this.updateSQLQueries} /> <EuiSpacer /> </EuiFlexItem> diff --git a/public/components/SQLPage/DataSelect.tsx b/public/components/SQLPage/DataSelect.tsx index bc63607a..0fe25e03 100644 --- a/public/components/SQLPage/DataSelect.tsx +++ b/public/components/SQLPage/DataSelect.tsx @@ -10,13 +10,18 @@ import { CoreStart } from '../../../../../src/core/public'; interface CustomView { http: CoreStart['http']; onSelect: (selectedItems: []) => void; + urlDataSource: string; } -export const DataSelect = ({ http, onSelect }: CustomView) => { - const [selectedOptions, setSelectedOptions] = useState<EuiComboBoxOptionOption[]>([{ label: 'OpenSearch' }]); +export const DataSelect = ({ http, onSelect, urlDataSource }: CustomView) => { + const [selectedOptions, setSelectedOptions] = useState<EuiComboBoxOptionOption[]>([ + { label: 'OpenSearch' }, + ]); const [options, setOptions] = useState<any[]>([]); const datasources = () => { + let dataOptions: EuiComboBoxOptionOption[] = []; + let urlSourceFound = false; http .get(`/api/get_datasources`) .then((res) => { @@ -34,21 +39,29 @@ export const DataSelect = ({ http, onSelect }: CustomView) => { } connectorGroups[connector].push(name); + if (name === urlDataSource) { + urlSourceFound = true; + } } }); - options.push({ label: 'OpenSearch' }); + dataOptions.push({ label: 'OpenSearch' }); + for (const connector in connectorGroups) { if (connectorGroups.hasOwnProperty(connector)) { const connectorNames = connectorGroups[connector]; - options.push({ + dataOptions.push({ label: connector, options: connectorNames.map((name) => ({ label: name })), }); } } - setOptions(options); + setOptions(dataOptions); + if (urlSourceFound) { + setSelectedOptions([{ label: urlDataSource }]); + onSelect([{ label: urlDataSource }]); + } }) .catch((err) => { console.error(err); diff --git a/public/components/SQLPage/SQLPage.tsx b/public/components/SQLPage/SQLPage.tsx index b0f1eb5c..6deab093 100644 --- a/public/components/SQLPage/SQLPage.tsx +++ b/public/components/SQLPage/SQLPage.tsx @@ -7,6 +7,7 @@ import { EuiButton, EuiCodeBlock, EuiCodeEditor, + EuiComboBoxOptionOption, EuiFlexGroup, EuiFlexItem, EuiModal, @@ -21,18 +22,20 @@ import { import 'brace/ext/language_tools'; import 'brace/mode/sql'; import React from 'react'; +import { CoreStart } from '../../../../../src/core/public'; import '../../ace-themes/sql_console'; import { ResponseDetail, TranslateResult } from '../Main/main'; import { CreateAcceleration } from '../acceleration/create/create_acceleration'; interface SQLPageProps { + http: CoreStart['http']; onRun: (query: string) => void; onTranslate: (query: string) => void; onClear: () => void; updateSQLQueries: (query: string) => void; sqlQuery: string; sqlTranslations: ResponseDetail<TranslateResult>[]; - selectedDatasource: string; + selectedDatasource: EuiComboBoxOptionOption[]; asyncLoading: boolean; } @@ -68,7 +71,8 @@ export class SQLPage extends React.Component<SQLPageProps, SQLPageState> { this.setState({ flyoutComponent: ( <CreateAcceleration - dataSource="ds" + http={this.props.http} + selectedDatasource={this.props.selectedDatasource} resetFlyout={this.resetFlyout} updateQueries={this.props.updateSQLQueries} /> @@ -170,17 +174,18 @@ export class SQLPage extends React.Component<SQLPageProps, SQLPageState> { </EuiFlexItem> </EuiFlexGroup> </EuiFlexItem> - {this.props.selectedDatasource === 'S3' && ( - <EuiFlexItem grow={false}> - <EuiButton - fill={true} - className="sql-accelerate-button" - onClick={this.setAccelerationFlyout} - > - Accelerate Table - </EuiButton> - </EuiFlexItem> - )} + {this.props.selectedDatasource && + this.props.selectedDatasource[0].label !== 'OpenSearch' && ( + <EuiFlexItem grow={false}> + <EuiButton + fill={true} + className="sql-accelerate-button" + onClick={this.setAccelerationFlyout} + > + Accelerate Table + </EuiButton> + </EuiFlexItem> + )} </EuiFlexGroup> </EuiPanel> {modal} diff --git a/public/components/SQLPage/TableView.tsx b/public/components/SQLPage/TableView.tsx index 3f168ccd..fcc78657 100644 --- a/public/components/SQLPage/TableView.tsx +++ b/public/components/SQLPage/TableView.tsx @@ -3,26 +3,51 @@ * SPDX-License-Identifier: Apache-2.0 */ -import { EuiEmptyPrompt, EuiIcon, EuiTreeView } from '@elastic/eui'; +import { EuiComboBoxOptionOption, 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 { AccelerationIndexFlyout } from './acceleration_index_flyout'; import { getJobId, pollQueryStatus } from './utils'; interface CustomView { http: CoreStart['http']; - selectedItems: any[]; + selectedItems: EuiComboBoxOptionOption[]; + updateSQLQueries: (query: string) => void; } -export const TableView = ({ http, selectedItems }: CustomView) => { +export const TableView = ({ http, selectedItems, updateSQLQueries }: CustomView) => { const [tablenames, setTablenames] = useState<string[]>([]); const [selectedNode, setSelectedNode] = useState<string | null>(null); const [childData, setChildData] = useState<string[]>([]); const [selectedChildNode, setSelectedChildNode] = useState<string | null>(null); const [indexData, setIndexedData] = useState<string[]>([]); const [isLoading, setIsLoading] = useState(false); - const [indiciesData, setIndiciesData] = useState<string []>([]); + const [indiciesData, setIndiciesData] = useState<string[]>([]); + const [indexFlyout, setIndexFlyout] = useState(<></>); + + const resetFlyout = () => { + setIndexFlyout(<></>); + }; + + const handleAccelerationIndexClick = ( + dataSource: string, + database: string, + dataTable: string, + indexName: string + ) => { + setIndexFlyout( + <AccelerationIndexFlyout + dataSource={dataSource} + database={database} + dataTable={dataTable} + indexName={indexName} + resetFlyout={resetFlyout} + updateSQLQueries={updateSQLQueries} + /> + ); + }; const get_async_query_results = (id, http, callback) => { pollQueryStatus(id, http, callback); @@ -64,7 +89,7 @@ export const TableView = ({ http, selectedItems }: CustomView) => { useEffect(() => { getSidebarContent(); - }, [selectedItems[0]['label']]); + }, [selectedItems]); const handleNodeClick = (nodeLabel: string) => { setSelectedNode(nodeLabel); @@ -89,8 +114,8 @@ export const TableView = ({ http, selectedItems }: CustomView) => { }; getJobId(coverQuery, http, (id) => { get_async_query_results(id, http, (data) => { - data = [].concat(...data) - indiciesData.push(data) + data = [].concat(...data); + indiciesData.push(data); setIndexedData(indiciesData); }); }); @@ -105,7 +130,7 @@ export const TableView = ({ http, selectedItems }: CustomView) => { getJobId(skipQuery, http, (id) => { get_async_query_results(id, http, (data) => { if (data.length > 0) { - indiciesData.push('skip_index'); + indiciesData.push('skip_index'); callCoverQuery(nodeLabel1); } }); @@ -141,6 +166,13 @@ export const TableView = ({ http, selectedItems }: CustomView) => { label: indexChild, id: `${table}_${indexChild}`, icon: <EuiIcon type="bolt" size="s" />, + callback: () => + handleAccelerationIndexClick( + selectedItems[0].label, + database, + table, + indexChild + ), })) : undefined, })) @@ -158,6 +190,7 @@ export const TableView = ({ http, selectedItems }: CustomView) => { title={<h2>Error loading Datasources</h2>} /> )} + {indexFlyout} </> ); }; diff --git a/public/components/SQLPage/__snapshots__/SQLPage.test.tsx.snap b/public/components/SQLPage/__snapshots__/SQLPage.test.tsx.snap index 96850ed5..603e920f 100644 --- a/public/components/SQLPage/__snapshots__/SQLPage.test.tsx.snap +++ b/public/components/SQLPage/__snapshots__/SQLPage.test.tsx.snap @@ -188,6 +188,7 @@ exports[`<SQLPage /> spec renders the component 1`] = ` </div> </div> </div> + </div> </div> </div> diff --git a/public/components/SQLPage/acceleration_index_flyout.tsx b/public/components/SQLPage/acceleration_index_flyout.tsx new file mode 100644 index 00000000..9b855384 --- /dev/null +++ b/public/components/SQLPage/acceleration_index_flyout.tsx @@ -0,0 +1,132 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { + EuiButton, + EuiButtonEmpty, + EuiFlexGroup, + EuiFlexItem, + EuiFlyout, + EuiFlyoutBody, + EuiFlyoutFooter, + EuiFlyoutHeader, + EuiHorizontalRule, + EuiPageHeader, + EuiPageHeaderSection, + EuiSpacer, + EuiTitle, +} from '@elastic/eui'; +import React from 'react'; + +interface AccelerationIndexFlyoutProps { + dataSource: string; + database: string; + dataTable: string; + indexName: string; + resetFlyout: () => void; + updateSQLQueries: (query: string) => void; +} + +export const AccelerationIndexFlyout = ({ + dataSource, + database, + dataTable, + indexName, + resetFlyout, + updateSQLQueries, +}: AccelerationIndexFlyoutProps) => { + const updateDescribeQuery = () => { + const describeQuery = + indexName === 'skipping_index' + ? `DESC SKIPPING INDEX ON ${dataSource}.${database}.${dataTable}` + : `DESC INDEX ${indexName} ON ${dataSource}.${database}.${dataTable}`; + updateSQLQueries(describeQuery); + resetFlyout(); + }; + + const updateDropQuery = () => { + const describeQuery = + indexName === 'skipping_index' + ? `DROP SKIPPING INDEX ON ${dataSource}.${database}.${dataTable}` + : `DROP INDEX ${indexName} ON ${dataSource}.${database}.${dataTable}`; + updateSQLQueries(describeQuery); + resetFlyout(); + }; + + return ( + <> + <EuiFlyout ownFocus onClose={resetFlyout} aria-labelledby="flyoutTitle" size="m"> + <EuiFlyoutHeader hasBorder> + <div> + <EuiPageHeader> + <EuiPageHeaderSection> + <EuiTitle size="l" data-test-subj="acceleration-index-desc-header"> + <h1>{indexName}</h1> + </EuiTitle> + </EuiPageHeaderSection> + </EuiPageHeader> + </div> + </EuiFlyoutHeader> + <EuiFlyoutBody> + <h3>Acceleration index Source</h3> + <EuiHorizontalRule /> + <EuiFlexGroup> + <EuiFlexItem grow={false}> + <h3>Data Source</h3> + <EuiSpacer /> + <p>{dataSource}</p> + </EuiFlexItem> + <EuiFlexItem grow={false}> + <h3>Database</h3> + <EuiSpacer /> + <p>{database}</p> + </EuiFlexItem> + <EuiFlexItem grow={false}> + <h3>Table</h3> + <EuiSpacer /> + <p>{dataTable}</p> + </EuiFlexItem> + </EuiFlexGroup> + <h3>Acceleration index destination</h3> + <EuiHorizontalRule /> + <EuiFlexGroup> + <EuiFlexItem grow={false}> + <h3>OpenSearch Index</h3> + <EuiSpacer /> + <p> + {indexName === 'skipping_index' + ? `flint_${dataSource}_${database}_${dataTable}_skipping_index` + : `flint_${dataSource}_${database}_${dataTable}_${indexName}_index`} + </p> + </EuiFlexItem> + </EuiFlexGroup> + <h3>Acceleration index actions</h3> + <EuiHorizontalRule /> + <EuiFlexGroup> + <EuiFlexItem grow={false}> + <EuiButton iconSide="right" fill iconType="lensApp" onClick={updateDescribeQuery}> + Describe Index + </EuiButton> + </EuiFlexItem> + <EuiFlexItem grow={false}> + <EuiButton iconSide="right" iconType="trash" onClick={updateDropQuery} color="danger"> + Drop Index + </EuiButton> + </EuiFlexItem> + </EuiFlexGroup> + </EuiFlyoutBody> + <EuiFlyoutFooter> + <EuiFlexGroup justifyContent="spaceBetween"> + <EuiFlexItem grow={false}> + <EuiButtonEmpty iconType="cross" onClick={resetFlyout} flush="left"> + Close + </EuiButtonEmpty> + </EuiFlexItem> + </EuiFlexGroup> + </EuiFlyoutFooter> + </EuiFlyout> + </> + ); +}; diff --git a/public/components/acceleration/create/__tests__/__snapshots__/caution_banner_callout.test.tsx.snap b/public/components/acceleration/create/__tests__/__snapshots__/caution_banner_callout.test.tsx.snap deleted file mode 100644 index f40a09f9..00000000 --- a/public/components/acceleration/create/__tests__/__snapshots__/caution_banner_callout.test.tsx.snap +++ /dev/null @@ -1,39 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`Acceleration callout renders acceleration flyout callout 1`] = ` -<div - className="euiCallOut euiCallOut--warning" -> - <div - className="euiCallOutHeader" - > - <svg - aria-hidden={true} - className="euiIcon euiIcon--medium euiIcon--inherit euiIcon-isLoading euiCallOutHeader__icon" - focusable="false" - height={16} - role="img" - style={null} - viewBox="0 0 16 16" - width={16} - xmlns="http://www.w3.org/2000/svg" - /> - <span - className="euiCallOutHeader__title" - > - Considerations for data indexing - </span> - </div> - <div - className="euiText euiText--small" - > - <div - className="euiTextColor euiTextColor--default" - > - <p> - Warning about not indexing personal or sensitive data, something about the cost of indexing. - </p> - </div> - </div> -</div> -`; diff --git a/public/components/acceleration/create/__tests__/__snapshots__/create_acceleration.test.tsx.snap b/public/components/acceleration/create/__tests__/__snapshots__/create_acceleration.test.tsx.snap index 3eded361..07b8f6a8 100644 --- a/public/components/acceleration/create/__tests__/__snapshots__/create_acceleration.test.tsx.snap +++ b/public/components/acceleration/create/__tests__/__snapshots__/create_acceleration.test.tsx.snap @@ -108,40 +108,6 @@ Array [ <div class="euiFlyoutBody__overflowContent" > - <div - class="euiCallOut euiCallOut--warning" - > - <div - class="euiCallOutHeader" - > - <svg - aria-hidden="true" - class="euiIcon euiIcon--medium euiIcon--inherit euiIcon-isLoading euiCallOutHeader__icon" - focusable="false" - height="16" - role="img" - viewBox="0 0 16 16" - width="16" - xmlns="http://www.w3.org/2000/svg" - /> - <span - class="euiCallOutHeader__title" - > - Considerations for data indexing - </span> - </div> - <div - class="euiText euiText--small" - > - <div - class="euiTextColor euiTextColor--default" - > - <p> - Warning about not indexing personal or sensitive data, something about the cost of indexing. - </p> - </div> - </div> - </div> <div class="euiSpacer euiSpacer--l" /> @@ -608,7 +574,7 @@ Array [ min="1" placeholder="Number of primary shards" type="number" - value="5" + value="1" /> </div> </div> @@ -616,7 +582,7 @@ Array [ class="euiFormHelpText euiFormRow__text" id="some_html_id-help-0" > - Specify the number of primary shards for the index. Default is 5. The number of primary shards cannot be changed after the index is created. + Specify the number of primary shards for the index. Default is 1. The number of primary shards cannot be changed after the index is created. </div> </div> </div> @@ -1252,41 +1218,6 @@ Array [ <div className="euiFlyoutBody__overflowContent" > - <div - className="euiCallOut euiCallOut--warning" - > - <div - className="euiCallOutHeader" - > - <svg - aria-hidden={true} - className="euiIcon euiIcon--medium euiIcon--inherit euiIcon-isLoading euiCallOutHeader__icon" - focusable="false" - height={16} - role="img" - style={null} - viewBox="0 0 16 16" - width={16} - xmlns="http://www.w3.org/2000/svg" - /> - <span - className="euiCallOutHeader__title" - > - Considerations for data indexing - </span> - </div> - <div - className="euiText euiText--small" - > - <div - className="euiTextColor euiTextColor--default" - > - <p> - Warning about not indexing personal or sensitive data, something about the cost of indexing. - </p> - </div> - </div> - </div> <div className="euiSpacer euiSpacer--l" /> @@ -1868,7 +1799,7 @@ Array [ onFocus={[Function]} placeholder="Number of primary shards" type="number" - value={5} + value={1} /> </div> </div> @@ -1876,7 +1807,7 @@ Array [ className="euiFormHelpText euiFormRow__text" id="some_html_id-help-0" > - Specify the number of primary shards for the index. Default is 5. The number of primary shards cannot be changed after the index is created. + Specify the number of primary shards for the index. Default is 1. The number of primary shards cannot be changed after the index is created. </div> </div> </div>, diff --git a/public/components/acceleration/create/__tests__/caution_banner_callout.test.tsx b/public/components/acceleration/create/__tests__/caution_banner_callout.test.tsx deleted file mode 100644 index 4ad06632..00000000 --- a/public/components/acceleration/create/__tests__/caution_banner_callout.test.tsx +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright OpenSearch Contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import { waitFor } from '@testing-library/dom'; -import { configure, mount } from 'enzyme'; -import Adapter from 'enzyme-adapter-react-16'; -import toJson from 'enzyme-to-json'; -import React from 'react'; -import { CautionBannerCallout } from '../caution_banner_callout'; - -describe('Acceleration callout', () => { - configure({ adapter: new Adapter() }); - - it('renders acceleration flyout callout', async () => { - const wrapper = mount(<CautionBannerCallout />); - wrapper.update(); - await waitFor(() => { - expect( - toJson(wrapper, { - noKey: false, - mode: 'deep', - }) - ).toMatchSnapshot(); - }); - }); -}); diff --git a/public/components/acceleration/create/__tests__/create_acceleration.test.tsx b/public/components/acceleration/create/__tests__/create_acceleration.test.tsx index 8736c5b0..104d0fe6 100644 --- a/public/components/acceleration/create/__tests__/create_acceleration.test.tsx +++ b/public/components/acceleration/create/__tests__/create_acceleration.test.tsx @@ -3,24 +3,30 @@ * SPDX-License-Identifier: Apache-2.0 */ +import { EuiComboBoxOptionOption } from '@elastic/eui'; import { waitFor } from '@testing-library/dom'; import { configure, mount } from 'enzyme'; import Adapter from 'enzyme-adapter-react-16'; import toJson from 'enzyme-to-json'; import React from 'react'; +import { httpClientMock } from '../../../../../test/mocks'; +import { mockDatasourcesQuery } from '../../../../../test/mocks/mockData'; import { CreateAcceleration } from '../create_acceleration'; describe('Create acceleration flyout components', () => { configure({ adapter: new Adapter() }); it('renders acceleration flyout component with default options', async () => { - const dataSource = ''; + const selectedDatasource: EuiComboBoxOptionOption[] = []; const resetFlyout = jest.fn(); const updateQueries = jest.fn(); + const client = httpClientMock; + client.get = jest.fn().mockResolvedValue(mockDatasourcesQuery); const wrapper = mount( <CreateAcceleration - dataSource={dataSource} + http={client} + selectedDatasource={selectedDatasource} resetFlyout={resetFlyout} updateQueries={updateQueries} /> diff --git a/public/components/acceleration/create/__tests__/utils.test.tsx b/public/components/acceleration/create/__tests__/utils.test.tsx index 060d6385..8e4efbf3 100644 --- a/public/components/acceleration/create/__tests__/utils.test.tsx +++ b/public/components/acceleration/create/__tests__/utils.test.tsx @@ -96,11 +96,11 @@ describe('validatePrimaryShardCount', () => { describe('validateReplicaCount', () => { it('should return an array with an error message when replicaCount is less than 1', () => { - expect(validateReplicaCount(0)).toEqual(['Replica count should be greater than 0']); - expect(validateReplicaCount(-1)).toEqual(['Replica count should be greater than 0']); // form throws validation error, doesn't allow user to proceed + expect(validateReplicaCount(-1)).toEqual(['Replica count should be equal or greater than 0']); // form throws validation error, doesn't allow user to proceed }); it('should return an empty array when replicaCount is greater than or equal to 1', () => { + expect(validateReplicaCount(0)).toEqual([]); expect(validateReplicaCount(1)).toEqual([]); expect(validateReplicaCount(5)).toEqual([]); expect(validateReplicaCount(100)).toEqual([]); diff --git a/public/components/acceleration/create/caution_banner_callout.tsx b/public/components/acceleration/create/caution_banner_callout.tsx deleted file mode 100644 index 2c97f82a..00000000 --- a/public/components/acceleration/create/caution_banner_callout.tsx +++ /dev/null @@ -1,17 +0,0 @@ -/* - * Copyright OpenSearch Contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import { EuiCallOut } from '@elastic/eui'; -import React from 'react'; - -export const CautionBannerCallout = () => { - return ( - <EuiCallOut title="Considerations for data indexing" color="warning" iconType="iInCircle"> - <p> - Warning about not indexing personal or sensitive data, something about the cost of indexing. - </p> - </EuiCallOut> - ); -}; diff --git a/public/components/acceleration/create/create_acceleration.tsx b/public/components/acceleration/create/create_acceleration.tsx index 4cfc5e44..152b01c5 100644 --- a/public/components/acceleration/create/create_acceleration.tsx +++ b/public/components/acceleration/create/create_acceleration.tsx @@ -6,6 +6,7 @@ import { EuiButton, EuiButtonEmpty, + EuiComboBoxOptionOption, EuiFlexGroup, EuiFlexItem, EuiFlyout, @@ -16,6 +17,7 @@ import { EuiSpacer, } from '@elastic/eui'; import React, { useState } from 'react'; +import { CoreStart } from '../../../../../../src/core/public'; import { ACCELERATION_DEFUALT_SKIPPING_INDEX_NAME, ACCELERATION_TIME_INTERVAL, @@ -26,23 +28,24 @@ import { IndexSettingOptions } from '../selectors/index_setting_options'; import { AccelerationDataSourceSelector } from '../selectors/source_selector'; import { accelerationQueryBuilder } from '../visual_editors/query_builder'; import { QueryVisualEditor } from '../visual_editors/query_visual_editor'; -import { CautionBannerCallout } from './caution_banner_callout'; import { CreateAccelerationHeader } from './create_acceleration_header'; import { formValidator, hasError } from './utils'; export interface CreateAccelerationProps { - dataSource: string; + http: CoreStart['http']; + selectedDatasource: EuiComboBoxOptionOption[]; resetFlyout: () => void; updateQueries: (query: string) => void; } export const CreateAcceleration = ({ - dataSource, + http, + selectedDatasource, resetFlyout, updateQueries, }: CreateAccelerationProps) => { const [accelerationFormData, setAccelerationFormData] = useState<CreateAccelerationForm>({ - dataSource: '', + dataSource: selectedDatasource.length > 0 ? selectedDatasource[0].label : '', dataTable: '', database: '', dataTableFields: [], @@ -58,7 +61,7 @@ export const CreateAcceleration = ({ }, }, accelerationIndexName: ACCELERATION_DEFUALT_SKIPPING_INDEX_NAME, - primaryShardsCount: 5, + primaryShardsCount: 1, replicaShardsCount: 1, refreshType: 'auto', checkpointLocation: undefined, @@ -98,7 +101,6 @@ export const CreateAcceleration = ({ <CreateAccelerationHeader /> </EuiFlyoutHeader> <EuiFlyoutBody> - <CautionBannerCallout /> <EuiSpacer size="l" /> <EuiForm isInvalid={hasError(accelerationFormData.formErrors)} @@ -107,11 +109,14 @@ export const CreateAcceleration = ({ id="acceleration-form" > <AccelerationDataSourceSelector + http={http} accelerationFormData={accelerationFormData} setAccelerationFormData={setAccelerationFormData} + selectedDatasource={selectedDatasource} /> <EuiSpacer size="xxl" /> <IndexSettingOptions + http={http} accelerationFormData={accelerationFormData} setAccelerationFormData={setAccelerationFormData} /> diff --git a/public/components/acceleration/create/utils.tsx b/public/components/acceleration/create/utils.tsx index a293298c..97933353 100644 --- a/public/components/acceleration/create/utils.tsx +++ b/public/components/acceleration/create/utils.tsx @@ -41,7 +41,7 @@ export const validatePrimaryShardCount = (primaryShardCount: number) => { }; export const validateReplicaCount = (replicaCount: number) => { - return replicaCount < 1 ? ['Replica count should be greater than 0'] : []; + return replicaCount < 0 ? ['Replica count should be equal or greater than 0'] : []; }; export const validateRefreshInterval = (refreshType: string, refreshWindow: number) => { diff --git a/public/components/acceleration/selectors/__tests__/__snapshots__/index_setting_options.test.tsx.snap b/public/components/acceleration/selectors/__tests__/__snapshots__/index_setting_options.test.tsx.snap index 72dad5ea..49459fd5 100644 --- a/public/components/acceleration/selectors/__tests__/__snapshots__/index_setting_options.test.tsx.snap +++ b/public/components/acceleration/selectors/__tests__/__snapshots__/index_setting_options.test.tsx.snap @@ -196,7 +196,7 @@ Array [ onFocus={[Function]} placeholder="Number of primary shards" type="number" - value={5} + value={1} /> </div> </div> @@ -204,7 +204,7 @@ Array [ className="euiFormHelpText euiFormRow__text" id="some_html_id-help-0" > - Specify the number of primary shards for the index. Default is 5. The number of primary shards cannot be changed after the index is created. + Specify the number of primary shards for the index. Default is 1. The number of primary shards cannot be changed after the index is created. </div> </div> </div>, @@ -583,7 +583,7 @@ Array [ onFocus={[Function]} placeholder="Number of primary shards" type="number" - value={5} + value={1} /> </div> </div> @@ -591,7 +591,7 @@ Array [ className="euiFormHelpText euiFormRow__text" id="some_html_id-help-0" > - Specify the number of primary shards for the index. Default is 5. The number of primary shards cannot be changed after the index is created. + Specify the number of primary shards for the index. Default is 1. The number of primary shards cannot be changed after the index is created. </div> </div> </div>, @@ -970,7 +970,7 @@ Array [ onFocus={[Function]} placeholder="Number of primary shards" type="number" - value={5} + value={1} /> </div> </div> @@ -978,7 +978,7 @@ Array [ className="euiFormHelpText euiFormRow__text" id="some_html_id-help-0" > - Specify the number of primary shards for the index. Default is 5. The number of primary shards cannot be changed after the index is created. + Specify the number of primary shards for the index. Default is 1. The number of primary shards cannot be changed after the index is created. </div> </div> </div>, diff --git a/public/components/acceleration/selectors/__tests__/__snapshots__/source_selector.test.tsx.snap b/public/components/acceleration/selectors/__tests__/__snapshots__/source_selector.test.tsx.snap index bf2a7962..47b7da24 100644 --- a/public/components/acceleration/selectors/__tests__/__snapshots__/source_selector.test.tsx.snap +++ b/public/components/acceleration/selectors/__tests__/__snapshots__/source_selector.test.tsx.snap @@ -442,11 +442,11 @@ Array [ onClick={[Function]} tabIndex={-1} > - <p - className="euiComboBoxPlaceholder" + <span + className="euiComboBoxPill euiComboBoxPill--plainText" > - Select a data source - </p> + ds + </span> <div className="euiComboBox__input" style={ @@ -681,7 +681,7 @@ Array [ className="euiFormControlLayout__childrenWrapper" > <div - className="euiComboBox__inputWrap euiComboBox__inputWrap--noWrap" + className="euiComboBox__inputWrap euiComboBox__inputWrap--noWrap euiComboBox__inputWrap-isLoading" data-test-subj="comboBoxInput" onClick={[Function]} tabIndex={-1} @@ -734,6 +734,9 @@ Array [ <div className="euiFormControlLayoutIcons euiFormControlLayoutIcons--right" > + <span + className="euiLoadingSpinner euiLoadingSpinner--medium" + /> <button aria-label="Open list of options" className="euiFormControlLayoutCustomIcon euiFormControlLayoutCustomIcon--clickable" diff --git a/public/components/acceleration/selectors/__tests__/source_selector.test.tsx b/public/components/acceleration/selectors/__tests__/source_selector.test.tsx index f5d1ff57..9d76e390 100644 --- a/public/components/acceleration/selectors/__tests__/source_selector.test.tsx +++ b/public/components/acceleration/selectors/__tests__/source_selector.test.tsx @@ -3,13 +3,16 @@ * SPDX-License-Identifier: Apache-2.0 */ +import { EuiComboBoxOptionOption } from '@elastic/eui'; import { waitFor } from '@testing-library/dom'; import { configure, mount } from 'enzyme'; import Adapter from 'enzyme-adapter-react-16'; import toJson from 'enzyme-to-json'; import React from 'react'; import { CreateAccelerationForm } from '../../../../../common/types'; +import { httpClientMock } from '../../../../../test/mocks'; import { createAccelerationEmptyDataMock } from '../../../../../test/mocks/accelerationMock'; +import { mockDatasourcesQuery } from '../../../../../test/mocks/mockData'; import { AccelerationDataSourceSelector } from '../source_selector'; describe('Source selector components', () => { @@ -17,9 +20,15 @@ describe('Source selector components', () => { it('renders source selector with default options', async () => { const accelerationFormData = createAccelerationEmptyDataMock; + const selectedDatasource: EuiComboBoxOptionOption[] = []; const setAccelerationFormData = jest.fn(); + const client = httpClientMock; + client.get = jest.fn().mockResolvedValue(mockDatasourcesQuery); + const wrapper = mount( <AccelerationDataSourceSelector + http={client} + selectedDatasource={selectedDatasource} accelerationFormData={accelerationFormData} setAccelerationFormData={setAccelerationFormData} /> @@ -36,6 +45,7 @@ describe('Source selector components', () => { }); it('renders source selector with different options', async () => { + const selectedDatasource: EuiComboBoxOptionOption[] = [{ label: 'ds' }]; const accelerationFormData: CreateAccelerationForm = { ...createAccelerationEmptyDataMock, dataSource: 'ds', @@ -43,8 +53,13 @@ describe('Source selector components', () => { dataTable: 'tb', }; const setAccelerationFormData = jest.fn(); + const client = httpClientMock; + client.get = jest.fn().mockResolvedValue(mockDatasourcesQuery); + client.post = jest.fn().mockResolvedValue([]); const wrapper = mount( <AccelerationDataSourceSelector + selectedDatasource={selectedDatasource} + http={client} accelerationFormData={accelerationFormData} setAccelerationFormData={setAccelerationFormData} /> diff --git a/public/components/acceleration/selectors/index_setting_options.tsx b/public/components/acceleration/selectors/index_setting_options.tsx index f5a0c69a..18797186 100644 --- a/public/components/acceleration/selectors/index_setting_options.tsx +++ b/public/components/acceleration/selectors/index_setting_options.tsx @@ -14,6 +14,7 @@ import { } from '@elastic/eui'; import producer from 'immer'; import React, { ChangeEvent, useState } from 'react'; +import { CoreStart } from '../../../../../../src/core/public'; import { ACCELERATION_TIME_INTERVAL } from '../../../../common/constants'; import { CreateAccelerationForm } from '../../../../common/types'; import { @@ -26,11 +27,13 @@ import { import { IndexTypeSelector } from './index_type_selector'; interface IndexSettingOptionsProps { + http: CoreStart['http']; accelerationFormData: CreateAccelerationForm; setAccelerationFormData: React.Dispatch<React.SetStateAction<CreateAccelerationForm>>; } export const IndexSettingOptions = ({ + http, accelerationFormData, setAccelerationFormData, }: IndexSettingOptionsProps) => { @@ -47,7 +50,7 @@ export const IndexSettingOptions = ({ }, ]; - const [primaryShards, setPrimaryShards] = useState(5); + const [primaryShards, setPrimaryShards] = useState(1); const [replicaCount, setReplicaCount] = useState(1); const [refreshTypeSelected, setRefreshTypeSelected] = useState(autoRefreshId); const [refreshWindow, setRefreshWindow] = useState(1); @@ -107,12 +110,13 @@ export const IndexSettingOptions = ({ </EuiText> <EuiSpacer size="s" /> <IndexTypeSelector + http={http} accelerationFormData={accelerationFormData} setAccelerationFormData={setAccelerationFormData} /> <EuiFormRow label="Number of primary shards" - helpText="Specify the number of primary shards for the index. Default is 5. The number of primary shards cannot be changed after the index is created." + helpText="Specify the number of primary shards for the index. Default is 1. The number of primary shards cannot be changed after the index is created." isInvalid={hasError(accelerationFormData.formErrors, 'primaryShardsError')} error={accelerationFormData.formErrors.primaryShardsError} > diff --git a/public/components/acceleration/selectors/index_type_selector.tsx b/public/components/acceleration/selectors/index_type_selector.tsx index 06b7828d..1e195c8f 100644 --- a/public/components/acceleration/selectors/index_type_selector.tsx +++ b/public/components/acceleration/selectors/index_type_selector.tsx @@ -3,27 +3,73 @@ * SPDX-License-Identifier: Apache-2.0 */ -import { EuiComboBox, EuiComboBoxOptionOption, EuiFormRow, EuiLink, EuiText } from '@elastic/eui'; -import React, { useState } from 'react'; +import { + EuiComboBox, + EuiComboBoxOptionOption, + EuiFormRow, + EuiLink, + EuiText, + htmlIdGenerator, +} from '@elastic/eui'; +import React, { useEffect, useState } from 'react'; +import { CoreStart } from '../../../../../../src/core/public'; import { ACCELERATION_DEFUALT_SKIPPING_INDEX_NAME, ACCELERATION_INDEX_TYPES, ACC_INDEX_TYPE_DOCUMENTATION_URL, } from '../../../../common/constants'; import { AccelerationIndexType, CreateAccelerationForm } from '../../../../common/types'; +import { getJobId, pollQueryStatus } from '../../SQLPage/utils'; interface IndexTypeSelectorProps { + http: CoreStart['http']; accelerationFormData: CreateAccelerationForm; setAccelerationFormData: React.Dispatch<React.SetStateAction<CreateAccelerationForm>>; } export const IndexTypeSelector = ({ + http, accelerationFormData, setAccelerationFormData, }: IndexTypeSelectorProps) => { const [selectedIndexType, setSelectedIndexType] = useState<EuiComboBoxOptionOption<string>[]>([ ACCELERATION_INDEX_TYPES[0], ]); + const [loading, setLoading] = useState(false); + + useEffect(() => { + if (accelerationFormData.dataTable !== '') { + setLoading(true); + const idPrefix = htmlIdGenerator()(); + const query = { + lang: 'sql', + query: `DESC ${accelerationFormData.dataSource}.${accelerationFormData.database}.${accelerationFormData.dataTable}`, + datasource: accelerationFormData.dataSource, + }; + getJobId(query, http, (id: string) => { + pollQueryStatus(id, http, (data: any[]) => { + setAccelerationFormData({ + ...accelerationFormData, + dataTableFields: [ + { id: `${idPrefix}1`, fieldName: 'Field1', dataType: 'Integer' }, + { id: `${idPrefix}2`, fieldName: 'Field2', dataType: 'Integer' }, + { id: `${idPrefix}3`, fieldName: 'Field3', dataType: 'Integer' }, + { id: `${idPrefix}4`, fieldName: 'Field4', dataType: 'Integer' }, + { id: `${idPrefix}5`, fieldName: 'Field5', dataType: 'Integer' }, + { id: `${idPrefix}6`, fieldName: 'Field6', dataType: 'Integer' }, + { id: `${idPrefix}7`, fieldName: 'Field7', dataType: 'Integer' }, + { id: `${idPrefix}8`, fieldName: 'Field8', dataType: 'Integer' }, + { id: `${idPrefix}9`, fieldName: 'Field9', dataType: 'Integer' }, + { id: `${idPrefix}10`, fieldName: 'Field10', dataType: 'Integer' }, + { id: `${idPrefix}11`, fieldName: 'Field11', dataType: 'Integer' }, + { id: `${idPrefix}12`, fieldName: 'Field12', dataType: 'TimestampType' }, + ], + }); + setLoading(false); + }); + }); + } + }, [accelerationFormData.dataTable]); const onChangeIndexType = (indexTypeOption: EuiComboBoxOptionOption<string>[]) => { const indexType = indexTypeOption[0].value as AccelerationIndexType; @@ -56,6 +102,7 @@ export const IndexTypeSelector = ({ onChange={onChangeIndexType} isInvalid={selectedIndexType.length === 0} isClearable={false} + isLoading={loading} /> </EuiFormRow> </> diff --git a/public/components/acceleration/selectors/source_selector.tsx b/public/components/acceleration/selectors/source_selector.tsx index a0f068ba..ea365876 100644 --- a/public/components/acceleration/selectors/source_selector.tsx +++ b/public/components/acceleration/selectors/source_selector.tsx @@ -3,101 +3,110 @@ * SPDX-License-Identifier: Apache-2.0 */ -import { - EuiComboBox, - EuiComboBoxOptionOption, - EuiFormRow, - EuiSpacer, - EuiText, - htmlIdGenerator, -} from '@elastic/eui'; +import { EuiComboBox, EuiComboBoxOptionOption, EuiFormRow, EuiSpacer, EuiText } from '@elastic/eui'; import producer from 'immer'; import React, { useEffect, useState } from 'react'; +import { CoreStart } from '../../../../../../src/core/public'; import { CreateAccelerationForm } from '../../../../common/types'; +import { getJobId, pollQueryStatus } from '../../SQLPage/utils'; import { hasError, validateDataSource } from '../create/utils'; interface AccelerationDataSourceSelectorProps { + http: CoreStart['http']; accelerationFormData: CreateAccelerationForm; setAccelerationFormData: React.Dispatch<React.SetStateAction<CreateAccelerationForm>>; + selectedDatasource: EuiComboBoxOptionOption[]; } export const AccelerationDataSourceSelector = ({ + http, accelerationFormData, setAccelerationFormData, + selectedDatasource, }: AccelerationDataSourceSelectorProps) => { const [dataConnections, setDataConnections] = useState<EuiComboBoxOptionOption<string>[]>([]); const [selectedDataConnection, setSelectedDataConnection] = useState< EuiComboBoxOptionOption<string>[] - >([]); + >(selectedDatasource.length > 0 ? [{ label: selectedDatasource[0].label }] : []); const [databases, setDatabases] = useState<EuiComboBoxOptionOption<string>[]>([]); const [selectedDatabase, setSelectedDatabase] = useState<EuiComboBoxOptionOption<string>[]>([]); const [tables, setTables] = useState<EuiComboBoxOptionOption<string>[]>([]); const [selectedTable, setSelectedTable] = useState<EuiComboBoxOptionOption<string>[]>([]); + const [loadingComboBoxes, setLoadingComboBoxes] = useState({ + dataSource: false, + database: false, + dataTable: false, + }); + + const loadDataSource = () => { + setLoadingComboBoxes({ ...loadingComboBoxes, dataSource: true }); + http + .get(`/api/get_datasources`) + .then((res) => { + const data = res.data.resp; + setDataConnections( + data + .filter((connection: any) => connection.connector.toUpperCase() === 'S3GLUE') + .map((connection: any) => ({ label: connection.name })) + ); + }) + .catch((err) => { + console.error(err); + }); + setLoadingComboBoxes({ ...loadingComboBoxes, dataSource: false }); + }; + + const loadDatabases = () => { + setLoadingComboBoxes({ ...loadingComboBoxes, database: true }); + const query = { + lang: 'sql', + query: `SHOW SCHEMAS IN ${accelerationFormData.dataSource}`, + datasource: accelerationFormData.dataSource, + }; + getJobId(query, http, (id: string) => { + pollQueryStatus(id, http, (data: any[][]) => { + let databaseOptions: EuiComboBoxOptionOption<string>[] = []; + if (data.length > 0) + databaseOptions = data.map((subArray: any[]) => ({ label: subArray[0] })); + setDatabases(databaseOptions); + setLoadingComboBoxes({ ...loadingComboBoxes, database: false }); + }); + }); + }; + + const loadTables = () => { + setLoadingComboBoxes({ ...loadingComboBoxes, dataTable: true }); + const query = { + lang: 'sql', + query: `SHOW TABLES IN ${accelerationFormData.dataSource}.${accelerationFormData.database}`, + datasource: accelerationFormData.dataSource, + }; + getJobId(query, http, (id: string) => { + pollQueryStatus(id, http, (data: any[]) => { + let dataTableOptions: EuiComboBoxOptionOption<string>[] = []; + if (data.length > 0) dataTableOptions = data.map((subArray) => ({ label: subArray[1] })); + setTables(dataTableOptions); + setLoadingComboBoxes({ ...loadingComboBoxes, dataTable: false }); + }); + }); + }; useEffect(() => { - // TODO: remove hardcoded responses - setDataConnections([ - { - label: 'spark1', - }, - { - label: 'spark2', - }, - ]); + loadDataSource(); }, []); useEffect(() => { - // TODO: remove hardcoded responses if (accelerationFormData.dataSource !== '') { - setDatabases([ - { - label: 'Database1', - }, - { - label: 'Database2', - }, - ]); + loadDatabases(); } }, [accelerationFormData.dataSource]); useEffect(() => { - // TODO: remove hardcoded responses if (accelerationFormData.database !== '') { - setTables([ - { - label: 'Table1', - }, - { - label: 'Table2', - }, - ]); + loadTables(); } }, [accelerationFormData.database]); - useEffect(() => { - // TODO: remove hardcoded responses - if (accelerationFormData.dataTable !== '') { - const idPrefix = htmlIdGenerator()(); - setAccelerationFormData({ - ...accelerationFormData, - dataTableFields: [ - { id: `${idPrefix}1`, fieldName: 'Field1', dataType: 'Integer' }, - { id: `${idPrefix}2`, fieldName: 'Field2', dataType: 'Integer' }, - { id: `${idPrefix}3`, fieldName: 'Field3', dataType: 'Integer' }, - { id: `${idPrefix}4`, fieldName: 'Field4', dataType: 'Integer' }, - { id: `${idPrefix}5`, fieldName: 'Field5', dataType: 'Integer' }, - { id: `${idPrefix}6`, fieldName: 'Field6', dataType: 'Integer' }, - { id: `${idPrefix}7`, fieldName: 'Field7', dataType: 'Integer' }, - { id: `${idPrefix}8`, fieldName: 'Field8', dataType: 'Integer' }, - { id: `${idPrefix}9`, fieldName: 'Field9', dataType: 'Integer' }, - { id: `${idPrefix}10`, fieldName: 'Field10', dataType: 'Integer' }, - { id: `${idPrefix}11`, fieldName: 'Field11', dataType: 'Integer' }, - { id: `${idPrefix}12`, fieldName: 'Field12', dataType: 'TimestampType' }, - ], - }); - } - }, [accelerationFormData.dataTable]); - return ( <> <EuiText data-test-subj="datasource-selector-header"> @@ -132,6 +141,7 @@ export const AccelerationDataSourceSelector = ({ }} isClearable={false} isInvalid={hasError(accelerationFormData.formErrors, 'dataSourceError')} + isLoading={loadingComboBoxes.dataSource} /> </EuiFormRow> <EuiFormRow @@ -156,6 +166,7 @@ export const AccelerationDataSourceSelector = ({ }} isClearable={false} isInvalid={hasError(accelerationFormData.formErrors, 'databaseError')} + isLoading={loadingComboBoxes.database} /> </EuiFormRow> <EuiFormRow @@ -180,6 +191,7 @@ export const AccelerationDataSourceSelector = ({ }} isClearable={false} isInvalid={hasError(accelerationFormData.formErrors, 'dataTableError')} + isLoading={loadingComboBoxes.dataTable} /> </EuiFormRow> </> diff --git a/public/components/acceleration/visual_editors/__tests__/__snapshots__/query_visual_editor.test.tsx.snap b/public/components/acceleration/visual_editors/__tests__/__snapshots__/query_visual_editor.test.tsx.snap index 8659a435..3a281f7a 100644 --- a/public/components/acceleration/visual_editors/__tests__/__snapshots__/query_visual_editor.test.tsx.snap +++ b/public/components/acceleration/visual_editors/__tests__/__snapshots__/query_visual_editor.test.tsx.snap @@ -39,20 +39,6 @@ Array [ </span> </span> </div> - <div - className="euiFlexItem euiFlexItem--flexGrowZero" - > - <span - className="euiExpression euiExpression-isUppercase euiExpression--success" - > - <span - className="euiExpression__description" - > - [IF NOT EXISTS] - </span> - - </span> - </div> <div className="euiFlexItem" > @@ -354,20 +340,6 @@ Array [ ..skipping </span> </span>, - <div - className="euiFlexItem euiFlexItem--flexGrowZero" - > - <span - className="euiExpression euiExpression-isUppercase euiExpression--success" - > - <span - className="euiExpression__description" - > - [IF NOT EXISTS] - </span> - - </span> - </div>, <div className="euiFlexGroup euiFlexGroup--gutterLarge euiFlexGroup--directionRow euiFlexGroup--responsive" > diff --git a/public/components/acceleration/visual_editors/covering_index/__tests__/__snapshots__/covering_index_builder.test.tsx.snap b/public/components/acceleration/visual_editors/covering_index/__tests__/__snapshots__/covering_index_builder.test.tsx.snap index 3d237119..24d90273 100644 --- a/public/components/acceleration/visual_editors/covering_index/__tests__/__snapshots__/covering_index_builder.test.tsx.snap +++ b/public/components/acceleration/visual_editors/covering_index/__tests__/__snapshots__/covering_index_builder.test.tsx.snap @@ -35,20 +35,6 @@ Array [ </span> </span> </div> - <div - className="euiFlexItem euiFlexItem--flexGrowZero" - > - <span - className="euiExpression euiExpression-isUppercase euiExpression--success" - > - <span - className="euiExpression__description" - > - [IF NOT EXISTS] - </span> - - </span> - </div> <div className="euiFlexItem" > @@ -130,20 +116,6 @@ Array [ </span> </span> </div> - <div - className="euiFlexItem euiFlexItem--flexGrowZero" - > - <span - className="euiExpression euiExpression-isUppercase euiExpression--success" - > - <span - className="euiExpression__description" - > - [IF NOT EXISTS] - </span> - - </span> - </div> <div className="euiFlexItem" > diff --git a/public/components/acceleration/visual_editors/covering_index/covering_index_builder.tsx b/public/components/acceleration/visual_editors/covering_index/covering_index_builder.tsx index 5968ca01..8d3c6019 100644 --- a/public/components/acceleration/visual_editors/covering_index/covering_index_builder.tsx +++ b/public/components/acceleration/visual_editors/covering_index/covering_index_builder.tsx @@ -58,9 +58,6 @@ export const CoveringIndexBuilder = ({ value={accelerationFormData.accelerationIndexName} /> </EuiFlexItem> - <EuiFlexItem grow={false}> - <EuiExpression description="[IF NOT EXISTS]" /> - </EuiFlexItem> <EuiFlexItem> <EuiExpression description="ON" diff --git a/public/components/acceleration/visual_editors/materialized_view/__tests__/__snapshots__/materialized_view_builder.test.tsx.snap b/public/components/acceleration/visual_editors/materialized_view/__tests__/__snapshots__/materialized_view_builder.test.tsx.snap index 75955730..c3ae3b8d 100644 --- a/public/components/acceleration/visual_editors/materialized_view/__tests__/__snapshots__/materialized_view_builder.test.tsx.snap +++ b/public/components/acceleration/visual_editors/materialized_view/__tests__/__snapshots__/materialized_view_builder.test.tsx.snap @@ -28,20 +28,6 @@ Array [ ..skipping </span> </span>, - <div - className="euiFlexItem euiFlexItem--flexGrowZero" - > - <span - className="euiExpression euiExpression-isUppercase euiExpression--success" - > - <span - className="euiExpression__description" - > - [IF NOT EXISTS] - </span> - - </span> - </div>, <div className="euiFlexGroup euiFlexGroup--gutterLarge euiFlexGroup--directionRow euiFlexGroup--responsive" > @@ -184,20 +170,6 @@ Array [ ..skipping </span> </span>, - <div - className="euiFlexItem euiFlexItem--flexGrowZero" - > - <span - className="euiExpression euiExpression-isUppercase euiExpression--success" - > - <span - className="euiExpression__description" - > - [IF NOT EXISTS] - </span> - - </span> - </div>, <div className="euiFlexGroup euiFlexGroup--gutterLarge euiFlexGroup--directionRow euiFlexGroup--responsive" > diff --git a/public/components/acceleration/visual_editors/materialized_view/add_column_popover.tsx b/public/components/acceleration/visual_editors/materialized_view/add_column_popover.tsx index df6b276f..6d91c5b7 100644 --- a/public/components/acceleration/visual_editors/materialized_view/add_column_popover.tsx +++ b/public/components/acceleration/visual_editors/materialized_view/add_column_popover.tsx @@ -7,6 +7,7 @@ import { EuiButton, EuiButtonEmpty, EuiComboBox, + EuiComboBoxOptionOption, EuiFieldText, EuiFlexGroup, EuiFlexItem, @@ -17,7 +18,6 @@ import { EuiSpacer, htmlIdGenerator, } from '@elastic/eui'; -import { EuiComboBoxOptionOption } from '@opensearch-project/oui'; import producer from 'immer'; import React, { ChangeEvent, useEffect, useState } from 'react'; import { ACCELERATION_AGGREGRATION_FUNCTIONS } from '../../../../../common/constants'; diff --git a/public/components/acceleration/visual_editors/materialized_view/materialized_view_builder.tsx b/public/components/acceleration/visual_editors/materialized_view/materialized_view_builder.tsx index 124b451c..e9ef4319 100644 --- a/public/components/acceleration/visual_editors/materialized_view/materialized_view_builder.tsx +++ b/public/components/acceleration/visual_editors/materialized_view/materialized_view_builder.tsx @@ -74,10 +74,6 @@ export const MaterializedViewBuilder = ({ value={`${accelerationFormData.dataSource}.${accelerationFormData.database}.${accelerationFormData.accelerationIndexName}`} /> - <EuiFlexItem grow={false}> - <EuiExpression description="[IF NOT EXISTS]" value="" /> - </EuiFlexItem> - <EuiFlexGroup> <EuiFlexItem grow={false}> <EuiExpression diff --git a/public/components/acceleration/visual_editors/query_builder.tsx b/public/components/acceleration/visual_editors/query_builder.tsx index 49d4482f..ef15bc9e 100644 --- a/public/components/acceleration/visual_editors/query_builder.tsx +++ b/public/components/acceleration/visual_editors/query_builder.tsx @@ -58,7 +58,6 @@ const buildSkippingIndexColumns = (skippingIndexQueryData: SkippingIndexRowType[ * Skipping Index create query example: * * CREATE SKIPPING INDEX - * [IF NOT EXISTS] * ON datasource.database.table * FOR COLUMNS ( * field1 VALUE_SET, @@ -74,8 +73,7 @@ const buildSkippingIndexColumns = (skippingIndexQueryData: SkippingIndexRowType[ export const skippingIndexQueryBuilder = (accelerationformData: CreateAccelerationForm) => { const { dataSource, database, dataTable, skippingIndexQueryData } = accelerationformData; - const codeQuery = `CREATE SKIPPING INDEX -[IF NOT EXISTS] + const codeQuery = `CREATE SKIPPING INDEX ON ${dataSource}.${database}.${dataTable} FOR COLUMNS ( ${buildSkippingIndexColumns(skippingIndexQueryData)} @@ -94,7 +92,6 @@ const buildCoveringIndexColumns = (coveringIndexQueryData: string[]) => { * Covering Index create query example: * * CREATE INDEX index_name - * [IF NOT EXISTS] * ON datasource.database.table * FOR COLUMNS ( * field1, @@ -117,7 +114,6 @@ export const coveringIndexQueryBuilder = (accelerationformData: CreateAccelerati } = accelerationformData; const codeQuery = `CREATE INDEX ${accelerationIndexName} -[IF NOT EXISTS] ON ${dataSource}.${database}.${dataTable} FOR COLUMNS ( ${buildCoveringIndexColumns(coveringIndexQueryData)} @@ -148,7 +144,6 @@ const buildTumbleValue = (GroupByTumbleValue: GroupByTumbleType) => { * Materialized View create query example: * * CREATE MATERIALIZED VIEW datasource.database.index_name - * [IF NOT EXISTS] * AS SELECT * count(field) as counter, * count(*) as counter1, @@ -171,7 +166,6 @@ export const materializedQueryViewBuilder = (accelerationformData: CreateAcceler } = accelerationformData; const codeQuery = `CREATE MATERIALIZED VIEW ${dataSource}.${database}.${accelerationIndexName} -[IF NOT EXISTS] AS SELECT ${buildMaterializedViewColumns(materializedViewQueryData.columnsValues)} FROM ${dataSource}.${database}.${dataTable} diff --git a/public/components/app.tsx b/public/components/app.tsx index 44f09b5f..a2f961eb 100644 --- a/public/components/app.tsx +++ b/public/components/app.tsx @@ -3,10 +3,9 @@ * SPDX-License-Identifier: Apache-2.0 */ - -import React from 'react'; import { I18nProvider } from '@osd/i18n/react'; -import { BrowserRouter as Router, Route } from 'react-router-dom'; +import React from 'react'; +import { HashRouter, Route, Switch } from 'react-router-dom'; import { EuiPage, EuiPageBody } from '@elastic/eui'; @@ -23,29 +22,64 @@ interface WorkbenchAppDeps { chrome: CoreStart['chrome']; } -const onChange = () => {}; - -export const WorkbenchApp = ({ basename, notifications, http, navigation, chrome }: WorkbenchAppDeps) => { +export const WorkbenchApp = ({ + basename, + notifications, + http, + navigation, + chrome, +}: WorkbenchAppDeps) => { return ( - <Router basename={'/' + basename}> + <HashRouter> <I18nProvider> <div> <EuiPage> <EuiPageBody> - <Route - path="/" - render={(props) => - <Main - httpClient={http} - {...props} - setBreadcrumbs={chrome.setBreadcrumbs} - /> - } - /> + <Switch> + <Route + exact + path="/" + render={(props) => ( + <Main + httpClient={http} + {...props} + setBreadcrumbs={chrome.setBreadcrumbs} + isAccelerationFlyoutOpen={false} + urlDataSource="" + /> + )} + /> + <Route + exact + path="/:dataSource" + render={(props) => ( + <Main + httpClient={http} + {...props} + setBreadcrumbs={chrome.setBreadcrumbs} + isAccelerationFlyoutOpen={false} + urlDataSource={props.match.params.dataSource} + /> + )} + /> + <Route + exact + path="/accelerate/:dataSource" + render={(props) => ( + <Main + httpClient={http} + {...props} + setBreadcrumbs={chrome.setBreadcrumbs} + isAccelerationFlyoutOpen={true} + urlDataSource={props.match.params.dataSource} + /> + )} + /> + </Switch> </EuiPageBody> </EuiPage> </div> </I18nProvider> - </Router> + </HashRouter> ); }; diff --git a/test/mocks/accelerationMock.ts b/test/mocks/accelerationMock.ts index 154dbd22..085459de 100644 --- a/test/mocks/accelerationMock.ts +++ b/test/mocks/accelerationMock.ts @@ -201,8 +201,7 @@ export const skippingIndexBuilderMock1: CreateAccelerationForm = { checkpointLocation: 's3://test/', }; -export const skippingIndexBuilderMockResult1 = `CREATE SKIPPING INDEX -[IF NOT EXISTS] +export const skippingIndexBuilderMockResult1 = `CREATE SKIPPING INDEX ON datasource.database.table FOR COLUMNS ( field1 PARTITION, @@ -234,8 +233,7 @@ export const skippingIndexBuilderMock2: CreateAccelerationForm = { checkpointLocation: 's3://test/', }; -export const skippingIndexBuilderMockResult2 = `CREATE SKIPPING INDEX -[IF NOT EXISTS] +export const skippingIndexBuilderMockResult2 = `CREATE SKIPPING INDEX ON datasource.database.table FOR COLUMNS ( field1 PARTITION @@ -263,7 +261,6 @@ export const coveringIndexBuilderMock1: CreateAccelerationForm = { }; export const coveringIndexBuilderMockResult1 = `CREATE INDEX index_name -[IF NOT EXISTS] ON datasource.database.table FOR COLUMNS ( field1, @@ -290,7 +287,6 @@ export const coveringIndexBuilderMock2: CreateAccelerationForm = { }; export const coveringIndexBuilderMockResult2 = `CREATE INDEX index_name -[IF NOT EXISTS] ON datasource.database.table FOR COLUMNS ( field1 @@ -330,7 +326,6 @@ export const materializedViewBuilderMock1: CreateAccelerationForm = { }; export const materializedViewBuilderMockResult1 = `CREATE MATERIALIZED VIEW datasource.database.index_name -[IF NOT EXISTS] AS SELECT count(field) AS counter, count(*) AS counter1, @@ -366,7 +361,6 @@ export const materializedViewBuilderMock2: CreateAccelerationForm = { }; export const materializedViewBuilderMockResult2 = `CREATE MATERIALIZED VIEW datasource.database.index_name -[IF NOT EXISTS] AS SELECT count(field) FROM datasource.database.table