From b02abd68204b7d6a027ae62305cba1590ab5ed28 Mon Sep 17 00:00:00 2001 From: SuZhou-Joe Date: Thu, 29 Feb 2024 13:43:13 +0800 Subject: [PATCH 1/9] Make url stateful in hash Make url stateful in hash Signed-off-by: SuZhou-Joe --- CHANGELOG.md | 2 +- src/plugins/workspace/common/constants.ts | 1 + .../workspace/opensearch_dashboards.json | 5 +- src/plugins/workspace/public/plugin.ts | 91 ++++++++++++++++++- src/plugins/workspace/public/utils.ts | 11 +++ 5 files changed, 105 insertions(+), 5 deletions(-) create mode 100644 src/plugins/workspace/public/utils.ts diff --git a/CHANGELOG.md b/CHANGELOG.md index b22b5556ac33..784f4f8a01b2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1039,4 +1039,4 @@ Inspired from [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) ### 🔩 Tests -- Update caniuse to fix failed integration tests ([#2322](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/2322)) +- Update caniuse to fix failed integration tests ([#2322](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/2322)) \ No newline at end of file diff --git a/src/plugins/workspace/common/constants.ts b/src/plugins/workspace/common/constants.ts index e60bb6aea0eb..745d62e822d5 100644 --- a/src/plugins/workspace/common/constants.ts +++ b/src/plugins/workspace/common/constants.ts @@ -3,6 +3,7 @@ * SPDX-License-Identifier: Apache-2.0 */ +export const WORKSPACE_ID_STATE_KEY = '_w'; export const WORKSPACE_SAVED_OBJECTS_CLIENT_WRAPPER_ID = 'workspace'; export const WORKSPACE_CONFLICT_CONTROL_SAVED_OBJECTS_CLIENT_WRAPPER_ID = 'workspace_conflict_control'; diff --git a/src/plugins/workspace/opensearch_dashboards.json b/src/plugins/workspace/opensearch_dashboards.json index 40a7eb5c3f9f..176bf5c2d132 100644 --- a/src/plugins/workspace/opensearch_dashboards.json +++ b/src/plugins/workspace/opensearch_dashboards.json @@ -2,9 +2,10 @@ "id": "workspace", "version": "opensearchDashboards", "server": true, - "ui": false, + "ui": true, "requiredPlugins": [ - "savedObjects" + "savedObjects", + "opensearchDashboardsUtils" ], "optionalPlugins": [], "requiredBundles": [] diff --git a/src/plugins/workspace/public/plugin.ts b/src/plugins/workspace/public/plugin.ts index 18e84e3a6f35..1fb4cd0f4046 100644 --- a/src/plugins/workspace/public/plugin.ts +++ b/src/plugins/workspace/public/plugin.ts @@ -3,10 +3,97 @@ * SPDX-License-Identifier: Apache-2.0 */ -import { Plugin } from '../../../core/public'; +import { BehaviorSubject, combineLatest } from 'rxjs'; +import { debounce } from 'lodash'; +import { CoreSetup, Plugin } from '../../../core/public'; +import { getStateFromOsdUrl } from '../../opensearch_dashboards_utils/public'; +import { formatUrlWithWorkspaceId } from './utils'; +import { WORKSPACE_ID_STATE_KEY } from '../common/constants'; export class WorkspacePlugin implements Plugin<{}, {}, {}> { - public async setup() { + private core?: CoreSetup; + private URLChange$ = new BehaviorSubject(''); + private getWorkpsaceIdFromURL(): string | null { + return getStateFromOsdUrl(WORKSPACE_ID_STATE_KEY); + } + private async getWorkpsaceId(): Promise { + if (this.getWorkpsaceIdFromURL()) { + return this.getWorkpsaceIdFromURL() || ''; + } + + return (await this.core?.workspaces.currentWorkspaceId$.getValue()) || ''; + } + private getPatchedUrl = (url: string, workspaceId: string) => { + return formatUrlWithWorkspaceId(url, workspaceId); + }; + private async listenToHashChange(): Promise { + window.addEventListener('hashchange', async () => { + if (this.shouldPatchUrl()) { + const workspaceId = await this.getWorkpsaceId(); + this.URLChange$.next(this.getPatchedUrl(window.location.href, workspaceId)); + } + }); + } + private shouldPatchUrl(): boolean { + const currentWorkspaceId = this.core?.workspaces.currentWorkspaceId$.getValue(); + const workspaceIdFromURL = this.getWorkpsaceIdFromURL(); + if (!currentWorkspaceId && !workspaceIdFromURL) { + return false; + } + + if (currentWorkspaceId === workspaceIdFromURL) { + return false; + } + + return true; + } + private async listenToApplicationChange(): Promise { + const startService = await this.core?.getStartServices(); + if (startService) { + combineLatest([ + this.core?.workspaces.currentWorkspaceId$, + startService[0].application.currentAppId$, + ]).subscribe(async ([]) => { + if (this.shouldPatchUrl()) { + const currentWorkspaceId = await this.getWorkpsaceId(); + this.URLChange$.next(this.getPatchedUrl(window.location.href, currentWorkspaceId)); + } + }); + } + } + public async setup(core: CoreSetup) { + this.core = core; + /** + * Retrive workspace id from url + */ + const workspaceId = this.getWorkpsaceIdFromURL(); + + if (workspaceId) { + /** + * Enter a workspace + */ + this.core.workspaces.currentWorkspaceId$.next(workspaceId); + } + + /** + * listen to application change and patch workspace id in hash + */ + this.listenToApplicationChange(); + + /** + * listen to application internal hash change and patch workspace id in hash + */ + this.listenToHashChange(); + + /** + * All the URLChange will flush in this subscriber + */ + this.URLChange$.subscribe( + debounce(async (url) => { + history.replaceState(history.state, '', url); + }, 500) + ); + return {}; } diff --git a/src/plugins/workspace/public/utils.ts b/src/plugins/workspace/public/utils.ts new file mode 100644 index 000000000000..4443e450a3cd --- /dev/null +++ b/src/plugins/workspace/public/utils.ts @@ -0,0 +1,11 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { setStateToOsdUrl } from '../../opensearch_dashboards_utils/public'; +import { WORKSPACE_ID_STATE_KEY } from '../common/constants'; + +export const formatUrlWithWorkspaceId = (url: string, workspaceId: string) => { + return setStateToOsdUrl(WORKSPACE_ID_STATE_KEY, workspaceId, undefined, url); +}; From 54a4a8fc8669dbcfb5061692fa39ce7edc28fb3d Mon Sep 17 00:00:00 2001 From: SuZhou-Joe Date: Thu, 29 Feb 2024 13:51:02 +0800 Subject: [PATCH 2/9] feat: change CHANGELOG Signed-off-by: SuZhou-Joe --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 784f4f8a01b2..17d5b1a5c659 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -81,6 +81,7 @@ Inspired from [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) - [[Dynamic Configurations] Add support for dynamic application configurations ([#5855](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/5855)) - [Workspace] Optional workspaces params in repository ([#5949](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/5949)) - [Multiple Datasource] Refactoring create and edit form to use authentication registry ([#6002](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/6002)) +- [Workspace] Make url stateful in hash with workspace id ([#5984](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/5984)) ### 🐛 Bug Fixes From 0535fd5a458543a64499dd675d5f08ff8a7cf801 Mon Sep 17 00:00:00 2001 From: SuZhou-Joe Date: Fri, 1 Mar 2024 20:13:30 +0800 Subject: [PATCH 3/9] feat: unsubscribe when stop Signed-off-by: SuZhou-Joe --- src/plugins/workspace/public/plugin.ts | 27 ++++++++++++++++---------- 1 file changed, 17 insertions(+), 10 deletions(-) diff --git a/src/plugins/workspace/public/plugin.ts b/src/plugins/workspace/public/plugin.ts index 1fb4cd0f4046..bafeb274fc14 100644 --- a/src/plugins/workspace/public/plugin.ts +++ b/src/plugins/workspace/public/plugin.ts @@ -3,7 +3,7 @@ * SPDX-License-Identifier: Apache-2.0 */ -import { BehaviorSubject, combineLatest } from 'rxjs'; +import { BehaviorSubject, Subscription, combineLatest } from 'rxjs'; import { debounce } from 'lodash'; import { CoreSetup, Plugin } from '../../../core/public'; import { getStateFromOsdUrl } from '../../opensearch_dashboards_utils/public'; @@ -13,6 +13,8 @@ import { WORKSPACE_ID_STATE_KEY } from '../common/constants'; export class WorkspacePlugin implements Plugin<{}, {}, {}> { private core?: CoreSetup; private URLChange$ = new BehaviorSubject(''); + private applicationSubscription = new Subscription(); + private urlChangeSubscription = new Subscription(); private getWorkpsaceIdFromURL(): string | null { return getStateFromOsdUrl(WORKSPACE_ID_STATE_KEY); } @@ -26,13 +28,14 @@ export class WorkspacePlugin implements Plugin<{}, {}, {}> { private getPatchedUrl = (url: string, workspaceId: string) => { return formatUrlWithWorkspaceId(url, workspaceId); }; + private hashChangeHandler = async () => { + if (this.shouldPatchUrl()) { + const workspaceId = await this.getWorkpsaceId(); + this.URLChange$.next(this.getPatchedUrl(window.location.href, workspaceId)); + } + }; private async listenToHashChange(): Promise { - window.addEventListener('hashchange', async () => { - if (this.shouldPatchUrl()) { - const workspaceId = await this.getWorkpsaceId(); - this.URLChange$.next(this.getPatchedUrl(window.location.href, workspaceId)); - } - }); + window.addEventListener('hashchange', this.hashChangeHandler); } private shouldPatchUrl(): boolean { const currentWorkspaceId = this.core?.workspaces.currentWorkspaceId$.getValue(); @@ -50,7 +53,7 @@ export class WorkspacePlugin implements Plugin<{}, {}, {}> { private async listenToApplicationChange(): Promise { const startService = await this.core?.getStartServices(); if (startService) { - combineLatest([ + this.applicationSubscription = combineLatest([ this.core?.workspaces.currentWorkspaceId$, startService[0].application.currentAppId$, ]).subscribe(async ([]) => { @@ -88,7 +91,7 @@ export class WorkspacePlugin implements Plugin<{}, {}, {}> { /** * All the URLChange will flush in this subscriber */ - this.URLChange$.subscribe( + this.urlChangeSubscription = this.URLChange$.subscribe( debounce(async (url) => { history.replaceState(history.state, '', url); }, 500) @@ -101,5 +104,9 @@ export class WorkspacePlugin implements Plugin<{}, {}, {}> { return {}; } - public stop() {} + public stop() { + this.urlChangeSubscription.unsubscribe(); + this.applicationSubscription.unsubscribe(); + window.removeEventListener('hashchange', this.hashChangeHandler); + } } From c9474ff357c7023327160d251a2f9b747002c060 Mon Sep 17 00:00:00 2001 From: SuZhou-Joe Date: Wed, 6 Mar 2024 11:33:33 +0800 Subject: [PATCH 4/9] feat: listen to history change Signed-off-by: SuZhou-Joe --- src/core/public/application/types.ts | 12 +++---- src/core/public/plugins/plugin_context.ts | 1 + src/plugins/workspace/public/plugin.ts | 41 +++++++++++++---------- 3 files changed, 31 insertions(+), 23 deletions(-) diff --git a/src/core/public/application/types.ts b/src/core/public/application/types.ts index 4744ab34cfd3..6a2d79a84d45 100644 --- a/src/core/public/application/types.ts +++ b/src/core/public/application/types.ts @@ -797,6 +797,12 @@ export interface ApplicationStart { * An observable that emits the current application id and each subsequent id update. */ currentAppId$: Observable; + + /** + * As the history is accessible when mounting the application, + * expose the global history instance to plugin in case plugin needs to listen to history change. + */ + history: History; } /** @internal */ @@ -826,10 +832,4 @@ export interface InternalApplicationStart extends Omit; - - /** - * The global history instance, exposed only to Core. - * @internal - */ - history: History; } diff --git a/src/core/public/plugins/plugin_context.ts b/src/core/public/plugins/plugin_context.ts index 6ef454abab46..62ea567e9234 100644 --- a/src/core/public/plugins/plugin_context.ts +++ b/src/core/public/plugins/plugin_context.ts @@ -156,6 +156,7 @@ export function createPluginStartContext< getUrlForApp: deps.application.getUrlForApp, registerMountContext: (contextName, provider) => deps.application.registerMountContext(plugin.opaqueId, contextName, provider), + history: deps.application.history, }, docLinks: deps.docLinks, http: deps.http, diff --git a/src/plugins/workspace/public/plugin.ts b/src/plugins/workspace/public/plugin.ts index bafeb274fc14..d3bb609628f2 100644 --- a/src/plugins/workspace/public/plugin.ts +++ b/src/plugins/workspace/public/plugin.ts @@ -3,7 +3,7 @@ * SPDX-License-Identifier: Apache-2.0 */ -import { BehaviorSubject, Subscription, combineLatest } from 'rxjs'; +import { BehaviorSubject, Subscription } from 'rxjs'; import { debounce } from 'lodash'; import { CoreSetup, Plugin } from '../../../core/public'; import { getStateFromOsdUrl } from '../../opensearch_dashboards_utils/public'; @@ -15,31 +15,37 @@ export class WorkspacePlugin implements Plugin<{}, {}, {}> { private URLChange$ = new BehaviorSubject(''); private applicationSubscription = new Subscription(); private urlChangeSubscription = new Subscription(); - private getWorkpsaceIdFromURL(): string | null { + private getworkspaceIdFromURL(): string | null { return getStateFromOsdUrl(WORKSPACE_ID_STATE_KEY); } - private async getWorkpsaceId(): Promise { - if (this.getWorkpsaceIdFromURL()) { - return this.getWorkpsaceIdFromURL() || ''; + private getworkspaceId(): string { + if (this.getworkspaceIdFromURL()) { + return this.getworkspaceIdFromURL() || ''; } - return (await this.core?.workspaces.currentWorkspaceId$.getValue()) || ''; + return this.core?.workspaces.currentWorkspaceId$.getValue() || ''; } private getPatchedUrl = (url: string, workspaceId: string) => { return formatUrlWithWorkspaceId(url, workspaceId); }; private hashChangeHandler = async () => { if (this.shouldPatchUrl()) { - const workspaceId = await this.getWorkpsaceId(); + const workspaceId = await this.getworkspaceId(); this.URLChange$.next(this.getPatchedUrl(window.location.href, workspaceId)); } }; private async listenToHashChange(): Promise { window.addEventListener('hashchange', this.hashChangeHandler); } + /** + * When navigating between applications or inside application, the hash state will be overwrote, + * compare the workspaceId in memory and the workspaceId in hash state, + * If do not match, return true + * @returns bool + */ private shouldPatchUrl(): boolean { const currentWorkspaceId = this.core?.workspaces.currentWorkspaceId$.getValue(); - const workspaceIdFromURL = this.getWorkpsaceIdFromURL(); + const workspaceIdFromURL = this.getworkspaceIdFromURL(); if (!currentWorkspaceId && !workspaceIdFromURL) { return false; } @@ -50,15 +56,16 @@ export class WorkspacePlugin implements Plugin<{}, {}, {}> { return true; } - private async listenToApplicationChange(): Promise { + /** + * When navigating between applications or the subApps inside an application e.g. Dashboard management, the hash state will be overwrote, + * listen to history change and try to patch the workspaceId into hash state + */ + private async listenToHistoryChange(): Promise { const startService = await this.core?.getStartServices(); if (startService) { - this.applicationSubscription = combineLatest([ - this.core?.workspaces.currentWorkspaceId$, - startService[0].application.currentAppId$, - ]).subscribe(async ([]) => { + startService[0].application.history.listen(() => { if (this.shouldPatchUrl()) { - const currentWorkspaceId = await this.getWorkpsaceId(); + const currentWorkspaceId = this.getworkspaceId(); this.URLChange$.next(this.getPatchedUrl(window.location.href, currentWorkspaceId)); } }); @@ -69,7 +76,7 @@ export class WorkspacePlugin implements Plugin<{}, {}, {}> { /** * Retrive workspace id from url */ - const workspaceId = this.getWorkpsaceIdFromURL(); + const workspaceId = this.getworkspaceIdFromURL(); if (workspaceId) { /** @@ -79,9 +86,9 @@ export class WorkspacePlugin implements Plugin<{}, {}, {}> { } /** - * listen to application change and patch workspace id in hash + * listen to history change and patch workspace id in hash */ - this.listenToApplicationChange(); + this.listenToHistoryChange(); /** * listen to application internal hash change and patch workspace id in hash From f52eeaa7a883d6bd0d3c726a36698e74a3fca7cf Mon Sep 17 00:00:00 2001 From: SuZhou-Joe Date: Wed, 6 Mar 2024 13:31:33 +0800 Subject: [PATCH 5/9] feat: support Discover edge case Signed-off-by: SuZhou-Joe --- src/plugins/workspace/public/plugin.ts | 71 +++++++++++++++++++++----- 1 file changed, 58 insertions(+), 13 deletions(-) diff --git a/src/plugins/workspace/public/plugin.ts b/src/plugins/workspace/public/plugin.ts index d3bb609628f2..f435804e694f 100644 --- a/src/plugins/workspace/public/plugin.ts +++ b/src/plugins/workspace/public/plugin.ts @@ -5,6 +5,7 @@ import { BehaviorSubject, Subscription } from 'rxjs'; import { debounce } from 'lodash'; +import { UnregisterCallback } from 'history'; import { CoreSetup, Plugin } from '../../../core/public'; import { getStateFromOsdUrl } from '../../opensearch_dashboards_utils/public'; import { formatUrlWithWorkspaceId } from './utils'; @@ -13,17 +14,39 @@ import { WORKSPACE_ID_STATE_KEY } from '../common/constants'; export class WorkspacePlugin implements Plugin<{}, {}, {}> { private core?: CoreSetup; private URLChange$ = new BehaviorSubject(''); - private applicationSubscription = new Subscription(); + private currentWorkspaceIdSubscription = new Subscription(); private urlChangeSubscription = new Subscription(); + private historyUnregisterCallback?: UnregisterCallback; private getworkspaceIdFromURL(): string | null { return getStateFromOsdUrl(WORKSPACE_ID_STATE_KEY); } + /** + * Current workspace id may come from multiple source: 1. url hash 2. memory: core.workspaces 3. localstorage + * this methods will detect if there is any workspace id present and return that. + * @returns string + */ private getworkspaceId(): string { - if (this.getworkspaceIdFromURL()) { - return this.getworkspaceIdFromURL() || ''; + // workspace id in url has highest priority + const workspaceIdFromUrl = this.getworkspaceIdFromURL(); + if (workspaceIdFromUrl) { + return workspaceIdFromUrl; + } + + // workspace id in memory has second priority and mainly used for reserve workspace id when navigating through SPA + const workspaceIdFromMemory = this.core?.workspaces.currentWorkspaceId$.getValue(); + + if (workspaceIdFromMemory) { + return workspaceIdFromMemory; + } + + // workspace in localStorage is used in cases like Discover that will open a new tab in the browser, the localStorage will be used for cross-tab communication. + const workspaceIdFromLocalStorage = localStorage.getItem(WORKSPACE_ID_STATE_KEY); + + if (workspaceIdFromLocalStorage) { + return workspaceIdFromLocalStorage; } - return this.core?.workspaces.currentWorkspaceId$.getValue() || ''; + return ''; } private getPatchedUrl = (url: string, workspaceId: string) => { return formatUrlWithWorkspaceId(url, workspaceId); @@ -63,7 +86,7 @@ export class WorkspacePlugin implements Plugin<{}, {}, {}> { private async listenToHistoryChange(): Promise { const startService = await this.core?.getStartServices(); if (startService) { - startService[0].application.history.listen(() => { + this.historyUnregisterCallback = startService[0].application.history.listen(() => { if (this.shouldPatchUrl()) { const currentWorkspaceId = this.getworkspaceId(); this.URLChange$.next(this.getPatchedUrl(window.location.href, currentWorkspaceId)); @@ -71,19 +94,27 @@ export class WorkspacePlugin implements Plugin<{}, {}, {}> { }); } } + private listenToCurrentWorkspaceChange() { + this.currentWorkspaceIdSubscription = (this + .core as CoreSetup).workspaces.currentWorkspaceId$.subscribe((currentWorkspaceId) => { + localStorage.setItem(WORKSPACE_ID_STATE_KEY, currentWorkspaceId); + if (this.shouldPatchUrl()) { + this.URLChange$.next(this.getPatchedUrl(window.location.href, currentWorkspaceId)); + } + }); + } public async setup(core: CoreSetup) { this.core = core; + /** * Retrive workspace id from url */ - const workspaceId = this.getworkspaceIdFromURL(); + const workspaceId = this.getworkspaceId(); - if (workspaceId) { - /** - * Enter a workspace - */ - this.core.workspaces.currentWorkspaceId$.next(workspaceId); - } + /** + * listen to current workspace change and patch workspace id in hash + */ + this.listenToCurrentWorkspaceChange(); /** * listen to history change and patch workspace id in hash @@ -104,6 +135,13 @@ export class WorkspacePlugin implements Plugin<{}, {}, {}> { }, 500) ); + if (workspaceId) { + /** + * Enter a workspace + */ + this.core.workspaces.currentWorkspaceId$.next(workspaceId); + } + return {}; } @@ -113,7 +151,14 @@ export class WorkspacePlugin implements Plugin<{}, {}, {}> { public stop() { this.urlChangeSubscription.unsubscribe(); - this.applicationSubscription.unsubscribe(); + this.currentWorkspaceIdSubscription.unsubscribe(); + this.historyUnregisterCallback?.(); window.removeEventListener('hashchange', this.hashChangeHandler); + + /** + * Remove the localStorage record here so that when user copy a url without workspace id + * the record in local storage won't pollute getWorkspaceId + */ + localStorage.removeItem(WORKSPACE_ID_STATE_KEY); } } From 3364ca6688e9d545b0f8b2b7bac7c439d387e5a7 Mon Sep 17 00:00:00 2001 From: SuZhou-Joe Date: Wed, 6 Mar 2024 13:34:25 +0800 Subject: [PATCH 6/9] feat: add empty line between each function Signed-off-by: SuZhou-Joe --- src/plugins/workspace/public/plugin.ts | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/plugins/workspace/public/plugin.ts b/src/plugins/workspace/public/plugin.ts index f435804e694f..088965db61d2 100644 --- a/src/plugins/workspace/public/plugin.ts +++ b/src/plugins/workspace/public/plugin.ts @@ -20,6 +20,7 @@ export class WorkspacePlugin implements Plugin<{}, {}, {}> { private getworkspaceIdFromURL(): string | null { return getStateFromOsdUrl(WORKSPACE_ID_STATE_KEY); } + /** * Current workspace id may come from multiple source: 1. url hash 2. memory: core.workspaces 3. localstorage * this methods will detect if there is any workspace id present and return that. @@ -48,18 +49,22 @@ export class WorkspacePlugin implements Plugin<{}, {}, {}> { return ''; } + private getPatchedUrl = (url: string, workspaceId: string) => { return formatUrlWithWorkspaceId(url, workspaceId); }; + private hashChangeHandler = async () => { if (this.shouldPatchUrl()) { const workspaceId = await this.getworkspaceId(); this.URLChange$.next(this.getPatchedUrl(window.location.href, workspaceId)); } }; + private async listenToHashChange(): Promise { window.addEventListener('hashchange', this.hashChangeHandler); } + /** * When navigating between applications or inside application, the hash state will be overwrote, * compare the workspaceId in memory and the workspaceId in hash state, @@ -79,6 +84,7 @@ export class WorkspacePlugin implements Plugin<{}, {}, {}> { return true; } + /** * When navigating between applications or the subApps inside an application e.g. Dashboard management, the hash state will be overwrote, * listen to history change and try to patch the workspaceId into hash state @@ -94,6 +100,7 @@ export class WorkspacePlugin implements Plugin<{}, {}, {}> { }); } } + private listenToCurrentWorkspaceChange() { this.currentWorkspaceIdSubscription = (this .core as CoreSetup).workspaces.currentWorkspaceId$.subscribe((currentWorkspaceId) => { @@ -103,6 +110,7 @@ export class WorkspacePlugin implements Plugin<{}, {}, {}> { } }); } + public async setup(core: CoreSetup) { this.core = core; From cedd7002191aa96aad702a6f680cdcb5eec1d3dd Mon Sep 17 00:00:00 2001 From: SuZhou-Joe Date: Wed, 6 Mar 2024 13:35:36 +0800 Subject: [PATCH 7/9] feat: optimize code Signed-off-by: SuZhou-Joe --- src/plugins/workspace/public/plugin.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/workspace/public/plugin.ts b/src/plugins/workspace/public/plugin.ts index 088965db61d2..fef2142444e7 100644 --- a/src/plugins/workspace/public/plugin.ts +++ b/src/plugins/workspace/public/plugin.ts @@ -66,7 +66,7 @@ export class WorkspacePlugin implements Plugin<{}, {}, {}> { } /** - * When navigating between applications or inside application, the hash state will be overwrote, + * When navigating between applications or inside application, the hash state will be overwritten, * compare the workspaceId in memory and the workspaceId in hash state, * If do not match, return true * @returns bool From 0a422849979f338c6a7d0dc236f9459f7ab161d6 Mon Sep 17 00:00:00 2001 From: SuZhou-Joe Date: Wed, 6 Mar 2024 13:41:29 +0800 Subject: [PATCH 8/9] feat: fix bootstrap error Signed-off-by: SuZhou-Joe --- src/core/public/application/application_service.mock.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/core/public/application/application_service.mock.ts b/src/core/public/application/application_service.mock.ts index b70a34095f0c..8d6068685a07 100644 --- a/src/core/public/application/application_service.mock.ts +++ b/src/core/public/application/application_service.mock.ts @@ -65,6 +65,7 @@ const createStartContractMock = (): jest.Mocked => { navigateToUrl: jest.fn(), getUrlForApp: jest.fn(), registerMountContext: jest.fn(), + history: createHistoryMock(), }; }; From 1392a65c2ab38b8dbfcf1903b56119b6719b182d Mon Sep 17 00:00:00 2001 From: SuZhou-Joe Date: Wed, 6 Mar 2024 18:13:58 +0800 Subject: [PATCH 9/9] feat: update snapshot to fix unit test Signed-off-by: SuZhou-Joe --- .../dashboard_listing.test.tsx.snap | 8298 ++++++++++++++++- .../dashboard_top_nav.test.tsx.snap | 114 + .../saved_objects_table.test.tsx.snap | 19 + 3 files changed, 8426 insertions(+), 5 deletions(-) diff --git a/src/plugins/dashboard/public/application/components/dashboard_listing/__snapshots__/dashboard_listing.test.tsx.snap b/src/plugins/dashboard/public/application/components/dashboard_listing/__snapshots__/dashboard_listing.test.tsx.snap index c9ffe147e5f8..e7e6d2891042 100644 --- a/src/plugins/dashboard/public/application/components/dashboard_listing/__snapshots__/dashboard_listing.test.tsx.snap +++ b/src/plugins/dashboard/public/application/components/dashboard_listing/__snapshots__/dashboard_listing.test.tsx.snap @@ -118,6 +118,25 @@ exports[`dashboard listing hideWriteControls 1`] = ` }, }, "getUrlForApp": [MockFunction], + "history": Object { + "action": "PUSH", + "block": [MockFunction], + "createHref": [MockFunction], + "go": [MockFunction], + "goBack": [MockFunction], + "goForward": [MockFunction], + "length": 1, + "listen": [MockFunction], + "location": Object { + "hash": "", + "key": "", + "pathname": "/", + "search": "", + "state": undefined, + }, + "push": [MockFunction], + "replace": [MockFunction], + }, "navigateToApp": [MockFunction], "navigateToUrl": [MockFunction], "registerMountContext": [MockFunction], @@ -1116,11 +1135,1481 @@ exports[`dashboard listing hideWriteControls 1`] = ` data-test-subj="dashboardLandingPage" >
+ > + + +
+
+ +
+ +
+ +

