From e53e80459dc4de63c895e2a35001ca1cb75901d2 Mon Sep 17 00:00:00 2001 From: Lukas Olson Date: Tue, 19 Oct 2021 16:01:27 -0700 Subject: [PATCH 1/7] [data.search.session] Use locators instead of URL generators --- examples/search_examples/public/plugin.ts | 20 +++---- .../public/search_sessions/app.tsx | 14 ++--- .../{url_generator.ts => app_locator.ts} | 60 ++++++++++--------- .../lib/dashboard_session_restoration.ts | 23 ++++--- .../data/common/search/session/types.ts | 9 +-- .../public/search/session/session_service.ts | 29 +++++---- .../public/search/session/sessions_client.ts | 8 +-- .../apps/main/services/discover_state.ts | 8 +-- src/plugins/discover/public/locator.ts | 2 +- .../search/sessions_mgmt/__mocks__/index.tsx | 6 -- .../sessions_mgmt/application/index.tsx | 2 +- .../public/search/sessions_mgmt/lib/api.ts | 30 ++++------ .../public/search/sessions_mgmt/types.ts | 2 +- .../data_enhanced/server/routes/session.ts | 6 +- .../server/saved_objects/search_session.ts | 2 +- .../saved_objects/search_session_migration.ts | 6 ++ .../server/search/session/session_service.ts | 6 +- .../api_integration/apis/search/session.ts | 30 +++++----- 18 files changed, 127 insertions(+), 136 deletions(-) rename examples/search_examples/public/search_sessions/{url_generator.ts => app_locator.ts} (52%) diff --git a/examples/search_examples/public/plugin.ts b/examples/search_examples/public/plugin.ts index b00362aef1f5e..95ea688f49cc2 100644 --- a/examples/search_examples/public/plugin.ts +++ b/examples/search_examples/public/plugin.ts @@ -8,18 +8,18 @@ import { AppMountParameters, + AppNavLinkStatus, CoreSetup, CoreStart, Plugin, - AppNavLinkStatus, } from '../../../src/core/public'; import { - SearchExamplesPluginSetup, - SearchExamplesPluginStart, AppPluginSetupDependencies, AppPluginStartDependencies, + SearchExamplesPluginSetup, + SearchExamplesPluginStart, } from './types'; -import { createSearchSessionsExampleUrlGenerator } from './search_sessions/url_generator'; +import { SearchSessionsExamplesAppLocatorDefinition } from './search_sessions/app_locator'; import { PLUGIN_NAME } from '../common'; import img from './search_examples.png'; @@ -67,14 +67,10 @@ export class SearchExamplesPlugin ], }); - // we need an URL generator for search session examples for restoring a search session - share.urlGenerators.registerUrlGenerator( - createSearchSessionsExampleUrlGenerator(() => { - return core - .getStartServices() - .then(([coreStart]) => ({ appBasePath: coreStart.http.basePath.get() })); - }) - ); + // we need an locator for search session examples for restoring a search session + const getAppBasePath = () => + core.getStartServices().then(([coreStart]) => coreStart.http.basePath.get()); + share.url.locators.create(new SearchSessionsExamplesAppLocatorDefinition(getAppBasePath)); return {}; } diff --git a/examples/search_examples/public/search_sessions/app.tsx b/examples/search_examples/public/search_sessions/app.tsx index 63ab706c945d5..c953da0895ccd 100644 --- a/examples/search_examples/public/search_sessions/app.tsx +++ b/examples/search_examples/public/search_sessions/app.tsx @@ -55,11 +55,7 @@ import { createStateContainer, useContainerState, } from '../../../../src/plugins/kibana_utils/public'; -import { - getInitialStateFromUrl, - SEARCH_SESSIONS_EXAMPLES_APP_URL_GENERATOR, - SearchSessionExamplesUrlGeneratorState, -} from './url_generator'; +import { getInitialStateFromUrl, SEARCH_SESSIONS_EXAMPLES_APP_LOCATOR } from './app_locator'; interface SearchSessionsExampleAppDeps { notifications: CoreStart['notifications']; @@ -140,14 +136,14 @@ export const SearchSessionsExampleApp = ({ const enableSessionStorage = useCallback(() => { data.search.session.enableStorage({ getName: async () => 'Search sessions example', - getUrlGeneratorData: async () => ({ + getLocatorData: async () => ({ initialState: { time: data.query.timefilter.timefilter.getTime(), filters: data.query.filterManager.getFilters(), query: data.query.queryString.getQuery(), indexPatternId: indexPattern?.id, numericFieldName, - } as SearchSessionExamplesUrlGeneratorState, + }, restoreState: { time: data.query.timefilter.timefilter.getAbsoluteTime(), filters: data.query.filterManager.getFilters(), @@ -155,8 +151,8 @@ export const SearchSessionsExampleApp = ({ indexPatternId: indexPattern?.id, numericFieldName, searchSessionId: data.search.session.getSessionId(), - } as SearchSessionExamplesUrlGeneratorState, - urlGeneratorId: SEARCH_SESSIONS_EXAMPLES_APP_URL_GENERATOR, + }, + id: SEARCH_SESSIONS_EXAMPLES_APP_LOCATOR, }), }); }, [ diff --git a/examples/search_examples/public/search_sessions/url_generator.ts b/examples/search_examples/public/search_sessions/app_locator.ts similarity index 52% rename from examples/search_examples/public/search_sessions/url_generator.ts rename to examples/search_examples/public/search_sessions/app_locator.ts index 69355f9046c46..1cbd27887c1c3 100644 --- a/examples/search_examples/public/search_sessions/url_generator.ts +++ b/examples/search_examples/public/search_sessions/app_locator.ts @@ -6,17 +6,17 @@ * Side Public License, v 1. */ -import { TimeRange, Filter, Query, esFilters } from '../../../../src/plugins/data/public'; +import { SerializableRecord } from '@kbn/utility-types'; +import { esFilters, Filter, Query, TimeRange } from '../../../../src/plugins/data/public'; import { getStatesFromKbnUrl, setStateToKbnUrl } from '../../../../src/plugins/kibana_utils/public'; -import { UrlGeneratorsDefinition } from '../../../../src/plugins/share/public'; +import { LocatorDefinition } from '../../../../src/plugins/share/common'; export const STATE_STORAGE_KEY = '_a'; export const GLOBAL_STATE_STORAGE_KEY = '_g'; -export const SEARCH_SESSIONS_EXAMPLES_APP_URL_GENERATOR = - 'SEARCH_SESSIONS_EXAMPLES_APP_URL_GENERATOR'; +export const SEARCH_SESSIONS_EXAMPLES_APP_LOCATOR = 'SEARCH_SESSIONS_EXAMPLES_APP_LOCATOR'; -export interface AppUrlState { +export interface AppUrlState extends SerializableRecord { filters?: Filter[]; query?: Query; indexPatternId?: string; @@ -24,32 +24,32 @@ export interface AppUrlState { searchSessionId?: string; } -export interface GlobalUrlState { +export interface GlobalUrlState extends SerializableRecord { filters?: Filter[]; time?: TimeRange; } -export type SearchSessionExamplesUrlGeneratorState = AppUrlState & GlobalUrlState; +export type SearchSessionsExamplesAppLocatorParams = AppUrlState & GlobalUrlState; -export const createSearchSessionsExampleUrlGenerator = ( - getStartServices: () => Promise<{ - appBasePath: string; - }> -): UrlGeneratorsDefinition => ({ - id: SEARCH_SESSIONS_EXAMPLES_APP_URL_GENERATOR, - createUrl: async (state: SearchSessionExamplesUrlGeneratorState) => { - const startServices = await getStartServices(); - const appBasePath = startServices.appBasePath; - const path = `${appBasePath}/app/searchExamples/search-sessions`; +export class SearchSessionsExamplesAppLocatorDefinition + implements LocatorDefinition +{ + public readonly id = SEARCH_SESSIONS_EXAMPLES_APP_LOCATOR; + + constructor(protected readonly getAppBasePath: () => Promise) {} + + public readonly getLocation = async (params: SearchSessionsExamplesAppLocatorParams) => { + const appBasePath = await this.getAppBasePath(); + const path = `${appBasePath}/search-sessions`; let url = setStateToKbnUrl( STATE_STORAGE_KEY, { - query: state.query, - filters: state.filters?.filter((f) => !esFilters.isFilterPinned(f)), - indexPatternId: state.indexPatternId, - numericFieldName: state.numericFieldName, - searchSessionId: state.searchSessionId, + query: params.query, + filters: params.filters?.filter((f) => !esFilters.isFilterPinned(f)), + indexPatternId: params.indexPatternId, + numericFieldName: params.numericFieldName, + searchSessionId: params.searchSessionId, } as AppUrlState, { useHash: false, storeInHashQuery: false }, path @@ -58,18 +58,22 @@ export const createSearchSessionsExampleUrlGenerator = ( url = setStateToKbnUrl( GLOBAL_STATE_STORAGE_KEY, { - time: state.time, - filters: state.filters?.filter((f) => esFilters.isFilterPinned(f)), + time: params.time, + filters: params.filters?.filter((f) => esFilters.isFilterPinned(f)), } as GlobalUrlState, { useHash: false, storeInHashQuery: false }, url ); - return url; - }, -}); + return { + app: 'searchExamples', + path: url, + state: {}, + }; + }; +} -export function getInitialStateFromUrl(): SearchSessionExamplesUrlGeneratorState { +export function getInitialStateFromUrl(): SearchSessionsExamplesAppLocatorParams { const { _a: { numericFieldName, indexPatternId, searchSessionId, filters: aFilters, query } = {}, _g: { filters: gFilters, time } = {}, diff --git a/src/plugins/dashboard/public/application/lib/dashboard_session_restoration.ts b/src/plugins/dashboard/public/application/lib/dashboard_session_restoration.ts index 7dd2b53a58155..ca4fa85b4b55c 100644 --- a/src/plugins/dashboard/public/application/lib/dashboard_session_restoration.ts +++ b/src/plugins/dashboard/public/application/lib/dashboard_session_restoration.ts @@ -7,18 +7,19 @@ */ import { History } from 'history'; -import { DashboardConstants } from '../..'; +import { DashboardAppLocatorParams, DashboardConstants } from '../..'; import { DashboardState } from '../../types'; import { getDashboardTitle } from '../../dashboard_strings'; import { DashboardSavedObject } from '../../saved_dashboards'; import { getQueryParams } from '../../services/kibana_utils'; import { createQueryParamObservable } from '../../../../kibana_utils/public'; -import { DASHBOARD_APP_URL_GENERATOR, DashboardUrlGeneratorState } from '../../url_generator'; import { DataPublicPluginStart, noSearchSessionStorageCapabilityMessage, + SearchSessionInfoProvider, } from '../../services/data'; import { stateToRawDashboardState } from './convert_dashboard_state'; +import { DASHBOARD_APP_LOCATOR } from '../../locator'; export const getSearchSessionIdFromURL = (history: History): string | undefined => getQueryParams(history.location)[DashboardConstants.SEARCH_SESSION_ID] as string | undefined; @@ -32,16 +33,14 @@ export function createSessionRestorationDataProvider(deps: { getAppState: () => DashboardState; getDashboardTitle: () => string; getDashboardId: () => string; -}) { +}): SearchSessionInfoProvider { return { getName: async () => deps.getDashboardTitle(), - getUrlGeneratorData: async () => { - return { - urlGeneratorId: DASHBOARD_APP_URL_GENERATOR, - initialState: getUrlGeneratorState({ ...deps, shouldRestoreSearchSession: false }), - restoreState: getUrlGeneratorState({ ...deps, shouldRestoreSearchSession: true }), - }; - }, + getLocatorData: async () => ({ + id: DASHBOARD_APP_LOCATOR, + initialState: getLocatorParams({ ...deps, shouldRestoreSearchSession: false }), + restoreState: getLocatorParams({ ...deps, shouldRestoreSearchSession: true }), + }), }; } @@ -93,7 +92,7 @@ export function enableDashboardSearchSessions({ * Fetches the state to store when a session is saved so that this dashboard can be recreated exactly * as it was. */ -function getUrlGeneratorState({ +function getLocatorParams({ data, getAppState, kibanaVersion, @@ -105,7 +104,7 @@ function getUrlGeneratorState({ getAppState: () => DashboardState; getDashboardId: () => string; shouldRestoreSearchSession: boolean; -}): DashboardUrlGeneratorState { +}): DashboardAppLocatorParams { const appState = stateToRawDashboardState({ state: getAppState(), version: kibanaVersion }); const { filterManager, queryString } = data.query; const { timefilter } = data.query.timefilter; diff --git a/src/plugins/data/common/search/session/types.ts b/src/plugins/data/common/search/session/types.ts index 8e3c298aa9316..cbe3de9be4c73 100644 --- a/src/plugins/data/common/search/session/types.ts +++ b/src/plugins/data/common/search/session/types.ts @@ -6,6 +6,7 @@ * Side Public License, v 1. */ +import { SerializableRecord } from '@kbn/utility-types'; import { SearchSessionStatus } from './status'; export const SEARCH_SESSION_TYPE = 'search-session'; @@ -43,19 +44,19 @@ export interface SearchSessionSavedObjectAttributes { */ status: SearchSessionStatus; /** - * urlGeneratorId + * locatorId (see share.url.locators service) */ - urlGeneratorId?: string; + locatorId?: string; /** * The application state that was used to create the session. * Should be used, for example, to re-load an expired search session. */ - initialState?: Record; + initialState?: SerializableRecord; /** * Application state that should be used to restore the session. * For example, relative dates are conveted to absolute ones. */ - restoreState?: Record; + restoreState?: SerializableRecord; /** * Mapping of search request hashes to their corresponsing info (async search id, etc.) */ diff --git a/src/plugins/data/public/search/session/session_service.ts b/src/plugins/data/public/search/session/session_service.ts index 874fad67c4df1..360e8808c186d 100644 --- a/src/plugins/data/public/search/session/session_service.ts +++ b/src/plugins/data/public/search/session/session_service.ts @@ -6,7 +6,7 @@ * Side Public License, v 1. */ -import { PublicContract } from '@kbn/utility-types'; +import { PublicContract, SerializableRecord } from '@kbn/utility-types'; import { distinctUntilChanged, map, startWith } from 'rxjs/operators'; import { Observable, Subscription } from 'rxjs'; import { @@ -15,14 +15,13 @@ import { ToastsStart as ToastService, } from 'kibana/public'; import { i18n } from '@kbn/i18n'; -import { UrlGeneratorId, UrlGeneratorStateMapping } from '../../../../share/public/'; import { ConfigSchema } from '../../../config'; import { createSessionStateContainer, SearchSessionState, - SessionStateInternal, SessionMeta, SessionStateContainer, + SessionStateInternal, } from './search_session_state'; import { ISessionsClient } from './sessions_client'; import { ISearchOptions } from '../../../common'; @@ -44,7 +43,7 @@ export type SessionSnapshot = SessionStateInternal; /** * Provide info about current search session to be stored in the Search Session saved object */ -export interface SearchSessionInfoProvider { +export interface SearchSessionInfoProvider

