diff --git a/src/core/public/chrome/chrome_service.tsx b/src/core/public/chrome/chrome_service.tsx index 97746f465abc..6b33b77a6f74 100644 --- a/src/core/public/chrome/chrome_service.tsx +++ b/src/core/public/chrome/chrome_service.tsx @@ -48,7 +48,7 @@ import { ChromeNavLinks, NavLinksService, ChromeNavLink } from './nav_links'; import { ChromeRecentlyAccessed, RecentlyAccessedService } from './recently_accessed'; import { Header } from './ui'; import { ChromeHelpExtensionMenuLink } from './ui/header/header_help_menu'; -import { Branding } from '../'; +import { Branding, WorkspacesStart } from '../'; export { ChromeNavControls, ChromeRecentlyAccessed, ChromeDocTitle }; const IS_LOCKED_KEY = 'core.chrome.isLocked'; @@ -99,6 +99,7 @@ interface StartDeps { injectedMetadata: InjectedMetadataStart; notifications: NotificationsStart; uiSettings: IUiSettingsClient; + workspaces: WorkspacesStart; } /** @internal */ @@ -152,6 +153,7 @@ export class ChromeService { injectedMetadata, notifications, uiSettings, + workspaces, }: StartDeps): Promise { this.initVisibility(application); @@ -262,6 +264,7 @@ export class ChromeService { isLocked$={getIsNavDrawerLocked$} branding={injectedMetadata.getBranding()} survey={injectedMetadata.getSurvey()} + currentWorkspace$={workspaces.client.currentWorkspace$} /> ), diff --git a/src/core/public/chrome/ui/header/collapsible_nav.tsx b/src/core/public/chrome/ui/header/collapsible_nav.tsx index 51d43d96f7fd..549f13997f79 100644 --- a/src/core/public/chrome/ui/header/collapsible_nav.tsx +++ b/src/core/public/chrome/ui/header/collapsible_nav.tsx @@ -51,6 +51,7 @@ import { HttpStart } from '../../../http'; import { OnIsLockedUpdate } from './'; import { createEuiListItem, createRecentNavLink, isModifiedOrPrevented } from './nav_link'; import { ChromeBranding } from '../../chrome_service'; +import { WorkspaceAttribute } from '../../../workspace'; function getAllCategories(allCategorizedLinks: Record) { const allCategories = {} as Record; @@ -102,6 +103,7 @@ interface Props { navigateToUrl: InternalApplicationStart['navigateToUrl']; customNavLink$: Rx.Observable; branding: ChromeBranding; + currentWorkspace$: Rx.BehaviorSubject; } export function CollapsibleNav({ @@ -122,11 +124,14 @@ export function CollapsibleNav({ const recentlyAccessed = useObservable(observables.recentlyAccessed$, []); const customNavLink = useObservable(observables.customNavLink$, undefined); const appId = useObservable(observables.appId$, ''); + const currentWorkspace = useObservable(observables.currentWorkspace$); const lockRef = useRef(null); const groupedNavLinks = groupBy(navLinks, (link) => link?.category?.id); const { undefined: unknowns = [], ...allCategorizedLinks } = groupedNavLinks; - const categoryDictionary = getAllCategories(allCategorizedLinks); - const orderedCategories = getOrderedCategories(allCategorizedLinks, categoryDictionary); + const filterdLinks = getFilterLinks(currentWorkspace, allCategorizedLinks); + const categoryDictionary = getAllCategories(filterdLinks); + const orderedCategories = getOrderedCategories(filterdLinks, categoryDictionary); + const readyForEUI = (link: ChromeNavLink, needsIcon: boolean = false) => { return createEuiListItem({ link, @@ -145,6 +150,24 @@ export function CollapsibleNav({ const markDefault = branding.mark?.defaultUrl; const markDarkMode = branding.mark?.darkModeUrl; + function getFilterLinks( + workspace: WorkspaceAttribute | null | undefined, + categorizedLinks: Record + ) { + // plugins are in this dictionary + const pluginsDictionary = categorizedLinks.opensearch; + if (!pluginsDictionary) return categorizedLinks; + + const features = workspace?.features ?? []; + const newPluginsDictionary = pluginsDictionary.filter((item) => features.indexOf(item.id) > -1); + if (newPluginsDictionary.length === 0) { + delete categorizedLinks.opensearch; + } else { + categorizedLinks.opensearch = newPluginsDictionary; + } + return categorizedLinks; + } + /** * Use branding configurations to check which URL to use for rendering * side menu opensearch logo in default mode diff --git a/src/core/public/chrome/ui/header/header.tsx b/src/core/public/chrome/ui/header/header.tsx index a78371f4f264..a2b218ae4087 100644 --- a/src/core/public/chrome/ui/header/header.tsx +++ b/src/core/public/chrome/ui/header/header.tsx @@ -42,7 +42,7 @@ import { i18n } from '@osd/i18n'; import classnames from 'classnames'; import React, { createRef, useState } from 'react'; import useObservable from 'react-use/lib/useObservable'; -import { Observable } from 'rxjs'; +import { Observable, BehaviorSubject } from 'rxjs'; import { LoadingIndicator } from '../'; import { ChromeBadge, @@ -63,6 +63,7 @@ import { HomeLoader } from './home_loader'; import { HeaderNavControls } from './header_nav_controls'; import { HeaderActionMenu } from './header_action_menu'; import { HeaderLogo } from './header_logo'; +import { WorkspaceAttribute } from '../../../workspace'; export interface HeaderProps { opensearchDashboardsVersion: string; @@ -90,6 +91,7 @@ export interface HeaderProps { onIsLockedUpdate: OnIsLockedUpdate; branding: ChromeBranding; survey: string | undefined; + currentWorkspace$: BehaviorSubject; } export function Header({ @@ -255,6 +257,7 @@ export function Header({ }} customNavLink$={observables.customNavLink$} branding={branding} + currentWorkspace$={observables.currentWorkspace$} /> diff --git a/src/core/public/core_system.ts b/src/core/public/core_system.ts index 1c0286cbd03c..9512560112f7 100644 --- a/src/core/public/core_system.ts +++ b/src/core/public/core_system.ts @@ -233,6 +233,7 @@ export class CoreSystem { injectedMetadata, notifications, uiSettings, + workspaces, }); this.coreApp.start({ application, http, notifications, uiSettings });