diff --git a/src/core/public/chrome/ui/header/__snapshots__/collapsible_nav.test.tsx.snap b/src/core/public/chrome/ui/header/__snapshots__/collapsible_nav.test.tsx.snap
index 00e1831d9f24..1991291a1c8c 100644
--- a/src/core/public/chrome/ui/header/__snapshots__/collapsible_nav.test.tsx.snap
+++ b/src/core/public/chrome/ui/header/__snapshots__/collapsible_nav.test.tsx.snap
@@ -398,7 +398,7 @@ exports[`CollapsibleNav renders links grouped by category 1`] = `
"observers": Array [],
"thrownError": null,
},
- "hasFetchedWorkspaceList$": BehaviorSubject {
+ "initialized$": BehaviorSubject {
"_isScalar": false,
"_value": false,
"closed": false,
@@ -568,7 +568,7 @@ exports[`CollapsibleNav renders links grouped by category 1`] = `
"observers": Array [],
"thrownError": null,
},
- "hasFetchedWorkspaceList$": BehaviorSubject {
+ "initialized$": BehaviorSubject {
"_isScalar": false,
"_value": false,
"closed": false,
@@ -3497,7 +3497,7 @@ exports[`CollapsibleNav renders the default nav 1`] = `
"observers": Array [],
"thrownError": null,
},
- "hasFetchedWorkspaceList$": BehaviorSubject {
+ "initialized$": BehaviorSubject {
"_isScalar": false,
"_value": false,
"closed": false,
@@ -3815,7 +3815,7 @@ exports[`CollapsibleNav renders the default nav 2`] = `
"observers": Array [],
"thrownError": null,
},
- "hasFetchedWorkspaceList$": BehaviorSubject {
+ "initialized$": BehaviorSubject {
"_isScalar": false,
"_value": false,
"closed": false,
@@ -4133,7 +4133,7 @@ exports[`CollapsibleNav renders the default nav 3`] = `
"observers": Array [],
"thrownError": null,
},
- "hasFetchedWorkspaceList$": BehaviorSubject {
+ "initialized$": BehaviorSubject {
"_isScalar": false,
"_value": false,
"closed": false,
@@ -4261,7 +4261,7 @@ exports[`CollapsibleNav renders the default nav 3`] = `
"observers": Array [],
"thrownError": null,
},
- "hasFetchedWorkspaceList$": BehaviorSubject {
+ "initialized$": BehaviorSubject {
"_isScalar": false,
"_value": false,
"closed": false,
@@ -5017,7 +5017,7 @@ exports[`CollapsibleNav with custom branding renders the nav bar in dark mode 1`
"observers": Array [],
"thrownError": null,
},
- "hasFetchedWorkspaceList$": BehaviorSubject {
+ "initialized$": BehaviorSubject {
"_isScalar": false,
"_value": false,
"closed": false,
@@ -5298,7 +5298,7 @@ exports[`CollapsibleNav with custom branding renders the nav bar in dark mode 1`
"observers": Array [],
"thrownError": null,
},
- "hasFetchedWorkspaceList$": BehaviorSubject {
+ "initialized$": BehaviorSubject {
"_isScalar": false,
"_value": false,
"closed": false,
@@ -7781,7 +7781,7 @@ exports[`CollapsibleNav without custom branding renders the nav bar in dark mode
"observers": Array [],
"thrownError": null,
},
- "hasFetchedWorkspaceList$": BehaviorSubject {
+ "initialized$": BehaviorSubject {
"_isScalar": false,
"_value": false,
"closed": false,
@@ -8062,7 +8062,7 @@ exports[`CollapsibleNav without custom branding renders the nav bar in dark mode
"observers": Array [],
"thrownError": null,
},
- "hasFetchedWorkspaceList$": BehaviorSubject {
+ "initialized$": BehaviorSubject {
"_isScalar": false,
"_value": false,
"closed": false,
@@ -9389,7 +9389,7 @@ exports[`CollapsibleNav without custom branding renders the nav bar in default m
"observers": Array [],
"thrownError": null,
},
- "hasFetchedWorkspaceList$": BehaviorSubject {
+ "initialized$": BehaviorSubject {
"_isScalar": false,
"_value": false,
"closed": false,
@@ -9633,7 +9633,7 @@ exports[`CollapsibleNav without custom branding renders the nav bar in default m
"observers": Array [],
"thrownError": null,
},
- "hasFetchedWorkspaceList$": BehaviorSubject {
+ "initialized$": BehaviorSubject {
"_isScalar": false,
"_value": false,
"closed": false,
diff --git a/src/core/public/chrome/ui/header/__snapshots__/header.test.tsx.snap b/src/core/public/chrome/ui/header/__snapshots__/header.test.tsx.snap
index 7915857b3c7a..fe958c7c4e0d 100644
--- a/src/core/public/chrome/ui/header/__snapshots__/header.test.tsx.snap
+++ b/src/core/public/chrome/ui/header/__snapshots__/header.test.tsx.snap
@@ -1947,7 +1947,7 @@ exports[`Header handles visibility and lock changes 1`] = `
],
"thrownError": null,
},
- "hasFetchedWorkspaceList$": BehaviorSubject {
+ "initialized$": BehaviorSubject {
"_isScalar": false,
"_value": false,
"closed": false,
@@ -6339,7 +6339,7 @@ exports[`Header handles visibility and lock changes 1`] = `
],
"thrownError": null,
},
- "hasFetchedWorkspaceList$": BehaviorSubject {
+ "initialized$": BehaviorSubject {
"_isScalar": false,
"_value": false,
"closed": false,
@@ -6542,7 +6542,7 @@ exports[`Header handles visibility and lock changes 1`] = `
],
"thrownError": null,
},
- "hasFetchedWorkspaceList$": BehaviorSubject {
+ "initialized$": BehaviorSubject {
"_isScalar": false,
"_value": false,
"closed": false,
@@ -6684,9 +6684,9 @@ exports[`Header handles visibility and lock changes 1`] = `
className="euiText euiText--medium"
>
-
+
OpenSearch Dashboards
-
+
@@ -8883,7 +8883,7 @@ exports[`Header renders condensed header 1`] = `
],
"thrownError": null,
},
- "hasFetchedWorkspaceList$": BehaviorSubject {
+ "initialized$": BehaviorSubject {
"_isScalar": false,
"_value": false,
"closed": false,
@@ -12243,7 +12243,7 @@ exports[`Header renders condensed header 1`] = `
],
"thrownError": null,
},
- "hasFetchedWorkspaceList$": BehaviorSubject {
+ "initialized$": BehaviorSubject {
"_isScalar": false,
"_value": false,
"closed": false,
diff --git a/src/core/public/workspace/workspaces_service.mock.ts b/src/core/public/workspace/workspaces_service.mock.ts
index ee813fffa8f4..3c35315aa850 100644
--- a/src/core/public/workspace/workspaces_service.mock.ts
+++ b/src/core/public/workspace/workspaces_service.mock.ts
@@ -9,14 +9,14 @@ import { WorkspaceAttribute } from '..';
const currentWorkspaceId$ = new BehaviorSubject('');
const workspaceList$ = new BehaviorSubject([]);
const currentWorkspace$ = new BehaviorSubject(null);
-const hasFetchedWorkspaceList$ = new BehaviorSubject(false);
+const initialized$ = new BehaviorSubject(false);
const workspaceEnabled$ = new BehaviorSubject(false);
const createWorkspacesSetupContractMock = () => ({
currentWorkspaceId$,
workspaceList$,
currentWorkspace$,
- hasFetchedWorkspaceList$,
+ initialized$,
workspaceEnabled$,
registerWorkspaceMenuRender: jest.fn(),
});
@@ -25,7 +25,7 @@ const createWorkspacesStartContractMock = () => ({
currentWorkspaceId$,
workspaceList$,
currentWorkspace$,
- hasFetchedWorkspaceList$,
+ initialized$,
workspaceEnabled$,
renderWorkspaceMenu: jest.fn(),
});
diff --git a/src/core/public/workspace/workspaces_service.ts b/src/core/public/workspace/workspaces_service.ts
index 9b386599cea0..b94bf0a17e23 100644
--- a/src/core/public/workspace/workspaces_service.ts
+++ b/src/core/public/workspace/workspaces_service.ts
@@ -3,7 +3,9 @@
* SPDX-License-Identifier: Apache-2.0
*/
-import { BehaviorSubject } from 'rxjs';
+import { BehaviorSubject, combineLatest } from 'rxjs';
+import { isEqual } from 'lodash';
+
import { CoreService, WorkspaceAttribute } from '../../types';
import { InternalApplicationStart } from '../application';
import { HttpSetup } from '../http';
@@ -23,7 +25,11 @@ export interface WorkspaceObservables {
currentWorkspace$: BehaviorSubject;
workspaceList$: BehaviorSubject;
workspaceEnabled$: BehaviorSubject;
- hasFetchedWorkspaceList$: BehaviorSubject;
+ initialized$: BehaviorSubject;
+}
+
+enum WORKSPACE_ERROR_REASON_MAP {
+ WORKSPACE_STALED = 'WORKSPACE_STALED',
}
/**
@@ -41,16 +47,45 @@ export class WorkspaceService implements CoreService('');
private workspaceList$ = new BehaviorSubject([]);
private currentWorkspace$ = new BehaviorSubject(null);
- private hasFetchedWorkspaceList$ = new BehaviorSubject(false);
+ private initialized$ = new BehaviorSubject(false);
private workspaceEnabled$ = new BehaviorSubject(false);
private _renderWorkspaceMenu: WorkspaceMenuRenderFn | null = null;
+ constructor() {
+ combineLatest([this.initialized$, this.workspaceList$, this.currentWorkspaceId$]).subscribe(
+ ([workspaceInitialized, workspaceList, currentWorkspaceId]) => {
+ if (workspaceInitialized) {
+ const currentWorkspace = workspaceList.find((w) => w && w.id === currentWorkspaceId);
+
+ /**
+ * Do a simple idempotent verification here
+ */
+ if (!isEqual(currentWorkspace, this.currentWorkspace$.getValue())) {
+ this.currentWorkspace$.next(currentWorkspace ?? null);
+ }
+
+ if (currentWorkspaceId && !currentWorkspace?.id) {
+ /**
+ * Current workspace is staled
+ */
+ this.currentWorkspaceId$.error({
+ reason: WORKSPACE_ERROR_REASON_MAP.WORKSPACE_STALED,
+ });
+ this.currentWorkspace$.error({
+ reason: WORKSPACE_ERROR_REASON_MAP.WORKSPACE_STALED,
+ });
+ }
+ }
+ }
+ );
+ }
+
public setup(): WorkspaceSetup {
return {
currentWorkspaceId$: this.currentWorkspaceId$,
currentWorkspace$: this.currentWorkspace$,
workspaceList$: this.workspaceList$,
- hasFetchedWorkspaceList$: this.hasFetchedWorkspaceList$,
+ initialized$: this.initialized$,
workspaceEnabled$: this.workspaceEnabled$,
registerWorkspaceMenuRender: (render: WorkspaceMenuRenderFn) =>
(this._renderWorkspaceMenu = render),
@@ -68,7 +103,7 @@ export class WorkspaceService implements CoreService
public async setup(core: CoreSetup, { savedObjectsManagement }: WorkspacePluginSetupDeps) {
core.workspaces.workspaceEnabled$.next(true);
core.workspaces.registerWorkspaceMenuRender(renderWorkspaceMenu);
-
+
const workspaceClient = new WorkspaceClient(core.http, core.workspaces);
- workspaceClient.init();
+ await workspaceClient.init();
/**
* Retrieve workspace id from url
diff --git a/src/plugins/workspace/public/workspace_client.ts b/src/plugins/workspace/public/workspace_client.ts
index a43624a5f076..60adc80a3d26 100644
--- a/src/plugins/workspace/public/workspace_client.ts
+++ b/src/plugins/workspace/public/workspace_client.ts
@@ -2,9 +2,6 @@
* Copyright OpenSearch Contributors
* SPDX-License-Identifier: Apache-2.0
*/
-import { combineLatest } from 'rxjs';
-import { isEqual } from 'lodash';
-
import {
HttpFetchError,
HttpFetchOptions,
@@ -16,10 +13,6 @@ import { WorkspacePermissionMode } from '../../../core/public';
const WORKSPACES_API_BASE_URL = '/api/workspaces';
-enum WORKSPACE_ERROR_REASON_MAP {
- WORKSPACE_STALED = 'WORKSPACE_STALED',
-}
-
const join = (...uriComponents: Array) =>
uriComponents
.filter((comp): comp is string => Boolean(comp))
@@ -67,57 +60,14 @@ export class WorkspaceClient {
constructor(http: HttpSetup, workspaces: WorkspaceSetup) {
this.http = http;
this.workspaces = workspaces;
-
- combineLatest([
- workspaces.hasFetchedWorkspaceList$,
- workspaces.workspaceList$,
- workspaces.currentWorkspaceId$,
- ]).subscribe(([hasFetchedWorkspaceList, workspaceList, currentWorkspaceId]) => {
- if (hasFetchedWorkspaceList) {
- const currentWorkspace = this.findWorkspace([workspaceList, currentWorkspaceId]);
-
- /**
- * Do a simple idempotent verification here
- */
- if (!isEqual(currentWorkspace, workspaces.currentWorkspace$.getValue())) {
- workspaces.currentWorkspace$.next(currentWorkspace);
- }
-
- if (currentWorkspaceId && !currentWorkspace?.id) {
- /**
- * Current workspace is staled
- */
- workspaces.currentWorkspaceId$.error({
- reason: WORKSPACE_ERROR_REASON_MAP.WORKSPACE_STALED,
- });
- workspaces.currentWorkspace$.error({
- reason: WORKSPACE_ERROR_REASON_MAP.WORKSPACE_STALED,
- });
- }
- }
- });
}
/**
* Initialize workspace list
*/
- public init() {
- this.updateWorkspaceListAndNotify();
- }
-
- private findWorkspace(payload: [WorkspaceAttribute[], string]): WorkspaceAttribute | null {
- const [workspaceList, currentWorkspaceId] = payload;
- if (!currentWorkspaceId || !workspaceList || !workspaceList.length) {
- return null;
- }
-
- const findItem = workspaceList.find((item) => item?.id === currentWorkspaceId);
-
- if (!findItem) {
- return null;
- }
-
- return findItem;
+ public async init() {
+ await this.updateWorkspaceList();
+ this.workspaces.initialized$.next(true);
}
/**
@@ -155,7 +105,7 @@ export class WorkspaceClient {
return [WORKSPACES_API_BASE_URL, join(...path)].filter((item) => item).join('/');
}
- private async updateWorkspaceListAndNotify(): Promise {
+ private async updateWorkspaceList(): Promise {
const result = await this.list({
perPage: 999,
});
@@ -163,8 +113,6 @@ export class WorkspaceClient {
if (result?.success) {
this.workspaces.workspaceList$.next(result.result.workspaces);
}
-
- this.workspaces.hasFetchedWorkspaceList$.next(true);
}
public async enterWorkspace(id: string): Promise> {
@@ -234,7 +182,7 @@ export class WorkspaceClient {
});
if (result.success) {
- this.updateWorkspaceListAndNotify();
+ this.updateWorkspaceList();
}
return result;
@@ -250,7 +198,7 @@ export class WorkspaceClient {
const result = await this.safeFetch(this.getPath([id]), { method: 'DELETE' });
if (result.success) {
- this.updateWorkspaceListAndNotify();
+ this.updateWorkspaceList();
}
return result;
@@ -325,7 +273,7 @@ export class WorkspaceClient {
});
if (result.success) {
- this.updateWorkspaceListAndNotify();
+ this.updateWorkspaceList();
}
return result;