+ Dashboards +

+
+
+
+
+
+ +
+ + + } + pagination={ + Object { + "initialPageIndex": 0, + "initialPageSize": 10, + "pageSizeOptions": Array [ + 10, + 20, + 50, + ], + } + } + responsive={true} + search={ + Object { + "box": Object { + "incremental": true, + }, + "defaultQuery": "", + "onChange": [Function], + "toolsLeft": undefined, + } + } + sorting={true} + tableLayout="fixed" + > +
+ + +
+ +
+ + + +
+
+ + + + +
+ + + + + +
+
+
+
+
+
+
+
+
+
+
+
+ +
+ + + } + onChange={[Function]} + pagination={ + Object { + "hidePerPageOptions": undefined, + "pageIndex": 0, + "pageSize": 10, + "pageSizeOptions": Array [ + 10, + 20, + 50, + ], + "totalItemCount": 2, + } + } + responsive={true} + sorting={ + Object { + "allowNeutralSort": true, + "sort": undefined, + } + } + tableLayout="fixed" + > +
+
+ +
+ +
+ +
+ + +
+ +
+ + + + } + closePopover={[Function]} + display="inlineBlock" + hasArrow={true} + isOpen={false} + ownFocus={true} + panelPaddingSize="none" + > +
+
+ + + +
+
+
+
+
+
+
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + + +
+
+ Title +
+
+ + + +
+
+
+ Type +
+
+ + dashboardSavedObjects + +
+
+
+ Description +
+
+ + dashboard0 desc + +
+
+
+ Last updated +
+
+
+
+ Title +
+
+ + + +
+
+
+ Type +
+
+ + dashboardSavedObjects + +
+
+
+ Description +
+
+ + dashboard1 desc + +
+
+
+ Last updated +
+
+
+
+
+ +
+ +
+ + + +
+ +
+ + + : + 10 + + } + closePopover={[Function]} + display="inlineBlock" + hasArrow={true} + isOpen={false} + ownFocus={true} + panelPaddingSize="none" + > +
+
+ + + +
+
+
+
+
+ +
+ + + +
+
+
+
+
+
+ +
+ +
+ +
+
+ + +
@@ -1250,6 +2739,25 @@ exports[`dashboard listing render table listing with initial filters from URL 1` }, }, "getUrlForApp": [MockFunction], + "history": Object { + "action": "PUSH", + "block": [MockFunction], + "createHref": [MockFunction], + "go": [MockFunction], + "goBack": [MockFunction], + "goForward": [MockFunction], + "length": 1, + "listen": [MockFunction], + "location": Object { + "hash": "", + "key": "", + "pathname": "/", + "search": "", + "state": undefined, + }, + "push": [MockFunction], + "replace": [MockFunction], + }, "navigateToApp": [MockFunction], "navigateToUrl": [MockFunction], "registerMountContext": [MockFunction], @@ -2309,11 +3817,2151 @@ exports[`dashboard listing render table listing with initial filters from URL 1` data-test-subj="dashboardLandingPage" >
+ > + + +
+
+ +
+ +
+ +

+ Dashboards +

+
+
+
+ + +
+ + + + + +
+
+
+
+
+ +
+ + + } + pagination={ + Object { + "initialPageIndex": 0, + "initialPageSize": 10, + "pageSizeOptions": Array [ + 10, + 20, + 50, + ], + } + } + responsive={true} + search={ + Object { + "box": Object { + "incremental": true, + }, + "defaultQuery": "dashboard", + "onChange": [Function], + "toolsLeft": undefined, + } + } + selection={ + Object { + "onSelectionChange": [Function], + } + } + sorting={true} + tableLayout="fixed" + > +
+ + +
+ +
+ + + +
+
+ + + + +
+ + + + + +
+
+ + + + + +
+
+
+
+
+
+
+
+
+
+
+
+ +
+ + + } + onChange={[Function]} + pagination={ + Object { + "hidePerPageOptions": undefined, + "pageIndex": 0, + "pageSize": 10, + "pageSizeOptions": Array [ + 10, + 20, + 50, + ], + "totalItemCount": 2, + } + } + responsive={true} + selection={ + Object { + "onSelectionChange": [Function], + } + } + sorting={ + Object { + "allowNeutralSort": true, + "sort": undefined, + } + } + tableLayout="fixed" + > +
+
+ +
+ +
+ +
+ + +
+ +
+ +
+ + +
+ + +
+ +
+ + + + } + closePopover={[Function]} + display="inlineBlock" + hasArrow={true} + isOpen={false} + ownFocus={true} + panelPaddingSize="none" + > +
+
+ + + +
+
+
+
+
+
+
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+ + +
+ +
+
+ + +
+
+ + + + + + + + + + + + + + Actions + + + + + +
+
+ + +
+ +
+
+ + +
+
+
+ Title +
+
+ + + +
+
+
+ Type +
+
+ + dashboardSavedObjects + +
+
+
+ Description +
+
+ + dashboard0 desc + +
+
+
+ Last updated +
+
+
+
+ + + + + + + + + + Edit + + + + + + +
+
+
+ + +
+ +
+
+ + +
+
+
+ Title +
+
+ + + +
+
+
+ Type +
+
+ + dashboardSavedObjects + +
+
+
+ Description +
+
+ + dashboard1 desc + +
+
+
+ Last updated +
+
+
+
+ + + + + + + + + + Edit + + + + + + +
+
+
+
+ +
+ +
+ + + +
+ +
+ + + : + 10 + + } + closePopover={[Function]} + display="inlineBlock" + hasArrow={true} + isOpen={false} + ownFocus={true} + panelPaddingSize="none" + > +
+
+ + + +
+
+
+
+
+ +
+ + + +
+
+
+
+
+
+ +
+ +
+ +
+
+ + +
@@ -2443,6 +6091,25 @@ exports[`dashboard listing renders call to action when no dashboards exist 1`] = }, }, "getUrlForApp": [MockFunction], + "history": Object { + "action": "PUSH", + "block": [MockFunction], + "createHref": [MockFunction], + "go": [MockFunction], + "goBack": [MockFunction], + "goForward": [MockFunction], + "length": 1, + "listen": [MockFunction], + "location": Object { + "hash": "", + "key": "", + "pathname": "/", + "search": "", + "state": undefined, + }, + "push": [MockFunction], + "replace": [MockFunction], + }, "navigateToApp": [MockFunction], "navigateToUrl": [MockFunction], "registerMountContext": [MockFunction], @@ -3502,11 +7169,274 @@ exports[`dashboard listing renders call to action when no dashboards exist 1`] = data-test-subj="dashboardLandingPage" >
+ > + + +
+ + + + } + body={ + +

+ +

+

+ + + , + } + } + /> +

