-
Notifications
You must be signed in to change notification settings - Fork 884
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[Discover] notify user about field_type_tolerance for SQL/PPL in quer…
…y footer Signed-off-by: Joshua Li <[email protected]>
- Loading branch information
1 parent
9a25d0d
commit 7bc469b
Showing
12 changed files
with
268 additions
and
10 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -4,3 +4,4 @@ | |
*/ | ||
|
||
@import "./query_assist"; | ||
@import "./query_editor_extensions"; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
15 changes: 15 additions & 0 deletions
15
src/plugins/query_enhancements/public/query_editor_extensions/_index.scss
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
/* | ||
* Copyright OpenSearch Contributors | ||
* SPDX-License-Identifier: Apache-2.0 | ||
*/ | ||
|
||
.queryEnhancements { | ||
.sqlArrayInfoPopoverText { | ||
width: 280px; | ||
|
||
p { | ||
// align with text after icon + gutter | ||
margin-left: calc($euiSizeM + $euiSizeM); | ||
} | ||
} | ||
} |
81 changes: 81 additions & 0 deletions
81
...query_enhancements/public/query_editor_extensions/field_type_tolerance_info_icon.test.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,81 @@ | ||
/* | ||
* Copyright OpenSearch Contributors | ||
* SPDX-License-Identifier: Apache-2.0 | ||
*/ | ||
|
||
import '@testing-library/jest-dom'; | ||
import { fireEvent, render, waitFor } from '@testing-library/react'; | ||
import React from 'react'; | ||
import { IntlProvider } from 'react-intl'; | ||
import { coreMock } from '../../../../core/public/mocks'; | ||
import { DEFAULT_DATA } from '../../../data/common'; | ||
import { dataPluginMock } from '../../../data/public/mocks'; | ||
import { useOpenSearchDashboards } from '../../../opensearch_dashboards_react/public'; | ||
import { FieldTypeToleranceInfoIcon } from './field_type_tolerance_info_icon'; | ||
|
||
jest.mock('../../../opensearch_dashboards_react/public', () => ({ | ||
useOpenSearchDashboards: jest.fn(), | ||
})); | ||
|
||
const coreSetupMock = coreMock.createSetup(); | ||
const dataMock = dataPluginMock.createSetupContract(); | ||
const getQueryMock = dataMock.query.queryString.getQuery as jest.Mock; | ||
const startMock = coreMock.createStart(); | ||
|
||
describe('FieldTypeToleranceInfoIcon', () => { | ||
const renderComponent = () => | ||
render( | ||
<IntlProvider locale="en"> | ||
<FieldTypeToleranceInfoIcon core={coreSetupMock} data={dataMock} /> | ||
</IntlProvider> | ||
); | ||
|
||
beforeEach(() => { | ||
jest.clearAllMocks(); | ||
localStorage.clear(); | ||
jest.useFakeTimers(); | ||
(useOpenSearchDashboards as jest.Mock).mockReturnValue({ services: startMock }); | ||
}); | ||
|
||
it('should render null when datasource is not OpenSearch', async () => { | ||
getQueryMock.mockReturnValueOnce({ dataset: { dataSource: { type: 'S3' } } }); | ||
const { container } = renderComponent(); | ||
jest.runAllTimers(); | ||
|
||
await waitFor(() => expect(coreSetupMock.http.post).not.toHaveBeenCalled()); | ||
expect(container).toBeEmptyDOMElement(); | ||
}); | ||
|
||
it('should render null when field type tolerance is enabled', async () => { | ||
coreSetupMock.http.post.mockResolvedValueOnce({ | ||
persistent: { 'plugins.query.field_type_tolerance': 'true' }, | ||
transient: {}, | ||
}); | ||
getQueryMock.mockReturnValueOnce({ | ||
dataset: { dataSource: { type: DEFAULT_DATA.SOURCE_TYPES.OPENSEARCH } }, | ||
}); | ||
|
||
const { container } = renderComponent(); | ||
jest.runAllTimers(); | ||
|
||
await waitFor(() => expect(coreSetupMock.http.post).toHaveBeenCalled()); | ||
expect(container).toBeEmptyDOMElement(); | ||
}); | ||
|
||
it('should show popover if field type tolerance is disabled', async () => { | ||
coreSetupMock.http.post.mockResolvedValueOnce({ | ||
persistent: { 'plugins.query.field_type_tolerance': 'false' }, | ||
transient: {}, | ||
}); | ||
getQueryMock.mockReturnValueOnce({ | ||
dataset: { dataSource: { type: DEFAULT_DATA.SOURCE_TYPES.OPENSEARCH } }, | ||
}); | ||
|
||
const { getByRole, queryByText } = renderComponent(); | ||
jest.runAllTimers(); | ||
|
||
await waitFor(() => expect(getByRole('button')).toBeInTheDocument()); | ||
fireEvent.click(getByRole('button')); | ||
expect(queryByText('No array datatype support')).toBeInTheDocument(); | ||
}); | ||
}); |
134 changes: 134 additions & 0 deletions
134
...gins/query_enhancements/public/query_editor_extensions/field_type_tolerance_info_icon.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,134 @@ | ||
/* | ||
* Copyright OpenSearch Contributors | ||
* SPDX-License-Identifier: Apache-2.0 | ||
*/ | ||
|
||
import { | ||
EuiButtonIcon, | ||
EuiFlexGroup, | ||
EuiFlexItem, | ||
EuiIcon, | ||
EuiLink, | ||
EuiPopover, | ||
EuiText, | ||
} from '@elastic/eui'; | ||
import { FormattedMessage } from '@osd/i18n/react'; | ||
import { i18n } from '@osd/i18n'; | ||
import React, { useState } from 'react'; | ||
import { useEffectOnce } from 'react-use'; | ||
import { CoreSetup, DocLinksStart } from '../../../../core/public'; | ||
import { DEFAULT_DATA } from '../../../data/common'; | ||
import { DataPublicPluginSetup } from '../../../data/public'; | ||
import { useOpenSearchDashboards } from '../../../opensearch_dashboards_react/public'; | ||
|
||
interface FieldTypeToleranceInfoIconProps { | ||
core: CoreSetup; | ||
data: DataPublicPluginSetup; | ||
} | ||
|
||
const SQL_ARRAY_INFO_FOOTER_STORAGE_KEY = 'queryEnhancements:sqlArrayInfoAcknowledged'; | ||
const FIELD_TYPE_TOLERANCE_SETTING_KEY = 'plugins.query.field_type_tolerance'; | ||
|
||
const fieldTypeToleranceEnabledByDataSource: Map<string | undefined, boolean> = new Map(); | ||
|
||
/** | ||
* Info icon to be added in query editor footer to notify user about SQL/PPL | ||
* field type tolerance. The icon should only be visible if field type | ||
* tolerance is unset or set to false, and the selected datasource is | ||
* OpenSearch Cluster. External datasources like S3 are not affected. | ||
*/ | ||
export const FieldTypeToleranceInfoIcon: React.FC<FieldTypeToleranceInfoIconProps> = (props) => { | ||
const { services } = useOpenSearchDashboards<{ docLinks: DocLinksStart }>(); | ||
const [isHidden, setIsHidden] = useState(true); | ||
const [isPopoverOpen, _setIsPopoverOpen] = useState(false); | ||
const setIsPopoverOpen: typeof _setIsPopoverOpen = (isOpen) => { | ||
if (!isOpen) { | ||
window.localStorage.setItem(SQL_ARRAY_INFO_FOOTER_STORAGE_KEY, 'true'); | ||
} | ||
_setIsPopoverOpen(isOpen); | ||
}; | ||
|
||
useEffectOnce(() => { | ||
const query = props.data.query.queryString.getQuery(); | ||
if ( | ||
query.dataset?.dataSource?.type !== DEFAULT_DATA.SOURCE_TYPES.OPENSEARCH && // datasource is not MDS OpenSearch | ||
query.dataset?.dataSource?.type !== 'DATA_SOURCE' && // datasource is not MDS OpenSearch when using indexes | ||
query.dataset?.type !== DEFAULT_DATA.SET_TYPES.INDEX_PATTERN // dataset is not index pattern | ||
) | ||
return; | ||
|
||
(async () => { | ||
const dataSourceId = query.dataset?.dataSource?.id || undefined; | ||
let isFieldTypeToleranceEnabled = fieldTypeToleranceEnabledByDataSource.get(dataSourceId); | ||
if (isFieldTypeToleranceEnabled === undefined) { | ||
isFieldTypeToleranceEnabled = await props.core.http | ||
.post('/api/console/proxy', { | ||
query: { path: '_cluster/settings?flat_settings=true', method: 'GET', dataSourceId }, | ||
}) | ||
.then( | ||
(settings) => | ||
!!( | ||
settings.persistent[FIELD_TYPE_TOLERANCE_SETTING_KEY] === 'true' || | ||
settings.transient[FIELD_TYPE_TOLERANCE_SETTING_KEY] === 'true' | ||
) | ||
) | ||
.catch(() => true); | ||
if (isFieldTypeToleranceEnabled === false) { | ||
setIsHidden(false); | ||
if (window.localStorage.getItem(SQL_ARRAY_INFO_FOOTER_STORAGE_KEY) !== 'true') { | ||
// open popover after button rendering to position it correctly | ||
setTimeout(() => setIsPopoverOpen(true), 1000); | ||
} | ||
} | ||
} | ||
})(); | ||
}); | ||
|
||
if (isHidden) return null; | ||
|
||
return ( | ||
<EuiPopover | ||
button={ | ||
<EuiButtonIcon | ||
aria-label={i18n.translate('queryEnhancements.sqlArrayInfo.buttonIcon.ariaLabel', { | ||
defaultMessage: 'Toggle field type tolerance information', | ||
})} | ||
iconType="iInCircle" | ||
color="text" | ||
onClick={() => setIsPopoverOpen(!isPopoverOpen)} | ||
/> | ||
} | ||
isOpen={isPopoverOpen} | ||
closePopover={() => setIsPopoverOpen(false)} | ||
panelClassName="queryEnhancements" | ||
> | ||
<EuiText size="s" className="sqlArrayInfoPopoverText"> | ||
<h4> | ||
<EuiFlexGroup gutterSize="s" alignItems="center"> | ||
<EuiFlexItem grow={false}> | ||
<EuiIcon type="iInCircle" /> | ||
</EuiFlexItem> | ||
<EuiFlexItem> | ||
<FormattedMessage | ||
id="queryEnhancements.sqlArrayInfo.title" | ||
defaultMessage="No array datatype support" | ||
/> | ||
</EuiFlexItem> | ||
</EuiFlexGroup> | ||
</h4> | ||
<p> | ||
<FormattedMessage | ||
id="queryEnhancements.sqlArrayInfo.message" | ||
defaultMessage="Only the first element of multiple field values will be returned. " | ||
/> | ||
<EuiLink href={services.docLinks.links.noDocumentation.sql.limitation} target="_blank"> | ||
<FormattedMessage | ||
id="queryEnhancements.sqlArrayInfo.learnMore" | ||
defaultMessage="Learn more" | ||
/> | ||
</EuiLink> | ||
</p> | ||
</EuiText> | ||
</EuiPopover> | ||
); | ||
}; |
Oops, something went wrong.