Skip to content

Commit

Permalink
[discover] Query editor UI clean up (#7896) (#7902)
Browse files Browse the repository at this point in the history
* follow up



* address comments



* Changeset file for PR #7896 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 cebd1a1 commit e886b27
Show file tree
Hide file tree
Showing 36 changed files with 192 additions and 190 deletions.
2 changes: 2 additions & 0 deletions changelogs/fragments/7896.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
fix:
- Query editor UI clean up ([#7896](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/7896))
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
/*
* Copyright OpenSearch Contributors
* SPDX-License-Identifier: Apache-2.0
*/

import { i18n } from '@osd/i18n';

import { EuiButtonIcon, EuiLink, EuiPopover, EuiPopoverTitle, EuiText } from '@elastic/eui';

import React from 'react';
import { FormattedMessage } from 'react-intl';
import { IDataPluginServices } from '../../../types';
import { useOpenSearchDashboards } from '../../../../../opensearch_dashboards_react/public';

export const DefaultLanguageReference = () => {
const opensearchDashboards = useOpenSearchDashboards<IDataPluginServices>();
const [isLanguageReferenceOpen, setIsLanguageReferenceOpen] = React.useState(false);
const osdDQLDocs = opensearchDashboards.services.docLinks?.links.opensearchDashboards.dql.base;
const dqlFullName = (
<FormattedMessage
id="data.query.queryBar.dqlFullLanguageName"
defaultMessage="OpenSearch Dashboards Query Language"
/>
);

const button = (
<div>
<EuiButtonIcon
iconType={'iInCircle'}
aria-label={i18n.translate('discover.queryControls.languageReference', {
defaultMessage: `Language Reference`,
})}
onClick={() => setIsLanguageReferenceOpen(!isLanguageReferenceOpen)}
/>
</div>
);

return (
<EuiPopover
id="languageReferencePopover"
button={button}
isOpen={isLanguageReferenceOpen}
closePopover={() => setIsLanguageReferenceOpen(false)}
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>
</EuiPopover>
);
};

export const createDefaultLanguageReference = () => {
return <DefaultLanguageReference />;
};
Original file line number Diff line number Diff line change
Expand Up @@ -3,170 +3,17 @@
* 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 = props.services.docLinks?.links.opensearchDashboards.dql.base;
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);
}
import React from 'react';
import { EuiFlexItem } from '@elastic/eui';

export const QueryControls = (props: { queryControls: React.ReactElement[] }) => {
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)}
/>
<>
{props.queryControls.map((queryControl, idx) => (
<EuiFlexItem grow={false} key={idx}>
{queryControl}
</EuiFlexItem>
))}
{props.savedQueryManagement}
</EuiFlexGroup>
</>
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import {
UiEnhancements,
} from '../../../ui';
import { DataStorage, setOverrides as setFieldOverrides } from '../../../../common';
import { createDefaultLanguageReference } from './default_language_reference';

export class LanguageService {
private languages: Map<string, LanguageConfig> = new Map();
Expand All @@ -27,22 +28,27 @@ export class LanguageService {
this.queryEditorExtensionMap = {};
}

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

public __enhance = (enhancements: UiEnhancements) => {
if (enhancements.queryEditorExtension) {
this.queryEditorExtensionMap[enhancements.queryEditorExtension.id] =
enhancements.queryEditorExtension;
}
};

public createDefaultLanguageReference = () => {
return createDefaultLanguageReference();
};

/**
* Registers default handlers for index patterns and indices.
*/
private registerDefaultLanguages() {
const defaultEditor = createEditor(SingleLineInput, SingleLineInput, DQLBody);
const defaultEditor = createEditor(
SingleLineInput,
SingleLineInput,
[this.createDefaultLanguageReference()],
DQLBody
);
this.registerLanguage(getDQLLanguageConfig(this.defaultSearchInterceptor, defaultEditor));
this.registerLanguage(getLuceneLanguageConfig(this.defaultSearchInterceptor, defaultEditor));
}
Expand Down
11 changes: 3 additions & 8 deletions src/plugins/data/public/ui/query_editor/editors/shared.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,18 +21,11 @@ type CollapsedComponent<T> = React.ComponentType<T>;
type ExpandedComponent<T> = React.ComponentType<T> | null;
type BodyComponent<T> = React.ComponentType<T>;

export interface Editor<TCollapsed, TExpanded, TBody> {
TopBar: {
Collapsed: CollapsedComponent<TCollapsed>;
Expanded: ExpandedComponent<TExpanded>;
};
Body: BodyComponent<TBody>;
}

export interface EditorInstance<TCollapsed, TExpanded, TBody> {
TopBar: {
Collapsed: () => React.ReactElement;
Expanded: (() => React.ReactElement) | null;
Controls: React.ReactElement[];
};
Body: () => React.ReactElement;
}
Expand All @@ -44,6 +37,7 @@ export function createEditor<
>(
collapsed: CollapsedComponent<TCollapsed>,
expanded: ExpandedComponent<TExpanded>,
controls: React.ReactElement[],
body: BodyComponent<TBody>
) {
return (
Expand All @@ -54,6 +48,7 @@ export function createEditor<
TopBar: {
Collapsed: () => React.createElement(collapsed, collapsedProps),
Expanded: expanded ? () => React.createElement(expanded, expandedProps) : null,
Controls: controls,
},
Body: () => React.createElement(body, bodyProps),
});
Expand Down
Loading

0 comments on commit e886b27

Please sign in to comment.