+
+ } + iconType="dashboardApp" + title={ +

+ +

+ } + > +
+ + + + +
+ + +

+ + Create your first dashboard + +

+
+ + + +
+ + +
+

+ + You can combine data views from any OpenSearch Dashboards app into one dashboard and see everything in one place. + +

+

+ + + , + } + } + > + New to OpenSearch Dashboards? + + + + to take a test drive. + +

+
+
+ + + +
+ + + + + + +
+ +
+ + +
@@ -3636,6 +7566,25 @@ exports[`dashboard listing renders table rows 1`] = ` }, }, "getUrlForApp": [MockFunction], + "history": Object { + "action": "PUSH", + "block": [MockFunction], + "createHref": [MockFunction], + "go": [MockFunction], + "goBack": [MockFunction], + "goForward": [MockFunction], + "length": 1, + "listen": [MockFunction], + "location": Object { + "hash": "", + "key": "", + "pathname": "/", + "search": "", + "state": undefined, + }, + "push": [MockFunction], + "replace": [MockFunction], + }, "navigateToApp": [MockFunction], "navigateToUrl": [MockFunction], "registerMountContext": [MockFunction], @@ -4695,11 +8644,2111 @@ exports[`dashboard listing renders table rows 1`] = ` data-test-subj="dashboardLandingPage" >
+ > + + +
+
+ +
+ +
+ +

