diff --git a/src/plugins/data/common/index.ts b/src/plugins/data/common/index.ts index 0250a6ec2e01..a10855a498cd 100644 --- a/src/plugins/data/common/index.ts +++ b/src/plugins/data/common/index.ts @@ -40,6 +40,7 @@ export * from './query'; export * from './search'; export * from './types'; export * from './utils'; +export * from './storage'; /** * Use data plugin interface instead diff --git a/src/plugins/data/common/storage/index.ts b/src/plugins/data/common/storage/index.ts new file mode 100644 index 000000000000..c37d921ee9d1 --- /dev/null +++ b/src/plugins/data/common/storage/index.ts @@ -0,0 +1,6 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +export { DataStorage, createStorage } from './storage'; diff --git a/src/plugins/data/common/storage/storage.ts b/src/plugins/data/common/storage/storage.ts new file mode 100644 index 000000000000..8ec5f6a13b8d --- /dev/null +++ b/src/plugins/data/common/storage/storage.ts @@ -0,0 +1,68 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { transform, startsWith, keys } from 'lodash'; +import { parse, stringify } from '@osd/std'; + +export enum StorageKeys { + WIDTH = 'widths', +} + +type IStorageEngine = typeof window.localStorage; +export class DataStorage { + constructor(private readonly engine: IStorageEngine, private readonly prefix: string) {} + + encode(val: any) { + return stringify(val); + } + + decode(val: any) { + if (typeof val === 'string') { + return parse(val); + } + } + + encodeKey(key: string) { + return `${this.prefix}${key}`; + } + + decodeKey(key: string) { + if (startsWith(key, this.prefix)) { + return `${key.slice(this.prefix.length)}`; + } + } + + set(key: string, val: any) { + this.engine.setItem(this.encodeKey(key), this.encode(val)); + return val; + } + + has(key: string) { + return this.engine.getItem(this.encodeKey(key)) != null; + } + + get(key: string, _default?: T) { + if (this.has(key)) { + return this.decode(this.engine.getItem(this.encodeKey(key))); + } else { + return _default; + } + } + + remove(key: string) { + return this.engine.removeItem(this.encodeKey(key)); + } + + keys(): string[] { + return transform(keys(this.engine), (ours, key) => { + const ourKey = this.decodeKey(key); + if (ourKey != null) ours.push(ourKey); + }); + } +} + +export function createStorage(deps: { engine: IStorageEngine; prefix: string }) { + return new DataStorage(deps.engine, deps.prefix); +} diff --git a/src/plugins/data/public/plugin.ts b/src/plugins/data/public/plugin.ts index e204058fee4e..09bdd96d58e2 100644 --- a/src/plugins/data/public/plugin.ts +++ b/src/plugins/data/public/plugin.ts @@ -32,11 +32,7 @@ import './index.scss'; import { PluginInitializerContext, CoreSetup, CoreStart, Plugin } from 'src/core/public'; import { ConfigSchema } from '../config'; -import { - Storage, - IStorageWrapper, - createStartServicesGetter, -} from '../../opensearch_dashboards_utils/public'; +import { createStartServicesGetter } from '../../opensearch_dashboards_utils/public'; import { DataPublicPluginSetup, DataPublicPluginStart, @@ -95,6 +91,7 @@ import { DefaultDslDataSource } from './data_sources/default_datasource'; import { DEFAULT_DATA_SOURCE_TYPE } from './data_sources/constants'; import { getSuggestions as getSQLSuggestions } from './antlr/opensearch_sql/code_completion'; import { getSuggestions as getDQLSuggestions } from './antlr/dql/code_completion'; +import { createStorage, DataStorage } from '../common'; declare module '../../ui_actions/public' { export interface ActionContextMapping { @@ -117,7 +114,7 @@ export class DataPublicPlugin private readonly uiService: UiService; private readonly fieldFormatsService: FieldFormatsService; private readonly queryService: QueryService; - private readonly storage: IStorageWrapper; + private readonly storage: DataStorage; constructor(initializerContext: PluginInitializerContext) { this.searchService = new SearchService(initializerContext); @@ -125,7 +122,7 @@ export class DataPublicPlugin this.queryService = new QueryService(); this.fieldFormatsService = new FieldFormatsService(); this.autocomplete = new AutocompleteService(initializerContext); - this.storage = new Storage(window.localStorage); + this.storage = createStorage({ engine: window.localStorage, prefix: 'opensearch_dashboards.' }); } public setup( diff --git a/src/plugins/data/public/query/lib/add_to_query_log.ts b/src/plugins/data/public/query/lib/add_to_query_log.ts index 206f18e31d84..038d2d4a2782 100644 --- a/src/plugins/data/public/query/lib/add_to_query_log.ts +++ b/src/plugins/data/public/query/lib/add_to_query_log.ts @@ -29,13 +29,12 @@ */ import { IUiSettingsClient } from 'src/core/public'; -import { IStorageWrapper } from 'src/plugins/opensearch_dashboards_utils/public'; -import { Query } from '../../../common'; +import { DataStorage, Query } from '../../../common'; import { getQueryLog } from './get_query_log'; interface AddToQueryLogDependencies { uiSettings: IUiSettingsClient; - storage: IStorageWrapper; + storage: DataStorage; } export function createAddToQueryLog({ storage, uiSettings }: AddToQueryLogDependencies) { diff --git a/src/plugins/data/public/query/lib/get_query_log.ts b/src/plugins/data/public/query/lib/get_query_log.ts index aaf471f522cf..d2a4c7ccb551 100644 --- a/src/plugins/data/public/query/lib/get_query_log.ts +++ b/src/plugins/data/public/query/lib/get_query_log.ts @@ -29,14 +29,13 @@ */ import { IUiSettingsClient } from 'src/core/public'; -import { IStorageWrapper } from 'src/plugins/opensearch_dashboards_utils/public'; import { PersistedLog } from '../persisted_log'; -import { UI_SETTINGS } from '../../../common'; +import { DataStorage, UI_SETTINGS } from '../../../common'; /** @internal */ export function getQueryLog( uiSettings: IUiSettingsClient, - storage: IStorageWrapper, + storage: DataStorage, appName: string, language: string ) { diff --git a/src/plugins/data/public/query/persisted_log/persisted_log.ts b/src/plugins/data/public/query/persisted_log/persisted_log.ts index 7b37ec51b736..ff230ee1ad09 100644 --- a/src/plugins/data/public/query/persisted_log/persisted_log.ts +++ b/src/plugins/data/public/query/persisted_log/persisted_log.ts @@ -31,7 +31,7 @@ import _ from 'lodash'; import * as Rx from 'rxjs'; import { map } from 'rxjs/operators'; -import { IStorageWrapper } from 'src/plugins/opensearch_dashboards_utils/public'; +import { DataStorage } from 'src/plugins/data/common'; const defaultIsDuplicate = (oldItem: any, newItem: any) => { return _.isEqual(oldItem, newItem); @@ -48,12 +48,12 @@ export class PersistedLog { public maxLength?: number; public filterDuplicates?: boolean; public isDuplicate: (oldItem: T, newItem: T) => boolean; - public storage: IStorageWrapper; + public storage: DataStorage; public items: T[]; private update$ = new Rx.BehaviorSubject(undefined); - constructor(name: string, options: PersistedLogOptions = {}, storage: IStorageWrapper) { + constructor(name: string, options: PersistedLogOptions = {}, storage: DataStorage) { this.name = name; this.maxLength = typeof options.maxLength === 'string' diff --git a/src/plugins/data/public/query/query_service.ts b/src/plugins/data/public/query/query_service.ts index 5c9c8b309367..17a7773567f3 100644 --- a/src/plugins/data/public/query/query_service.ts +++ b/src/plugins/data/public/query/query_service.ts @@ -30,7 +30,6 @@ import { share } from 'rxjs/operators'; import { IUiSettingsClient, SavedObjectsClientContract } from 'src/core/public'; -import { IStorageWrapper } from 'src/plugins/opensearch_dashboards_utils/public'; import { FilterManager } from './filter_manager'; import { createAddToQueryLog } from './lib'; import { TimefilterService, TimefilterSetup } from './timefilter'; @@ -38,7 +37,12 @@ import { createSavedQueryService } from './saved_query/saved_query_service'; import { createQueryStateObservable } from './state_sync/create_global_query_observable'; import { QueryStringManager, QueryStringContract } from './query_string'; import { DataSetContract, DataSetManager } from './dataset_manager'; -import { buildOpenSearchQuery, getOpenSearchQueryConfig, IndexPatternsService } from '../../common'; +import { + buildOpenSearchQuery, + DataStorage, + getOpenSearchQueryConfig, + IndexPatternsService, +} from '../../common'; import { getUiSettings } from '../services'; import { IndexPattern } from '..'; @@ -48,13 +52,13 @@ import { IndexPattern } from '..'; */ interface QueryServiceSetupDependencies { - storage: IStorageWrapper; + storage: DataStorage; uiSettings: IUiSettingsClient; } interface QueryServiceStartDependencies { savedObjectsClient: SavedObjectsClientContract; - storage: IStorageWrapper; + storage: DataStorage; uiSettings: IUiSettingsClient; indexPatterns: IndexPatternsService; } diff --git a/src/plugins/data/public/query/query_string/query_history.ts b/src/plugins/data/public/query/query_string/query_history.ts new file mode 100644 index 000000000000..17e5f2cd1494 --- /dev/null +++ b/src/plugins/data/public/query/query_string/query_history.ts @@ -0,0 +1,64 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { DataStorage, SimpleDataSet } from 'src/plugins/data/common'; +import { BehaviorSubject } from 'rxjs'; +import { Query, TimeRange } from '../..'; + +// Todo: Implement a more advanced QueryHistory class when needed for recent query history +export class QueryHistory { + constructor(private readonly storage: DataStorage) {} + + private changeEmitter = new BehaviorSubject(this.getHistory() || []); + + getHistoryKeys() { + return this.storage + .keys() + .filter((key: string) => key.indexOf('query_') === 0) + .sort() + .reverse(); + } + + getHistory() { + return this.getHistoryKeys().map((key) => this.storage.get(key)); + } + + // This is used as an optimization mechanism so that different components + // can listen for changes to history and update because changes to history can + // be triggered from different places in the app. The alternative would be to store + // this in state so that we hook into the React model, but it would require loading history + // every time the application starts even if a user is not going to view history. + change(listener: (reqs: any[]) => void) { + const subscription = this.changeEmitter.subscribe(listener); + return () => subscription.unsubscribe(); + } + + addQueryToHistory(dataSet: SimpleDataSet, query: Query, dateRange?: TimeRange) { + const keys = this.getHistoryKeys(); + keys.splice(0, 500); // only maintain most recent X; + keys.forEach((key) => { + this.storage.remove(key); + }); + + const timestamp = new Date().getTime(); + const k = 'query_' + timestamp; + this.storage.set(k, { + dataSet, + time: timestamp, + query, + dateRange, + }); + + this.changeEmitter.next(this.getHistory()); + } + + clearHistory() { + this.getHistoryKeys().forEach((key) => this.storage.remove(key)); + } +} + +export function createHistory(deps: { storage: DataStorage }) { + return new QueryHistory(deps.storage); +} diff --git a/src/plugins/data/public/query/query_string/query_string_manager.test.ts b/src/plugins/data/public/query/query_string/query_string_manager.test.ts index 9def385c7dda..b9feb3be30d1 100644 --- a/src/plugins/data/public/query/query_string/query_string_manager.test.ts +++ b/src/plugins/data/public/query/query_string/query_string_manager.test.ts @@ -29,17 +29,16 @@ */ import { QueryStringManager } from './query_string_manager'; -import { Storage } from '../../../../opensearch_dashboards_utils/public/storage'; -import { StubBrowserStorage } from 'test_utils/stub_browser_storage'; import { coreMock } from '../../../../../core/public/mocks'; import { Query } from '../../../common/query'; +import { DataStorage } from '../../../../data/common'; describe('QueryStringManager', () => { let service: QueryStringManager; beforeEach(() => { service = new QueryStringManager( - new Storage(new StubBrowserStorage()), + new DataStorage(window.localStorage, 'opensearch_dashboards.'), coreMock.createSetup().uiSettings ); }); diff --git a/src/plugins/data/public/query/query_string/query_string_manager.ts b/src/plugins/data/public/query/query_string/query_string_manager.ts index 3747cabaf9ca..98a348b58254 100644 --- a/src/plugins/data/public/query/query_string/query_string_manager.ts +++ b/src/plugins/data/public/query/query_string/query_string_manager.ts @@ -31,26 +31,28 @@ import { BehaviorSubject } from 'rxjs'; import { skip } from 'rxjs/operators'; import { CoreStart } from 'opensearch-dashboards/public'; -import { IStorageWrapper } from 'src/plugins/opensearch_dashboards_utils/public'; -import { Query, UI_SETTINGS } from '../../../common'; +import { DataStorage, Query, SimpleDataSet, TimeRange, UI_SETTINGS } from '../../../common'; +import { createHistory, QueryHistory } from './query_history'; export class QueryStringManager { private query$: BehaviorSubject; + private queryHistory: QueryHistory; constructor( - private readonly storage: IStorageWrapper, + private readonly storage: DataStorage, private readonly uiSettings: CoreStart['uiSettings'] ) { this.query$ = new BehaviorSubject(this.getDefaultQuery()); + this.queryHistory = createHistory({ storage }); } private getDefaultQueryString() { - return this.storage.get('opensearchDashboards.userQueryString') || ''; + return this.storage.get('userQueryString') || ''; } private getDefaultLanguage() { return ( - this.storage.get('opensearchDashboards.userQueryLanguage') || + this.storage.get('userQueryLanguage') || this.uiSettings.get(UI_SETTINGS.SEARCH_QUERY_LANGUAGE) ); } @@ -100,6 +102,25 @@ export class QueryStringManager { public clearQuery = () => { this.setQuery(this.getDefaultQuery()); }; + + // Todo: update this function to use the Query object when it is udpated, Query object should include time range and dataset + public addToQueryHistory(dataSet: SimpleDataSet, query: Query, timeRange?: TimeRange) { + if (query.query) { + this.queryHistory.addQueryToHistory(dataSet, query, timeRange); + } + } + + public getQueryHistory() { + return this.queryHistory.getHistory(); + } + + public clearQueryHistory() { + this.queryHistory.clearHistory(); + } + + public changeQueryHistory(listener: (reqs: any[]) => void) { + return this.queryHistory.change(listener); + } } export type QueryStringContract = PublicMethodsOf; diff --git a/src/plugins/data/public/query/state_sync/connect_to_query_state.test.ts b/src/plugins/data/public/query/state_sync/connect_to_query_state.test.ts index fd73c589371e..17b9de0f4872 100644 --- a/src/plugins/data/public/query/state_sync/connect_to_query_state.test.ts +++ b/src/plugins/data/public/query/state_sync/connect_to_query_state.test.ts @@ -32,6 +32,7 @@ import { Subscription } from 'rxjs'; import { FilterManager } from '../filter_manager'; import { getFilter } from '../filter_manager/test_helpers/get_stub_filter'; import { + DataStorage, Filter, FilterStateStore, IndexPatternsService, @@ -44,10 +45,8 @@ import { createStateContainer, IOsdUrlStateStorage, createOsdUrlStateStorage, - Storage, } from '../../../../opensearch_dashboards_utils/public'; import { QueryService, QueryStart } from '../query_service'; -import { StubBrowserStorage } from '../../../../../test_utils/public/stub_browser_storage'; import { connectStorageToQueryState, connectToQueryState } from './connect_to_query_state'; import { TimefilterContract } from '../timefilter'; import { QueryState } from './types'; @@ -118,11 +117,11 @@ describe('connect_storage_to_query_state', () => { const queryService = new QueryService(); queryService.setup({ uiSettings: setupMock.uiSettings, - storage: new Storage(new StubBrowserStorage()), + storage: new DataStorage(window.localStorage, 'opensearch_dashboards.'), }); queryServiceStart = queryService.start({ uiSettings: setupMock.uiSettings, - storage: new Storage(new StubBrowserStorage()), + storage: new DataStorage(window.localStorage, 'opensearch_dashboards.'), savedObjectsClient: startMock.savedObjects.client, indexPatterns: indexPatternsMock, }); @@ -226,11 +225,11 @@ describe('connect_to_global_state', () => { const queryService = new QueryService(); queryService.setup({ uiSettings: setupMock.uiSettings, - storage: new Storage(new StubBrowserStorage()), + storage: new DataStorage(window.localStorage, 'opensearch_dashboards.'), }); queryServiceStart = queryService.start({ uiSettings: setupMock.uiSettings, - storage: new Storage(new StubBrowserStorage()), + storage: new DataStorage(window.localStorage, 'opensearch_dashboards.'), savedObjectsClient: startMock.savedObjects.client, indexPatterns: indexPatternsMock, }); @@ -464,11 +463,11 @@ describe('connect_to_app_state', () => { const queryService = new QueryService(); queryService.setup({ uiSettings: setupMock.uiSettings, - storage: new Storage(new StubBrowserStorage()), + storage: new DataStorage(window.localStorage, 'opensearch_dashboards.'), }); queryServiceStart = queryService.start({ uiSettings: setupMock.uiSettings, - storage: new Storage(new StubBrowserStorage()), + storage: new DataStorage(window.localStorage, 'opensearch_dashboards.'), savedObjectsClient: startMock.savedObjects.client, indexPatterns: indexPatternsMock, }); @@ -647,11 +646,11 @@ describe('filters with different state', () => { const queryService = new QueryService(); queryService.setup({ uiSettings: setupMock.uiSettings, - storage: new Storage(new StubBrowserStorage()), + storage: new DataStorage(window.localStorage, 'opensearch_dashboards.'), }); queryServiceStart = queryService.start({ uiSettings: setupMock.uiSettings, - storage: new Storage(new StubBrowserStorage()), + storage: new DataStorage(window.localStorage, 'opensearch_dashboards.'), savedObjectsClient: startMock.savedObjects.client, indexPatterns: indexPatternsMock, }); diff --git a/src/plugins/data/public/query/state_sync/sync_state_with_url.test.ts b/src/plugins/data/public/query/state_sync/sync_state_with_url.test.ts index 94c2ccc9a350..ca87637eb467 100644 --- a/src/plugins/data/public/query/state_sync/sync_state_with_url.test.ts +++ b/src/plugins/data/public/query/state_sync/sync_state_with_url.test.ts @@ -32,15 +32,19 @@ import { Subscription } from 'rxjs'; import { createBrowserHistory, History } from 'history'; import { FilterManager } from '../filter_manager'; import { getFilter } from '../filter_manager/test_helpers/get_stub_filter'; -import { Filter, FilterStateStore, IndexPatternsService, UI_SETTINGS } from '../../../common'; +import { + DataStorage, + Filter, + FilterStateStore, + IndexPatternsService, + UI_SETTINGS, +} from '../../../common'; import { coreMock } from '../../../../../core/public/mocks'; import { createOsdUrlStateStorage, IOsdUrlStateStorage, - Storage, } from '../../../../opensearch_dashboards_utils/public'; import { QueryService, QueryStart } from '../query_service'; -import { StubBrowserStorage } from 'test_utils/stub_browser_storage'; import { TimefilterContract } from '../timefilter'; import { syncQueryStateWithUrl } from './sync_state_with_url'; import { QueryState } from './types'; @@ -94,12 +98,12 @@ describe('sync_query_state_with_url', () => { const queryService = new QueryService(); queryService.setup({ uiSettings: setupMock.uiSettings, - storage: new Storage(new StubBrowserStorage()), + storage: new DataStorage(window.localStorage, 'opensearch_dashboards.'), }); queryServiceStart = queryService.start({ indexPatterns: indexPatternsMock, uiSettings: startMock.uiSettings, - storage: new Storage(new StubBrowserStorage()), + storage: new DataStorage(window.localStorage, 'opensearch_dashboards.'), savedObjectsClient: startMock.savedObjects.client, }); filterManager = queryServiceStart.filterManager; diff --git a/src/plugins/data/public/query/timefilter/time_history.ts b/src/plugins/data/public/query/timefilter/time_history.ts index b755fbf36da4..6c28892a0a05 100644 --- a/src/plugins/data/public/query/timefilter/time_history.ts +++ b/src/plugins/data/public/query/timefilter/time_history.ts @@ -29,14 +29,13 @@ */ import moment from 'moment'; -import { IStorageWrapper } from 'src/plugins/opensearch_dashboards_utils/public'; import { PersistedLog } from '../persisted_log'; -import { TimeRange } from '../../../common'; +import { DataStorage, TimeRange } from '../../../common'; export class TimeHistory { private history: PersistedLog; - constructor(storage: IStorageWrapper) { + constructor(storage: DataStorage) { const historyOptions = { maxLength: 10, filterDuplicates: true, @@ -44,11 +43,7 @@ export class TimeHistory { return oldItem.from === newItem.from && oldItem.to === newItem.to; }, }; - this.history = new PersistedLog( - 'opensearchDashboards.timepicker.timeHistory', - historyOptions, - storage - ); + this.history = new PersistedLog('timepicker.timeHistory', historyOptions, storage); } add(time: TimeRange) { diff --git a/src/plugins/data/public/query/timefilter/timefilter_service.ts b/src/plugins/data/public/query/timefilter/timefilter_service.ts index dbea62d46f89..b9bb0d3c3da0 100644 --- a/src/plugins/data/public/query/timefilter/timefilter_service.ts +++ b/src/plugins/data/public/query/timefilter/timefilter_service.ts @@ -29,9 +29,8 @@ */ import { IUiSettingsClient } from 'src/core/public'; -import { IStorageWrapper } from 'src/plugins/opensearch_dashboards_utils/public'; import { TimeHistory, Timefilter, TimeHistoryContract, TimefilterContract } from './index'; -import { UI_SETTINGS } from '../../../common'; +import { DataStorage, UI_SETTINGS } from '../../../common'; /** * Filter Service @@ -40,7 +39,7 @@ import { UI_SETTINGS } from '../../../common'; export interface TimeFilterServiceDependencies { uiSettings: IUiSettingsClient; - storage: IStorageWrapper; + storage: DataStorage; } export class TimefilterService { diff --git a/src/plugins/data/public/types.ts b/src/plugins/data/public/types.ts index 4f7936006a94..236ebfbb6e00 100644 --- a/src/plugins/data/public/types.ts +++ b/src/plugins/data/public/types.ts @@ -29,7 +29,6 @@ */ import { CoreStart } from 'src/core/public'; -import { IStorageWrapper } from 'src/plugins/opensearch_dashboards_utils/public'; import { ExpressionsSetup } from 'src/plugins/expressions/public'; import { UiActionsSetup, UiActionsStart } from 'src/plugins/ui_actions/public'; import { AutocompleteSetup, AutocompleteStart } from './autocomplete'; @@ -41,6 +40,7 @@ import { IndexPatternsContract } from './index_patterns'; import { UsageCollectionSetup } from '../../usage_collection/public'; import { DataSourceStart } from './data_sources/datasource_services/types'; import { IUiStart, UiEnhancements } from './ui'; +import { DataStorage } from '../common'; export interface DataPublicPluginEnhancements { search?: SearchEnhancements; @@ -131,6 +131,6 @@ export interface IDataPluginServices extends Partial { savedObjects: CoreStart['savedObjects']; notifications: CoreStart['notifications']; http: CoreStart['http']; - storage: IStorageWrapper; + storage: DataStorage; data: DataPublicPluginStart; } diff --git a/src/plugins/data/public/ui/query_string_input/no_data_popover.tsx b/src/plugins/data/public/ui/query_string_input/no_data_popover.tsx index 73edbcc3a1d2..8fae21a7c4e2 100644 --- a/src/plugins/data/public/ui/query_string_input/no_data_popover.tsx +++ b/src/plugins/data/public/ui/query_string_input/no_data_popover.tsx @@ -31,8 +31,8 @@ import { ReactElement, useEffect, useState } from 'react'; import React from 'react'; import { EuiButtonEmpty, EuiText, EuiTourStep } from '@elastic/eui'; -import { IStorageWrapper } from 'src/plugins/opensearch_dashboards_utils/public'; import { i18n } from '@osd/i18n'; +import { DataStorage } from '../../../common'; const NO_DATA_POPOVER_STORAGE_KEY = 'data.noDataPopover'; @@ -42,7 +42,7 @@ export function NoDataPopover({ children, }: { showNoDataPopover?: boolean; - storage: IStorageWrapper; + storage: DataStorage; children: ReactElement; }) { const [noDataPopoverDismissed, setNoDataPopoverDismissed] = useState(() => diff --git a/src/plugins/data/public/ui/query_string_input/query_bar_top_row.tsx b/src/plugins/data/public/ui/query_string_input/query_bar_top_row.tsx index f2679a6f5fc1..a14b044c6bae 100644 --- a/src/plugins/data/public/ui/query_string_input/query_bar_top_row.tsx +++ b/src/plugins/data/public/ui/query_string_input/query_bar_top_row.tsx @@ -333,7 +333,7 @@ export default function QueryBarTopRow(props: QueryBarTopRowProps) { if ( language === 'kuery' && typeof query === 'string' && - (!storage || !storage.get('opensearchDashboards.luceneSyntaxWarningOptOut')) && + (!storage || !storage.get('luceneSyntaxWarningOptOut')) && doesKueryExpressionHaveLuceneSyntaxError(query) ) { const toast = notifications!.toasts.addWarning({ @@ -379,7 +379,7 @@ export default function QueryBarTopRow(props: QueryBarTopRowProps) { function onLuceneSyntaxWarningOptOut(toast: Toast) { if (!storage) return; - storage.set('opensearchDashboards.luceneSyntaxWarningOptOut', true); + storage.set('luceneSyntaxWarningOptOut', true); notifications!.toasts.remove(toast); } diff --git a/src/plugins/data/public/ui/query_string_input/query_string_input.test.tsx b/src/plugins/data/public/ui/query_string_input/query_string_input.test.tsx index dfa5d57411d0..392071f0d10a 100644 --- a/src/plugins/data/public/ui/query_string_input/query_string_input.test.tsx +++ b/src/plugins/data/public/ui/query_string_input/query_string_input.test.tsx @@ -179,10 +179,7 @@ describe('QueryStringInput', () => { ); component.find(QueryLanguageSwitcher).props().onSelectLanguage('lucene'); - expect(mockStorage.set).toHaveBeenCalledWith( - 'opensearchDashboards.userQueryLanguage', - 'lucene' - ); + expect(mockStorage.set).toHaveBeenCalledWith('userQueryLanguage', 'lucene'); expect(mockCallback).toHaveBeenCalledWith({ query: '', language: 'lucene' }); }); diff --git a/src/plugins/data/public/ui/query_string_input/query_string_input.tsx b/src/plugins/data/public/ui/query_string_input/query_string_input.tsx index fed716bde2d2..62eca6bac579 100644 --- a/src/plugins/data/public/ui/query_string_input/query_string_input.tsx +++ b/src/plugins/data/public/ui/query_string_input/query_string_input.tsx @@ -381,13 +381,13 @@ export default class QueryStringInputUI extends Component { 'field' in suggestion && suggestion.field.subType && suggestion.field.subType.nested && - !this.services.storage.get('opensearchDashboards.DQLNestedQuerySyntaxInfoOptOut') + !this.services.storage.get('DQLNestedQuerySyntaxInfoOptOut') ) { const { notifications, docLinks } = this.services; const onDQLNestedQuerySyntaxInfoOptOut = (toast: Toast) => { if (!this.services.storage) return; - this.services.storage.set('opensearchDashboards.DQLNestedQuerySyntaxInfoOptOut', true); + this.services.storage.set('DQLNestedQuerySyntaxInfoOptOut', true); notifications!.toasts.remove(toast); }; @@ -469,7 +469,7 @@ export default class QueryStringInputUI extends Component { body: JSON.stringify({ opt_in: language === 'kuery' }), }); - this.services.storage.set('opensearchDashboards.userQueryLanguage', language); + this.services.storage.set('userQueryLanguage', language); const newQuery = { query: '', language }; this.onChange(newQuery); 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 dc3d9191e056..675f6cdc5791 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 @@ -31,7 +31,6 @@ import _ from 'lodash'; import React, { useCallback, useEffect, useRef } from 'react'; import { CoreStart } from 'src/core/public'; -import { IStorageWrapper } from 'src/plugins/opensearch_dashboards_utils/public'; import { OpenSearchDashboardsContextProvider } from '../../../../opensearch_dashboards_react/public'; import { QueryStart, SavedQuery } from '../../query'; import { SearchBar, SearchBarOwnProps } from './'; @@ -39,14 +38,14 @@ import { useFilterManager } from './lib/use_filter_manager'; import { useTimefilter } from './lib/use_timefilter'; import { useSavedQuery } from './lib/use_saved_query'; import { DataPublicPluginStart } from '../../types'; -import { Filter, Query, TimeRange } from '../../../common'; +import { DataStorage, Filter, Query, TimeRange } from '../../../common'; import { useQueryStringManager } from './lib/use_query_string_manager'; import { Settings } from '../types'; interface StatefulSearchBarDeps { core: CoreStart; data: Omit; - storage: IStorageWrapper; + storage: DataStorage; settings: Settings; setDataSetContainerRef: (ref: HTMLDivElement | null) => void; } 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 3db269074015..fd8ff3dc21c1 100644 --- a/src/plugins/data/public/ui/search_bar/search_bar.tsx +++ b/src/plugins/data/public/ui/search_bar/search_bar.tsx @@ -119,6 +119,8 @@ class SearchBarUI extends Component { }; private services = this.props.opensearchDashboards.services; + private dataSetService = this.services.data.query.dataSetManager; + private queryStringService = this.services.data.query.queryString; private savedQueryService = this.services.data.query.savedQueries; public filterBarRef: Element | null = null; public filterBarWrapperRef: Element | null = null; @@ -372,6 +374,14 @@ class SearchBarUI extends Component { } } ); + const dataSet = this.dataSetService.getDataSet(); + if (dataSet && queryAndDateRange.query) { + this.queryStringService.addToQueryHistory( + dataSet, + queryAndDateRange.query, + queryAndDateRange.dateRange + ); + } }; public onLoadSavedQuery = (savedQuery: SavedQuery) => { diff --git a/src/plugins/data/public/ui/settings/settings.ts b/src/plugins/data/public/ui/settings/settings.ts index 007800738952..7fc758712ad2 100644 --- a/src/plugins/data/public/ui/settings/settings.ts +++ b/src/plugins/data/public/ui/settings/settings.ts @@ -4,8 +4,7 @@ */ import { BehaviorSubject } from 'rxjs'; -import { IStorageWrapper } from '../../../../opensearch_dashboards_utils/public'; -import { setOverrides as setFieldOverrides } from '../../../common'; +import { DataStorage, setOverrides as setFieldOverrides } from '../../../common'; import { ConfigSchema } from '../../../config'; import { ISearchStart } from '../../search'; import { QueryEditorExtensionConfig } from '../query_editor/query_editor_extensions'; @@ -31,7 +30,7 @@ export class Settings { constructor( private readonly config: ConfigSchema['enhancements'], private readonly search: ISearchStart, - private readonly storage: IStorageWrapper, + private readonly storage: DataStorage, private readonly queryEnhancements: Map, private readonly queryEditorExtensionMap: Record ) { @@ -72,26 +71,26 @@ export class Settings { } getUserQueryLanguageBlocklist() { - return this.storage.get('opensearchDashboards.userQueryLanguageBlocklist') || []; + return this.storage.get('userQueryLanguageBlocklist') || []; } setUserQueryLanguageBlocklist(languages: string[]) { this.storage.set( - 'opensearchDashboards.userQueryLanguageBlocklist', + 'userQueryLanguageBlocklist', languages.map((language) => language.toLowerCase()) ); return true; } getUserQueryLanguage() { - return this.storage.get('opensearchDashboards.userQueryLanguage') || 'kuery'; + return this.storage.get('userQueryLanguage') || 'kuery'; } setUserQueryLanguage(language: string) { if (language !== this.getUserQueryLanguage()) { this.search.df.clear(); } - this.storage.set('opensearchDashboards.userQueryLanguage', language); + this.storage.set('userQueryLanguage', language); const queryEnhancement = this.queryEnhancements.get(language); this.search.__enhance({ searchInterceptor: queryEnhancement @@ -104,25 +103,25 @@ export class Settings { } getUserQueryString() { - return this.storage.get('opensearchDashboards.userQueryString') || ''; + return this.storage.get('userQueryString') || ''; } setUserQueryString(query: string) { - this.storage.set('opensearchDashboards.userQueryString', query); + this.storage.set('userQueryString', query); return true; } getUiOverrides() { - return this.storage.get('opensearchDashboards.uiOverrides') || {}; + return this.storage.get('uiOverrides') || {}; } setUiOverrides(overrides?: { [key: string]: any }) { if (!overrides) { - this.storage.remove('opensearchDashboards.uiOverrides'); + this.storage.remove('uiOverrides'); setFieldOverrides(undefined); return true; } - this.storage.set('opensearchDashboards.uiOverrides', overrides); + this.storage.set('uiOverrides', overrides); setFieldOverrides(overrides.fields); return true; } @@ -171,7 +170,7 @@ export class Settings { interface Deps { config: ConfigSchema['enhancements']; search: ISearchStart; - storage: IStorageWrapper; + storage: DataStorage; queryEnhancements: Map; queryEditorExtensionMap: Record; } diff --git a/src/plugins/data/public/ui/ui_service.ts b/src/plugins/data/public/ui/ui_service.ts index 8359872137b2..1802e3b79320 100644 --- a/src/plugins/data/public/ui/ui_service.ts +++ b/src/plugins/data/public/ui/ui_service.ts @@ -5,7 +5,6 @@ import { BehaviorSubject } from 'rxjs'; import { CoreSetup, CoreStart, Plugin, PluginInitializerContext } from 'src/core/public'; -import { IStorageWrapper } from '../../../opensearch_dashboards_utils/public'; import { ConfigSchema } from '../../config'; import { DataPublicPluginStart } from '../types'; import { createDataSetNavigator } from './dataset_navigator'; @@ -15,6 +14,7 @@ import { createSearchBar } from './search_bar/create_search_bar'; import { createSettings } from './settings'; import { SuggestionsComponent } from './typeahead'; import { IUiSetup, IUiStart, QueryEnhancement, UiEnhancements } from './types'; +import { DataStorage } from '../../common'; /** @internal */ // eslint-disable-next-line @typescript-eslint/no-empty-interface @@ -23,7 +23,7 @@ export interface UiServiceSetupDependencies {} /** @internal */ export interface UiServiceStartDependencies { dataServices: Omit; - storage: IStorageWrapper; + storage: DataStorage; } export class UiService implements Plugin {