{ /** * User-facing name of the session. * e.g. will be displayed in saved Search Sessions management list @@ -57,10 +56,10 @@ export interface SearchSessionInfoProvider Promise<{ - urlGeneratorId: ID; - initialState: UrlGeneratorStateMapping[ID]['State']; - restoreState: UrlGeneratorStateMapping[ID]['State']; + getLocatorData: () => Promise<{ + id: string; + initialState: P; + restoreState: P; }>; } @@ -316,9 +315,9 @@ export class SessionService { if (!this.hasAccess()) throw new Error('No access to search sessions'); const currentSessionInfoProvider = this.searchSessionInfoProvider; if (!currentSessionInfoProvider) throw new Error('No info provider for current session'); - const [name, { initialState, restoreState, urlGeneratorId }] = await Promise.all([ + const [name, { initialState, restoreState, id: locatorId }] = await Promise.all([ currentSessionInfoProvider.getName(), - currentSessionInfoProvider.getUrlGeneratorData(), + currentSessionInfoProvider.getLocatorData(), ]); const formattedName = formatSessionName(name, { @@ -329,9 +328,9 @@ export class SessionService { const searchSessionSavedObject = await this.sessionsClient.create({ name: formattedName, appId: currentSessionApp, - restoreState: restoreState as unknown as Record, - initialState: initialState as unknown as Record, - urlGeneratorId, + locatorId, + restoreState, + initialState, sessionId, }); @@ -411,8 +410,8 @@ export class SessionService { * @param searchSessionInfoProvider - info provider for saving a search session * @param searchSessionIndicatorUiConfig - config for "Search session indicator" UI */ - public enableStorage( - searchSessionInfoProvider: SearchSessionInfoProvider, + public enableStorage

( + searchSessionInfoProvider: SearchSessionInfoProvider

, searchSessionIndicatorUiConfig?: SearchSessionIndicatorUiConfig ) { this.searchSessionInfoProvider = { diff --git a/src/plugins/data/public/search/session/sessions_client.ts b/src/plugins/data/public/search/session/sessions_client.ts index 0b6f1b79f0c63..d267ba52b024c 100644 --- a/src/plugins/data/public/search/session/sessions_client.ts +++ b/src/plugins/data/public/search/session/sessions_client.ts @@ -37,26 +37,26 @@ export class SessionsClient { public create({ name, appId, - urlGeneratorId, + locatorId, initialState, restoreState, sessionId, }: { name: string; appId: string; + locatorId: string; initialState: Record; restoreState: Record; - urlGeneratorId: string; sessionId: string; }): Promise { return this.http.post(`/internal/session`, { body: JSON.stringify({ name, + appId, + locatorId, initialState, restoreState, sessionId, - appId, - urlGeneratorId, }), }); } diff --git a/src/plugins/discover/public/application/apps/main/services/discover_state.ts b/src/plugins/discover/public/application/apps/main/services/discover_state.ts index 16eb622c4a7c4..6bc4bff21a2bd 100644 --- a/src/plugins/discover/public/application/apps/main/services/discover_state.ts +++ b/src/plugins/discover/public/application/apps/main/services/discover_state.ts @@ -32,9 +32,9 @@ import { } from '../../../../../../data/public'; import { migrateLegacyQuery } from '../../../helpers/migrate_legacy_query'; import { DiscoverGridSettings } from '../../../components/discover_grid/types'; -import { DISCOVER_APP_URL_GENERATOR, DiscoverUrlGeneratorState } from '../../../../url_generator'; import { SavedSearch } from '../../../../saved_searches'; import { handleSourceColumnState } from '../../../helpers/state_helpers'; +import { DISCOVER_APP_LOCATOR, DiscoverAppLocatorParams } from '../../../../locator'; export interface AppState { /** @@ -352,9 +352,9 @@ export function createSearchSessionRestorationDataProvider(deps: { }) ); }, - getUrlGeneratorData: async () => { + getLocatorData: async () => { return { - urlGeneratorId: DISCOVER_APP_URL_GENERATOR, + id: DISCOVER_APP_LOCATOR, initialState: createUrlGeneratorState({ ...deps, getSavedSearchId, @@ -380,7 +380,7 @@ function createUrlGeneratorState({ data: DataPublicPluginStart; getSavedSearchId: () => string | undefined; shouldRestoreSearchSession: boolean; -}): DiscoverUrlGeneratorState { +}): DiscoverAppLocatorParams { const appState = appStateContainer.get(); return { filters: data.query.filterManager.getFilters(), diff --git a/src/plugins/discover/public/locator.ts b/src/plugins/discover/public/locator.ts index bc632c7e1ccb7..40b62841f19d1 100644 --- a/src/plugins/discover/public/locator.ts +++ b/src/plugins/discover/public/locator.ts @@ -69,7 +69,7 @@ export interface DiscoverAppLocatorParams extends SerializableRecord { /** * Array of the used sorting [[field,direction],...] */ - sort?: string[][] & SerializableRecord; + sort?: string[][]; /** * id of the used saved query diff --git a/x-pack/plugins/data_enhanced/public/search/sessions_mgmt/__mocks__/index.tsx b/x-pack/plugins/data_enhanced/public/search/sessions_mgmt/__mocks__/index.tsx index af0a1a583e447..d21b72b85f8d5 100644 --- a/x-pack/plugins/data_enhanced/public/search/sessions_mgmt/__mocks__/index.tsx +++ b/x-pack/plugins/data_enhanced/public/search/sessions_mgmt/__mocks__/index.tsx @@ -7,13 +7,7 @@ import React, { ReactNode } from 'react'; import { __IntlProvider as IntlProvider } from '@kbn/i18n/react'; -// eslint-disable-next-line @kbn/eslint/no-restricted-paths -import { UrlGeneratorsStart } from '../../../../../../../src/plugins/share/public/url_generators'; export function LocaleWrapper({ children }: { children?: ReactNode }) { return {children}; } - -export const mockUrls = { - getUrlGenerator: (id: string) => ({ createUrl: () => `hello-cool-${id}-url` }), -} as unknown as UrlGeneratorsStart; diff --git a/x-pack/plugins/data_enhanced/public/search/sessions_mgmt/application/index.tsx b/x-pack/plugins/data_enhanced/public/search/sessions_mgmt/application/index.tsx index a2d51d7d21248..7f5117740f38c 100644 --- a/x-pack/plugins/data_enhanced/public/search/sessions_mgmt/application/index.tsx +++ b/x-pack/plugins/data_enhanced/public/search/sessions_mgmt/application/index.tsx @@ -49,7 +49,7 @@ export class SearchSessionsMgmtApp { const { sessionsClient } = data.search; const api = new SearchSessionsMgmtAPI(sessionsClient, this.config, { notifications, - urls: share.urlGenerators, + locators: share.url.locators, application, usageCollector: pluginsSetup.data.search.usageCollector, }); diff --git a/x-pack/plugins/data_enhanced/public/search/sessions_mgmt/lib/api.ts b/x-pack/plugins/data_enhanced/public/search/sessions_mgmt/lib/api.ts index 01b64dcaf8a85..fbd7f472177cb 100644 --- a/x-pack/plugins/data_enhanced/public/search/sessions_mgmt/lib/api.ts +++ b/x-pack/plugins/data_enhanced/public/search/sessions_mgmt/lib/api.ts @@ -11,6 +11,7 @@ import moment from 'moment'; import { from, race, timer } from 'rxjs'; import { mapTo, tap } from 'rxjs/operators'; import type { SharePluginStart } from 'src/plugins/share/public'; +import { SerializableRecord } from '@kbn/utility-types'; import { ISessionsClient, SearchUsageCollector, @@ -24,7 +25,7 @@ import { } from '../types'; import { SessionsConfigSchema } from '..'; -type UrlGeneratorsStart = SharePluginStart['urlGenerators']; +type LocatorsStart = SharePluginStart['url']['locators']; function getActions(status: UISearchSessionState) { const actions: ACTION[] = []; @@ -61,26 +62,21 @@ function getUIStatus(session: PersistedSearchSessionSavedObjectAttributes): UISe return session.status; } -async function getUrlFromState( - urls: UrlGeneratorsStart, - urlGeneratorId: string, - state: Record -) { - let url = '/'; +function getUrlFromState(locators: LocatorsStart, locatorId: string, state: SerializableRecord) { try { - url = await urls.getUrlGenerator(urlGeneratorId).createUrl(state); + const locator = locators.get(locatorId); + return locator?.getRedirectUrl(state); } catch (err) { // eslint-disable-next-line no-console console.error('Could not create URL from restoreState'); // eslint-disable-next-line no-console console.error(err); } - return url; } // Helper: factory for a function to map server objects to UI objects const mapToUISession = - (urls: UrlGeneratorsStart, config: SessionsConfigSchema) => + (locators: LocatorsStart, config: SessionsConfigSchema) => async ( savedObject: SavedObject ): Promise => { @@ -89,7 +85,7 @@ const mapToUISession = appId, created, expires, - urlGeneratorId, + locatorId, initialState, restoreState, idMapping, @@ -102,8 +98,8 @@ const mapToUISession = // TODO: initialState should be saved without the searchSessionID if (initialState) delete initialState.searchSessionId; // derive the URL and add it in - const reloadUrl = await getUrlFromState(urls, urlGeneratorId, initialState); - const restoreUrl = await getUrlFromState(urls, urlGeneratorId, restoreState); + const reloadUrl = await getUrlFromState(locators, locatorId, initialState); + const restoreUrl = await getUrlFromState(locators, locatorId, restoreState); return { id: savedObject.id, @@ -113,8 +109,8 @@ const mapToUISession = expires, status, actions, - restoreUrl, - reloadUrl, + restoreUrl: restoreUrl!, + reloadUrl: reloadUrl!, initialState, restoreState, numSearches: Object.keys(idMapping).length, @@ -123,7 +119,7 @@ const mapToUISession = }; interface SearchSessionManagementDeps { - urls: UrlGeneratorsStart; + locators: LocatorsStart; notifications: NotificationsStart; application: ApplicationStart; usageCollector?: SearchUsageCollector; @@ -174,7 +170,7 @@ export class SearchSessionsMgmtAPI { const savedObjects = result.saved_objects as Array< SavedObject >; - return await Promise.all(savedObjects.map(mapToUISession(this.deps.urls, this.config))); + return await Promise.all(savedObjects.map(mapToUISession(this.deps.locators, this.config))); } } catch (err) { // eslint-disable-next-line no-console diff --git a/x-pack/plugins/data_enhanced/public/search/sessions_mgmt/types.ts b/x-pack/plugins/data_enhanced/public/search/sessions_mgmt/types.ts index f4f928e67e19c..7489a1ce26aa5 100644 --- a/x-pack/plugins/data_enhanced/public/search/sessions_mgmt/types.ts +++ b/x-pack/plugins/data_enhanced/public/search/sessions_mgmt/types.ts @@ -21,7 +21,7 @@ export type PersistedSearchSessionSavedObjectAttributes = SearchSessionSavedObje Required< Pick< SearchSessionSavedObjectAttributes, - 'name' | 'appId' | 'urlGeneratorId' | 'initialState' | 'restoreState' + 'name' | 'appId' | 'locatorId' | 'initialState' | 'restoreState' > >; diff --git a/x-pack/plugins/data_enhanced/server/routes/session.ts b/x-pack/plugins/data_enhanced/server/routes/session.ts index 3e293aa82dc83..3f36bd0a75746 100644 --- a/x-pack/plugins/data_enhanced/server/routes/session.ts +++ b/x-pack/plugins/data_enhanced/server/routes/session.ts @@ -22,7 +22,7 @@ export function registerSessionRoutes(router: DataEnhancedPluginRouter, logger: name: schema.string(), appId: schema.string(), expires: schema.maybe(schema.string()), - urlGeneratorId: schema.string(), + locatorId: schema.string(), initialState: schema.maybe(schema.object({}, { unknowns: 'allow' })), restoreState: schema.maybe(schema.object({}, { unknowns: 'allow' })), }), @@ -32,7 +32,7 @@ export function registerSessionRoutes(router: DataEnhancedPluginRouter, logger: }, }, async (context, request, res) => { - const { sessionId, name, expires, initialState, restoreState, appId, urlGeneratorId } = + const { sessionId, name, expires, initialState, restoreState, appId, locatorId } = request.body; try { @@ -40,7 +40,7 @@ export function registerSessionRoutes(router: DataEnhancedPluginRouter, logger: name, appId, expires, - urlGeneratorId, + locatorId, initialState, restoreState, }); diff --git a/x-pack/plugins/data_enhanced/server/saved_objects/search_session.ts b/x-pack/plugins/data_enhanced/server/saved_objects/search_session.ts index 9a359679c0e7a..f921ed78eb247 100644 --- a/x-pack/plugins/data_enhanced/server/saved_objects/search_session.ts +++ b/x-pack/plugins/data_enhanced/server/saved_objects/search_session.ts @@ -42,7 +42,7 @@ export const searchSessionSavedObjectType: SavedObjectsType = { appId: { type: 'keyword', }, - urlGeneratorId: { + locatorId: { type: 'keyword', }, initialState: { diff --git a/x-pack/plugins/data_enhanced/server/saved_objects/search_session_migration.ts b/x-pack/plugins/data_enhanced/server/saved_objects/search_session_migration.ts index fa1428b3a3aad..9173090a65a0a 100644 --- a/x-pack/plugins/data_enhanced/server/saved_objects/search_session_migration.ts +++ b/x-pack/plugins/data_enhanced/server/saved_objects/search_session_migration.ts @@ -60,4 +60,10 @@ export const searchSessionSavedObjectMigrations: SavedObjectMigrationMap = { }, }; }, + '7.16.0': ( + doc: SavedObjectUnsanitizedDoc + ): SavedObjectUnsanitizedDoc => { + // TODO: Convert `urlGeneratorId` to `locatorId` (do we need to convert state as well?) + return doc; + }, }; diff --git a/x-pack/plugins/data_enhanced/server/search/session/session_service.ts b/x-pack/plugins/data_enhanced/server/search/session/session_service.ts index 75f404d0f8790..84266e2545810 100644 --- a/x-pack/plugins/data_enhanced/server/search/session/session_service.ts +++ b/x-pack/plugins/data_enhanced/server/search/session/session_service.ts @@ -287,7 +287,7 @@ export class SearchSessionService { name, appId, - urlGeneratorId, + locatorId, initialState = {}, restoreState = {}, }: Partial @@ -295,12 +295,12 @@ export class SearchSessionService if (!this.sessionConfig.enabled) throw new Error('Search sessions are disabled'); if (!name) throw new Error('Name is required'); if (!appId) throw new Error('AppId is required'); - if (!urlGeneratorId) throw new Error('UrlGeneratorId is required'); + if (!locatorId) throw new Error('locatorId is required'); return this.updateOrCreate(deps, user, sessionId, { name, appId, - urlGeneratorId, + locatorId, initialState, restoreState, persisted: true, diff --git a/x-pack/test/api_integration/apis/search/session.ts b/x-pack/test/api_integration/apis/search/session.ts index 06be7c6759bc0..1fa65172cdee3 100644 --- a/x-pack/test/api_integration/apis/search/session.ts +++ b/x-pack/test/api_integration/apis/search/session.ts @@ -27,7 +27,7 @@ export default function ({ getService }: FtrProviderContext) { sessionId, appId: 'discover', expires: '123', - urlGeneratorId: 'discover', + locatorId: 'discover', }) .expect(400); }); @@ -42,7 +42,7 @@ export default function ({ getService }: FtrProviderContext) { name: 'My Session', appId: 'discover', expires: '123', - urlGeneratorId: 'discover', + locatorId: 'discover', }) .expect(200); @@ -63,7 +63,7 @@ export default function ({ getService }: FtrProviderContext) { name: 'My Session', appId: 'discover', expires: '123', - urlGeneratorId: 'discover', + locatorId: 'discover', }) .expect(200); @@ -82,7 +82,7 @@ export default function ({ getService }: FtrProviderContext) { name: 'My Session', appId: 'discover', expires: '123', - urlGeneratorId: 'discover', + locatorId: 'discover', }) .expect(200); @@ -114,7 +114,7 @@ export default function ({ getService }: FtrProviderContext) { name: oldName, appId: 'discover', expires: '123', - urlGeneratorId: 'discover', + locatorId: 'discover', }) .expect(200); @@ -165,7 +165,7 @@ export default function ({ getService }: FtrProviderContext) { name: 'My Session', appId: 'discover', expires: '123', - urlGeneratorId: 'discover', + locatorId: 'discover', }) .expect(200); @@ -217,7 +217,7 @@ export default function ({ getService }: FtrProviderContext) { name: 'My Session', appId: 'discover', expires: '123', - urlGeneratorId: 'discover', + locatorId: 'discover', }) .expect(200); @@ -337,7 +337,7 @@ export default function ({ getService }: FtrProviderContext) { name: 'My Session', appId: 'discover', expires: '123', - urlGeneratorId: 'discover', + locatorId: 'discover', }) .expect(200); @@ -463,7 +463,7 @@ export default function ({ getService }: FtrProviderContext) { name: 'My Session', appId: 'discover', expires: '123', - urlGeneratorId: 'discover', + locatorId: 'discover', }) .expect(200); @@ -484,7 +484,7 @@ export default function ({ getService }: FtrProviderContext) { name: 'My Session', appId: 'discover', expires: '123', - urlGeneratorId: 'discover', + locatorId: 'discover', }) .expect(200); @@ -505,7 +505,7 @@ export default function ({ getService }: FtrProviderContext) { name: 'My Session', appId: 'discover', expires: '123', - urlGeneratorId: 'discover', + locatorId: 'discover', }) .expect(200); @@ -526,7 +526,7 @@ export default function ({ getService }: FtrProviderContext) { name: 'My Session', appId: 'discover', expires: '123', - urlGeneratorId: 'discover', + locatorId: 'discover', }) .expect(200); @@ -550,7 +550,7 @@ export default function ({ getService }: FtrProviderContext) { name: 'My Session', appId: 'discover', expires: '123', - urlGeneratorId: 'discover', + locatorId: 'discover', }) .expect(401); }); @@ -591,7 +591,7 @@ export default function ({ getService }: FtrProviderContext) { name: 'My Session', appId: 'discover', expires: '123', - urlGeneratorId: 'discover', + locatorId: 'discover', }) .expect(403); @@ -714,7 +714,7 @@ export default function ({ getService }: FtrProviderContext) { name: 'My Session', appId: 'discover', expires: '123', - urlGeneratorId: 'discover', + locatorId: 'discover', }) .expect(200); From 271e21cada4aa66decea399b7fde0ea2b899b529 Mon Sep 17 00:00:00 2001 From: Lukas Olson Date: Thu, 21 Oct 2021 14:36:02 -0700 Subject: [PATCH 2/7] Add migration --- .../search_session_migration.test.ts | 191 ++++++++++++++++++ .../saved_objects/search_session_migration.ts | 32 ++- 2 files changed, 218 insertions(+), 5 deletions(-) diff --git a/x-pack/plugins/data_enhanced/server/saved_objects/search_session_migration.test.ts b/x-pack/plugins/data_enhanced/server/saved_objects/search_session_migration.test.ts index cdb86772482fe..60d2ef3315dda 100644 --- a/x-pack/plugins/data_enhanced/server/saved_objects/search_session_migration.test.ts +++ b/x-pack/plugins/data_enhanced/server/saved_objects/search_session_migration.test.ts @@ -9,6 +9,7 @@ import { searchSessionSavedObjectMigrations, SearchSessionSavedObjectAttributesPre$7$13$0, SearchSessionSavedObjectAttributesPre$7$14$0, + SearchSessionSavedObjectAttributesPre$8$0$0, } from './search_session_migration'; import { SavedObject } from '../../../../../src/core/types'; import { SEARCH_SESSION_TYPE, SearchSessionStatus } from '../../../../../src/plugins/data/common'; @@ -164,3 +165,193 @@ describe('7.13.0 -> 7.14.0', () => { `); }); }); + +describe('7.14.0 -> 7.18.0', () => { + const migration = searchSessionSavedObjectMigrations['8.0.0']; + + test('Discover app URL generator migrates to locator', () => { + const mockSessionSavedObject: SavedObject = { + id: 'id', + type: SEARCH_SESSION_TYPE, + attributes: { + name: 'my_name', + appId: 'my_app_id', + sessionId: 'sessionId', + urlGeneratorId: 'DISCOVER_APP_URL_GENERATOR', + initialState: {}, + restoreState: {}, + persisted: true, + idMapping: {}, + realmType: 'realmType', + realmName: 'realmName', + username: 'username', + created: '2021-03-26T00:00:00.000Z', + expires: '2021-03-30T00:00:00.000Z', + touched: '2021-03-29T00:00:00.000Z', + completed: '2021-03-29T00:00:00.000Z', + status: SearchSessionStatus.COMPLETE, + version: '7.14.0', + }, + references: [], + }; + + const migratedSession = migration(mockSessionSavedObject, {} as SavedObjectMigrationContext); + + expect(migratedSession.attributes).toMatchInlineSnapshot(` + Object { + "appId": "my_app_id", + "completed": "2021-03-29T00:00:00.000Z", + "created": "2021-03-26T00:00:00.000Z", + "expires": "2021-03-30T00:00:00.000Z", + "idMapping": Object {}, + "initialState": Object {}, + "locatorId": "DISCOVER_APP_LOCATOR", + "name": "my_name", + "persisted": true, + "realmName": "realmName", + "realmType": "realmType", + "restoreState": Object {}, + "sessionId": "sessionId", + "status": "complete", + "touched": "2021-03-29T00:00:00.000Z", + "username": "username", + "version": "7.14.0", + } + `); + }); + + test('Dashboard app URL generator migrates to locator', () => { + const mockSessionSavedObject: SavedObject = { + id: 'id', + type: SEARCH_SESSION_TYPE, + attributes: { + name: 'my_name', + appId: 'my_app_id', + sessionId: 'sessionId', + urlGeneratorId: 'DASHBOARD_APP_URL_GENERATOR', + initialState: {}, + restoreState: {}, + persisted: true, + idMapping: {}, + realmType: 'realmType', + realmName: 'realmName', + username: 'username', + created: '2021-03-26T00:00:00.000Z', + expires: '2021-03-30T00:00:00.000Z', + touched: '2021-03-29T00:00:00.000Z', + completed: '2021-03-29T00:00:00.000Z', + status: SearchSessionStatus.COMPLETE, + version: '7.14.0', + }, + references: [], + }; + + const migratedSession = migration(mockSessionSavedObject, {} as SavedObjectMigrationContext); + + expect(migratedSession.attributes).toMatchInlineSnapshot(` + Object { + "appId": "my_app_id", + "completed": "2021-03-29T00:00:00.000Z", + "created": "2021-03-26T00:00:00.000Z", + "expires": "2021-03-30T00:00:00.000Z", + "idMapping": Object {}, + "initialState": Object {}, + "locatorId": "DASHBOARD_APP_LOCATOR", + "name": "my_name", + "persisted": true, + "realmName": "realmName", + "realmType": "realmType", + "restoreState": Object {}, + "sessionId": "sessionId", + "status": "complete", + "touched": "2021-03-29T00:00:00.000Z", + "username": "username", + "version": "7.14.0", + } + `); + }); + + test('Undefined URL generator returns undefined locator', () => { + const mockSessionSavedObject: SavedObject = { + id: 'id', + type: SEARCH_SESSION_TYPE, + attributes: { + name: 'my_name', + appId: 'my_app_id', + sessionId: 'sessionId', + urlGeneratorId: undefined, + initialState: {}, + restoreState: {}, + persisted: true, + idMapping: {}, + realmType: 'realmType', + realmName: 'realmName', + username: 'username', + created: '2021-03-26T00:00:00.000Z', + expires: '2021-03-30T00:00:00.000Z', + touched: '2021-03-29T00:00:00.000Z', + completed: '2021-03-29T00:00:00.000Z', + status: SearchSessionStatus.COMPLETE, + version: '7.14.0', + }, + references: [], + }; + + const migratedSession = migration(mockSessionSavedObject, {} as SavedObjectMigrationContext); + + expect(migratedSession.attributes).toMatchInlineSnapshot(` + Object { + "appId": "my_app_id", + "completed": "2021-03-29T00:00:00.000Z", + "created": "2021-03-26T00:00:00.000Z", + "expires": "2021-03-30T00:00:00.000Z", + "idMapping": Object {}, + "initialState": Object {}, + "locatorId": undefined, + "name": "my_name", + "persisted": true, + "realmName": "realmName", + "realmType": "realmType", + "restoreState": Object {}, + "sessionId": "sessionId", + "status": "complete", + "touched": "2021-03-29T00:00:00.000Z", + "username": "username", + "version": "7.14.0", + } + `); + }); + + test('Other URL generator throws error', () => { + const mockSessionSavedObject: SavedObject = { + id: 'id', + type: SEARCH_SESSION_TYPE, + attributes: { + name: 'my_name', + appId: 'my_app_id', + sessionId: 'sessionId', + urlGeneratorId: 'my_url_generator_id', + initialState: {}, + restoreState: {}, + persisted: true, + idMapping: {}, + realmType: 'realmType', + realmName: 'realmName', + username: 'username', + created: '2021-03-26T00:00:00.000Z', + expires: '2021-03-30T00:00:00.000Z', + touched: '2021-03-29T00:00:00.000Z', + completed: '2021-03-29T00:00:00.000Z', + status: SearchSessionStatus.COMPLETE, + version: '7.14.0', + }, + references: [], + }; + + expect(() => + migration(mockSessionSavedObject, {} as SavedObjectMigrationContext) + ).toThrowErrorMatchingInlineSnapshot( + `"No migration found for search session URL generator my_url_generator_id"` + ); + }); +}); diff --git a/x-pack/plugins/data_enhanced/server/saved_objects/search_session_migration.ts b/x-pack/plugins/data_enhanced/server/saved_objects/search_session_migration.ts index 9173090a65a0a..4fa5964929f7c 100644 --- a/x-pack/plugins/data_enhanced/server/saved_objects/search_session_migration.ts +++ b/x-pack/plugins/data_enhanced/server/saved_objects/search_session_migration.ts @@ -29,10 +29,28 @@ export type SearchSessionSavedObjectAttributesPre$7$13$0 = Omit< * but what is important for 7.14.0 is that the version is less then "7.14.0" */ export type SearchSessionSavedObjectAttributesPre$7$14$0 = Omit< - SearchSessionSavedObjectAttributesLatest, + SearchSessionSavedObjectAttributesPre$8$0$0, 'version' >; +/** + * In 8.0.0, we migrated from using URL generators to the locators service. As a result, we move + * from using `urlGeneratorId` to `locatorId`. + */ +export type SearchSessionSavedObjectAttributesPre$8$0$0 = Omit< + SearchSessionSavedObjectAttributesLatest, + 'locatorId' +> & { + urlGeneratorId?: string; +}; + +function getLocatorId(urlGeneratorId?: string) { + if (!urlGeneratorId) return; + if (urlGeneratorId === 'DISCOVER_APP_URL_GENERATOR') return 'DISCOVER_APP_LOCATOR'; + if (urlGeneratorId === 'DASHBOARD_APP_URL_GENERATOR') return 'DASHBOARD_APP_LOCATOR'; + throw new Error(`No migration found for search session URL generator ${urlGeneratorId}`); +} + export const searchSessionSavedObjectMigrations: SavedObjectMigrationMap = { '7.13.0': ( doc: SavedObjectUnsanitizedDoc @@ -60,10 +78,14 @@ export const searchSessionSavedObjectMigrations: SavedObjectMigrationMap = { }, }; }, - '7.16.0': ( - doc: SavedObjectUnsanitizedDoc + '8.0.0': ( + doc: SavedObjectUnsanitizedDoc ): SavedObjectUnsanitizedDoc => { - // TODO: Convert `urlGeneratorId` to `locatorId` (do we need to convert state as well?) - return doc; + const { + attributes: { urlGeneratorId, ...otherAttrs }, + } = doc; + const locatorId = getLocatorId(urlGeneratorId); + const attributes = { ...otherAttrs, locatorId }; + return { ...doc, attributes }; }, }; From f6c2123d2b3a0e00e4ad5a6b6bea56002156b55e Mon Sep 17 00:00:00 2001 From: Lukas Olson Date: Thu, 21 Oct 2021 15:00:47 -0700 Subject: [PATCH 3/7] Fix/update tests --- .../search/session/session_service.test.ts | 26 +++++++++---------- .../apps/main/services/discover_state.test.ts | 13 +++++++--- .../search/sessions_mgmt/lib/api.test.ts | 25 ++++++++++-------- .../search/session/session_service.test.ts | 16 ++++++------ 4 files changed, 44 insertions(+), 36 deletions(-) diff --git a/src/plugins/data/public/search/session/session_service.test.ts b/src/plugins/data/public/search/session/session_service.test.ts index 5c1882248f76a..4a11cdb38bb7d 100644 --- a/src/plugins/data/public/search/session/session_service.test.ts +++ b/src/plugins/data/public/search/session/session_service.test.ts @@ -25,7 +25,7 @@ const mockSavedObject: SearchSessionSavedObject = { attributes: { name: 'my_name', appId: 'my_app_id', - urlGeneratorId: 'my_url_generator_id', + locatorId: 'my_locator_id', idMapping: {}, sessionId: 'session_id', touched: new Date().toISOString(), @@ -192,8 +192,8 @@ describe('Session service', () => { sessionService.enableStorage({ getName: async () => 'Name', - getUrlGeneratorData: async () => ({ - urlGeneratorId: 'id', + getLocatorData: async () => ({ + id: 'id', initialState: {}, restoreState: {}, }), @@ -245,8 +245,8 @@ describe('Session service', () => { sessionService.enableStorage({ getName: async () => 'Name', - getUrlGeneratorData: async () => ({ - urlGeneratorId: 'id', + getLocatorData: async () => ({ + id: 'id', initialState: {}, restoreState: {}, }), @@ -299,8 +299,8 @@ describe('Session service', () => { sessionService.enableStorage({ getName: async () => 'Name', - getUrlGeneratorData: async () => ({ - urlGeneratorId: 'id', + getLocatorData: async () => ({ + id: 'id', initialState: {}, restoreState: {}, }), @@ -319,8 +319,8 @@ describe('Session service', () => { sessionService.enableStorage( { getName: async () => 'Name', - getUrlGeneratorData: async () => ({ - urlGeneratorId: 'id', + getLocatorData: async () => ({ + id: 'id', initialState: {}, restoreState: {}, }), @@ -336,10 +336,10 @@ describe('Session service', () => { expect(sessionService.getSearchSessionIndicatorUiConfig().isDisabled().disabled).toBe(false); }); - test('save() throws in case getUrlGeneratorData returns throws', async () => { + test('save() throws in case getLocatorData returns throws', async () => { sessionService.enableStorage({ getName: async () => 'Name', - getUrlGeneratorData: async () => { + getLocatorData: async () => { throw new Error('Haha'); }, }); @@ -373,8 +373,8 @@ describe('Session service', () => { sessionsClient.rename.mockRejectedValue(renameError); sessionService.enableStorage({ getName: async () => 'Name', - getUrlGeneratorData: async () => ({ - urlGeneratorId: 'id', + getLocatorData: async () => ({ + id: 'id', initialState: {}, restoreState: {}, }), diff --git a/src/plugins/discover/public/application/apps/main/services/discover_state.test.ts b/src/plugins/discover/public/application/apps/main/services/discover_state.test.ts index 9968ca6f1f63f..7f875be0a42c5 100644 --- a/src/plugins/discover/public/application/apps/main/services/discover_state.test.ts +++ b/src/plugins/discover/public/application/apps/main/services/discover_state.test.ts @@ -183,7 +183,7 @@ describe('createSearchSessionRestorationDataProvider', () => { (mockDataPlugin.search.session.getSessionId as jest.Mock).mockImplementation( () => searchSessionId ); - const { initialState, restoreState } = await searchSessionInfoProvider.getUrlGeneratorData(); + const { initialState, restoreState } = await searchSessionInfoProvider.getLocatorData(); expect(initialState.searchSessionId).toBeUndefined(); expect(restoreState.searchSessionId).toBe(searchSessionId); }); @@ -197,15 +197,20 @@ describe('createSearchSessionRestorationDataProvider', () => { (mockDataPlugin.query.timefilter.timefilter.getAbsoluteTime as jest.Mock).mockImplementation( () => absoluteTime ); - const { initialState, restoreState } = await searchSessionInfoProvider.getUrlGeneratorData(); + const { initialState, restoreState } = await searchSessionInfoProvider.getLocatorData(); expect(initialState.timeRange).toBe(relativeTime); expect(restoreState.timeRange).toBe(absoluteTime); }); test('restoreState has paused autoRefresh', async () => { - const { initialState, restoreState } = await searchSessionInfoProvider.getUrlGeneratorData(); + const { initialState, restoreState } = await searchSessionInfoProvider.getLocatorData(); expect(initialState.refreshInterval).toBe(undefined); - expect(restoreState.refreshInterval?.pause).toBe(true); + expect(restoreState.refreshInterval).toMatchInlineSnapshot(` + Object { + "pause": true, + "value": 0, + } + `); }); }); }); diff --git a/x-pack/plugins/data_enhanced/public/search/sessions_mgmt/lib/api.test.ts b/x-pack/plugins/data_enhanced/public/search/sessions_mgmt/lib/api.test.ts index a3bc3b51f61bd..a0b6aa80f2500 100644 --- a/x-pack/plugins/data_enhanced/public/search/sessions_mgmt/lib/api.test.ts +++ b/x-pack/plugins/data_enhanced/public/search/sessions_mgmt/lib/api.test.ts @@ -14,11 +14,13 @@ import type { SavedObjectsFindResponse } from 'src/core/server'; import { SessionsClient } from 'src/plugins/data/public/search'; import type { SessionsConfigSchema } from '../'; import { SearchSessionStatus } from '../../../../../../../src/plugins/data/common'; -import { mockUrls } from '../__mocks__'; +import { sharePluginMock } from '../../../../../../../src/plugins/share/public/mocks'; +import { SharePluginStart } from '../../../../../../../src/plugins/share/public'; import { SearchSessionsMgmtAPI } from './api'; let mockCoreSetup: MockedKeys; let mockCoreStart: MockedKeys; +let mockShareStart: jest.Mocked; let mockConfig: SessionsConfigSchema; let sessionsClient: SessionsClient; @@ -26,6 +28,7 @@ describe('Search Sessions Management API', () => { beforeEach(() => { mockCoreSetup = coreMock.createSetup(); mockCoreStart = coreMock.createStart(); + mockShareStart = sharePluginMock.createStartContract(); mockConfig = { defaultExpiration: moment.duration('7d'), management: { @@ -60,7 +63,7 @@ describe('Search Sessions Management API', () => { }); const api = new SearchSessionsMgmtAPI(sessionsClient, mockConfig, { - urls: mockUrls, + locators: mockShareStart.url.locators, notifications: mockCoreStart.notifications, application: mockCoreStart.application, }); @@ -80,9 +83,9 @@ describe('Search Sessions Management API', () => { "initialState": Object {}, "name": "Veggie", "numSearches": 0, - "reloadUrl": "hello-cool-undefined-url", + "reloadUrl": undefined, "restoreState": Object {}, - "restoreUrl": "hello-cool-undefined-url", + "restoreUrl": undefined, "status": "complete", "version": undefined, }, @@ -111,7 +114,7 @@ describe('Search Sessions Management API', () => { }); const api = new SearchSessionsMgmtAPI(sessionsClient, mockConfig, { - urls: mockUrls, + locators: mockShareStart.url.locators, notifications: mockCoreStart.notifications, application: mockCoreStart.application, }); @@ -124,7 +127,7 @@ describe('Search Sessions Management API', () => { sessionsClient.find = jest.fn().mockRejectedValue(new Error('implementation is so bad')); const api = new SearchSessionsMgmtAPI(sessionsClient, mockConfig, { - urls: mockUrls, + locators: mockShareStart.url.locators, notifications: mockCoreStart.notifications, application: mockCoreStart.application, }); @@ -153,7 +156,7 @@ describe('Search Sessions Management API', () => { }); const api = new SearchSessionsMgmtAPI(sessionsClient, mockConfig, { - urls: mockUrls, + locators: mockShareStart.url.locators, notifications: mockCoreStart.notifications, application: mockCoreStart.application, }); @@ -181,7 +184,7 @@ describe('Search Sessions Management API', () => { test('send cancel calls the cancel endpoint with a session ID', async () => { const api = new SearchSessionsMgmtAPI(sessionsClient, mockConfig, { - urls: mockUrls, + locators: mockShareStart.url.locators, notifications: mockCoreStart.notifications, application: mockCoreStart.application, }); @@ -196,7 +199,7 @@ describe('Search Sessions Management API', () => { sessionsClient.delete = jest.fn().mockRejectedValue(new Error('implementation is so bad')); const api = new SearchSessionsMgmtAPI(sessionsClient, mockConfig, { - urls: mockUrls, + locators: mockShareStart.url.locators, notifications: mockCoreStart.notifications, application: mockCoreStart.application, }); @@ -225,7 +228,7 @@ describe('Search Sessions Management API', () => { test('send extend throws an error for now', async () => { const api = new SearchSessionsMgmtAPI(sessionsClient, mockConfig, { - urls: mockUrls, + locators: mockShareStart.url.locators, notifications: mockCoreStart.notifications, application: mockCoreStart.application, }); @@ -238,7 +241,7 @@ describe('Search Sessions Management API', () => { test('displays error on reject', async () => { sessionsClient.extend = jest.fn().mockRejectedValue({}); const api = new SearchSessionsMgmtAPI(sessionsClient, mockConfig, { - urls: mockUrls, + locators: mockShareStart.url.locators, notifications: mockCoreStart.notifications, application: mockCoreStart.application, }); diff --git a/x-pack/plugins/data_enhanced/server/search/session/session_service.test.ts b/x-pack/plugins/data_enhanced/server/search/session/session_service.test.ts index 4b5e1a1f86a11..437e146f0d0f7 100644 --- a/x-pack/plugins/data_enhanced/server/search/session/session_service.test.ts +++ b/x-pack/plugins/data_enhanced/server/search/session/session_service.test.ts @@ -57,7 +57,7 @@ describe('SearchSessionService', () => { attributes: { name: 'my_name', appId: 'my_app_id', - urlGeneratorId: 'my_url_generator_id', + locatorId: 'my_locator_id', idMapping: {}, realmType: mockUser1.authentication_realm.type, realmName: mockUser1.authentication_realm.name, @@ -202,13 +202,13 @@ describe('SearchSessionService', () => { ).rejects.toMatchInlineSnapshot(`[Error: AppId is required]`); }); - it('throws if `generator id` is not provided', () => { + it('throws if `locatorId` is not provided', () => { expect( service.save({ savedObjectsClient }, mockUser1, sessionId, { name: 'banana', appId: 'nanana', }) - ).rejects.toMatchInlineSnapshot(`[Error: UrlGeneratorId is required]`); + ).rejects.toMatchInlineSnapshot(`[Error: locatorId is required]`); }); it('saving updates an existing saved object and persists it', async () => { @@ -222,7 +222,7 @@ describe('SearchSessionService', () => { await service.save({ savedObjectsClient }, mockUser1, sessionId, { name: 'banana', appId: 'nanana', - urlGeneratorId: 'panama', + locatorId: 'panama', }); expect(savedObjectsClient.update).toHaveBeenCalled(); @@ -236,7 +236,7 @@ describe('SearchSessionService', () => { expect(callAttributes).toHaveProperty('persisted', true); expect(callAttributes).toHaveProperty('name', 'banana'); expect(callAttributes).toHaveProperty('appId', 'nanana'); - expect(callAttributes).toHaveProperty('urlGeneratorId', 'panama'); + expect(callAttributes).toHaveProperty('locatorId', 'panama'); expect(callAttributes).toHaveProperty('initialState', {}); expect(callAttributes).toHaveProperty('restoreState', {}); }); @@ -255,7 +255,7 @@ describe('SearchSessionService', () => { await service.save({ savedObjectsClient }, mockUser1, sessionId, { name: 'banana', appId: 'nanana', - urlGeneratorId: 'panama', + locatorId: 'panama', }); expect(savedObjectsClient.update).toHaveBeenCalledTimes(1); @@ -271,7 +271,7 @@ describe('SearchSessionService', () => { expect(callAttributes).toHaveProperty('persisted', true); expect(callAttributes).toHaveProperty('name', 'banana'); expect(callAttributes).toHaveProperty('appId', 'nanana'); - expect(callAttributes).toHaveProperty('urlGeneratorId', 'panama'); + expect(callAttributes).toHaveProperty('locatorId', 'panama'); expect(callAttributes).toHaveProperty('initialState', {}); expect(callAttributes).toHaveProperty('restoreState', {}); expect(callAttributes).toHaveProperty('realmType', mockUser1.authentication_realm.type); @@ -300,7 +300,7 @@ describe('SearchSessionService', () => { { name: 'my_name', appId: 'my_app_id', - urlGeneratorId: 'my_url_generator_id', + locatorId: 'my_locator_id', } ); From dd1cde8f520c69d56d73794104acb5f8f4f991cb Mon Sep 17 00:00:00 2001 From: Lukas Olson Date: Thu, 21 Oct 2021 16:37:15 -0700 Subject: [PATCH 4/7] Fix types --- .../data/public/search/session/search_session_state.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/data/public/search/session/search_session_state.test.ts b/src/plugins/data/public/search/session/search_session_state.test.ts index 65b931f23cf2e..ef18275da12fa 100644 --- a/src/plugins/data/public/search/session/search_session_state.test.ts +++ b/src/plugins/data/public/search/session/search_session_state.test.ts @@ -16,7 +16,7 @@ const mockSavedObject: SearchSessionSavedObject = { attributes: { name: 'my_name', appId: 'my_app_id', - urlGeneratorId: 'my_url_generator_id', + locatorId: 'my_url_generator_id', idMapping: {}, sessionId: 'session_id', touched: new Date().toISOString(), From 201b7fa1fb56e265063d25a30b742067dfa1c9c2 Mon Sep 17 00:00:00 2001 From: Lukas Olson Date: Mon, 25 Oct 2021 12:56:16 -0700 Subject: [PATCH 5/7] Fix test setup --- .../public/application/lib/session_restoration.test.ts | 6 +++--- .../public/search/sessions_mgmt/components/main.test.tsx | 8 ++++++-- .../search/sessions_mgmt/components/table/table.test.tsx | 8 ++++++-- .../public/search/sessions_mgmt/lib/get_columns.test.tsx | 7 +++++-- 4 files changed, 20 insertions(+), 9 deletions(-) diff --git a/src/plugins/dashboard/public/application/lib/session_restoration.test.ts b/src/plugins/dashboard/public/application/lib/session_restoration.test.ts index 571dfb0a8beeb..55366ac50fd2e 100644 --- a/src/plugins/dashboard/public/application/lib/session_restoration.test.ts +++ b/src/plugins/dashboard/public/application/lib/session_restoration.test.ts @@ -34,7 +34,7 @@ describe('createSessionRestorationDataProvider', () => { (mockDataPlugin.search.session.getSessionId as jest.Mock).mockImplementation( () => searchSessionId ); - const { initialState, restoreState } = await searchSessionInfoProvider.getUrlGeneratorData(); + const { initialState, restoreState } = await searchSessionInfoProvider.getLocatorData(); expect(initialState.searchSessionId).toBeUndefined(); expect(restoreState.searchSessionId).toBe(searchSessionId); }); @@ -48,13 +48,13 @@ describe('createSessionRestorationDataProvider', () => { (mockDataPlugin.query.timefilter.timefilter.getAbsoluteTime as jest.Mock).mockImplementation( () => absoluteTime ); - const { initialState, restoreState } = await searchSessionInfoProvider.getUrlGeneratorData(); + const { initialState, restoreState } = await searchSessionInfoProvider.getLocatorData(); expect(initialState.timeRange).toBe(relativeTime); expect(restoreState.timeRange).toBe(absoluteTime); }); test('restoreState has refreshInterval paused', async () => { - const { initialState, restoreState } = await searchSessionInfoProvider.getUrlGeneratorData(); + const { initialState, restoreState } = await searchSessionInfoProvider.getLocatorData(); expect(initialState.refreshInterval).toBeUndefined(); expect(restoreState.refreshInterval?.pause).toBe(true); }); diff --git a/x-pack/plugins/data_enhanced/public/search/sessions_mgmt/components/main.test.tsx b/x-pack/plugins/data_enhanced/public/search/sessions_mgmt/components/main.test.tsx index 4c945e717464c..b79a4939b3fdd 100644 --- a/x-pack/plugins/data_enhanced/public/search/sessions_mgmt/components/main.test.tsx +++ b/x-pack/plugins/data_enhanced/public/search/sessions_mgmt/components/main.test.tsx @@ -16,13 +16,16 @@ import { SessionsClient } from 'src/plugins/data/public/search'; import { IManagementSectionsPluginsSetup, SessionsConfigSchema } from '..'; import { SearchSessionsMgmtAPI } from '../lib/api'; import { AsyncSearchIntroDocumentation } from '../lib/documentation'; -import { LocaleWrapper, mockUrls } from '../__mocks__'; +import { LocaleWrapper } from '../__mocks__'; import { SearchSessionsMgmtMain } from './main'; import { dataPluginMock } from '../../../../../../../src/plugins/data/public/mocks'; import { managementPluginMock } from '../../../../../../../src/plugins/management/public/mocks'; +import { SharePluginStart } from '../../../../../../../src/plugins/share/public'; +import { sharePluginMock } from '../../../../../../../src/plugins/share/public/mocks'; let mockCoreSetup: MockedKeys; let mockCoreStart: MockedKeys; +let mockShareStart: jest.Mocked; let mockPluginsSetup: IManagementSectionsPluginsSetup; let mockConfig: SessionsConfigSchema; let sessionsClient: SessionsClient; @@ -32,6 +35,7 @@ describe('Background Search Session Management Main', () => { beforeEach(() => { mockCoreSetup = coreMock.createSetup(); mockCoreStart = coreMock.createStart(); + mockShareStart = sharePluginMock.createStartContract(); mockPluginsSetup = { data: dataPluginMock.createSetupContract(), management: managementPluginMock.createSetupContract(), @@ -49,7 +53,7 @@ describe('Background Search Session Management Main', () => { sessionsClient = new SessionsClient({ http: mockCoreSetup.http }); api = new SearchSessionsMgmtAPI(sessionsClient, mockConfig, { - urls: mockUrls, + locators: mockShareStart.url.locators, notifications: mockCoreStart.notifications, application: mockCoreStart.application, }); diff --git a/x-pack/plugins/data_enhanced/public/search/sessions_mgmt/components/table/table.test.tsx b/x-pack/plugins/data_enhanced/public/search/sessions_mgmt/components/table/table.test.tsx index f3079155f7eb5..863e5e85d9ef3 100644 --- a/x-pack/plugins/data_enhanced/public/search/sessions_mgmt/components/table/table.test.tsx +++ b/x-pack/plugins/data_enhanced/public/search/sessions_mgmt/components/table/table.test.tsx @@ -16,13 +16,16 @@ import { SessionsClient } from 'src/plugins/data/public/search'; import { SearchSessionStatus } from '../../../../../../../../src/plugins/data/common'; import { IManagementSectionsPluginsSetup, SessionsConfigSchema } from '../../'; import { SearchSessionsMgmtAPI } from '../../lib/api'; -import { LocaleWrapper, mockUrls } from '../../__mocks__'; +import { LocaleWrapper } from '../../__mocks__'; import { SearchSessionsMgmtTable } from './table'; import { dataPluginMock } from '../../../../../../../../src/plugins/data/public/mocks'; import { managementPluginMock } from '../../../../../../../../src/plugins/management/public/mocks'; +import { SharePluginStart } from '../../../../../../../../src/plugins/share/public'; +import { sharePluginMock } from '../../../../../../../../src/plugins/share/public/mocks'; let mockCoreSetup: MockedKeys; let mockCoreStart: CoreStart; +let mockShareStart: jest.Mocked; let mockPluginsSetup: IManagementSectionsPluginsSetup; let mockConfig: SessionsConfigSchema; let sessionsClient: SessionsClient; @@ -32,6 +35,7 @@ describe('Background Search Session Management Table', () => { beforeEach(async () => { mockCoreSetup = coreMock.createSetup(); mockCoreStart = coreMock.createStart(); + mockShareStart = sharePluginMock.createStartContract(); mockPluginsSetup = { data: dataPluginMock.createSetupContract(), management: managementPluginMock.createSetupContract(), @@ -48,7 +52,7 @@ describe('Background Search Session Management Table', () => { sessionsClient = new SessionsClient({ http: mockCoreSetup.http }); api = new SearchSessionsMgmtAPI(sessionsClient, mockConfig, { - urls: mockUrls, + locators: mockShareStart.url.locators, notifications: mockCoreStart.notifications, application: mockCoreStart.application, }); diff --git a/x-pack/plugins/data_enhanced/public/search/sessions_mgmt/lib/get_columns.test.tsx b/x-pack/plugins/data_enhanced/public/search/sessions_mgmt/lib/get_columns.test.tsx index 4764e273e5a68..9578d56e44b1c 100644 --- a/x-pack/plugins/data_enhanced/public/search/sessions_mgmt/lib/get_columns.test.tsx +++ b/x-pack/plugins/data_enhanced/public/search/sessions_mgmt/lib/get_columns.test.tsx @@ -17,14 +17,16 @@ import { IManagementSectionsPluginsSetup, SessionsConfigSchema } from '../'; import { SearchSessionStatus } from '../../../../../../../src/plugins/data/common'; import { OnActionComplete } from '../components'; import { UISession } from '../types'; -import { mockUrls } from '../__mocks__'; import { SearchSessionsMgmtAPI } from './api'; import { getColumns } from './get_columns'; import { dataPluginMock } from '../../../../../../../src/plugins/data/public/mocks'; import { managementPluginMock } from '../../../../../../../src/plugins/management/public/mocks'; +import { SharePluginStart } from '../../../../../../../src/plugins/share/public'; +import { sharePluginMock } from '../../../../../../../src/plugins/share/public/mocks'; let mockCoreSetup: MockedKeys; let mockCoreStart: CoreStart; +let mockShareStart: jest.Mocked; let mockPluginsSetup: IManagementSectionsPluginsSetup; let mockConfig: SessionsConfigSchema; let api: SearchSessionsMgmtAPI; @@ -38,6 +40,7 @@ describe('Search Sessions Management table column factory', () => { beforeEach(async () => { mockCoreSetup = coreMock.createSetup(); mockCoreStart = coreMock.createStart(); + mockShareStart = sharePluginMock.createStartContract(); mockPluginsSetup = { data: dataPluginMock.createSetupContract(), management: managementPluginMock.createSetupContract(), @@ -54,7 +57,7 @@ describe('Search Sessions Management table column factory', () => { sessionsClient = new SessionsClient({ http: mockCoreSetup.http }); api = new SearchSessionsMgmtAPI(sessionsClient, mockConfig, { - urls: mockUrls, + locators: mockShareStart.url.locators, notifications: mockCoreStart.notifications, application: mockCoreStart.application, }); From db0116f46f1ae7898e976ff8ccc5a41faf59c75e Mon Sep 17 00:00:00 2001 From: Lukas Olson Date: Mon, 25 Oct 2021 13:04:04 -0700 Subject: [PATCH 6/7] Update docs --- dev_docs/tutorials/data/search.mdx | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/dev_docs/tutorials/data/search.mdx b/dev_docs/tutorials/data/search.mdx index 1585adbdd37be..425736ddb03bb 100644 --- a/dev_docs/tutorials/data/search.mdx +++ b/dev_docs/tutorials/data/search.mdx @@ -13,7 +13,7 @@ tags: ['kibana', 'onboarding', 'dev', 'tutorials', 'search', 'sessions', 'search Searching data stored in Elasticsearch can be done in various ways, for example using the Elasticsearch REST API or using an `Elasticsearch Client` for low level access. -However, the recommended and easist way to search Elasticsearch is by using the low level search service. The service is exposed from the `data` plugin, and by using it, you not only gain access to the data you stored, but also to capabilities, such as Custom Search Strategies, Asynchronous Search, Partial Results, Search Sessions, and more. +However, the recommended and easiest way to search Elasticsearch is by using the low level search service. The service is exposed from the `data` plugin, and by using it, you not only gain access to the data you stored, but also to capabilities, such as Custom Search Strategies, Asynchronous Search, Partial Results, Search Sessions, and more. Here is a basic example for using the `data.search` service from a custom plugin: @@ -418,11 +418,11 @@ export class MyPlugin implements Plugin { // return the name you want to give the saved Search Session return `MyApp_${Math.random()}`; }, - getUrlGeneratorData: async () => { + getLocatorData: async () => { return { - urlGeneratorId: MY_URL_GENERATOR, - initialState: getUrlGeneratorState({ ...deps, shouldRestoreSearchSession: false }), - restoreState: getUrlGeneratorState({ ...deps, shouldRestoreSearchSession: true }), + id: MY_LOCATOR, + initialState: getLocatorParams({ ...deps, shouldRestoreSearchSession: false }), + restoreState: getLocatorParams({ ...deps, shouldRestoreSearchSession: true }), }; }, }); From 8de1a7a9bed7f49c003cb27e2309d1d05e2ee795 Mon Sep 17 00:00:00 2001 From: Lukas Olson Date: Tue, 26 Oct 2021 09:21:13 -0700 Subject: [PATCH 7/7] Fix version :) --- .../server/saved_objects/search_session_migration.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x-pack/plugins/data_enhanced/server/saved_objects/search_session_migration.test.ts b/x-pack/plugins/data_enhanced/server/saved_objects/search_session_migration.test.ts index 60d2ef3315dda..aa344da68f931 100644 --- a/x-pack/plugins/data_enhanced/server/saved_objects/search_session_migration.test.ts +++ b/x-pack/plugins/data_enhanced/server/saved_objects/search_session_migration.test.ts @@ -166,7 +166,7 @@ describe('7.13.0 -> 7.14.0', () => { }); }); -describe('7.14.0 -> 7.18.0', () => { +describe('7.14.0 -> 8.0.0', () => { const migration = searchSessionSavedObjectMigrations['8.0.0']; test('Discover app URL generator migrates to locator', () => {