diff --git a/src/plugins/workspace/public/plugin.test.ts b/src/plugins/workspace/public/plugin.test.ts index ab1daf0a0235..d56ebe6a1db7 100644 --- a/src/plugins/workspace/public/plugin.test.ts +++ b/src/plugins/workspace/public/plugin.test.ts @@ -189,4 +189,38 @@ describe('Workspace plugin', () => { workspacePlugin.start(startMock); expect(startMock.chrome.setBreadcrumbs).not.toHaveBeenCalled(); }); + + it('#start should call navGroupUpdater$.next after currentWorkspace set', async () => { + const workspacePlugin = new WorkspacePlugin(); + const setupMock = getSetupMock(); + const coreStart = coreMock.createStart(); + await workspacePlugin.setup(setupMock, {}); + + expect(setupMock.chrome.navGroup.registerNavGroupUpdater).toHaveBeenCalled(); + const navGroupUpdater$ = setupMock.chrome.navGroup.registerNavGroupUpdater.mock.calls[0][0]; + + expect(navGroupUpdater$).toBeTruthy(); + jest.spyOn(navGroupUpdater$, 'next'); + + expect(navGroupUpdater$.next).not.toHaveBeenCalled(); + workspacePlugin.start(coreStart); + + waitFor(() => { + expect(navGroupUpdater$.next).toHaveBeenCalled(); + }); + }); + + it('#stop should call unregisterNavGroupUpdater', async () => { + const workspacePlugin = new WorkspacePlugin(); + const setupMock = getSetupMock(); + const unregisterNavGroupUpdater = jest.fn(); + setupMock.chrome.navGroup.registerNavGroupUpdater.mockReturnValueOnce( + unregisterNavGroupUpdater + ); + await workspacePlugin.setup(setupMock, {}); + + workspacePlugin.stop(); + + expect(unregisterNavGroupUpdater).toHaveBeenCalled(); + }); }); diff --git a/src/plugins/workspace/public/plugin.ts b/src/plugins/workspace/public/plugin.ts index 969459e188ee..146b95582482 100644 --- a/src/plugins/workspace/public/plugin.ts +++ b/src/plugins/workspace/public/plugin.ts @@ -18,6 +18,8 @@ import { PublicAppInfo, ChromeBreadcrumb, WorkspaceAvailability, + ChromeNavGroupUpdater, + NavGroupStatus, } from '../../../core/public'; import { WORKSPACE_FATAL_ERROR_APP_ID, @@ -33,7 +35,11 @@ import { SavedObjectsManagementPluginSetup } from '../../../plugins/saved_object import { ManagementSetup } from '../../../plugins/management/public'; import { WorkspaceMenu } from './components/workspace_menu/workspace_menu'; import { getWorkspaceColumn } from './components/workspace_column'; -import { filterWorkspaceConfigurableApps, isAppAccessibleInWorkspace } from './utils'; +import { + filterWorkspaceConfigurableApps, + isAppAccessibleInWorkspace, + isNavGroupInFeatureConfigs, +} from './utils'; type WorkspaceAppType = ( params: AppMountParameters, @@ -53,7 +59,10 @@ export class WorkspacePlugin implements Plugin<{}, {}, WorkspacePluginSetupDeps> private currentWorkspaceIdSubscription?: Subscription; private managementCurrentWorkspaceIdSubscription?: Subscription; private appUpdater$ = new BehaviorSubject(() => undefined); + private navGroupUpdater$ = new BehaviorSubject(() => undefined); private workspaceConfigurableApps$ = new BehaviorSubject([]); + private unregisterNavGroupUpdater?: () => void; + private _changeSavedObjectCurrentWorkspace() { if (this.coreStart) { return this.coreStart.workspaces.currentWorkspaceId$.subscribe((currentWorkspaceId) => { @@ -89,6 +98,17 @@ export class WorkspacePlugin implements Plugin<{}, {}, WorkspacePluginSetupDeps> */ return { status: AppStatus.inaccessible }; }); + + this.navGroupUpdater$.next((navGroup) => { + if ( + currentWorkspace.features && + !isNavGroupInFeatureConfigs(navGroup.id, currentWorkspace.features) + ) { + return { + status: NavGroupStatus.Hidden, + }; + } + }); } }); }; @@ -166,6 +186,9 @@ export class WorkspacePlugin implements Plugin<{}, {}, WorkspacePluginSetupDeps> const workspaceClient = new WorkspaceClient(core.http, core.workspaces); await workspaceClient.init(); core.application.registerAppUpdater(this.appUpdater$); + this.unregisterNavGroupUpdater = core.chrome.navGroup.registerNavGroupUpdater( + this.navGroupUpdater$ + ); // Hide advance settings and dataSource menus and disable in setup if (management) { @@ -331,5 +354,6 @@ export class WorkspacePlugin implements Plugin<{}, {}, WorkspacePluginSetupDeps> this.currentWorkspaceIdSubscription?.unsubscribe(); this.managementCurrentWorkspaceIdSubscription?.unsubscribe(); this.breadcrumbsSubscription?.unsubscribe(); + this.unregisterNavGroupUpdater?.(); } } diff --git a/src/plugins/workspace/public/utils.test.ts b/src/plugins/workspace/public/utils.test.ts index 70eb91cfbdda..6ca878ec51dd 100644 --- a/src/plugins/workspace/public/utils.test.ts +++ b/src/plugins/workspace/public/utils.test.ts @@ -9,6 +9,7 @@ import { filterWorkspaceConfigurableApps, isAppAccessibleInWorkspace, isFeatureIdInsideUseCase, + isNavGroupInFeatureConfigs, } from './utils'; import { WorkspaceAvailability } from '../../../core/public'; @@ -276,3 +277,19 @@ describe('workspace utils: isFeatureIdInsideUseCase', () => { expect(isFeatureIdInsideUseCase('discover', 'use-case-invalid')).toBe(false); }); }); + +describe('workspace utils: isNavGroupInFeatureConfigs', () => { + it('should return false if nav group not in feature configs', () => { + expect( + isNavGroupInFeatureConfigs('dataAdministration', [ + 'use-case-observability', + 'use-case-search', + ]) + ).toBe(false); + }); + it('should return true if nav group in feature configs', () => { + expect( + isNavGroupInFeatureConfigs('observability', ['use-case-observability', 'use-case-search']) + ).toBe(true); + }); +}); diff --git a/src/plugins/workspace/public/utils.ts b/src/plugins/workspace/public/utils.ts index eaf96c80a4df..ce77d8370d5f 100644 --- a/src/plugins/workspace/public/utils.ts +++ b/src/plugins/workspace/public/utils.ts @@ -41,6 +41,9 @@ export const isFeatureIdInsideUseCase = (featureId: string, featureConfig: strin return false; }; +export const isNavGroupInFeatureConfigs = (navGroupId: string, featureConfigs: string[]) => + featureConfigs.includes(getUseCaseFeatureConfig(navGroupId)); + /** * Checks if a given feature matches the provided feature configuration. *