Skip to content

Commit

Permalink
[discover] Query editor UI changes (#7866)
Browse files Browse the repository at this point in the history
* UI changes

Signed-off-by: abbyhu2000 <[email protected]>

* Changeset file for PR #7866 created/updated

---------

Signed-off-by: abbyhu2000 <[email protected]>
Co-authored-by: opensearch-changeset-bot[bot] <154024398+opensearch-changeset-bot[bot]@users.noreply.github.com>
  • Loading branch information
1 parent 8a96664 commit 333957b
Show file tree
Hide file tree
Showing 46 changed files with 3,829 additions and 140 deletions.
2 changes: 2 additions & 0 deletions changelogs/fragments/7866.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
feat:
- Query editor UI changes ([#7866](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/7866))
1 change: 1 addition & 0 deletions docs/_sidebar.md
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,7 @@
- [Opensearch dashboards.release notes 1.3.14](../release-notes/opensearch-dashboards.release-notes-1.3.14.md)
- [Opensearch dashboards.release notes 1.3.15](../release-notes/opensearch-dashboards.release-notes-1.3.15.md)
- [Opensearch dashboards.release notes 1.3.17](../release-notes/opensearch-dashboards.release-notes-1.3.17.md)
- [Opensearch dashboards.release notes 1.3.19](../release-notes/opensearch-dashboards.release-notes-1.3.19.md)
- [Opensearch dashboards.release notes 1.3.2](../release-notes/opensearch-dashboards.release-notes-1.3.2.md)
- [Opensearch dashboards.release notes 1.3.3](../release-notes/opensearch-dashboards.release-notes-1.3.3.md)
- [Opensearch dashboards.release notes 1.3.5](../release-notes/opensearch-dashboards.release-notes-1.3.5.md)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
.recentQuery__table {
padding: $euiSizeXS;
width: 1320px;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
/*
* Copyright OpenSearch Contributors
* SPDX-License-Identifier: Apache-2.0
*/

import { EuiFlyout } from '@elastic/eui';
import React from 'react';

/*
* "FlyoutContainers" component used to create flyouts
*
* Props taken in as params are:
* flyoutHeader - header JSX element of flyout
* flyoutBody - body JSX element of flyout
* flyoutFooter - footer JSX element of flyout
* ariaLabel - aria-label for focus of flyout
*/

interface Props {
closeFlyout: () => void;
flyoutHeader: JSX.Element;
flyoutBody: JSX.Element;
flyoutFooter: JSX.Element;
ariaLabel: string;
size?: string;
}

export const FlyoutContainers = ({
closeFlyout,
flyoutHeader,
flyoutBody,
flyoutFooter,
ariaLabel,
size,
}: Props) => {
return (
<div>
<EuiFlyout
className="observability-flyout"
ownFocus={false}
onClose={() => closeFlyout()}
size={size ? size : 'm'}
aria-labelledby={ariaLabel}
>
{flyoutHeader}
{flyoutBody}
{flyoutFooter}
</EuiFlyout>
</div>
);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,172 @@
/*
* Copyright OpenSearch Contributors
* SPDX-License-Identifier: Apache-2.0
*/

import { i18n } from '@osd/i18n';
import React, { useState } from 'react';
import {
EuiButtonIcon,
EuiFlexGroup,
EuiFlexItem,
EuiLink,
EuiPopoverTitle,
EuiText,
EuiWrappingPopover,
} from '@elastic/eui';
import ReactDOM from 'react-dom';
import { FormattedMessage } from 'react-intl';
import {
OpenSearchDashboardsContextProvider,
toMountPoint,
} from '../../../../../opensearch_dashboards_react/public';
import { IDataPluginServices } from '../../../types';
import { PPLReferenceFlyout } from './ppl_reference_flyout';

export interface QueryControl {
id: string;
label: string;
testId: string;
ariaLabel: string;
run: (anchorElement: HTMLElement) => void;
iconType: string;
}

export const QueryControls = (props: {
services: IDataPluginServices;
queryLanguage: string;
onToggleCollapse: () => void;
savedQueryManagement?: any;
additionalControls?: QueryControl[];
}) => {
const [isCollapsed, setIsCollapsed] = useState<boolean>(false);
const [isLanguageReferenceOpen, setIsLanguageReferenceOpen] = useState<boolean>(false);

const languageReferenceContainer = document.createElement('div');

const onCloseLanguageReference = () => {
ReactDOM.unmountComponentAtNode(languageReferenceContainer);
setIsLanguageReferenceOpen(false);
};

const osdDQLDocs = 'https://opensearch.org/docs/2.16/dashboards/dql)';
const dqlFullName = (
<FormattedMessage
id="data.query.queryBar.dqlFullLanguageName"
defaultMessage="OpenSearch Dashboards Query Language"
/>
);

const languageReference: QueryControl = {
id: 'languageReference',
label: i18n.translate('discover.queryControls.languageReference', {
defaultMessage: 'Open',
}),
testId: 'languageReference',
ariaLabel: i18n.translate('discover.queryControls.languageReference', {
defaultMessage: `Language Reference`,
}),
run: async (anchorElement) => {
if (props.queryLanguage === 'PPL' || props.queryLanguage === 'SQL') {
const flyoutSession = props.services.overlays!.openFlyout(
toMountPoint(
<OpenSearchDashboardsContextProvider services={props.services}>
<PPLReferenceFlyout
onClose={() => flyoutSession?.close?.().then()}
makeUrl={(searchId: any) => `#/view/${encodeURIComponent(searchId)}`}
/>
</OpenSearchDashboardsContextProvider>
)
);
} else {
if (isLanguageReferenceOpen) {
onCloseLanguageReference();
return;
}

setIsLanguageReferenceOpen(true);
document.body.appendChild(languageReferenceContainer);

const element = (
<EuiWrappingPopover
id="languageReferencePopover"
button={anchorElement}
isOpen={true}
closePopover={onCloseLanguageReference}
panelPaddingSize="s"
anchorPosition="downLeft"
anchorClassName="euiFormControlLayout__append"
>
<EuiPopoverTitle>
<FormattedMessage
id="data.query.queryBar.syntaxOptionsTitle"
defaultMessage="Syntax options"
/>
</EuiPopoverTitle>
<div style={{ width: '350px' }}>
<EuiText size="s">
<p>
<FormattedMessage
id="data.query.queryBar.syntaxOptionsDescription"
defaultMessage="The {docsLink} (DQL) offers a simplified query
syntax and support for scripted fields."
values={{
docsLink: (
<EuiLink href={osdDQLDocs} target="_blank">
{dqlFullName}
</EuiLink>
),
}}
/>
</p>
</EuiText>
</div>
</EuiWrappingPopover>
);

ReactDOM.render(element, languageReferenceContainer);
}
},
iconType: 'iInCircle',
};

const languageToggle: QueryControl = {
id: 'languageToggle',
label: i18n.translate('discover.queryControls.languageToggle', {
defaultMessage: 'Toggle',
}),
testId: 'languageToggle',
ariaLabel: i18n.translate('discover.queryControls.languageToggle', {
defaultMessage: `Language Toggle`,
}),
run: () => {
setIsCollapsed(!isCollapsed);
props.onToggleCollapse();
},
iconType: isCollapsed ? 'expand' : 'minimize',
};

const queryControls =
props.queryLanguage === 'PPL' || props.queryLanguage === 'SQL'
? [languageReference, languageToggle]
: [languageReference];

if (props.additionalControls) {
queryControls.push(...props.additionalControls);
}

return (
<EuiFlexGroup responsive={false} gutterSize="s" alignItems="center">
{queryControls.map((queryControl) => (
<EuiFlexItem grow={false}>
<EuiButtonIcon
iconType={queryControl.iconType}
aria-label={queryControl.ariaLabel}
onClick={(event) => queryControl.run(event.currentTarget)}
/>
</EuiFlexItem>
))}
{props.savedQueryManagement}
</EuiFlexGroup>
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,10 @@ export class LanguageService {
this.queryEditorExtensionMap = {};
}

public createDefaultQueryEditor() {
return createEditor(SingleLineInput, SingleLineInput, DQLBody);
}

public __enhance = (enhancements: UiEnhancements) => {
if (enhancements.queryEditorExtension) {
this.queryEditorExtensionMap[enhancements.queryEditorExtension.id] =
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
/*
* Copyright OpenSearch Contributors
* SPDX-License-Identifier: Apache-2.0
*/

export const dedupCmd = `## dedup
---
### Description
Use the \'dedup\' command to remove identical documents from the search results, based on the specified field.
### Syntax
dedup \[int\] &lt;field-list&gt; \[keepempty=&lt;bool&gt;\]
\[consecutive=&lt;bool&gt;\]
- \`field-list\`: Required. The comma-delimited field list. At least one field is required.
- \`consecutive\`: Optional. If set to \`true\`, removes duplicate events, where the duplicate events have consecutive timestamps. Default is \`false\`.
- \`int\`: Optional. The \'dedup\' command retains multiple events for each combination when you specify \`&lt;int&gt;\`. The number for \`&lt;int&gt;\` must be greater than 0. If you do not specify a number, only the first occurring event is kept. All other duplicates are removed from the results. Default is \`1\`.
- \`keepempty\`: Optional. If set to \`true\`, keeps the document if any field in the \`field-list\` is null or missing. Default is \`false\`.
#### Example 1: Dedup by one field
The following example PPL query shows how to use \`dedup\` to remove duplicate documents based on the \`gender\` field:
os> source=accounts | dedup gender | fields account_number, gender;
fetched rows / total rows = 2/2
+------------------+----------+
| account_number | gender |
|------------------+----------|
| 1 | M |
| 13 | F |
+------------------+----------+
#### Example 2: Keep two duplicate documents
The following example PPL query shows how to use \`dedup\` to remove duplicate documents based on the \`gender\` field while keeping two duplicates:
os> source=accounts | dedup 2 gender | fields account_number, gender;
fetched rows / total rows = 3/3
+------------------+----------+
| account_number | gender |
|------------------+----------|
| 1 | M |
| 6 | M |
| 13 | F |
+------------------+----------+
#### Example 3: Keep or ignore empty fields by default
The following example PPL query shows how to use \`dedup\` to remove duplicate documents while keeping documents with null values in the specified field:
os> source=accounts | dedup email keepempty=true | fields account_number, email;
fetched rows / total rows = 4/4
+------------------+-----------------------+
| account_number | email |
|------------------+-----------------------|
| 1 | [email protected] |
| 6 | [email protected] |
| 13 | null |
| 18 | [email protected] |
+------------------+-----------------------+
The following example PPL query shows how to use \`dedup\` to remove duplicate documents while ignoring documents with empty values in the specified field:
os> source=accounts | dedup email | fields account_number, email;
fetched rows / total rows = 3/3
+------------------+-----------------------+
| account_number | email |
|------------------+-----------------------|
| 1 | [email protected] |
| 6 | [email protected] |
| 18 | [email protected] |
+------------------+-----------------------+
#### Example 4: Remove duplicate consecutive documents
The following example PPL query shows how to use \`dedup\` to remove duplicate consecutive documents:
os> source=accounts | dedup gender consecutive=true | fields account_number, gender;
fetched rows / total rows = 3/3
+------------------+----------+
| account_number | gender |
|------------------+----------|
| 1 | M |
| 13 | F |
| 18 | M |
+------------------+----------+
### Limitation
The \`dedup\` command is not rewritten to [query domain-specific language (DSL)](https://opensearch.org/docs/latest/query-dsl/index/). It is only run on the coordinating node.
`;
Loading

0 comments on commit 333957b

Please sign in to comment.