+ Dashboards +

+
+
+
+ + +
+ + + + + +
+
+
+
+
+ +
+ + + } + pagination={ + Object { + "initialPageIndex": 0, + "initialPageSize": 10, + "pageSizeOptions": Array [ + 10, + 20, + 50, + ], + } + } + responsive={true} + search={ + Object { + "box": Object { + "incremental": true, + }, + "defaultQuery": "", + "onChange": [Function], + "toolsLeft": undefined, + } + } + selection={ + Object { + "onSelectionChange": [Function], + } + } + sorting={true} + tableLayout="fixed" + > +
+ + +
+ +
+ + + +
+
+ + + + +
+ + + + + +
+
+
+
+
+
+
+
+
+
+
+
+ +
+ + + } + onChange={[Function]} + pagination={ + Object { + "hidePerPageOptions": undefined, + "pageIndex": 0, + "pageSize": 10, + "pageSizeOptions": Array [ + 10, + 20, + 50, + ], + "totalItemCount": 2, + } + } + responsive={true} + selection={ + Object { + "onSelectionChange": [Function], + } + } + sorting={ + Object { + "allowNeutralSort": true, + "sort": undefined, + } + } + tableLayout="fixed" + > +
+
+ +
+ +
+ +
+ + +
+ +
+ +
+ + +
+ + +
+ +
+ + + + } + closePopover={[Function]} + display="inlineBlock" + hasArrow={true} + isOpen={false} + ownFocus={true} + panelPaddingSize="none" + > +
+
+ + + +
+
+
+
+
+
+
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+ + +
+ +
+
+ + +
+
+ + + + + + + + + + + + + + Actions + + + + + +
+
+ + +
+ +
+
+ + +
+
+
+ Title +
+
+ + + +
+
+
+ Type +
+
+ + dashboardSavedObjects + +
+
+
+ Description +
+
+ + dashboard0 desc + +
+
+
+ Last updated +
+
+
+
+ + + + + + + + + + Edit + + + + + + +
+
+
+ + +
+ +
+
+ + +
+
+
+ Title +
+
+ + + +
+
+
+ Type +
+
+ + dashboardSavedObjects + +
+
+
+ Description +
+
+ + dashboard1 desc + +
+
+
+ Last updated +
+
+
+
+ + + + + + + + + + Edit + + + + + + +
+
+
+
+ +
+ +
+ + + +
+ +
+ + + : + 10 + + } + closePopover={[Function]} + display="inlineBlock" + hasArrow={true} + isOpen={false} + ownFocus={true} + panelPaddingSize="none" + > +
+
+ + + +
+
+
+
+
+ +
+ + + +
+
+
+
+
+
+ +
+ +
+ +
+
+ + +
@@ -4829,6 +10878,25 @@ exports[`dashboard listing renders warning when listingLimit is exceeded 1`] = ` }, }, "getUrlForApp": [MockFunction], + "history": Object { + "action": "PUSH", + "block": [MockFunction], + "createHref": [MockFunction], + "go": [MockFunction], + "goBack": [MockFunction], + "goForward": [MockFunction], + "length": 1, + "listen": [MockFunction], + "location": Object { + "hash": "", + "key": "", + "pathname": "/", + "search": "", + "state": undefined, + }, + "push": [MockFunction], + "replace": [MockFunction], + }, "navigateToApp": [MockFunction], "navigateToUrl": [MockFunction], "registerMountContext": [MockFunction], @@ -5888,11 +11956,2231 @@ exports[`dashboard listing renders warning when listingLimit is exceeded 1`] = ` data-test-subj="dashboardLandingPage" >
+ > + + +
+
+ +
+ +
+ +

