Skip to content

Commit

Permalink
Add query result and time to the query editor footer (#7951) (#8003)
Browse files Browse the repository at this point in the history
* add query result to the footer



* fix unit test



* conditional language



* native language still use toast



* refactor to not use two states



* address comments



---------


(cherry picked from commit 7e8612f)

Signed-off-by: abbyhu2000 <[email protected]>
Signed-off-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
  • Loading branch information
1 parent 1c710f1 commit 9d5bf9a
Show file tree
Hide file tree
Showing 26 changed files with 215 additions and 51 deletions.
2 changes: 2 additions & 0 deletions changelogs/fragments/7951.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
feat:
- Add query result and time to the query editor footer ([#7951](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/7951))
2 changes: 2 additions & 0 deletions src/plugins/data/public/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -473,6 +473,8 @@ export {
LanguageServiceContract,
RecentQueriesTable,
QueryControls,
QueryResult,
QueryStatus,
SavedQuery,
SavedQueryService,
SavedQueryTimeFilter,
Expand Down
2 changes: 2 additions & 0 deletions src/plugins/data/public/query/query_string/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,4 +37,6 @@ export {
EditorEnhancements,
RecentQueriesTable,
QueryControls,
QueryResult,
QueryStatus,
} from './language_service';
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,4 @@

export * from './types';
export { LanguageServiceContract, LanguageService } from './language_service';
export { RecentQueriesTable, QueryControls } from './lib';
export { RecentQueriesTable, QueryControls, QueryResult, QueryStatus } from './lib';
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,4 @@ export * from './lucene_language';
export * from './default_language_reference';
export * from './get_query_control_links';
export * from './recent_query';
export * from './query_result';
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
/*
* Copyright OpenSearch Contributors
* SPDX-License-Identifier: Apache-2.0
*/

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

import './_recent_query.scss';
import { EuiButtonEmpty, EuiPopover, EuiText, EuiPopoverTitle } from '@elastic/eui';

import React, { useState } from 'react';

export enum ResultStatus {
UNINITIALIZED = 'uninitialized',
LOADING = 'loading', // initial data load
READY = 'ready', // results came back
NO_RESULTS = 'none', // no results came back
ERROR = 'error', // error occurred
}

export interface QueryStatus {
status: ResultStatus;
body?: {
error?: {
reason?: string;
details: string;
};
statusCode?: number;
};
elapsedMs?: number;
}

export function QueryResult(props: { queryStatus: QueryStatus }) {
const [isPopoverOpen, setPopover] = useState(false);
const onButtonClick = () => {
setPopover(!isPopoverOpen);
};

if (props.queryStatus.status === ResultStatus.READY) {
return (
<EuiButtonEmpty iconSide="left" iconType={'checkInCircleEmpty'} size="xs" onClick={() => {}}>
<EuiText size="xs" color="subdued">
{props.queryStatus.elapsedMs
? `Completed in ${props.queryStatus.elapsedMs} ms`
: 'Completed'}
</EuiText>
</EuiButtonEmpty>
);
}

if (!props.queryStatus.body || !props.queryStatus.body.error) {
return null;
}

return (
<EuiPopover
button={
<EuiButtonEmpty iconSide="left" iconType={'alert'} size="xs" onClick={onButtonClick}>
<EuiText size="xs" color="subdued">
{'Error'}
</EuiText>
</EuiButtonEmpty>
}
isOpen={isPopoverOpen}
closePopover={() => setPopover(false)}
panelPaddingSize="s"
anchorPosition={'downRight'}
>
<EuiPopoverTitle>ERRORS</EuiPopoverTitle>
<div style={{ width: '250px' }}>
<EuiText size="s">
<strong>
{i18n.translate('data.query.languageService.queryResults.reasons', {
defaultMessage: `Reasons:`,
})}
</strong>
{props.queryStatus.body.error.reason}
</EuiText>
<EuiText size="s">
<p>
<strong>
{i18n.translate('data.query.languageService.queryResults.details', {
defaultMessage: `Details:`,
})}
</strong>{' '}
{props.queryStatus.body.error.details}
</p>
</EuiText>
</div>
</EuiPopover>
);
}
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,7 @@ export class QueryStringManager {
const language = this.languageService.getLanguage(languageId);
const dataset = curQuery.dataset;
const input = language?.getQueryString(curQuery) || '';
this.languageService.setUserQueryString(input);

return {
query: input,
Expand Down
5 changes: 5 additions & 0 deletions src/plugins/data/public/ui/query_editor/query_editor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import {
EuiText,
PopoverAnchorPosition,
} from '@elastic/eui';
import { BehaviorSubject } from 'rxjs';
import classNames from 'classnames';
import { isEqual } from 'lodash';
import React, { Component, createRef, RefObject } from 'react';
Expand All @@ -27,6 +28,8 @@ import {
TimeRange,
QueryControls,
RecentQueriesTable,
QueryResult,
QueryStatus,
} from '../..';
import { OpenSearchDashboardsReactContextValue } from '../../../../opensearch_dashboards_react/public';
import { fromUser, getQueryLog, PersistedLog, toUser } from '../../query';
Expand Down Expand Up @@ -61,6 +64,7 @@ export interface QueryEditorProps {
filterBar?: any;
prepend?: React.ComponentProps<typeof EuiCompressedFieldText>['prepend'];
savedQueryManagement?: any;
queryStatus?: QueryStatus;
}

interface Props extends QueryEditorProps {
Expand Down Expand Up @@ -366,6 +370,7 @@ export default class QueryEditorUI extends Component<Props, State> {
<EuiText size="xs" color="subdued">
{this.props.query.dataset?.timeFieldName || ''}
</EuiText>,
<QueryResult queryStatus={this.props.queryStatus!} />,
],
end: [
<EuiButtonEmpty
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ import {
withOpenSearchDashboards,
} from '../../../../opensearch_dashboards_react/public';
import { UI_SETTINGS } from '../../../common';
import { getQueryLog, PersistedLog } from '../../query';
import { getQueryLog, PersistedLog, QueryStatus } from '../../query';
import { NoDataPopover } from './no_data_popover';
import QueryEditorUI from './query_editor';

Expand Down Expand Up @@ -54,6 +54,7 @@ export interface QueryEditorTopRowProps {
indicateNoData?: boolean;
datePickerRef?: React.RefObject<HTMLDivElement>;
savedQueryManagement?: any;
queryStatus?: QueryStatus;
}

// Needed for React.lazy
Expand Down Expand Up @@ -186,6 +187,7 @@ export default function QueryEditorTopRow(props: QueryEditorTopRowProps) {
dataTestSubj={props.dataTestSubj}
filterBar={props.filterBar}
savedQueryManagement={props.savedQueryManagement}
queryStatus={props.queryStatus}
/>
</EuiFlexItem>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,7 @@ export function createSearchBar({ core, storage, data }: StatefulSearchBarDeps)
showQueryBar={props.showQueryBar}
showQueryInput={props.showQueryInput}
showSaveQuery={props.showSaveQuery}
queryStatus={props.queryStatus}
screenTitle={props.screenTitle}
indexPatterns={props.indexPatterns}
indicateNoData={props.indicateNoData}
Expand Down
4 changes: 3 additions & 1 deletion src/plugins/data/public/ui/search_bar/search_bar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ import {
withOpenSearchDashboards,
} from '../../../../opensearch_dashboards_react/public';
import { Filter, IIndexPattern, Query, TimeRange, UI_SETTINGS } from '../../../common';
import { SavedQuery, SavedQueryAttributes, TimeHistoryContract } from '../../query';
import { SavedQuery, SavedQueryAttributes, TimeHistoryContract, QueryStatus } from '../../query';
import { IDataPluginServices } from '../../types';
import { FilterBar } from '../filter_bar/filter_bar';
import { QueryEditorTopRow } from '../query_editor';
Expand Down Expand Up @@ -92,6 +92,7 @@ export interface SearchBarOwnProps {

onRefresh?: (payload: { dateRange: TimeRange }) => void;
indicateNoData?: boolean;
queryStatus?: QueryStatus;
}

export type SearchBarProps = SearchBarOwnProps & SearchBarInjectedDeps;
Expand Down Expand Up @@ -550,6 +551,7 @@ class SearchBarUI extends Component<SearchBarProps, State> {
indicateNoData={this.props.indicateNoData}
datePickerRef={this.props.datePickerRef}
savedQueryManagement={searchBarMenu(false, true)}
queryStatus={this.props.queryStatus}
/>
);
}
Expand Down
1 change: 1 addition & 0 deletions src/plugins/data/public/ui/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
* SPDX-License-Identifier: Apache-2.0
*/

import { QueryStatus } from '../query';
import { IndexPatternSelectProps } from './index_pattern_select';
import { StatefulSearchBarProps } from './search_bar';
import { SuggestionsComponentProps } from './typeahead/suggestions_component';
Expand Down
3 changes: 3 additions & 0 deletions src/plugins/data/public/ui/ui_service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,16 @@
*/

import { CoreSetup, CoreStart, Plugin, PluginInitializerContext } from 'src/core/public';
import { BehaviorSubject } from 'rxjs';
import { ConfigSchema } from '../../config';
import { DataPublicPluginStart } from '../types';
import { createIndexPatternSelect } from './index_pattern_select';
import { createSearchBar } from './search_bar/create_search_bar';
import { SuggestionsComponent } from './typeahead';
import { IUiSetup, IUiStart } from './types';
import { DataStorage } from '../../common';
import { QueryStatus } from '../query';
import { ResultStatus } from '../query/query_string/language_service/lib';

/** @internal */
// eslint-disable-next-line @typescript-eslint/no-empty-interface
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,9 @@ export default function DiscoverCanvas({ setHeaderActionMenu, history, optionalR
{fetchState.status === ResultStatus.NO_RESULTS && (
<DiscoverNoResults timeFieldName={timeField} queryLanguage={''} />
)}
{fetchState.status === ResultStatus.ERROR && (
<DiscoverNoResults timeFieldName={timeField} queryLanguage={''} />
)}
{fetchState.status === ResultStatus.UNINITIALIZED && (
<DiscoverUninitialized onRefresh={() => refetch$.next()} />
)}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,11 @@ import { createPortal } from 'react-dom';
import { EuiButtonIcon, EuiFlexGroup, EuiFlexItem, EuiToolTip } from '@elastic/eui';
import { i18n } from '@osd/i18n';
import { AppMountParameters } from '../../../../../../core/public';
import { connectStorageToQueryState, opensearchFilters } from '../../../../../data/public';
import {
connectStorageToQueryState,
opensearchFilters,
QueryStatus,
} from '../../../../../data/public';
import { useOpenSearchDashboards } from '../../../../../opensearch_dashboards_react/public';
import { PLUGIN_ID } from '../../../../common';
import { DiscoverViewServices } from '../../../build_services';
Expand All @@ -21,6 +25,7 @@ import { useDispatch, setSavedQuery, useSelector } from '../../utils/state_manag

import './discover_canvas.scss';
import { TopNavMenuItemRenderType } from '../../../../../navigation/public';
import { ResultStatus } from '../utils';

export interface TopNavProps {
opts: {
Expand All @@ -34,9 +39,10 @@ export interface TopNavProps {

export const TopNav = ({ opts, showSaveQuery, isEnhancementsEnabled }: TopNavProps) => {
const { services } = useOpenSearchDashboards<DiscoverViewServices>();
const { inspectorAdapters, savedSearch, indexPattern } = useDiscoverContext();
const { data$, inspectorAdapters, savedSearch, indexPattern } = useDiscoverContext();
const [indexPatterns, setIndexPatterns] = useState<IndexPattern[] | undefined>(undefined);
const [screenTitle, setScreenTitle] = useState<string>('');
const [queryStatus, setQueryStatus] = useState<QueryStatus>({ status: ResultStatus.READY });
const state = useSelector((s) => s.discover);
const dispatch = useDispatch();

Expand Down Expand Up @@ -69,6 +75,16 @@ export const TopNav = ({ opts, showSaveQuery, isEnhancementsEnabled }: TopNavPro
uiSettings
);

useEffect(() => {
const subscription = data$.subscribe((queryData) => {
const result = {
status: queryData.status,
...queryData.queryStatus,
};
setQueryStatus(result);
});
}, [data$]);

useEffect(() => {
let isMounted = true;
const initializeDataset = async () => {
Expand Down Expand Up @@ -160,6 +176,7 @@ export const TopNav = ({ opts, showSaveQuery, isEnhancementsEnabled }: TopNavPro
datePickerRef={opts?.optionalRef?.datePickerRef}
groupActions={showActionsInGroup}
screenTitle={screenTitle}
queryStatus={queryStatus}
/>
</>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,4 @@

export * from './canvas';
export * from './panel';
export * from './utils';
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
/*
* Copyright OpenSearch Contributors
* SPDX-License-Identifier: Apache-2.0
*/

export { SearchData, ResultStatus } from './use_search';
Loading

0 comments on commit 9d5bf9a

Please sign in to comment.