diff --git a/src/core/public/fatal_errors/fatal_errors_service.mock.ts b/src/core/public/fatal_errors/fatal_errors_service.mock.ts index 5079fc8f4b6a..e495d66ae568 100644 --- a/src/core/public/fatal_errors/fatal_errors_service.mock.ts +++ b/src/core/public/fatal_errors/fatal_errors_service.mock.ts @@ -30,7 +30,7 @@ import type { PublicMethodsOf } from '@osd/utility-types'; import { FatalErrorsService, FatalErrorsSetup } from './fatal_errors_service'; -import { BehaviorSubject, Subject } from 'rxjs'; +import { BehaviorSubject } from 'rxjs'; import { WorkspaceAttribute } from '../workspace'; const createSetupContractMock = () => { @@ -62,12 +62,14 @@ export const fatalErrorsServiceMock = { }; const currentWorkspaceId$ = new BehaviorSubject(''); -const workspaceList$ = new Subject(); +const workspaceList$ = new BehaviorSubject([]); +const currentWorkspace$ = new BehaviorSubject(null); const createWorkspacesSetupContractMock = () => ({ client: { currentWorkspaceId$, workspaceList$, + currentWorkspace$, stop: jest.fn(), enterWorkspace: jest.fn(), exitWorkspace: jest.fn(), diff --git a/src/core/public/workspace/workspaces_client.ts b/src/core/public/workspace/workspaces_client.ts index 91d83dd1639f..f37fd89ae249 100644 --- a/src/core/public/workspace/workspaces_client.ts +++ b/src/core/public/workspace/workspaces_client.ts @@ -3,7 +3,8 @@ * SPDX-License-Identifier: Apache-2.0 */ import type { PublicContract } from '@osd/utility-types'; -import { BehaviorSubject } from 'rxjs'; +import { BehaviorSubject, combineLatest } from 'rxjs'; +import { isEqual } from 'lodash'; import { HttpFetchError, HttpFetchOptions, HttpSetup } from '../http'; import { WorkspaceAttribute, WorkspaceFindOptions } from '.'; import { WORKSPACES_API_BASE_URL, WORKSPACE_ERROR_REASON_MAP } from './consts'; @@ -41,26 +42,34 @@ export class WorkspacesClient { private http: HttpSetup; public currentWorkspaceId$ = new BehaviorSubject(''); public workspaceList$ = new BehaviorSubject([]); + public currentWorkspace$ = new BehaviorSubject(null); constructor(http: HttpSetup) { this.http = http; - /** - * Add logic to check if current workspace id is still valid - * If not, remove the current workspace id and notify other subscribers - */ - this.workspaceList$.subscribe(async (workspaceList) => { - const currentWorkspaceId = this.currentWorkspaceId$.getValue(); - if (currentWorkspaceId) { - const findItem = workspaceList.find((item) => item.id === currentWorkspaceId); - if (!findItem) { + + combineLatest([this.workspaceList$, this.currentWorkspaceId$]).subscribe( + ([workspaceList, currentWorkspaceId]) => { + const currentWorkspace = this.findWorkspace([workspaceList, currentWorkspaceId]); + + /** + * Do a simple idempotent verification here + */ + if (!isEqual(currentWorkspace, this.currentWorkspace$.getValue())) { + this.currentWorkspace$.next(currentWorkspace); + } + + 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, + }); } } - }); + ); /** * Initialize workspace list @@ -68,6 +77,21 @@ export class WorkspacesClient { 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; + } + /** * Add a non-throw-error fetch method for internal use. */