+ Dashboards +

+
+
+
+ + +
+ + + + + +
+
+
+
+
+ +
+ + + } + > +
+
+ + + + Listing limit exceeded + + +
+ +
+ +
+

+ + + , + "entityNamePlural": "dashboards", + "listingLimitText": + listingLimit + , + "listingLimitValue": 1, + "totalItems": 2, + } + } + > + You have 2 dashboards, but your + + listingLimit + + setting prevents the table below from displaying more than 1. You can change this setting under + + + + Advanced Settings + + + + . + +

+
+
+
+
+
+
+ +
+ + + } + pagination={ + Object { + "initialPageIndex": 0, + "initialPageSize": 10, + "pageSizeOptions": Array [ + 10, + 20, + 50, + ], + } + } + responsive={true} + search={ + Object { + "box": Object { + "incremental": true, + }, + "defaultQuery": "", + "onChange": [Function], + "toolsLeft": undefined, + } + } + selection={ + Object { + "onSelectionChange": [Function], + } + } + sorting={true} + tableLayout="fixed" + > +
+ + +
+ +
+ + + +
+
+ + + + +
+ + + + + +
+
+
+
+
+
+
+
+
+
+
+
+ +
+ + + } + onChange={[Function]} + pagination={ + Object { + "hidePerPageOptions": undefined, + "pageIndex": 0, + "pageSize": 10, + "pageSizeOptions": Array [ + 10, + 20, + 50, + ], + "totalItemCount": 2, + } + } + responsive={true} + selection={ + Object { + "onSelectionChange": [Function], + } + } + sorting={ + Object { + "allowNeutralSort": true, + "sort": undefined, + } + } + tableLayout="fixed" + > +
+
+ +
+ +
+ +
+ + +
+ +
+ +
+ + +
+ + +
+ +
+ + + + } + closePopover={[Function]} + display="inlineBlock" + hasArrow={true} + isOpen={false} + ownFocus={true} + panelPaddingSize="none" + > +
+
+ + + +
+
+
+
+
+
+
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+ + +
+ +
+
+ + +
+
+ + + + + + + + + + + + + + Actions + + + + + +
+
+ + +
+ +
+
+ + +
+
+
+ Title +
+
+ + + +
+
+
+ Type +
+
+ + dashboardSavedObjects + +
+
+
+ Description +
+
+ + dashboard0 desc + +
+
+
+ Last updated +
+
+
+
+ + + + + + + + + + Edit + + + + + + +
+
+
+ + +
+ +
+
+ + +
+
+
+ Title +
+
+ + + +
+
+
+ Type +
+
+ + dashboardSavedObjects + +
+
+
+ Description +
+
+ + dashboard1 desc + +
+
+
+ Last updated +
+
+
+
+ + + + + + + + + + Edit + + + + + + +
+
+
+
+ +
+ +
+ + + +
+ +
+ + + : + 10 + + } + closePopover={[Function]} + display="inlineBlock" + hasArrow={true} + isOpen={false} + ownFocus={true} + panelPaddingSize="none" + > +
+
+ + + +
+
+
+
+
+ +
+ + + +
+
+
+
+
+
+ +
+ +
+ +
+
+ + +
diff --git a/src/plugins/dashboard/public/application/components/dashboard_top_nav/__snapshots__/dashboard_top_nav.test.tsx.snap b/src/plugins/dashboard/public/application/components/dashboard_top_nav/__snapshots__/dashboard_top_nav.test.tsx.snap index 1954051c9474..f7b3356a91c7 100644 --- a/src/plugins/dashboard/public/application/components/dashboard_top_nav/__snapshots__/dashboard_top_nav.test.tsx.snap +++ b/src/plugins/dashboard/public/application/components/dashboard_top_nav/__snapshots__/dashboard_top_nav.test.tsx.snap @@ -118,6 +118,25 @@ exports[`Dashboard top nav render in embed mode 1`] = ` }, }, "getUrlForApp": [MockFunction], + "history": Object { + "action": "PUSH", + "block": [MockFunction], + "createHref": [MockFunction], + "go": [MockFunction], + "goBack": [MockFunction], + "goForward": [MockFunction], + "length": 1, + "listen": [MockFunction], + "location": Object { + "hash": "", + "key": "", + "pathname": "/", + "search": "", + "state": undefined, + }, + "push": [MockFunction], + "replace": [MockFunction], + }, "navigateToApp": [MockFunction], "navigateToUrl": [MockFunction], "registerMountContext": [MockFunction], @@ -1075,6 +1094,25 @@ exports[`Dashboard top nav render in embed mode, and force hide filter bar 1`] = }, }, "getUrlForApp": [MockFunction], + "history": Object { + "action": "PUSH", + "block": [MockFunction], + "createHref": [MockFunction], + "go": [MockFunction], + "goBack": [MockFunction], + "goForward": [MockFunction], + "length": 1, + "listen": [MockFunction], + "location": Object { + "hash": "", + "key": "", + "pathname": "/", + "search": "", + "state": undefined, + }, + "push": [MockFunction], + "replace": [MockFunction], + }, "navigateToApp": [MockFunction], "navigateToUrl": [MockFunction], "registerMountContext": [MockFunction], @@ -2032,6 +2070,25 @@ exports[`Dashboard top nav render in embed mode, components can be forced show b }, }, "getUrlForApp": [MockFunction], + "history": Object { + "action": "PUSH", + "block": [MockFunction], + "createHref": [MockFunction], + "go": [MockFunction], + "goBack": [MockFunction], + "goForward": [MockFunction], + "length": 1, + "listen": [MockFunction], + "location": Object { + "hash": "", + "key": "", + "pathname": "/", + "search": "", + "state": undefined, + }, + "push": [MockFunction], + "replace": [MockFunction], + }, "navigateToApp": [MockFunction], "navigateToUrl": [MockFunction], "registerMountContext": [MockFunction], @@ -2989,6 +3046,25 @@ exports[`Dashboard top nav render in full screen mode with appended URL param bu }, }, "getUrlForApp": [MockFunction], + "history": Object { + "action": "PUSH", + "block": [MockFunction], + "createHref": [MockFunction], + "go": [MockFunction], + "goBack": [MockFunction], + "goForward": [MockFunction], + "length": 1, + "listen": [MockFunction], + "location": Object { + "hash": "", + "key": "", + "pathname": "/", + "search": "", + "state": undefined, + }, + "push": [MockFunction], + "replace": [MockFunction], + }, "navigateToApp": [MockFunction], "navigateToUrl": [MockFunction], "registerMountContext": [MockFunction], @@ -3946,6 +4022,25 @@ exports[`Dashboard top nav render in full screen mode, no componenets should be }, }, "getUrlForApp": [MockFunction], + "history": Object { + "action": "PUSH", + "block": [MockFunction], + "createHref": [MockFunction], + "go": [MockFunction], + "goBack": [MockFunction], + "goForward": [MockFunction], + "length": 1, + "listen": [MockFunction], + "location": Object { + "hash": "", + "key": "", + "pathname": "/", + "search": "", + "state": undefined, + }, + "push": [MockFunction], + "replace": [MockFunction], + }, "navigateToApp": [MockFunction], "navigateToUrl": [MockFunction], "registerMountContext": [MockFunction], @@ -4903,6 +4998,25 @@ exports[`Dashboard top nav render with all components 1`] = ` }, }, "getUrlForApp": [MockFunction], + "history": Object { + "action": "PUSH", + "block": [MockFunction], + "createHref": [MockFunction], + "go": [MockFunction], + "goBack": [MockFunction], + "goForward": [MockFunction], + "length": 1, + "listen": [MockFunction], + "location": Object { + "hash": "", + "key": "", + "pathname": "/", + "search": "", + "state": undefined, + }, + "push": [MockFunction], + "replace": [MockFunction], + }, "navigateToApp": [MockFunction], "navigateToUrl": [MockFunction], "registerMountContext": [MockFunction], diff --git a/src/plugins/saved_objects_management/public/management_section/objects_table/__snapshots__/saved_objects_table.test.tsx.snap b/src/plugins/saved_objects_management/public/management_section/objects_table/__snapshots__/saved_objects_table.test.tsx.snap index d18762f4912f..d761ebf8baaf 100644 --- a/src/plugins/saved_objects_management/public/management_section/objects_table/__snapshots__/saved_objects_table.test.tsx.snap +++ b/src/plugins/saved_objects_management/public/management_section/objects_table/__snapshots__/saved_objects_table.test.tsx.snap @@ -244,6 +244,25 @@ exports[`SavedObjectsTable should render normally 1`] = ` }, }, "getUrlForApp": [MockFunction], + "history": Object { + "action": "PUSH", + "block": [MockFunction], + "createHref": [MockFunction], + "go": [MockFunction], + "goBack": [MockFunction], + "goForward": [MockFunction], + "length": 1, + "listen": [MockFunction], + "location": Object { + "hash": "", + "key": "", + "pathname": "/", + "search": "", + "state": undefined, + }, + "push": [MockFunction], + "replace": [MockFunction], + }, "navigateToApp": [MockFunction], "navigateToUrl": [MockFunction], "registerMountContext": [MockFunction],