From 53e64547e1bfe7cf3b70b85820f06618efde9f20 Mon Sep 17 00:00:00 2001 From: tygao Date: Wed, 14 Jun 2023 16:46:14 +0800 Subject: [PATCH 1/3] feat: init workspace menu stage 1 Signed-off-by: tygao --- src/core/public/chrome/chrome_service.tsx | 5 ++++- .../public/chrome/ui/header/collapsible_nav.tsx | 17 +++++++++++++++-- src/core/public/chrome/ui/header/header.tsx | 3 +++ src/core/public/core_system.ts | 1 + src/core/server/dev/dev_config.ts | 2 +- 5 files changed, 24 insertions(+), 4 deletions(-) diff --git a/src/core/public/chrome/chrome_service.tsx b/src/core/public/chrome/chrome_service.tsx index 97746f465abc..321f4db06958 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()} + workspaces={workspaces} /> ), diff --git a/src/core/public/chrome/ui/header/collapsible_nav.tsx b/src/core/public/chrome/ui/header/collapsible_nav.tsx index 51d43d96f7fd..df7a42874ed3 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 { WorkspacesStart } from '../../../workspace'; function getAllCategories(allCategorizedLinks: Record) { const allCategories = {} as Record; @@ -102,6 +103,7 @@ interface Props { navigateToUrl: InternalApplicationStart['navigateToUrl']; customNavLink$: Rx.Observable; branding: ChromeBranding; + workspaces: WorkspacesStart; } export function CollapsibleNav({ @@ -116,6 +118,7 @@ export function CollapsibleNav({ navigateToApp, navigateToUrl, branding, + workspaces, ...observables }: Props) { const navLinks = useObservable(observables.navLinks$, []).filter((link) => !link.hidden); @@ -125,8 +128,9 @@ export function CollapsibleNav({ 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 = filterLinks(allCategorizedLinks); + const categoryDictionary = getAllCategories(filterdLinks); + const orderedCategories = getOrderedCategories(filterdLinks, categoryDictionary); const readyForEUI = (link: ChromeNavLink, needsIcon: boolean = false) => { return createEuiListItem({ link, @@ -145,6 +149,15 @@ export function CollapsibleNav({ const markDefault = branding.mark?.defaultUrl; const markDarkMode = branding.mark?.darkModeUrl; + function filterLinks(links: Record) { + return links; + // TODO: features is an array of string, wait specific and real data to do integration + // const data = await workspaces.client.getCurrentWorkspace(); + // if (data.success) { + // const result = data.result.features; + // } + } + /** * 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..c07af860b582 100644 --- a/src/core/public/chrome/ui/header/header.tsx +++ b/src/core/public/chrome/ui/header/header.tsx @@ -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 { WorkspacesStart } from '../../../workspace'; export interface HeaderProps { opensearchDashboardsVersion: string; @@ -90,6 +91,7 @@ export interface HeaderProps { onIsLockedUpdate: OnIsLockedUpdate; branding: ChromeBranding; survey: string | undefined; + workspaces: WorkspacesStart; } export function Header({ @@ -255,6 +257,7 @@ export function Header({ }} customNavLink$={observables.customNavLink$} branding={branding} + workspaces={observables.workspaces} /> 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 }); diff --git a/src/core/server/dev/dev_config.ts b/src/core/server/dev/dev_config.ts index 26e410076d8f..ac64d69abe51 100644 --- a/src/core/server/dev/dev_config.ts +++ b/src/core/server/dev/dev_config.ts @@ -34,7 +34,7 @@ export const config = { path: 'dev', schema: schema.object({ basePathProxyTarget: schema.number({ - defaultValue: 5603, + defaultValue: 6603, }), }), }; From ec1e486c7cf89a4d1005d7f2c443602716d397ca Mon Sep 17 00:00:00 2001 From: tygao Date: Wed, 14 Jun 2023 19:57:35 +0800 Subject: [PATCH 2/3] fix: remove port diff Signed-off-by: tygao --- src/core/server/dev/dev_config.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/server/dev/dev_config.ts b/src/core/server/dev/dev_config.ts index ac64d69abe51..26e410076d8f 100644 --- a/src/core/server/dev/dev_config.ts +++ b/src/core/server/dev/dev_config.ts @@ -34,7 +34,7 @@ export const config = { path: 'dev', schema: schema.object({ basePathProxyTarget: schema.number({ - defaultValue: 6603, + defaultValue: 5603, }), }), }; From 594a8cdd4b3008aa86f959321f80dd023b75fb7a Mon Sep 17 00:00:00 2001 From: tygao Date: Fri, 16 Jun 2023 11:58:35 +0800 Subject: [PATCH 3/3] feat: update menu logic Signed-off-by: tygao --- src/core/public/chrome/chrome_service.tsx | 2 +- .../chrome/ui/header/collapsible_nav.tsx | 32 ++++++++++++------- src/core/public/chrome/ui/header/header.tsx | 8 ++--- 3 files changed, 26 insertions(+), 16 deletions(-) diff --git a/src/core/public/chrome/chrome_service.tsx b/src/core/public/chrome/chrome_service.tsx index 321f4db06958..6b33b77a6f74 100644 --- a/src/core/public/chrome/chrome_service.tsx +++ b/src/core/public/chrome/chrome_service.tsx @@ -264,7 +264,7 @@ export class ChromeService { isLocked$={getIsNavDrawerLocked$} branding={injectedMetadata.getBranding()} survey={injectedMetadata.getSurvey()} - workspaces={workspaces} + 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 df7a42874ed3..549f13997f79 100644 --- a/src/core/public/chrome/ui/header/collapsible_nav.tsx +++ b/src/core/public/chrome/ui/header/collapsible_nav.tsx @@ -51,7 +51,7 @@ import { HttpStart } from '../../../http'; import { OnIsLockedUpdate } from './'; import { createEuiListItem, createRecentNavLink, isModifiedOrPrevented } from './nav_link'; import { ChromeBranding } from '../../chrome_service'; -import { WorkspacesStart } from '../../../workspace'; +import { WorkspaceAttribute } from '../../../workspace'; function getAllCategories(allCategorizedLinks: Record) { const allCategories = {} as Record; @@ -103,7 +103,7 @@ interface Props { navigateToUrl: InternalApplicationStart['navigateToUrl']; customNavLink$: Rx.Observable; branding: ChromeBranding; - workspaces: WorkspacesStart; + currentWorkspace$: Rx.BehaviorSubject; } export function CollapsibleNav({ @@ -118,19 +118,20 @@ export function CollapsibleNav({ navigateToApp, navigateToUrl, branding, - workspaces, ...observables }: Props) { const navLinks = useObservable(observables.navLinks$, []).filter((link) => !link.hidden); 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 filterdLinks = filterLinks(allCategorizedLinks); + const filterdLinks = getFilterLinks(currentWorkspace, allCategorizedLinks); const categoryDictionary = getAllCategories(filterdLinks); const orderedCategories = getOrderedCategories(filterdLinks, categoryDictionary); + const readyForEUI = (link: ChromeNavLink, needsIcon: boolean = false) => { return createEuiListItem({ link, @@ -149,13 +150,22 @@ export function CollapsibleNav({ const markDefault = branding.mark?.defaultUrl; const markDarkMode = branding.mark?.darkModeUrl; - function filterLinks(links: Record) { - return links; - // TODO: features is an array of string, wait specific and real data to do integration - // const data = await workspaces.client.getCurrentWorkspace(); - // if (data.success) { - // const result = data.result.features; - // } + 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; } /** diff --git a/src/core/public/chrome/ui/header/header.tsx b/src/core/public/chrome/ui/header/header.tsx index c07af860b582..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,7 +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 { WorkspacesStart } from '../../../workspace'; +import { WorkspaceAttribute } from '../../../workspace'; export interface HeaderProps { opensearchDashboardsVersion: string; @@ -91,7 +91,7 @@ export interface HeaderProps { onIsLockedUpdate: OnIsLockedUpdate; branding: ChromeBranding; survey: string | undefined; - workspaces: WorkspacesStart; + currentWorkspace$: BehaviorSubject; } export function Header({ @@ -257,7 +257,7 @@ export function Header({ }} customNavLink$={observables.customNavLink$} branding={branding} - workspaces={observables.workspaces} + currentWorkspace$={observables.currentWorkspace$} />