From c819cd40fd322f5eac4c808f839c25d6a0664e3c Mon Sep 17 00:00:00 2001 From: Shenoy Pratik Date: Thu, 5 Oct 2023 15:30:37 -0700 Subject: [PATCH] Bug fixes for SQL UI buttons (#147) * adding paper cuts Signed-off-by: Shenoy Pratik * update snapshots Signed-off-by: Shenoy Pratik --------- Signed-off-by: Shenoy Pratik --- common/constants/index.ts | 4 +- .../Main/__snapshots__/main.test.tsx.snap | 275 +------------- public/components/Main/main.tsx | 7 +- .../components/QueryResults/QueryResults.tsx | 53 +-- .../QueryResults/QueryResultsBody.test.tsx | 221 +++++++---- .../QueryResults/QueryResultsBody.tsx | 359 ++++++++++-------- .../__snapshots__/QueryResults.test.tsx.snap | 95 +---- .../QueryResultsBody.test.tsx.snap | 4 + public/components/SQLPage/CreateButton.tsx | 75 ++-- public/components/SQLPage/SQLPage.test.tsx | 4 +- public/components/SQLPage/SQLPage.tsx | 28 +- .../__snapshots__/SQLPage.test.tsx.snap | 19 - .../create_acceleration.test.tsx.snap | 4 +- .../create/__tests__/utils.test.tsx | 3 +- .../define_index_options.test.tsx.snap | 6 +- .../selectors/define_index_options.tsx | 2 +- 16 files changed, 455 insertions(+), 704 deletions(-) diff --git a/common/constants/index.ts b/common/constants/index.ts index ed37754e..c7ed1d43 100644 --- a/common/constants/index.ts +++ b/common/constants/index.ts @@ -63,7 +63,7 @@ export const SKIPPING_INDEX_ACCELERATION_METHODS = [ ]; export const ACCELERATION_ADD_FIELDS_TEXT = '(add fields here)'; -export const ACCELERATION_INDEX_NAME_REGEX = /^[a-z][a-z_\-]*$/; +export const ACCELERATION_INDEX_NAME_REGEX = /^[a-z][a-z_]*$/; export const ACCELERATION_S3_URL_REGEX = /^(s3|s3a):\/\/[a-zA-Z0-9.\-]+\/.*/; export const ACCELERATION_DEFUALT_SKIPPING_INDEX_NAME = 'skipping'; @@ -78,7 +78,7 @@ export const ACCELERATION_INDEX_NAME_INFO = `All OpenSearch acceleration indices - 'Materialized View' indices also enable users to define their index name, but they do not have a suffix. - An example of a 'Materialized View' index name might look like: \`flint_mydatasource_mydb_mytable_myindexname\`. ##### Note: -- All user given index names must be in lowercase letters. Cannot begin with underscores or hyphens. Spaces, commas, and characters :, ", *, +, /, \, |, ?, #, >, or < are not allowed. +- All user given index names must be in lowercase letters. Index name cannot begin with underscores. Spaces, commas, and characters -, :, ", *, +, /, \, |, ?, #, >, or < are not allowed. `; export const SIDEBAR_POLL_INTERVAL_MS = 5000; diff --git a/public/components/Main/__snapshots__/main.test.tsx.snap b/public/components/Main/__snapshots__/main.test.tsx.snap index d8ef37d5..baa291c8 100644 --- a/public/components/Main/__snapshots__/main.test.tsx.snap +++ b/public/components/Main/__snapshots__/main.test.tsx.snap @@ -203,45 +203,7 @@ exports[`
spec click clear button 1`] = ` >
-
-
- -
-
-
+ />
@@ -763,45 +725,7 @@ exports[`
spec click run button, and response causes an error 1`] = ` >
-
-
- -
-
-
+ />
@@ -1323,45 +1247,7 @@ exports[`
spec click run button, and response is not ok 1`] = ` >
-
-
- -
-
-
+ />
@@ -1883,45 +1769,7 @@ exports[`
spec click run button, and response is ok 1`] = ` >
-
-
- -
-
-
+ />
@@ -2531,45 +2379,7 @@ exports[`
spec click run button, response fills null and missing values >
-
-
- -
-
-
+ />
@@ -3178,45 +2988,7 @@ exports[`
spec click translation button, and response is ok 1`] = ` >
-
-
- -
-
-
+ />
@@ -3729,40 +3501,7 @@ exports[`
spec renders the component 1`] = ` >
-
-
- -
-
-
+ />
diff --git a/public/components/Main/main.tsx b/public/components/Main/main.tsx index a8b38326..86f24463 100644 --- a/public/components/Main/main.tsx +++ b/public/components/Main/main.tsx @@ -881,6 +881,7 @@ export class Main extends React.Component { asyncLoading={this.state.asyncLoading} asyncLoadingStatus={this.state.asyncLoadingStatus} cancelAsyncQuery={this.cancelAsyncQuery} + selectedDatasource={this.state.selectedDatasource} />
); @@ -919,7 +920,10 @@ export class Main extends React.Component { - + { asyncLoading={this.state.asyncLoading} asyncLoadingStatus={this.state.asyncLoadingStatus} cancelAsyncQuery={this.cancelAsyncQuery} + selectedDatasource={this.state.selectedDatasource} />
diff --git a/public/components/QueryResults/QueryResults.tsx b/public/components/QueryResults/QueryResults.tsx index 1002e378..58d204e8 100644 --- a/public/components/QueryResults/QueryResults.tsx +++ b/public/components/QueryResults/QueryResults.tsx @@ -8,44 +8,45 @@ import React from 'react'; import { SortableProperties, SortableProperty } from '@elastic/eui/lib/services'; // @ts-ignore import { - EuiPanel, - EuiFlexGroup, - EuiFlexItem, - EuiTab, - EuiTabs, - EuiPopover, + Comparators, + EuiButton, + EuiButtonIcon, + EuiComboBoxOptionOption, EuiContextMenuItem, EuiContextMenuPanel, + EuiFlexGroup, + EuiFlexItem, EuiHorizontalRule, - EuiSearchBar, - Pager, EuiIcon, - EuiText, + EuiPanel, + EuiPopover, + EuiSearchBar, EuiSpacer, + EuiTab, + EuiTabs, + EuiText, EuiTextAlign, - EuiButton, - EuiButtonIcon, - Comparators, + Pager, } from '@elastic/eui'; -import { - QueryResult, - QueryMessage, - Tab, - ResponseDetail, - ItemIdToExpandedRowMap, - DataRow, -} from '../Main/main'; -import QueryResultsBody from './QueryResultsBody'; -import { getQueryIndex, needsScrolling, getSelectedResults } from '../../utils/utils'; +import _ from 'lodash'; +import { AsyncQueryLoadingStatus } from '../../../common/types'; +import { PanelWrapper } from '../../utils/PanelWrapper'; import { DEFAULT_NUM_RECORDS_PER_PAGE, MESSAGE_TAB_LABEL, TAB_CONTAINER_ID, } from '../../utils/constants'; -import { PanelWrapper } from '../../utils/PanelWrapper'; -import _ from 'lodash'; +import { getQueryIndex, getSelectedResults, needsScrolling } from '../../utils/utils'; +import { + DataRow, + ItemIdToExpandedRowMap, + QueryMessage, + QueryResult, + ResponseDetail, + Tab, +} from '../Main/main'; import { AsyncQueryBody } from './AsyncQueryBody'; -import { AsyncQueryLoadingStatus } from '../../../common/types'; +import QueryResultsBody from './QueryResultsBody'; interface QueryResultsProps { language: string; @@ -73,6 +74,7 @@ interface QueryResultsProps { asyncLoading: boolean; asyncLoadingStatus: AsyncQueryLoadingStatus; cancelAsyncQuery: () => void; + selectedDatasource: EuiComboBoxOptionOption[]; } interface QueryResultsState { @@ -429,6 +431,7 @@ class QueryResults extends React.Component getCsv={this.props.getCsv} getText={this.props.getText} onSort={this.onSort} + selectedDatasource={this.props.selectedDatasource} /> diff --git a/public/components/QueryResults/QueryResultsBody.test.tsx b/public/components/QueryResults/QueryResultsBody.test.tsx index b0be92f6..b9f5aa1c 100644 --- a/public/components/QueryResults/QueryResultsBody.test.tsx +++ b/public/components/QueryResults/QueryResultsBody.test.tsx @@ -3,21 +3,27 @@ * SPDX-License-Identifier: Apache-2.0 */ - -import React from "react"; -import "@testing-library/jest-dom/extend-expect"; -import { render, fireEvent, cleanup } from "@testing-library/react"; -import QueryResultsBody from "./QueryResultsBody"; +import '@testing-library/jest-dom/extend-expect'; +import { cleanup, fireEvent, render } from '@testing-library/react'; +import React from 'react'; +import QueryResultsBody from './QueryResultsBody'; // @ts-ignore -import { Pager } from "@elastic/eui/lib"; +import { Pager } from '@elastic/eui/lib'; // @ts-ignore -import { SortableProperties } from "@elastic/eui/lib/services"; -import { mockQueryResults, mockQueryResultJSONResponse, mockErrorMessage, mockSuccessfulMessage, mockSortableColumns, mockQueryResultJDBCResponse } from "../../../test/mocks/mockData"; -import userEvent from "@testing-library/user-event"; -import { QueryMessage, QueryResult } from "../Main/main"; - - -function renderSQLQueryResultsBody(mockQueries: string[], +import { SortableProperties } from '@elastic/eui/lib/services'; +import userEvent from '@testing-library/user-event'; +import { + mockErrorMessage, + mockQueryResultJDBCResponse, + mockQueryResultJSONResponse, + mockQueryResults, + mockSortableColumns, + mockSuccessfulMessage, +} from '../../../test/mocks/mockData'; +import { QueryMessage, QueryResult } from '../Main/main'; + +function renderSQLQueryResultsBody( + mockQueries: string[], mockQueryResultsSelected: QueryResult, mockQueryResultsRaw: string, mockSortableProperties: SortableProperties, @@ -28,11 +34,12 @@ function renderSQLQueryResultsBody(mockQueries: string[], getJson: (queries: string[]) => void, getJdbc: (queries: string[]) => void, getCsv: (queries: string[]) => void, - getText: (queries: string[]) => void) { + getText: (queries: string[]) => void +) { return { ...render( { }} + onChangePage={() => {}} sortedColumn={'col1'} sortableProperties={mockSortableProperties} itemIdToExpandedRowMap={{}} @@ -59,13 +66,13 @@ function renderSQLQueryResultsBody(mockQueries: string[], getJdbc={getJdbc} getCsv={getCsv} getText={getText} + selectedDatasource={[{ label: 'OpenSearch' }]} /> ), }; } -describe(" spec", () => { - +describe(' spec', () => { afterEach(cleanup); const onQueryChange = jest.fn(); const updateExpandedMap = jest.fn(); @@ -75,21 +82,32 @@ describe(" spec", () => { const getCsv = jest.fn(); const getText = jest.fn(); - it("renders the component", () => { + it('renders the component', () => { const mockSortableProperties = new SortableProperties( [ { - name: "", - getValue: (item: any) => "", - isAscending: true - } + name: '', + getValue: (item: any) => '', + isAscending: true, + }, ], - "" + '' ); - const { queryByTestId } = renderSQLQueryResultsBody(undefined, undefined, undefined, - mockSortableProperties, mockErrorMessage, onQueryChange, updateExpandedMap, onChangeItemsPerPage, - getJson, getJdbc, getCsv, getText); + const { queryByTestId } = renderSQLQueryResultsBody( + undefined, + undefined, + undefined, + mockSortableProperties, + mockErrorMessage, + onQueryChange, + updateExpandedMap, + onChangeItemsPerPage, + getJson, + getJdbc, + getCsv, + getText + ); // Download buttons, pagination, search area, table should not be visible when there is no data expect(queryByTestId('Download')).toBeNull(); @@ -98,21 +116,36 @@ describe(" spec", () => { expect(queryByTestId('Search')).toBeNull(); expect(document.body.children[0]).toMatchSnapshot(); - }); - it("renders component with mock QueryResults data", async () => { + it('renders component with mock QueryResults data', async () => { const mockSortableProperties = new SortableProperties( mockSortableColumns, mockSortableColumns[0].name ); - (window as any).HTMLElement.prototype.scrollIntoView = function () { }; - - const { getAllByText, getAllByTestId, getAllByLabelText, getByText, getByPlaceholderText } = - renderSQLQueryResultsBody(undefined, mockQueryResults[0].data, mockQueryResultJSONResponse.data.resp, mockSortableProperties, - mockSuccessfulMessage, onQueryChange, updateExpandedMap, onChangeItemsPerPage, getJson, getJdbc, - getCsv, getText); + (window as any).HTMLElement.prototype.scrollIntoView = function () {}; + + const { + getAllByText, + getAllByTestId, + getAllByLabelText, + getByText, + getByPlaceholderText, + } = renderSQLQueryResultsBody( + undefined, + mockQueryResults[0].data, + mockQueryResultJSONResponse.data.resp, + mockSortableProperties, + mockSuccessfulMessage, + onQueryChange, + updateExpandedMap, + onChangeItemsPerPage, + getJson, + getJdbc, + getCsv, + getText + ); expect(document.body.children[0]).toMatchSnapshot(); // Test sorting @@ -121,11 +154,11 @@ describe(" spec", () => { // Test pagination await fireEvent.click(getAllByText('Rows per page', { exact: false })[0]); - expect(getByText("10 rows")); - expect(getByText("20 rows")); - expect(getByText("50 rows")); - expect(getByText("100 rows")); - await fireEvent.click(getByText("20 rows")); + expect(getByText('10 rows')); + expect(getByText('20 rows')); + expect(getByText('50 rows')); + expect(getByText('100 rows')); + await fireEvent.click(getByText('20 rows')); expect(onChangeItemsPerPage).toHaveBeenCalled(); // Test nested tables - click on row icon @@ -141,19 +174,19 @@ describe(" spec", () => { const downloadButton = getAllByText('Download')[0]; expect(downloadButton).not.toBe(null); await fireEvent.click(downloadButton); - expect(getByText("Download JSON")); - expect(getByText("Download JDBC")); - expect(getByText("Download CSV")); - expect(getByText("Download Text")); - await fireEvent.click(getByText("Download JSON")); - await fireEvent.click(getByText("Download JDBC")); - await fireEvent.click(getByText("Download CSV")); - await fireEvent.click(getByText("Download Text")); + expect(getByText('Download JSON')); + expect(getByText('Download JDBC')); + expect(getByText('Download CSV')); + expect(getByText('Download Text')); + await fireEvent.click(getByText('Download JSON')); + await fireEvent.click(getByText('Download JDBC')); + await fireEvent.click(getByText('Download CSV')); + await fireEvent.click(getByText('Download Text')); // Test search field const searchField = getByPlaceholderText('Search keyword'); expect(searchField).not.toBe(null); - await userEvent.type(searchField, 'Test') + await userEvent.type(searchField, 'Test'); expect(onQueryChange).toHaveBeenCalled(); // Test collapse button @@ -161,12 +194,11 @@ describe(" spec", () => { expect(getAllByLabelText('Collapse').length).toBeGreaterThan(0); await fireEvent.click(getAllByLabelText('Collapse')[0]); expect(updateExpandedMap).toHaveBeenCalled(); - }); }); - -function renderPPLQueryResultsBody(mockQueries: string[], +function renderPPLQueryResultsBody( + mockQueries: string[], mockQueryResultsSelected: QueryResult, mockQueryResultsRaw: string, mockSortableProperties: SortableProperties, @@ -177,11 +209,12 @@ function renderPPLQueryResultsBody(mockQueries: string[], getJson: (queries: string[]) => void, getJdbc: (queries: string[]) => void, getCsv: (queries: string[]) => void, - getText: (queries: string[]) => void) { + getText: (queries: string[]) => void +) { return { ...render( { }} + onChangePage={() => {}} sortedColumn={'col1'} sortableProperties={mockSortableProperties} itemIdToExpandedRowMap={{}} @@ -213,8 +246,7 @@ function renderPPLQueryResultsBody(mockQueries: string[], }; } -describe(" spec", () => { - +describe(' spec', () => { afterEach(cleanup); const onQueryChange = jest.fn(); const updateExpandedMap = jest.fn(); @@ -224,21 +256,32 @@ describe(" spec", () => { const getCsv = jest.fn(); const getText = jest.fn(); - it("renders the component", () => { + it('renders the component', () => { const mockSortableProperties = new SortableProperties( [ { - name: "", - getValue: (item: any) => "", - isAscending: true - } + name: '', + getValue: (item: any) => '', + isAscending: true, + }, ], - "" + '' ); - const { queryByTestId } = renderPPLQueryResultsBody(undefined, undefined, undefined, - mockSortableProperties, mockErrorMessage, onQueryChange, updateExpandedMap, onChangeItemsPerPage, - getJson, getJdbc, getCsv, getText); + const { queryByTestId } = renderPPLQueryResultsBody( + undefined, + undefined, + undefined, + mockSortableProperties, + mockErrorMessage, + onQueryChange, + updateExpandedMap, + onChangeItemsPerPage, + getJson, + getJdbc, + getCsv, + getText + ); // Download buttons, pagination, search area, table should not be visible when there is no data expect(queryByTestId('Download')).toBeNull(); @@ -247,21 +290,36 @@ describe(" spec", () => { expect(queryByTestId('Search')).toBeNull(); expect(document.body.children[0]).toMatchSnapshot(); - }); - it("renders component with mock QueryResults data", async () => { + it('renders component with mock QueryResults data', async () => { const mockSortableProperties = new SortableProperties( mockSortableColumns, mockSortableColumns[0].name ); - (window as any).HTMLElement.prototype.scrollIntoView = function () { }; - - const { getAllByText, getAllByTestId, getAllByLabelText, getByText, getByPlaceholderText } = - renderPPLQueryResultsBody(undefined, mockQueryResults[0].data, mockQueryResultJDBCResponse.data.resp, mockSortableProperties, - mockSuccessfulMessage, onQueryChange, updateExpandedMap, onChangeItemsPerPage, getJson, getJdbc, - getCsv, getText); + (window as any).HTMLElement.prototype.scrollIntoView = function () {}; + + const { + getAllByText, + getAllByTestId, + getAllByLabelText, + getByText, + getByPlaceholderText, + } = renderPPLQueryResultsBody( + undefined, + mockQueryResults[0].data, + mockQueryResultJDBCResponse.data.resp, + mockSortableProperties, + mockSuccessfulMessage, + onQueryChange, + updateExpandedMap, + onChangeItemsPerPage, + getJson, + getJdbc, + getCsv, + getText + ); expect(document.body.children[0]).toMatchSnapshot(); // Test sorting @@ -270,11 +328,11 @@ describe(" spec", () => { // Test pagination await fireEvent.click(getAllByText('Rows per page', { exact: false })[0]); - expect(getByText("10 rows")); - expect(getByText("20 rows")); - expect(getByText("50 rows")); - expect(getByText("100 rows")); - await fireEvent.click(getByText("20 rows")); + expect(getByText('10 rows')); + expect(getByText('20 rows')); + expect(getByText('50 rows')); + expect(getByText('100 rows')); + await fireEvent.click(getByText('20 rows')); expect(onChangeItemsPerPage).toHaveBeenCalled(); // Test nested tables - click on row icon @@ -285,6 +343,5 @@ describe(" spec", () => { // Test nested tables - click on cell link await fireEvent.click(getAllByText('manufacturer: [2]', { exact: false })[0]); expect(updateExpandedMap).toHaveBeenCalled(); - }); }); diff --git a/public/components/QueryResults/QueryResultsBody.tsx b/public/components/QueryResults/QueryResultsBody.tsx index 4f222d2b..9ccb2366 100644 --- a/public/components/QueryResults/QueryResultsBody.tsx +++ b/public/components/QueryResults/QueryResultsBody.tsx @@ -3,20 +3,29 @@ * SPDX-License-Identifier: Apache-2.0 */ - -import React, { Fragment } from "react"; +import React, { Fragment } from 'react'; // @ts-ignore -import { SortableProperties } from "@elastic/eui/lib/services"; +import { SortableProperties } from '@elastic/eui/lib/services'; // @ts-ignore -import { Comparators, EuiBasicTable, EuiCodeEditor, EuiModal, EuiModalBody, EuiModalFooter, EuiModalHeader, EuiModalHeaderTitle, EuiOverlayMask, EuiPanel, EuiPortal, EuiSearchBar, EuiSideNav } from "@elastic/eui"; import { + Comparators, EuiButton, EuiButtonIcon, + EuiCodeEditor, + EuiComboBoxOptionOption, EuiContextMenu, EuiFlexGroup, EuiFlexItem, EuiLink, + EuiModal, + EuiModalBody, + EuiModalFooter, + EuiModalHeader, + EuiModalHeaderTitle, + EuiOverlayMask, EuiPopover, + EuiSearchBar, + EuiSideNav, EuiTable, EuiTableBody, EuiTableHeader, @@ -25,21 +34,21 @@ import { EuiTableRow, EuiTableRowCell, EuiText, - Pager -} from "@elastic/eui"; + Pager, +} from '@elastic/eui'; +import _ from 'lodash'; +import '../../ace-themes/sql_console'; +import { COLUMN_WIDTH, PAGE_OPTIONS, SMALL_COLUMN_WIDTH } from '../../utils/constants'; import { + Node, findRootNode, getMessageString, getRowTree, isEmpty, - Node, onDownloadFile, - scrollToNode -} from "../../utils/utils"; -import "../../ace-themes/sql_console"; -import { COLUMN_WIDTH, PAGE_OPTIONS, SMALL_COLUMN_WIDTH } from "../../utils/constants"; -import { DataRow, ItemIdToExpandedRowMap, QueryMessage, QueryResult } from "../Main/main"; -import _ from "lodash"; + scrollToNode, +} from '../../utils/utils'; +import { DataRow, ItemIdToExpandedRowMap, QueryMessage, QueryResult } from '../Main/main'; const DoubleScrollbar = require('react-double-scrollbar'); @@ -63,6 +72,7 @@ interface QueryResultsBodyProps { lastItemIndex: number; itemIdToExpandedRowMap: ItemIdToExpandedRowMap; sortedColumn: string; + selectedDatasource: EuiComboBoxOptionOption[]; onChangeItemsPerPage: (itemsPerPage: number) => void; onChangePage: (pageIndex: number) => void; onQueryChange: (query: object) => void; @@ -115,13 +125,13 @@ class QueryResultsBody extends React.Component { this.onDownloadJSON(); - } + }, }, { - name: "Download JDBC", + name: 'Download JDBC', onClick: () => { this.onDownloadJDBC(); - } + }, }, { - name: "Download CSV", + name: 'Download CSV', onClick: () => { this.onDownloadCSV(); - } + }, }, { - name: "Download Text", + name: 'Download Text', onClick: () => { this.onDownloadText(); - } - } - ] - } + }, + }, + ], + }, ]; } setIsModalVisible(visible: boolean): void { this.setState({ - isModalVisible: visible - }) + isModalVisible: visible, + }); } getModal = (errorMessage: string): any => { @@ -177,9 +187,7 @@ class QueryResultsBody extends React.Component - - {errorMessage} - + {errorMessage} @@ -191,14 +199,16 @@ class QueryResultsBody extends React.Component ); return modal; - } + }; // Actions for Download files onDownloadJSON() { if (this.props.language == 'PPL') { this.setState({ - downloadErrorModal: this.getModal("PPL result in JSON format is not supported, please select JDBC format."), - }) + downloadErrorModal: this.getModal( + 'PPL result in JSON format is not supported, please select JDBC format.' + ), + }); this.setIsModalVisible(true); return; } @@ -208,9 +218,9 @@ class QueryResultsBody extends React.Component { const jsonObject = JSON.parse(this.props.queryResultsJSON); const data = JSON.stringify(jsonObject, undefined, 4); - onDownloadFile(data, "json", this.props.selectedTabName + ".json"); + onDownloadFile(data, 'json', this.props.selectedTabName + '.json'); }, 2000); - }; + } onDownloadJDBC = (): void => { if (!this.props.queryResultsJDBC) { @@ -219,15 +229,17 @@ class QueryResultsBody extends React.Component { const jsonObject = JSON.parse(this.props.queryResultsJDBC); const data = JSON.stringify(jsonObject, undefined, 4); - onDownloadFile(data, "json", this.props.selectedTabName + ".json"); + onDownloadFile(data, 'json', this.props.selectedTabName + '.json'); }, 2000); }; onDownloadCSV = (): void => { if (this.props.language == 'PPL') { this.setState({ - downloadErrorModal: this.getModal("PPL result in CSV format is not supported, please select JDBC format."), - }) + downloadErrorModal: this.getModal( + 'PPL result in CSV format is not supported, please select JDBC format.' + ), + }); this.setIsModalVisible(true); return; } @@ -236,15 +248,17 @@ class QueryResultsBody extends React.Component { const data = this.props.queryResultsCSV; - onDownloadFile(data, "csv", this.props.selectedTabName + ".csv"); + onDownloadFile(data, 'csv', this.props.selectedTabName + '.csv'); }, 2000); }; onDownloadText = (): void => { if (this.props.language == 'PPL') { this.setState({ - downloadErrorModal: this.getModal("PPL result in Text format is not supported, please select JDBC format."), - }) + downloadErrorModal: this.getModal( + 'PPL result in Text format is not supported, please select JDBC format.' + ), + }); this.setIsModalVisible(true); return; } @@ -253,27 +267,29 @@ class QueryResultsBody extends React.Component { const data = this.props.queryResultsTEXT; - onDownloadFile(data, "plain", this.props.selectedTabName + ".txt"); + onDownloadFile(data, 'plain', this.props.selectedTabName + '.txt'); }, 2000); }; // Actions for Downloads Button onDownloadButtonClick = (): void => { - this.setState(prevState => ({ - isDownloadPopoverOpen: !prevState.isDownloadPopoverOpen + this.setState((prevState) => ({ + isDownloadPopoverOpen: !prevState.isDownloadPopoverOpen, })); }; closeDownloadPopover = (): void => { this.setState({ - isDownloadPopoverOpen: false + isDownloadPopoverOpen: false, }); }; // It filters table values that conatins the given items getItems(records: DataRow[]) { - const matchingItems = this.props.searchQuery ? this.searchItems(records, this.props.searchQuery) : records; - let field: string = ""; + const matchingItems = this.props.searchQuery + ? this.searchItems(records, this.props.searchQuery) + : records; + let field: string = ''; if (_.get(this.props.sortedColumn, this.columns)) { field = this.props.sortedColumn; } @@ -283,7 +299,7 @@ class QueryResultsBody extends React.Component { - if (typeof property === "undefined") { + if (typeof property === 'undefined') { return 0; } let dataA = a.data; @@ -321,7 +337,7 @@ class QueryResultsBody extends React.Component this.toggleNodeData(node, expandedRowMap)} aria-label={ expandedRowMap[node.nodeId] && expandedRowMap[node.nodeId].expandedRow - ? "Collapse" - : "Expand" + ? 'Collapse' + : 'Expand' } iconType={ expandedRowMap[node.nodeId] && expandedRowMap[node.nodeId].expandedRow - ? "minusInCircle" - : "plusInCircle" + ? 'minusInCircle' + : 'plusInCircle' } /> ); @@ -415,17 +431,17 @@ class QueryResultsBody extends React.Component this.updateExpandedRowMap(node, expandedRowMap)} aria-label={ expandedRowMap[node.parent!.nodeId] && - expandedRowMap[node.parent!.nodeId].selectedNodes && - expandedRowMap[node.parent!.nodeId].selectedNodes.hasOwnProperty(node.nodeId) - ? "Collapse" - : "Expand" + expandedRowMap[node.parent!.nodeId].selectedNodes && + expandedRowMap[node.parent!.nodeId].selectedNodes.hasOwnProperty(node.nodeId) + ? 'Collapse' + : 'Expand' } iconType={ expandedRowMap[node.parent!.nodeId] && - expandedRowMap[node.parent!.nodeId].selectedNodes && - expandedRowMap[node.parent!.nodeId].selectedNodes.hasOwnProperty(node.nodeId) - ? "minusInCircle" - : "plusInCircle" + expandedRowMap[node.parent!.nodeId].selectedNodes && + expandedRowMap[node.parent!.nodeId].selectedNodes.hasOwnProperty(node.nodeId) + ? 'minusInCircle' + : 'plusInCircle' } /> ); @@ -434,18 +450,23 @@ class QueryResultsBody extends React.Component +
{this.renderNav(node, node.name, expandedRowMap)}
); @@ -480,11 +501,20 @@ class QueryResultsBody extends React.Component 0 ? this.props.messages[0].className - : "successful-message" + : 'successful-message' } mode="text" theme="sql_console" @@ -574,10 +600,10 @@ class QueryResultsBody extends React.Component @@ -586,8 +612,8 @@ class QueryResultsBody extends React.Component { - const label: string = field.id === "expandIcon" ? field.label : field; - const colwidth = field.id === "expandIcon" ? SMALL_COLUMN_WIDTH : COLUMN_WIDTH; + const label: string = field.id === 'expandIcon' ? field.label : field; + const colwidth = field.id === 'expandIcon' ? SMALL_COLUMN_WIDTH : COLUMN_WIDTH; return ( { - const label = field.id === "expandIcon" ? field.label : field; - const colwidth = field.id === "expandIcon" ? field.width : COLUMN_WIDTH; + const label = field.id === 'expandIcon' ? field.label : field; + const colwidth = field.id === 'expandIcon' ? field.width : COLUMN_WIDTH; return ( {label} @@ -614,11 +640,18 @@ class QueryResultsBody extends React.Component 0)) + if ( + data && + ((typeof data === 'object' && !isEmpty(data)) || (Array.isArray(data) && data.length > 0)) ) { let rowItems: any[] = []; @@ -638,30 +671,30 @@ class QueryResultsBody extends React.Component 0 ? this.addExpandingNodeIcon(tree._root, expandedRowMap) : ""; + tree && tree._root.children.length > 0 + ? this.addExpandingNodeIcon(tree._root, expandedRowMap) + : ''; if (columns.length > 0) { columns.map((field: any) => { // Table cell - if (field.id !== "expandIcon") { + if (field.id !== 'expandIcon') { const fieldObj = this.getFieldValue(rowItem[field], field); let fieldValue: any; // If field is expandable if (fieldObj.hasExpandingRow || fieldObj.hasExpandingArray) { - const fieldNode = expandedRowMap[tree._root.nodeId].nodes._root.children.find((node: Node) => node.name === field); + const fieldNode = expandedRowMap[tree._root.nodeId].nodes._root.children.find( + (node: Node) => node.name === field + ); fieldValue = ( - {" "} + {' '} {fieldObj.value} { - this.updateExpandedRowMap( - fieldNode, - expandedRowMap, - true - ); + this.updateExpandedRowMap(fieldNode, expandedRowMap, true); scrollToNode(tree._root.nodeId); }} > @@ -693,7 +726,7 @@ class QueryResultsBody extends React.Component {fieldObj.value} @@ -701,13 +734,17 @@ class QueryResultsBody extends React.Component{tableCells}; + const tableRow = ( + + {tableCells} + + ); let row = {tableRow}; if (expandedRowMap[rowId] && expandedRowMap[rowId].expandedRow) { const tableRow = ( - {tableCells}{" "} + {tableCells}{' '} ); const expandedRow = ( @@ -737,12 +774,7 @@ class QueryResultsBody extends React.Component @@ -777,15 +809,15 @@ class QueryResultsBody extends React.Component console.log('open side nav'), - } + }, ]; return ( @@ -819,7 +851,7 @@ class QueryResultsBody extends React.Component ); } @@ -856,12 +888,14 @@ class QueryResultsBody extends React.Component - {this.props.language === 'SQL' && ( - <> - - {/*Table name*/} + <> + + {/*Table name*/} + {this.props.language === 'SQL' && (

@@ -874,27 +908,30 @@ class QueryResultsBody extends React.Component - - {/*Download button*/} - -
- - - -
-
- - {modal} - - )} + )} + {/*Download button*/} + {this.props.language === 'SQL' && + this.props.selectedDatasource && + this.props.selectedDatasource[0].label === 'OpenSearch' && ( + +
+ + + +
+
+ )} + + {modal} + {/*Table*/}
@@ -908,11 +945,7 @@ class QueryResultsBody extends React.Component - {this.renderRows( - this.items, - this.columns, - this.props.itemIdToExpandedRowMap - )} + {this.renderRows(this.items, this.columns, this.props.itemIdToExpandedRowMap)} diff --git a/public/components/QueryResults/__snapshots__/QueryResults.test.tsx.snap b/public/components/QueryResults/__snapshots__/QueryResults.test.tsx.snap index cd11dc41..5c99ca41 100644 --- a/public/components/QueryResults/__snapshots__/QueryResults.test.tsx.snap +++ b/public/components/QueryResults/__snapshots__/QueryResults.test.tsx.snap @@ -328,52 +328,6 @@ exports[` spec renders the component to test tabs down

-
-
-
-
- -
-
-
-
spec renders the component to test tabs down class="euiHorizontalRule euiHorizontalRule--full" />
+
@@ -9778,47 +9736,6 @@ exports[` spec renders the component with mock query re
-
-
-
-
- -
-
-
-
spec renders the component with mock query re class="euiHorizontalRule euiHorizontalRule--full" />
+
diff --git a/public/components/QueryResults/__snapshots__/QueryResultsBody.test.tsx.snap b/public/components/QueryResults/__snapshots__/QueryResultsBody.test.tsx.snap index 21f700e8..5e7ddd8f 100644 --- a/public/components/QueryResults/__snapshots__/QueryResultsBody.test.tsx.snap +++ b/public/components/QueryResults/__snapshots__/QueryResultsBody.test.tsx.snap @@ -9938,6 +9938,10 @@ exports[` spec renders component with mock QueryResults data exports[` spec renders component with mock QueryResults data 3`] = `
+
diff --git a/public/components/SQLPage/CreateButton.tsx b/public/components/SQLPage/CreateButton.tsx index b7ccf53c..d22eaf34 100644 --- a/public/components/SQLPage/CreateButton.tsx +++ b/public/components/SQLPage/CreateButton.tsx @@ -3,7 +3,7 @@ * SPDX-License-Identifier: Apache-2.0 */ -import { EuiButton, EuiContextMenu, EuiPopover } from '@elastic/eui'; +import { EuiButton, EuiComboBoxOptionOption, EuiContextMenu, EuiPopover } from '@elastic/eui'; import React, { useState } from 'react'; import { COVERING_INDEX_QUERY, @@ -14,9 +14,10 @@ import { interface CreateButtonProps { updateSQLQueries: (query: string) => void; + selectedDatasource: EuiComboBoxOptionOption[]; } -export const CreateButton = ({ updateSQLQueries }: CreateButtonProps) => { +export const CreateButton = ({ updateSQLQueries, selectedDatasource }: CreateButtonProps) => { const [isPopoverOpen, setIsPopoverOpen] = useState(false); const [selectedOption, setSelectedOption] = useState(null); @@ -63,42 +64,46 @@ export const CreateButton = ({ updateSQLQueries }: CreateButtonProps) => { ); return ( - - + {selectedDatasource && selectedDatasource[0].label !== 'OpenSearch' && ( + + - + { + id: 2, + title: 'Acceleration Index Options', + items: acceleratedIndexItems, + }, + ]} + /> + + )} + ); }; diff --git a/public/components/SQLPage/SQLPage.test.tsx b/public/components/SQLPage/SQLPage.test.tsx index d1e7ccc3..06f23edf 100644 --- a/public/components/SQLPage/SQLPage.test.tsx +++ b/public/components/SQLPage/SQLPage.test.tsx @@ -18,7 +18,7 @@ describe(' spec', () => { updateSQLQueries={() => {}} sqlTranslations={[]} sqlQuery={''} - selectedDatasource={''} + selectedDatasource={[{ label: 'OpenSearch' }]} /> ); expect(document.body.children[0]).toMatchSnapshot(); @@ -38,7 +38,7 @@ describe(' spec', () => { updateSQLQueries={updateSQLQueries} sqlTranslations={[]} sqlQuery={''} - selectedDatasource={'S3'} + selectedDatasource={[{ label: 'OpenSearch' }]} /> ); diff --git a/public/components/SQLPage/SQLPage.tsx b/public/components/SQLPage/SQLPage.tsx index 6d6436c8..b70029e6 100644 --- a/public/components/SQLPage/SQLPage.tsx +++ b/public/components/SQLPage/SQLPage.tsx @@ -141,7 +141,6 @@ export class SQLPage extends React.Component { enableLiveAutocompletion: true, }} aria-label="Code Editor" - isReadOnly={this.props.asyncLoading} /> @@ -167,18 +166,21 @@ export class SQLPage extends React.Component { Clear - this.props.onTranslate(this.props.sqlQuery)} - > - - Explain - - + {this.props.selectedDatasource && + this.props.selectedDatasource[0].label === 'OpenSearch' && ( + this.props.onTranslate(this.props.sqlQuery)} + > + + Explain + + + )} {this.props.selectedDatasource && diff --git a/public/components/SQLPage/__snapshots__/SQLPage.test.tsx.snap b/public/components/SQLPage/__snapshots__/SQLPage.test.tsx.snap index 603e920f..4db824cc 100644 --- a/public/components/SQLPage/__snapshots__/SQLPage.test.tsx.snap +++ b/public/components/SQLPage/__snapshots__/SQLPage.test.tsx.snap @@ -188,7 +188,6 @@ exports[` spec renders the component 1`] = `
-
@@ -382,24 +381,6 @@ exports[` spec tests the action buttons 1`] = `
-
- -
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 07b8f6a8..4d3fcc14 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 @@ -838,7 +838,7 @@ Array [ class="euiFormHelpText euiFormRow__text" id="some_html_id-help-0" > - Must be in lowercase letters. Cannot begin with underscores or hyphens. Spaces, commas, and characters :, ", *, +, /, \\, |, ?, #, >, or < are not allowed. Prefix and suffix are added to the name of generated OpenSearch index. + Must be in lowercase letters. Cannot begin with underscores. Spaces, commas, and characters -, :, ", *, +, /, \\, |, ?, #, >, or < are not allowed. Prefix and suffix are added to the name of generated OpenSearch index. @@ -2085,7 +2085,7 @@ Array [ className="euiFormHelpText euiFormRow__text" id="some_html_id-help-0" > - Must be in lowercase letters. Cannot begin with underscores or hyphens. Spaces, commas, and characters :, ", *, +, /, \\, |, ?, #, >, or < are not allowed. Prefix and suffix are added to the name of generated OpenSearch index. + Must be in lowercase letters. Cannot begin with underscores. Spaces, commas, and characters -, :, ", *, +, /, \\, |, ?, #, >, or < are not allowed. Prefix and suffix are added to the name of generated OpenSearch index. , diff --git a/public/components/acceleration/create/__tests__/utils.test.tsx b/public/components/acceleration/create/__tests__/utils.test.tsx index 8e4efbf3..6c2a9c68 100644 --- a/public/components/acceleration/create/__tests__/utils.test.tsx +++ b/public/components/acceleration/create/__tests__/utils.test.tsx @@ -134,12 +134,13 @@ describe('validateIndexName', () => { expect(validateIndexName('-invalid')).toEqual(['Enter a valid index name']); expect(validateIndexName('InVal1d')).toEqual(['Enter a valid index name']); expect(validateIndexName('invalid_with spaces')).toEqual(['Enter a valid index name']); + expect(validateIndexName('another-valid-name')).toEqual(['Enter a valid index name']); }); it('should return an empty array when the index name is valid', () => { expect(validateIndexName('valid')).toEqual([]); expect(validateIndexName('valid_name')).toEqual([]); - expect(validateIndexName('another-valid-name')).toEqual([]); + expect(validateIndexName('valid_name_index')).toEqual([]); }); it('should use the ACCELERATION_INDEX_NAME_REGEX pattern to validate the index name', () => { diff --git a/public/components/acceleration/selectors/__tests__/__snapshots__/define_index_options.test.tsx.snap b/public/components/acceleration/selectors/__tests__/__snapshots__/define_index_options.test.tsx.snap index 2ff218f3..acc218be 100644 --- a/public/components/acceleration/selectors/__tests__/__snapshots__/define_index_options.test.tsx.snap +++ b/public/components/acceleration/selectors/__tests__/__snapshots__/define_index_options.test.tsx.snap @@ -107,7 +107,7 @@ Array [ className="euiFormHelpText euiFormRow__text" id="some_html_id-help-0" > - Must be in lowercase letters. Cannot begin with underscores or hyphens. Spaces, commas, and characters :, ", *, +, /, \\, |, ?, #, >, or < are not allowed. Prefix and suffix are added to the name of generated OpenSearch index. + Must be in lowercase letters. Cannot begin with underscores. Spaces, commas, and characters -, :, ", *, +, /, \\, |, ?, #, >, or < are not allowed. Prefix and suffix are added to the name of generated OpenSearch index. , @@ -218,7 +218,7 @@ Array [ className="euiFormHelpText euiFormRow__text" id="some_html_id-help-0" > - Must be in lowercase letters. Cannot begin with underscores or hyphens. Spaces, commas, and characters :, ", *, +, /, \\, |, ?, #, >, or < are not allowed. Prefix and suffix are added to the name of generated OpenSearch index. + Must be in lowercase letters. Cannot begin with underscores. Spaces, commas, and characters -, :, ", *, +, /, \\, |, ?, #, >, or < are not allowed. Prefix and suffix are added to the name of generated OpenSearch index. , @@ -327,7 +327,7 @@ Array [ className="euiFormHelpText euiFormRow__text" id="some_html_id-help-0" > - Must be in lowercase letters. Cannot begin with underscores or hyphens. Spaces, commas, and characters :, ", *, +, /, \\, |, ?, #, >, or < are not allowed. Prefix and suffix are added to the name of generated OpenSearch index. + Must be in lowercase letters. Cannot begin with underscores. Spaces, commas, and characters -, :, ", *, +, /, \\, |, ?, #, >, or < are not allowed. Prefix and suffix are added to the name of generated OpenSearch index. , diff --git a/public/components/acceleration/selectors/define_index_options.tsx b/public/components/acceleration/selectors/define_index_options.tsx index 9deebd87..6d57e675 100644 --- a/public/components/acceleration/selectors/define_index_options.tsx +++ b/public/components/acceleration/selectors/define_index_options.tsx @@ -93,7 +93,7 @@ export const DefineIndexOptions = ({