From e20149e52006d17a706138f57e490de940b191bf Mon Sep 17 00:00:00 2001 From: Anan Zhuang Date: Thu, 17 Oct 2024 20:04:31 -0700 Subject: [PATCH] Fix No data selected appearance (#8668) Also: * Fix some React errors Signed-off-by: Miki --------- Fix random big number during loading in query editor result (#8650) * Fix random big number during loading in query editor result Signed-off-by: abbyhu2000 * Changeset file for PR #8650 created/updated * Fix initial loading number Signed-off-by: abbyhu2000 (cherry picked from commit a7414f07c987d64d50fe1d72b08eadb033381dae) --------- [bug] address different issues with dataset selector (#8665) * [bug] address some issues with dataset selector Moved the dataset selector back to the search bar and access it by ref in the sidebar. Avoid out of sync issue. * update the logic for ensuring index pattern * dont add ability to open button * empty state but missing data set selector button * fix tests * add back styling Signed-off-by: Kawika Avilla (cherry picked from commit e23f3327d95552b2b42767149725eb987d56c3e7) --------- [bug] Discover UI stuck on searching after deleting index pattern (#8659) * [bug] Discover UI stuck on searching after deleting index pattern When using Discover with query enhancement enabled, deleting an index pattern from Index Management does not properly update the "Recently selected data" list in Discover. This causes the UI to become stuck in a "Searching" state when attempting to use Discover after deleting an index pattern. Handle the error case where the use index patterns hook caught error when enhancements was enabled. issue resolved: https://github.com/opensearch-project/OpenSearch-Dashboards/issues/8612 (cherry picked from commit 480809431497fc1a0c114452a40526dc32c92ec7) --------- [Discover]Sample Queries and Saved Queries in No Results Page (#8616) * Sample Queries and Saved Queries in No Results Page Signed-off-by: Sean Li Signed-off-by: Miki * Changeset file for PR #8616 created/updated * Update styling Signed-off-by: Miki (cherry picked from commit 9da1b77bca36d209be7ec9a986500b691fc521e0) --------- Improve Empty State Handling: Add No Index Patterns Panel with Data Selection in Discover View (#8613) * Improve Empty State Handling: Add No Index Patterns Panel with Data Selection in Discover View This PR primarily addresses the scenario when no index patterns (general) is available in the Discover view. Instead of redirecting users to the index management page, it introduces a new "No Index Patterns" panel. This panel provides users with the option to open a data selector and add index patterns directly from the Discover view, improving the user experience for new or empty deployments. To achieve, we move the selectedDataset state from ConnectedDatasetSelector to the app container's state management. This allows the AdvancedSelector, opened from the AppContainer, to update the dataset state effectively. Key changes include: * Implementing NoIndexPatternsPanel and AdvancedSelector components. * Refactoring dataset state management in AppContainer and Sidebar. * Modifying DiscoverCanvas to conditionally render NoIndexPatternsPanel. * Updating ConnectedDatasetSelector to use shared state and dataset change handling. * Update design of no data selected * use i18n * fix comments * Update design of no data selected * fix lint error Signed-off-by: Anan Zhuang (cherry picked from commit 66591391f631400ec6825c7b6e09659aa0760a5d) --------- Update Discover appearance (#8651) * Update Discover appearance Signed-off-by: Miki (cherry picked from commit 17103ba86370456fa5df6ccc722a22bee8fe2d35) --------- Move DatasetSelector from data plugin queryString comp to DataExplorer (#8598) * Move DatasetSelector to DataExplorer * Style Disover after moving DatasetSelector to DataExplorer * fix the test by adding the getUpdates$ method to the mock queryString object Signed-off-by: Anan Zhuang (cherry picked from commit 923cce847b09001dc5b3730c9bad54857d363532) --- changelogs/fragments/8650.yml | 2 + .../ensure_default_index_pattern.ts | 11 +- .../language_service/lib/dql_language.ts | 6 ++ .../language_service/lib/lucene_language.ts | 6 ++ .../language_service/lib/query_result.tsx | 62 +++++------ .../query_string/language_service/types.ts | 4 + .../data/public/ui/dataset_selector/index.tsx | 33 +++--- .../public/ui/filter_bar/filter_options.tsx | 3 +- src/plugins/data/public/ui/index.ts | 5 +- .../language_selector.test.tsx.snap | 8 -- .../public/ui/query_editor/_query_editor.scss | 3 - .../editors/default_editor/index.tsx | 16 ++- .../ui/query_editor/language_selector.tsx | 1 - .../public/ui/query_editor/query_editor.tsx | 2 - .../ui/query_editor/query_editor_top_row.tsx | 37 +++++-- .../ui/search_bar/create_search_bar.tsx | 1 + .../data/public/ui/search_bar/search_bar.tsx | 5 +- src/plugins/data/public/ui/ui_service.ts | 3 - .../public/components/app_container.tsx | 14 +-- .../public/components/sidebar/index.tsx | 80 ++++---------- src/plugins/data_explorer/public/index.ts | 2 - .../no_index_patterns/no_index_patterns.scss | 12 +++ .../no_index_patterns/no_index_patterns.tsx | 89 ++++++++++++++++ .../components/no_results/no_results.tsx | 28 ++--- .../lib/get_index_pattern_field_list.ts | 3 +- .../view_components/canvas/index.tsx | 100 ++++-------------- .../view_components/canvas/top_nav.tsx | 57 +++------- .../query_enhancements/public/plugin.tsx | 12 +++ 28 files changed, 302 insertions(+), 303 deletions(-) create mode 100644 changelogs/fragments/8650.yml create mode 100644 src/plugins/discover/public/application/components/no_index_patterns/no_index_patterns.scss create mode 100644 src/plugins/discover/public/application/components/no_index_patterns/no_index_patterns.tsx diff --git a/changelogs/fragments/8650.yml b/changelogs/fragments/8650.yml new file mode 100644 index 000000000000..3f53ba7a41fa --- /dev/null +++ b/changelogs/fragments/8650.yml @@ -0,0 +1,2 @@ +fix: +- Fix random big number when loading in query result ([#8650](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/8650)) \ No newline at end of file diff --git a/src/plugins/data/common/index_patterns/index_patterns/ensure_default_index_pattern.ts b/src/plugins/data/common/index_patterns/index_patterns/ensure_default_index_pattern.ts index 9fed0e1d0519..94df6995186a 100644 --- a/src/plugins/data/common/index_patterns/index_patterns/ensure_default_index_pattern.ts +++ b/src/plugins/data/common/index_patterns/index_patterns/ensure_default_index_pattern.ts @@ -32,9 +32,7 @@ import { includes } from 'lodash'; import { IndexPatternsContract } from './index_patterns'; import { UiSettingsCommon } from '../types'; -export type EnsureDefaultIndexPattern = ( - shouldRedirect?: boolean -) => Promise | undefined; +export type EnsureDefaultIndexPattern = () => Promise | undefined; export const createEnsureDefaultIndexPattern = ( uiSettings: UiSettingsCommon, @@ -44,10 +42,7 @@ export const createEnsureDefaultIndexPattern = ( * Checks whether a default index pattern is set and exists and defines * one otherwise. */ - return async function ensureDefaultIndexPattern( - this: IndexPatternsContract, - shouldRedirect: boolean = true - ) { + return async function ensureDefaultIndexPattern(this: IndexPatternsContract) { const patterns = await this.getIds(); let defaultId = await uiSettings.get('defaultIndex'); let defined = !!defaultId; @@ -67,6 +62,8 @@ export const createEnsureDefaultIndexPattern = ( defaultId = patterns[0]; await uiSettings.set('defaultIndex', defaultId); } else { + const isEnhancementsEnabled = await uiSettings.get('query:enhancements:enabled'); + const shouldRedirect = !isEnhancementsEnabled; if (shouldRedirect) return onRedirectNoIndexPattern(); else return; } diff --git a/src/plugins/data/public/query/query_string/language_service/lib/dql_language.ts b/src/plugins/data/public/query/query_string/language_service/lib/dql_language.ts index 6816bf0d7121..402af7482d08 100644 --- a/src/plugins/data/public/query/query_string/language_service/lib/dql_language.ts +++ b/src/plugins/data/public/query/query_string/language_service/lib/dql_language.ts @@ -24,6 +24,12 @@ export const getDQLLanguageConfig = ( visualizable: true, }, showDocLinks: true, + docLink: { + title: i18n.translate('data.dqlLanguage.docLink', { + defaultMessage: 'DQL documentation', + }), + url: 'https://opensearch.org/docs/latest/query-dsl/full-text/query-string/', + }, editorSupportedAppNames: ['discover'], supportedAppNames: ['discover', 'dashboards', 'visualize', 'data-explorer', 'vis-builder', '*'], sampleQueries: [ diff --git a/src/plugins/data/public/query/query_string/language_service/lib/lucene_language.ts b/src/plugins/data/public/query/query_string/language_service/lib/lucene_language.ts index c42b14543633..4da92f868654 100644 --- a/src/plugins/data/public/query/query_string/language_service/lib/lucene_language.ts +++ b/src/plugins/data/public/query/query_string/language_service/lib/lucene_language.ts @@ -24,6 +24,12 @@ export const getLuceneLanguageConfig = ( visualizable: true, }, showDocLinks: true, + docLink: { + title: i18n.translate('data.luceneLanguage.docLink', { + defaultMessage: 'Lucene documentation', + }), + url: 'https://opensearch.org/docs/latest/query-dsl/full-text/query-string/', + }, editorSupportedAppNames: ['discover'], supportedAppNames: ['discover', 'dashboards', 'visualize', 'data-explorer', 'vis-builder', '*'], sampleQueries: [ diff --git a/src/plugins/data/public/query/query_string/language_service/lib/query_result.tsx b/src/plugins/data/public/query/query_string/language_service/lib/query_result.tsx index 042d2e11a664..074ba4b5d0d5 100644 --- a/src/plugins/data/public/query/query_string/language_service/lib/query_result.tsx +++ b/src/plugins/data/public/query/query_string/language_service/lib/query_result.tsx @@ -41,40 +41,42 @@ export function QueryResult(props: { queryStatus: QueryStatus }) { setPopover(!isPopoverOpen); }; - const updateElapsedTime = () => { - const time = Date.now() - (props.queryStatus.startTime || 0); - if (time > BUFFER_TIME) { - setElapsedTime(time); - } else { - setElapsedTime(0); - } - }; - useEffect(() => { + const updateElapsedTime = () => { + const currentTime = Date.now(); + if (!props.queryStatus.startTime) { + return; + } + const elapsed = currentTime - props.queryStatus.startTime; + setElapsedTime(elapsed); + }; + const interval = setInterval(updateElapsedTime, 1000); - return () => clearInterval(interval); - }); + return () => { + clearInterval(interval); + setElapsedTime(0); + }; + }, [props.queryStatus.startTime]); - if (props.queryStatus.status === ResultStatus.LOADING) { - if (elapsedTime < BUFFER_TIME) { - return null; + if (elapsedTime > BUFFER_TIME) { + if (props.queryStatus.status === ResultStatus.LOADING) { + const time = Math.floor(elapsedTime / 1000); + return ( + {}} + isLoading + data-test-subj="queryResultLoading" + > + {i18n.translate('data.query.languageService.queryResults.loadTime', { + defaultMessage: 'Loading {time} s', + values: { time }, + })} + + ); } - const time = Math.floor(elapsedTime / 1000); - return ( - {}} - isLoading - data-test-subj="queryResultLoading" - > - {i18n.translate('data.query.languageService.queryResults.loadTime', { - defaultMessage: 'Loading {time} s', - values: { time }, - })} - - ); } if (props.queryStatus.status === ResultStatus.READY) { @@ -85,7 +87,7 @@ export function QueryResult(props: { queryStatus: QueryStatus }) { }); } else if (props.queryStatus.elapsedMs < 1000) { message = i18n.translate( - 'data.query.languageService.queryResults.completeTimeInMiliseconds', + 'data.query.languageService.queryResults.completeTimeInMilliseconds', { defaultMessage: 'Completed in {timeMS} ms', values: { timeMS: props.queryStatus.elapsedMs }, diff --git a/src/plugins/data/public/query/query_string/language_service/types.ts b/src/plugins/data/public/query/query_string/language_service/types.ts index 0889f7e63950..c80858d67102 100644 --- a/src/plugins/data/public/query/query_string/language_service/types.ts +++ b/src/plugins/data/public/query/query_string/language_service/types.ts @@ -55,6 +55,10 @@ export interface LanguageConfig { visualizable?: boolean; }; showDocLinks?: boolean; + docLink?: { + title: string; + url: string; + }; editorSupportedAppNames?: string[]; supportedAppNames?: string[]; hideDatePicker?: boolean; diff --git a/src/plugins/data/public/ui/dataset_selector/index.tsx b/src/plugins/data/public/ui/dataset_selector/index.tsx index 48cd2926de22..53966ed6375f 100644 --- a/src/plugins/data/public/ui/dataset_selector/index.tsx +++ b/src/plugins/data/public/ui/dataset_selector/index.tsx @@ -3,7 +3,7 @@ * SPDX-License-Identifier: Apache-2.0 */ -import { useCallback, useEffect } from 'react'; +import { useCallback, useState, useEffect } from 'react'; import React from 'react'; import { Dataset, Query, TimeRange } from '../../../common'; import { @@ -12,42 +12,37 @@ import { DatasetSelectorUsingButtonProps, DatasetSelectorAppearance, } from './dataset_selector'; -import { AdvancedSelector } from './advanced_selector'; +import { useOpenSearchDashboards } from '../../../../opensearch_dashboards_react/public'; +import { IDataPluginServices } from '../../types'; interface ConnectedDatasetSelectorProps { onSubmit: ((query: Query, dateRange?: TimeRange | undefined) => void) | undefined; - selectedDataset?: Dataset; - setSelectedDataset: (data: Dataset | undefined) => void; - setIndexPattern: (id: string | undefined) => void; - services?: any; } const ConnectedDatasetSelector = ({ onSubmit, - selectedDataset, - setSelectedDataset, - setIndexPattern, - services, ...datasetSelectorProps }: ConnectedDatasetSelectorProps & (DatasetSelectorUsingButtonProps | DatasetSelectorUsingButtonEmptyProps)) => { + const { services } = useOpenSearchDashboards(); const queryString = services.data.query.queryString; + const [selectedDataset, setSelectedDataset] = useState( + () => queryString.getQuery().dataset || queryString.getDefaultQuery().dataset + ); useEffect(() => { const subscription = queryString.getUpdates$().subscribe((query) => { setSelectedDataset(query.dataset); - setIndexPattern(query.dataset?.id); }); return () => { subscription.unsubscribe(); }; - }, [queryString, setSelectedDataset, setIndexPattern]); + }, [queryString]); const handleDatasetChange = useCallback( (dataset?: Dataset) => { setSelectedDataset(dataset); - setIndexPattern(dataset?.id); if (dataset) { const query = queryString.getInitialQueryByDataset(dataset); queryString.setQuery(query); @@ -55,19 +50,21 @@ const ConnectedDatasetSelector = ({ queryString.getDatasetService().addRecentDataset(dataset); } }, - [onSubmit, queryString, setSelectedDataset, setIndexPattern] + [onSubmit, queryString] ); return ( ); }; -export { ConnectedDatasetSelector as DatasetSelector, AdvancedSelector, DatasetSelectorAppearance }; +export { + ConnectedDatasetSelector as DatasetSelector, + ConnectedDatasetSelectorProps as DatasetSelectorProps, + DatasetSelectorAppearance, +}; diff --git a/src/plugins/data/public/ui/filter_bar/filter_options.tsx b/src/plugins/data/public/ui/filter_bar/filter_options.tsx index 26fcc9714212..6de37d562ce1 100644 --- a/src/plugins/data/public/ui/filter_bar/filter_options.tsx +++ b/src/plugins/data/public/ui/filter_bar/filter_options.tsx @@ -88,8 +88,7 @@ const FilterOptionsUI = (props: Props) => { const uiSettings = opensearchDashboards.services.uiSettings; const isPinned = uiSettings!.get(UI_SETTINGS.FILTERS_PINNED_BY_DEFAULT); const useNewHeader = Boolean(uiSettings!.get(UI_SETTINGS.NEW_HOME_PAGE)); - const [indexPattern] = props.indexPatterns; - const index = indexPattern && indexPattern.id; + const index = Array.isArray(props.indexPatterns) ? props.indexPatterns[0]?.id : undefined; const newFilter = buildEmptyFilter(isPinned, index); const togglePopover = () => { diff --git a/src/plugins/data/public/ui/index.ts b/src/plugins/data/public/ui/index.ts index 00ac361bb26e..bdde4cc42a39 100644 --- a/src/plugins/data/public/ui/index.ts +++ b/src/plugins/data/public/ui/index.ts @@ -28,7 +28,7 @@ * under the License. */ -export { UiEnhancements, IUiStart, IUiSetup } from './types'; +export { IUiStart, IUiSetup } from './types'; export { IndexPatternSelectProps } from './index_pattern_select'; export { FilterLabel } from './filter_bar'; export { QueryStringInput, QueryStringInputProps } from './query_string_input'; @@ -51,5 +51,4 @@ export { useQueryStringManager, } from './search_bar'; export { SuggestionsComponent } from './typeahead'; -export { DatasetSelector, AdvancedSelector, DatasetSelectorAppearance } from './dataset_selector'; -export { NoIndexPatternsPanel } from './no_index_patterns'; +export { DatasetSelector, DatasetSelectorAppearance } from './dataset_selector'; diff --git a/src/plugins/data/public/ui/query_editor/__snapshots__/language_selector.test.tsx.snap b/src/plugins/data/public/ui/query_editor/__snapshots__/language_selector.test.tsx.snap index 740611ae6d36..68e06485f77c 100644 --- a/src/plugins/data/public/ui/query_editor/__snapshots__/language_selector.test.tsx.snap +++ b/src/plugins/data/public/ui/query_editor/__snapshots__/language_selector.test.tsx.snap @@ -508,7 +508,6 @@ exports[`LanguageSelector should select DQL if language is kuery 1`] = ` @@ -532,14 +531,12 @@ exports[`LanguageSelector should select DQL if language is kuery 1`] = ` @@ -1104,7 +1100,6 @@ exports[`LanguageSelector should select lucene if language is lucene 1`] = ` @@ -1128,14 +1123,12 @@ exports[`LanguageSelector should select lucene if language is lucene 1`] = ` diff --git a/src/plugins/data/public/ui/query_editor/_query_editor.scss b/src/plugins/data/public/ui/query_editor/_query_editor.scss index 719cc65785c2..cf2321cf3d4e 100644 --- a/src/plugins/data/public/ui/query_editor/_query_editor.scss +++ b/src/plugins/data/public/ui/query_editor/_query_editor.scss @@ -150,9 +150,6 @@ } .osdQueryEditor__querycontrols { - float: right; - margin: $euiSizeS $euiSizeS; - .osdQueryEditor__extensionQueryControls { display: flex; padding: 0 $euiSizeS 0 $euiSizeXS; diff --git a/src/plugins/data/public/ui/query_editor/editors/default_editor/index.tsx b/src/plugins/data/public/ui/query_editor/editors/default_editor/index.tsx index 1134d104befd..0d76ff0e78f3 100644 --- a/src/plugins/data/public/ui/query_editor/editors/default_editor/index.tsx +++ b/src/plugins/data/public/ui/query_editor/editors/default_editor/index.tsx @@ -77,14 +77,22 @@ export const DefaultInput: React.FC = ({ gutterSize="none" className="defaultEditor__footerRow" > - {footerItems.start?.map((item) => ( - + {footerItems.start?.map((item, idx) => ( + {item} ))} - {footerItems.end?.map((item) => ( - + {footerItems.end?.map((item, idx) => ( + {item} ))} diff --git a/src/plugins/data/public/ui/query_editor/language_selector.tsx b/src/plugins/data/public/ui/query_editor/language_selector.tsx index ed7598fea563..6fc0606c1997 100644 --- a/src/plugins/data/public/ui/query_editor/language_selector.tsx +++ b/src/plugins/data/public/ui/query_editor/language_selector.tsx @@ -111,7 +111,6 @@ export const QueryLanguageSelector = (props: QueryLanguageSelectorProps) => { button={ { className={classNames('osdQueryEditor__banner', this.props.bannerClassName)} />
-
{this.state.isCollapsed ? languageEditor.TopBar.Collapsed() diff --git a/src/plugins/data/public/ui/query_editor/query_editor_top_row.tsx b/src/plugins/data/public/ui/query_editor/query_editor_top_row.tsx index 62ba24527cd5..ab9b8c50e038 100644 --- a/src/plugins/data/public/ui/query_editor/query_editor_top_row.tsx +++ b/src/plugins/data/public/ui/query_editor/query_editor_top_row.tsx @@ -15,7 +15,15 @@ import { import classNames from 'classnames'; import React, { useState } from 'react'; import { createPortal } from 'react-dom'; -import { IDataPluginServices, IIndexPattern, Query, TimeHistoryContract, TimeRange } from '../..'; +import { + DatasetSelector, + DatasetSelectorAppearance, + IDataPluginServices, + IIndexPattern, + Query, + TimeHistoryContract, + TimeRange, +} from '../..'; import { useOpenSearchDashboards, withOpenSearchDashboards, @@ -52,6 +60,7 @@ export interface QueryEditorTopRowProps { isDirty: boolean; timeHistory?: TimeHistoryContract; indicateNoData?: boolean; + datasetSelectorRef?: React.RefObject; datePickerRef?: React.RefObject; savedQueryManagement?: any; queryStatus?: QueryStatus; @@ -63,14 +72,7 @@ export default function QueryEditorTopRow(props: QueryEditorTopRowProps) { const [isDateRangeInvalid, setIsDateRangeInvalid] = useState(false); const [isQueryEditorFocused, setIsQueryEditorFocused] = useState(false); const opensearchDashboards = useOpenSearchDashboards(); - const { - uiSettings, - storage, - appName, - data: { - query: { queryString }, - }, - } = opensearchDashboards.services; + const { uiSettings, storage, appName } = opensearchDashboards.services; const queryLanguage = props.query && props.query.language; const persistedLog: PersistedLog | undefined = React.useMemo( @@ -170,6 +172,19 @@ export default function QueryEditorTopRow(props: QueryEditorTopRowProps) { return valueAsMoment.toISOString(); } + function renderDatasetSelector() { + return ( + + ); + } + function renderQueryEditor() { if (!shouldRenderQueryEditor()) return; return ( @@ -315,6 +330,8 @@ export default function QueryEditorTopRow(props: QueryEditorTopRowProps) { ); + const datasetSelector = <>{renderDatasetSelector()}; + return ( + {props?.datasetSelectorRef?.current && + createPortal(datasetSelector, props.datasetSelectorRef.current)} {props?.datePickerRef?.current && uiSettings.get(UI_SETTINGS.QUERY_ENHANCEMENTS_ENABLED) ? createPortal(datePicker, props.datePickerRef.current) : datePicker} diff --git a/src/plugins/data/public/ui/search_bar/create_search_bar.tsx b/src/plugins/data/public/ui/search_bar/create_search_bar.tsx index 03bb2abfa508..f8b9694caabc 100644 --- a/src/plugins/data/public/ui/search_bar/create_search_bar.tsx +++ b/src/plugins/data/public/ui/search_bar/create_search_bar.tsx @@ -209,6 +209,7 @@ export function createSearchBar({ core, storage, data }: StatefulSearchBarDeps) onClearSavedQuery={defaultOnClearSavedQuery(props, clearSavedQuery)} onSavedQueryUpdated={defaultOnSavedQueryUpdated(props, setSavedQuery)} onSaved={defaultOnSavedQueryUpdated(props, setSavedQuery)} + datasetSelectorRef={props.datasetSelectorRef} datePickerRef={props.datePickerRef} isFilterBarPortable={props.isFilterBarPortable} {...overrideDefaultBehaviors(props)} diff --git a/src/plugins/data/public/ui/search_bar/search_bar.tsx b/src/plugins/data/public/ui/search_bar/search_bar.tsx index 975b0535c9d8..35c2065b14c8 100644 --- a/src/plugins/data/public/ui/search_bar/search_bar.tsx +++ b/src/plugins/data/public/ui/search_bar/search_bar.tsx @@ -75,6 +75,7 @@ export interface SearchBarOwnProps { refreshInterval?: number; dateRangeFrom?: string; dateRangeTo?: string; + datasetSelectorRef?: React.RefObject; datePickerRef?: React.RefObject; // Query bar - should be in SearchBarInjectedDeps query?: Query; @@ -223,7 +224,8 @@ class SearchBarUI extends Component { const showDatePicker = this.props.showDatePicker || this.props.showAutoRefreshOnly; // TODO: MQL showQueryEditor should be a prop of it's own but using showQueryInput for now const showQueryEditor = - this.props.showQueryInput && this.props.indexPatterns && this.state.query; + (this.props.showQueryInput && this.props.indexPatterns && this.state.query) || + this.props.datasetSelectorRef?.current; return this.props.showQueryBar && (showDatePicker || showQueryEditor); } @@ -549,6 +551,7 @@ class SearchBarUI extends Component { filterBar={filterBar} dataTestSubj={this.props.dataTestSubj} indicateNoData={this.props.indicateNoData} + datasetSelectorRef={this.props.datasetSelectorRef} datePickerRef={this.props.datePickerRef} savedQueryManagement={searchBarMenu(false, true)} queryStatus={this.props.queryStatus} diff --git a/src/plugins/data/public/ui/ui_service.ts b/src/plugins/data/public/ui/ui_service.ts index 4eb45b1a67f2..87cfcf630965 100644 --- a/src/plugins/data/public/ui/ui_service.ts +++ b/src/plugins/data/public/ui/ui_service.ts @@ -4,7 +4,6 @@ */ 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'; @@ -12,8 +11,6 @@ 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 diff --git a/src/plugins/data_explorer/public/components/app_container.tsx b/src/plugins/data_explorer/public/components/app_container.tsx index abd1328bafeb..63f759f65408 100644 --- a/src/plugins/data_explorer/public/components/app_container.tsx +++ b/src/plugins/data_explorer/public/components/app_container.tsx @@ -3,7 +3,7 @@ * SPDX-License-Identifier: Apache-2.0 */ -import React, { memo, useEffect, useRef } from 'react'; +import React, { memo, useRef } from 'react'; import { EuiFlexGroup, EuiFlexItem, @@ -23,13 +23,7 @@ import './app_container.scss'; import { useOpenSearchDashboards } from '../../../opensearch_dashboards_react/public'; import { IDataPluginServices } from '../../../data/public'; import { QUERY_ENHANCEMENT_ENABLED_SETTING } from './constants'; -import { - DISCOVER_LOAD_EVENT, - NEW_DISCOVER_LOAD_EVENT, - NEW_DISCOVER_OPT_IN, - NEW_DISCOVER_OPT_OUT, - trackUiMetric, -} from '../ui_metric'; +import { DISCOVER_LOAD_EVENT, NEW_DISCOVER_LOAD_EVENT, trackUiMetric } from '../ui_metric'; export const AppContainer = React.memo( ({ view, params }: { view?: View; params: AppMountParameters }) => { @@ -41,6 +35,7 @@ export const AppContainer = React.memo( const showActionsInGroup = uiSettings?.get('home:useNewHomePage'); const topLinkRef = useRef(null); + const datasetSelectorRef = useRef(null); const datePickerRef = useRef(null); if (!view) { @@ -59,6 +54,7 @@ export const AppContainer = React.memo( params.optionalRef = { topLinkRef, + datasetSelectorRef, datePickerRef, }; // Render the application DOM. @@ -103,7 +99,7 @@ export const AppContainer = React.memo( mode={['collapsible', { position: 'top' }]} paddingSize="none" > - + diff --git a/src/plugins/data_explorer/public/components/sidebar/index.tsx b/src/plugins/data_explorer/public/components/sidebar/index.tsx index 3c5975d9452e..6a4ef0585e33 100644 --- a/src/plugins/data_explorer/public/components/sidebar/index.tsx +++ b/src/plugins/data_explorer/public/components/sidebar/index.tsx @@ -12,50 +12,32 @@ import { DataSourceSelectable, UI_SETTINGS, } from '../../../../data/public'; -import { - DataSourceOption, - DatasetSelector, - DatasetSelectorAppearance, -} from '../../../../data/public/'; -import { Dataset } from '../../../../data/common'; +import { DataSourceOption } from '../../../../data/public/'; import { useOpenSearchDashboards } from '../../../../opensearch_dashboards_react/public'; import { DataExplorerServices } from '../../types'; -import { - setIndexPattern, - useTypedDispatch, - useTypedSelector, - setSelectedDataset, -} from '../../utils/state_management'; +import { setIndexPattern, useTypedDispatch, useTypedSelector } from '../../utils/state_management'; import './index.scss'; -type HandleSetIndexPattern = (id: string | undefined) => void; -type HandleSelectedDataset = (data: Dataset | undefined) => void; +interface SidebarProps { + children: React.ReactNode; + datasetSelectorRef: React.RefObject; +} -export const Sidebar: FC = ({ children }) => { - const { indexPattern: indexPatternId, selectedDataset } = useTypedSelector( - (state) => state.metadata - ); +export const Sidebar: FC = ({ children, datasetSelectorRef }) => { + const { indexPattern: indexPatternId } = useTypedSelector((state) => state.metadata); const dispatch = useTypedDispatch(); const [selectedSources, setSelectedSources] = useState([]); const [dataSourceOptionList, setDataSourceOptionList] = useState([]); const [activeDataSources, setActiveDataSources] = useState([]); - const { services } = useOpenSearchDashboards(); + const { - data: { indexPatterns, dataSources }, - notifications: { toasts }, - application, - uiSettings, - } = services; - - const handleDatasetSubmit = useCallback( - (query: any) => { - // Update the index pattern - if (query.dataset) { - dispatch(setIndexPattern(query.dataset.id)); - } + services: { + data: { indexPatterns, dataSources }, + notifications: { toasts }, + application, + uiSettings, }, - [dispatch] - ); + } = useOpenSearchDashboards(); const [isEnhancementEnabled, setIsEnhancementEnabled] = useState(false); @@ -137,14 +119,6 @@ export const Sidebar: FC = ({ children }) => { dataSources.dataSourceService.reload(); }, [dataSources.dataSourceService]); - const handleSetIndexPattern: HandleSetIndexPattern = (id: string | undefined) => { - dispatch(setIndexPattern(id)); - }; - - const handleSelectedDataset: HandleSelectedDataset = (data: Dataset | undefined) => { - dispatch(setSelectedDataset(data)); - }; - return ( { hasBorder={true} borderRadius="l" > - - {isEnhancementEnabled ? ( - - ) : ( + + {isEnhancementEnabled &&
} + {!isEnhancementEnabled && ( { /> )} + {children} diff --git a/src/plugins/data_explorer/public/index.ts b/src/plugins/data_explorer/public/index.ts index 9d9ae2f46d2b..f8adda434ced 100644 --- a/src/plugins/data_explorer/public/index.ts +++ b/src/plugins/data_explorer/public/index.ts @@ -18,6 +18,4 @@ export { useTypedSelector, useTypedDispatch, setIndexPattern, - setSelectedDataset, - setDataSet, } from './utils/state_management'; diff --git a/src/plugins/discover/public/application/components/no_index_patterns/no_index_patterns.scss b/src/plugins/discover/public/application/components/no_index_patterns/no_index_patterns.scss new file mode 100644 index 000000000000..b435d3b36a6d --- /dev/null +++ b/src/plugins/discover/public/application/components/no_index_patterns/no_index_patterns.scss @@ -0,0 +1,12 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +.discoverNoIndexPatterns-centerPanel { + width: 100%; + + & > * { + @include euiLegibilityMaxWidth(100%); + } +} diff --git a/src/plugins/discover/public/application/components/no_index_patterns/no_index_patterns.tsx b/src/plugins/discover/public/application/components/no_index_patterns/no_index_patterns.tsx new file mode 100644 index 000000000000..7906a2f06041 --- /dev/null +++ b/src/plugins/discover/public/application/components/no_index_patterns/no_index_patterns.tsx @@ -0,0 +1,89 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import './no_index_patterns.scss'; +import React from 'react'; +import { i18n } from '@osd/i18n'; +import { + EuiPanel, + EuiFlexGroup, + EuiFlexItem, + EuiIcon, + EuiText, + EuiTitle, + EuiButtonEmpty, +} from '@elastic/eui'; +import { getServices } from '../../../opensearch_dashboards_services'; + +export const DiscoverNoIndexPatterns: React.FC = () => { + const languageService = getServices().data.query.queryString.getLanguageService(); + const registeredLanguages = languageService.getLanguages(); + + return ( + + + + + + + + + +

+ {i18n.translate('discover.noIndexPatterns.selectDataTitle', { + defaultMessage: 'Select data', + })} +

+
+
+ + + {i18n.translate('discover.noIndexPatterns.selectDataDescription', { + defaultMessage: + 'Select an available data source and choose a query language to use for running queries. You can use the data dropdown or use the enhanced data selector to select data.', + })} + + + + +

+ {i18n.translate('discover.noIndexPatterns.learnMoreAboutQueryLanguages', { + defaultMessage: 'Learn more about query languages', + })} +

+
+
+ + + {registeredLanguages.map( + (language) => + language.docLink && ( + + + {language.docLink.title} + + + ) + )} + + +
+
+
+
+ ); +}; diff --git a/src/plugins/discover/public/application/components/no_results/no_results.tsx b/src/plugins/discover/public/application/components/no_results/no_results.tsx index 6c8421535fde..57d34b64ef64 100644 --- a/src/plugins/discover/public/application/components/no_results/no_results.tsx +++ b/src/plugins/discover/public/application/components/no_results/no_results.tsx @@ -41,31 +41,21 @@ import { EuiPanel, } from '@elastic/eui'; import { i18n } from '@osd/i18n'; -import { Query } from '../../../../../data/common'; import { - DatasetServiceContract, - LanguageServiceContract, + Query, + QueryStringContract, SavedQuery, SavedQueryService, } from '../../../../../data/public/'; interface Props { - datasetService: DatasetServiceContract; + queryString: QueryStringContract; savedQuery: SavedQueryService; - languageService: LanguageServiceContract; query: Query | undefined; timeFieldName?: string; - queryLanguage?: string; } -export const DiscoverNoResults = ({ - datasetService, - savedQuery, - languageService, - query, - timeFieldName, - queryLanguage, -}: Props) => { +export const DiscoverNoResults = ({ queryString, query, savedQuery, timeFieldName }: Props) => { // Commented out due to no usage in code // See: https://github.com/opensearch-project/OpenSearch-Dashboards/issues/8149 // @@ -212,15 +202,17 @@ export const DiscoverNoResults = ({ // Samples for the dataset type if (query?.dataset?.type) { - const datasetSampleQueries = datasetService - .getType(query.dataset.type) + const datasetSampleQueries = queryString + .getDatasetService() + ?.getType(query.dataset.type) ?.getSampleQueries?.(query.dataset, query.language); if (Array.isArray(datasetSampleQueries)) sampleQueries.push(...datasetSampleQueries); } // Samples for the language if (query?.language) { - const languageSampleQueries = languageService.getLanguage(query.language)?.sampleQueries; + const languageSampleQueries = queryString.getLanguageService()?.getLanguage(query.language) + ?.sampleQueries; if (Array.isArray(languageSampleQueries)) sampleQueries.push(...languageSampleQueries); } @@ -264,7 +256,7 @@ export const DiscoverNoResults = ({ ] : []), ]; - }, [datasetService, languageService, query, savedQueries]); + }, [queryString, query, savedQueries]); return ( diff --git a/src/plugins/discover/public/application/components/sidebar/lib/get_index_pattern_field_list.ts b/src/plugins/discover/public/application/components/sidebar/lib/get_index_pattern_field_list.ts index 93b80ae99653..5d9a030e2e13 100644 --- a/src/plugins/discover/public/application/components/sidebar/lib/get_index_pattern_field_list.ts +++ b/src/plugins/discover/public/application/components/sidebar/lib/get_index_pattern_field_list.ts @@ -28,8 +28,7 @@ * under the License. */ -import { difference } from 'lodash'; -import { IndexPattern, IndexPatternField } from 'src/plugins/data/public'; +import { IndexPattern } from 'src/plugins/data/public'; export function getIndexPatternFieldList( indexPattern?: IndexPattern, diff --git a/src/plugins/discover/public/application/view_components/canvas/index.tsx b/src/plugins/discover/public/application/view_components/canvas/index.tsx index af94e0e6f542..cf834888b4f0 100644 --- a/src/plugins/discover/public/application/view_components/canvas/index.tsx +++ b/src/plugins/discover/public/application/view_components/canvas/index.tsx @@ -4,7 +4,7 @@ */ import React, { useEffect, useState, useRef, useCallback } from 'react'; -import { EuiPanel } from '@elastic/eui'; +import { EuiPanel, EuiSpacer } from '@elastic/eui'; import { TopNav } from './top_nav'; import { ViewProps } from '../../../../../data_explorer/public'; import { DiscoverTable } from './discover_table'; @@ -12,6 +12,7 @@ import { DiscoverChartContainer } from './discover_chart_container'; import { useDiscoverContext } from '../context'; import { ResultStatus, SearchData } from '../utils/use_search'; import { DiscoverNoResults } from '../../components/no_results/no_results'; +import { DiscoverNoIndexPatterns } from '../../components/no_index_patterns/no_index_patterns'; import { DiscoverUninitialized } from '../../components/uninitialized/uninitialized'; import { LoadingSpinner } from '../../components/loading_spinner/loading_spinner'; import { setColumns, useDispatch, useSelector } from '../../utils/state_management'; @@ -27,31 +28,19 @@ import { OpenSearchSearchHit } from '../../../application/doc_views/doc_views_ty import { buildColumns } from '../../utils/columns'; import './discover_canvas.scss'; import { HeaderVariant } from '../../../../../../core/public'; -import { Query } from '../../../../../../../src/plugins/data/common/types'; -import { setIndexPattern, setSelectedDataset } from '../../../../../data_explorer/public'; -import { NoIndexPatternsPanel, AdvancedSelector } from '../../../../../data/public'; -import { Dataset } from '../../../../../data/common'; -import { toMountPoint } from '../../../../../opensearch_dashboards_react/public'; // eslint-disable-next-line import/no-default-export export default function DiscoverCanvas({ setHeaderActionMenu, history, optionalRef }: ViewProps) { - const { indexPattern: currentIndexPattern, selectedDataset } = useSelector( - (state) => state.metadata - ); - const [loadedIndexPattern, setLoadedIndexPattern] = useState(selectedDataset?.id); const panelRef = useRef(null); const { data$, refetch$, indexPattern } = useDiscoverContext(); - const { services } = useOpenSearchDashboards(); const { - uiSettings, - capabilities, - chrome: { setHeaderVariant }, - data, - overlays, - } = services; - const datasetService = data.query.queryString.getDatasetService(); - const savedQuery = data.query.savedQueries; - const languageService = data.query.queryString.getLanguageService(); + services: { + uiSettings, + capabilities, + chrome: { setHeaderVariant }, + data, + }, + } = useOpenSearchDashboards(); const { columns } = useSelector((state) => { const stateColumns = state.discover.columns; @@ -69,7 +58,6 @@ export default function DiscoverCanvas({ setHeaderActionMenu, history, optionalR ); const dispatch = useDispatch(); const prevIndexPattern = useRef(indexPattern); - const [query, setQuery] = useState(); const [fetchState, setFetchState] = useState({ status: data$.getValue().status, @@ -79,9 +67,6 @@ export default function DiscoverCanvas({ setHeaderActionMenu, history, optionalR const onQuerySubmit = useCallback( (payload, isUpdate) => { - if (payload?.query) { - setQuery(payload?.query); - } if (isUpdate === false) { refetch$.next(); } @@ -139,48 +124,10 @@ export default function DiscoverCanvas({ setHeaderActionMenu, history, optionalR }; const showSaveQuery = !!capabilities.discover?.saveQuery; - const handleDatasetChange = (dataset: Dataset) => { - dispatch(setSelectedDataset(dataset)); - - // Update query and other necessary state - const queryString = data.query.queryString; - const initialQuery = queryString.getInitialQueryByDataset(dataset); - queryString.setQuery(initialQuery); - queryString.getDatasetService().addRecentDataset(dataset); - }; - - const handleOpenDataSelector = () => { - const overlay = overlays?.openModal( - toMountPoint( - { - overlay?.close(); - if (dataset) { - handleDatasetChange(dataset); - } - }} - onCancel={() => overlay?.close()} - selectedDataset={undefined} - setSelectedDataset={setSelectedDataset} - setIndexPattern={setIndexPattern} - dispatch={dispatch} - /> - ), - { - maxWidth: false, - className: 'datasetSelector__advancedModal', - } - ); - }; - - const hasNoDataset = !currentIndexPattern && !loadedIndexPattern && isEnhancementsEnabled; - return ( - {hasNoDataset ? ( - - ) : ( + + {indexPattern ? ( <> {fetchState.status === ResultStatus.NO_RESULTS && ( )} {fetchState.status === ResultStatus.ERROR && ( )} {fetchState.status === ResultStatus.UNINITIALIZED && ( @@ -237,6 +178,11 @@ export default function DiscoverCanvas({ setHeaderActionMenu, history, optionalR )} + ) : ( + <> + + + )} ); diff --git a/src/plugins/discover/public/application/view_components/canvas/top_nav.tsx b/src/plugins/discover/public/application/view_components/canvas/top_nav.tsx index 0b3f1275d7ff..6f827e563ec6 100644 --- a/src/plugins/discover/public/application/view_components/canvas/top_nav.tsx +++ b/src/plugins/discover/public/application/view_components/canvas/top_nav.tsx @@ -35,15 +35,9 @@ export interface TopNavProps { }; showSaveQuery: boolean; isEnhancementsEnabled?: boolean; - useNoIndexPatternsTopNav?: boolean; } -export const TopNav = ({ - opts, - showSaveQuery, - isEnhancementsEnabled, - useNoIndexPatternsTopNav = false, -}: TopNavProps) => { +export const TopNav = ({ opts, showSaveQuery, isEnhancementsEnabled }: TopNavProps) => { const { services } = useOpenSearchDashboards(); const { data$, inspectorAdapters, savedSearch, indexPattern } = useDiscoverContext(); const [indexPatterns, setIndexPatterns] = useState(undefined); @@ -68,13 +62,7 @@ export const TopNav = ({ const showActionsInGroup = uiSettings.get('home:useNewHomePage'); const topNavLinks = savedSearch - ? getTopNavLinks( - services, - inspectorAdapters, - savedSearch, - isEnhancementsEnabled, - useNoIndexPatternsTopNav - ) + ? getTopNavLinks(services, inspectorAdapters, savedSearch, isEnhancementsEnabled) : []; connectStorageToQueryState( @@ -100,18 +88,11 @@ export const TopNav = ({ useEffect(() => { let isMounted = true; const initializeDataset = async () => { - await data.indexPatterns.ensureDefaultIndexPattern(isEnhancementsEnabled ? false : true); + await data.indexPatterns.ensureDefaultIndexPattern(); const defaultIndexPattern = await data.indexPatterns.getDefault(); - // TODO: ROCKY do we need this? - // const queryString = data.query.queryString; - // const defaultDataset = queryString.getDatasetService().getDefault(); - if (!isMounted) return; setIndexPatterns(defaultIndexPattern ? [defaultIndexPattern] : undefined); - // if (defaultDataset) { - // datasetManager.setDataset(defaultDataset); - // } }; initializeDataset(); @@ -119,7 +100,7 @@ export const TopNav = ({ return () => { isMounted = false; }; - }, [data.indexPatterns, data.query, isEnhancementsEnabled]); + }, [data.indexPatterns, data.query]); useEffect(() => { const pageTitleSuffix = savedSearch?.id && savedSearch.title ? `: ${savedSearch.title}` : ''; @@ -176,31 +157,21 @@ export const TopNav = ({ {} : opts.onQuerySubmit} - savedQueryId={useNoIndexPatternsTopNav ? undefined : state.savedQuery} - onSavedQueryIdChange={useNoIndexPatternsTopNav ? () => {} : updateSavedQueryId} - datePickerRef={useNoIndexPatternsTopNav ? undefined : opts?.optionalRef?.datePickerRef} + indexPatterns={indexPattern ? [indexPattern] : indexPatterns} + onQuerySubmit={opts.onQuerySubmit} + savedQueryId={state.savedQuery} + onSavedQueryIdChange={updateSavedQueryId} + datasetSelectorRef={opts?.optionalRef?.datasetSelectorRef} + datePickerRef={opts?.optionalRef?.datePickerRef} groupActions={showActionsInGroup} - screenTitle={ - useNoIndexPatternsTopNav - ? i18n.translate('discover.noIndexPatterns.screenTitle', { - defaultMessage: 'Select data', - }) - : screenTitle - } + screenTitle={screenTitle} queryStatus={queryStatus} + showQueryBar={!!opts?.optionalRef?.datasetSelectorRef} /> ); diff --git a/src/plugins/query_enhancements/public/plugin.tsx b/src/plugins/query_enhancements/public/plugin.tsx index ff3df7e9ce1c..cbd40cb60b60 100644 --- a/src/plugins/query_enhancements/public/plugin.tsx +++ b/src/plugins/query_enhancements/public/plugin.tsx @@ -77,6 +77,12 @@ export class QueryEnhancementsPlugin filterable: false, visualizable: false, }, + docLink: { + title: i18n.translate('queryEnhancements.pplLanguage.docLink', { + defaultMessage: 'PPL documentation', + }), + url: 'https://opensearch.org/docs/latest/search-plugins/sql/ppl/syntax/', + }, showDocLinks: false, editor: enhancedPPLQueryEditor, editorSupportedAppNames: ['discover'], @@ -96,6 +102,12 @@ export class QueryEnhancementsPlugin filterable: false, visualizable: false, }, + docLink: { + title: i18n.translate('queryEnhancements.sqlLanguage.docLink', { + defaultMessage: 'SQL documentation', + }), + url: 'https://opensearch.org/docs/latest/search-plugins/sql/sql/basic/', + }, showDocLinks: false, editor: enhancedSQLQueryEditor, editorSupportedAppNames: ['discover'],