diff --git a/packages/core/chrome/core-chrome-browser-internal/src/chrome_service.tsx b/packages/core/chrome/core-chrome-browser-internal/src/chrome_service.tsx index 5d86209ec8800..434639b07efdf 100644 --- a/packages/core/chrome/core-chrome-browser-internal/src/chrome_service.tsx +++ b/packages/core/chrome/core-chrome-browser-internal/src/chrome_service.tsx @@ -36,6 +36,7 @@ import type { ChromeSetProjectBreadcrumbsParams, NavigationTreeDefinition, AppDeepLinkId, + SolutionId, } from '@kbn/core-chrome-browser'; import type { CustomBrandingStart } from '@kbn/core-custom-branding-browser'; import type { @@ -343,7 +344,10 @@ export class ChromeService { LinkId extends AppDeepLinkId = AppDeepLinkId, Id extends string = string, ChildrenId extends string = Id - >(id: string, navigationTree$: Observable>) { + >( + id: SolutionId, + navigationTree$: Observable> + ) { validateChromeStyle(); projectNavigation.initNavigation(id, navigationTree$); } diff --git a/packages/core/chrome/core-chrome-browser-internal/src/project_navigation/project_navigation_service.test.ts b/packages/core/chrome/core-chrome-browser-internal/src/project_navigation/project_navigation_service.test.ts index d1be94aad246a..124b44e80e30f 100644 --- a/packages/core/chrome/core-chrome-browser-internal/src/project_navigation/project_navigation_service.test.ts +++ b/packages/core/chrome/core-chrome-browser-internal/src/project_navigation/project_navigation_service.test.ts @@ -110,7 +110,7 @@ describe('initNavigation()', () => { beforeAll(() => { projectNavigation.initNavigation( - 'foo', + 'es', of({ body: [ { @@ -185,7 +185,7 @@ describe('initNavigation()', () => { const { projectNavigation: projNavigation, getNavigationTree: getNavTree } = setupInitNavigation(); projNavigation.initNavigation( - 'foo', + 'es', of({ body: [ { @@ -210,7 +210,7 @@ describe('initNavigation()', () => { const { projectNavigation: projNavigation } = setupInitNavigation(); projNavigation.initNavigation( - 'foo', + 'es', of({ body: [ { @@ -399,7 +399,7 @@ describe('initNavigation()', () => { // 2. initNavigation() is called projectNavigation.initNavigation( - 'foo', + 'es', of({ body: [ { @@ -427,7 +427,7 @@ describe('initNavigation()', () => { }); projectNavigation.initNavigation( - 'foo', + 'es', // @ts-expect-error - We pass a non valid cloudLink that is not TS valid of({ body: [ @@ -533,7 +533,7 @@ describe('breadcrumbs', () => { const obs = subj.asObservable(); if (initiateNavigation) { - projectNavigation.initNavigation('foo', obs); + projectNavigation.initNavigation('es', obs); } return { @@ -740,7 +740,7 @@ describe('breadcrumbs', () => { { text: 'custom1', href: '/custom1' }, { text: 'custom2', href: '/custom1/custom2' }, ]); - projectNavigation.initNavigation('foo', of(mockNavigation)); // init navigation + projectNavigation.initNavigation('es', of(mockNavigation)); // init navigation const breadcrumbs = await firstValueFrom(projectNavigation.getProjectBreadcrumbs$()); expect(breadcrumbs).toHaveLength(4); @@ -779,7 +779,7 @@ describe('getActiveNodes$()', () => { expect(activeNodes).toEqual([]); projectNavigation.initNavigation( - 'foo', + 'es', of({ body: [ { @@ -835,7 +835,7 @@ describe('getActiveNodes$()', () => { expect(activeNodes).toEqual([]); projectNavigation.initNavigation( - 'foo', + 'es', of({ body: [ { @@ -889,7 +889,7 @@ describe('getActiveNodes$()', () => { describe('solution navigations', () => { const solution1: SolutionNavigationDefinition = { - id: 'solution1', + id: 'es', title: 'Solution 1', icon: 'logoSolution1', homePage: 'discover', @@ -897,7 +897,7 @@ describe('solution navigations', () => { }; const solution2: SolutionNavigationDefinition = { - id: 'solution2', + id: 'oblt', title: 'Solution 2', icon: 'logoSolution2', homePage: 'app2', @@ -906,7 +906,7 @@ describe('solution navigations', () => { }; const solution3: SolutionNavigationDefinition = { - id: 'solution3', + id: 'security', title: 'Solution 3', icon: 'logoSolution3', homePage: 'discover', @@ -943,30 +943,30 @@ describe('solution navigations', () => { } { - projectNavigation.updateSolutionNavigations({ 1: solution1, 2: solution2 }); + projectNavigation.updateSolutionNavigations({ es: solution1, oblt: solution2 }); const solutionNavs = await lastValueFrom( projectNavigation.getSolutionsNavDefinitions$().pipe(take(1)) ); - expect(solutionNavs).toEqual({ 1: solution1, 2: solution2 }); + expect(solutionNavs).toEqual({ es: solution1, oblt: solution2 }); } { // Test partial update - projectNavigation.updateSolutionNavigations({ 3: solution3 }, false); + projectNavigation.updateSolutionNavigations({ security: solution3 }, false); const solutionNavs = await lastValueFrom( projectNavigation.getSolutionsNavDefinitions$().pipe(take(1)) ); - expect(solutionNavs).toEqual({ 1: solution1, 2: solution2, 3: solution3 }); + expect(solutionNavs).toEqual({ es: solution1, oblt: solution2, security: solution3 }); } { // Test full replacement - projectNavigation.updateSolutionNavigations({ 4: solution3 }, true); + projectNavigation.updateSolutionNavigations({ security: solution3 }, true); const solutionNavs = await lastValueFrom( projectNavigation.getSolutionsNavDefinitions$().pipe(take(1)) ); - expect(solutionNavs).toEqual({ 4: solution3 }); + expect(solutionNavs).toEqual({ security: solution3 }); } }); @@ -980,8 +980,8 @@ describe('solution navigations', () => { expect(activeSolution).toBeNull(); } - projectNavigation.changeActiveSolutionNavigation('2'); // Set **before** the navs are registered - projectNavigation.updateSolutionNavigations({ 1: solution1, 2: solution2 }); + projectNavigation.changeActiveSolutionNavigation('oblt'); // Set **before** the navs are registered + projectNavigation.updateSolutionNavigations({ es: solution1, oblt: solution2 }); { const activeSolution = await lastValueFrom( @@ -994,7 +994,7 @@ describe('solution navigations', () => { expect(activeSolution).toEqual(rest); } - projectNavigation.changeActiveSolutionNavigation('1'); // Set **after** the navs are registered + projectNavigation.changeActiveSolutionNavigation('es'); // Set **after** the navs are registered { const activeSolution = await lastValueFrom( @@ -1027,7 +1027,7 @@ describe('solution navigations', () => { { const fooSolution: SolutionNavigationDefinition = { - id: 'fooSolution', + id: 'es', title: 'Foo solution', icon: 'logoSolution', homePage: 'discover', @@ -1053,8 +1053,8 @@ describe('solution navigations', () => { }), }; - projectNavigation.changeActiveSolutionNavigation('foo'); - projectNavigation.updateSolutionNavigations({ foo: fooSolution }); + projectNavigation.changeActiveSolutionNavigation('es'); + projectNavigation.updateSolutionNavigations({ es: fooSolution }); projectNavigation.setPanelSelectedNode('link2'); // Set the selected node using its id diff --git a/packages/core/chrome/core-chrome-browser-internal/src/project_navigation/project_navigation_service.ts b/packages/core/chrome/core-chrome-browser-internal/src/project_navigation/project_navigation_service.ts index 85c3fd1905adb..7960d9f710c90 100644 --- a/packages/core/chrome/core-chrome-browser-internal/src/project_navigation/project_navigation_service.ts +++ b/packages/core/chrome/core-chrome-browser-internal/src/project_navigation/project_navigation_service.ts @@ -17,6 +17,7 @@ import type { NavigationTreeDefinition, SolutionNavigationDefinitions, CloudLinks, + SolutionId, } from '@kbn/core-chrome-browser'; import type { InternalHttpStart } from '@kbn/core-http-browser-internal'; import { @@ -86,9 +87,9 @@ export class ProjectNavigationService { private readonly solutionNavDefinitions$ = new BehaviorSubject({}); // As the active definition **id** and the definitions are set independently, one before the other without // any guarantee of order, we need to store the next active definition id in a separate BehaviorSubject - private readonly nextSolutionNavDefinitionId$ = new BehaviorSubject(null); + private readonly nextSolutionNavDefinitionId$ = new BehaviorSubject(null); // The active solution navigation definition id that has been initiated and is currently active - private readonly activeSolutionNavDefinitionId$ = new BehaviorSubject(null); + private readonly activeSolutionNavDefinitionId$ = new BehaviorSubject(null); private readonly location$ = new BehaviorSubject(createLocation('/')); private deepLinksMap$: Observable> = of({}); private cloudLinks$ = new BehaviorSubject({}); @@ -138,7 +139,7 @@ export class ProjectNavigationService { return this.projectName$.asObservable(); }, initNavigation: ( - id: string, + id: SolutionId, navTreeDefinition$: Observable> ) => { this.initNavigation(id, navTreeDefinition$); @@ -202,7 +203,7 @@ export class ProjectNavigationService { * @param id Id for the navigation tree definition * @param navTreeDefinition$ The navigation tree definition */ - private initNavigation(id: string, navTreeDefinition$: Observable) { + private initNavigation(id: SolutionId, navTreeDefinition$: Observable) { if (this.activeSolutionNavDefinitionId$.getValue() === id) return; if (this.navigationChangeSubscription) { @@ -220,7 +221,7 @@ export class ProjectNavigationService { .pipe( takeUntil(this.stop$), map(([def, deepLinksMap, cloudLinks]) => { - return parseNavigationTree(def, { + return parseNavigationTree(id, def, { deepLinks: deepLinksMap, cloudLinks, }); @@ -382,7 +383,7 @@ export class ProjectNavigationService { this.projectHome$.next(homeHref); } - private changeActiveSolutionNavigation(id: string | null) { + private changeActiveSolutionNavigation(id: SolutionId | null) { if (this.nextSolutionNavDefinitionId$.getValue() === id) return; this.nextSolutionNavDefinitionId$.next(id); } @@ -400,7 +401,7 @@ export class ProjectNavigationService { if (!definitions[id]) return null; // We strip out the sideNavComponent from the definition as it should only be used internally - const { sideNavComponent, ...definition } = definitions[id]; + const { sideNavComponent, ...definition } = definitions[id]!; return definition; }) ); diff --git a/packages/core/chrome/core-chrome-browser-internal/src/project_navigation/utils.ts b/packages/core/chrome/core-chrome-browser-internal/src/project_navigation/utils.ts index 9a45290c95389..bdf3929c464dc 100644 --- a/packages/core/chrome/core-chrome-browser-internal/src/project_navigation/utils.ts +++ b/packages/core/chrome/core-chrome-browser-internal/src/project_navigation/utils.ts @@ -22,6 +22,7 @@ import type { CloudLinkId, CloudLinks, ItemDefinition, + SolutionId, } from '@kbn/core-chrome-browser/src'; import type { Location } from 'history'; import type { MouseEventHandler } from 'react'; @@ -364,6 +365,7 @@ const isRecentlyAccessedDefinition = ( }; export const parseNavigationTree = ( + id: SolutionId, navigationTreeDef: NavigationTreeDefinition, { deepLinks, cloudLinks }: { deepLinks: Record; cloudLinks: CloudLinks } ): { @@ -376,7 +378,7 @@ export const parseNavigationTree = ( const navigationTree: ChromeProjectNavigationNode[] = []; // Contains UI layout information (body, footer) and render "special" blocks like recently accessed. - const navigationTreeUI: NavigationTreeDefinitionUI = { body: [] }; + const navigationTreeUI: NavigationTreeDefinitionUI = { id, body: [] }; const initNodeAndChildren = ( node: GroupDefinition | ItemDefinition | NodeDefinition, diff --git a/packages/core/chrome/core-chrome-browser-internal/src/types.ts b/packages/core/chrome/core-chrome-browser-internal/src/types.ts index 0e6bec4d2678c..36a247e22f847 100644 --- a/packages/core/chrome/core-chrome-browser-internal/src/types.ts +++ b/packages/core/chrome/core-chrome-browser-internal/src/types.ts @@ -18,6 +18,7 @@ import type { NavigationTreeDefinitionUI, CloudURLs, SolutionNavigationDefinitions, + SolutionId, } from '@kbn/core-chrome-browser'; import type { Observable } from 'rxjs'; @@ -66,7 +67,7 @@ export interface InternalChromeStart extends ChromeStart { Id extends string = string, ChildrenId extends string = Id >( - id: string, + id: SolutionId, navigationTree$: Observable> ): void; @@ -117,6 +118,6 @@ export interface InternalChromeStart extends ChromeStart { * @param id The id of the active solution navigation. If `null` is provided, the solution navigation * will be replaced with the legacy Kibana navigation. */ - changeActiveSolutionNavigation(id: string | null): void; + changeActiveSolutionNavigation(id: SolutionId | null): void; }; } diff --git a/packages/core/chrome/core-chrome-browser/index.ts b/packages/core/chrome/core-chrome-browser/index.ts index afb2050d12e80..7b8658791340f 100644 --- a/packages/core/chrome/core-chrome-browser/index.ts +++ b/packages/core/chrome/core-chrome-browser/index.ts @@ -60,4 +60,5 @@ export type { SolutionNavigationDefinitions, EuiSideNavItemTypeEnhanced, RenderAs, + SolutionId, } from './src'; diff --git a/packages/core/chrome/core-chrome-browser/src/index.ts b/packages/core/chrome/core-chrome-browser/src/index.ts index efc2fb5636d84..efc709ff512da 100644 --- a/packages/core/chrome/core-chrome-browser/src/index.ts +++ b/packages/core/chrome/core-chrome-browser/src/index.ts @@ -38,6 +38,7 @@ export type { PanelSelectedNode, AppDeepLinkId, AppId, + SolutionId, CloudLinkId, CloudLink, CloudLinks, diff --git a/packages/core/chrome/core-chrome-browser/src/project_navigation.ts b/packages/core/chrome/core-chrome-browser/src/project_navigation.ts index 3e6afeb8f6117..f4a5af26c4176 100644 --- a/packages/core/chrome/core-chrome-browser/src/project_navigation.ts +++ b/packages/core/chrome/core-chrome-browser/src/project_navigation.ts @@ -42,6 +42,8 @@ import type { AppId as SharedApp, DeepLinkId as SharedLink } from '@kbn/deeplink import type { ChromeNavLink } from './nav_links'; import type { ChromeRecentlyAccessedHistoryItem } from './recently_accessed'; +export type SolutionId = 'es' | 'oblt' | 'security'; + /** @public */ export type AppId = | DevToolsApp @@ -414,6 +416,7 @@ export interface NavigationTreeDefinition< * with their corresponding "deepLink"...) */ export interface NavigationTreeDefinitionUI { + id: SolutionId; body: Array; footer?: Array; } @@ -429,7 +432,7 @@ export interface NavigationTreeDefinitionUI { export interface SolutionNavigationDefinition { /** Unique id for the solution navigation. */ - id: string; + id: SolutionId; /** Title for the solution navigation. */ title: string; /** The navigation tree definition */ @@ -442,9 +445,9 @@ export interface SolutionNavigationDefinition { ]; const { findByTestId } = renderNavigation({ - navTreeDef: of({ body: navigationBody }), + navTreeDef: of({ id: 'es', body: navigationBody }), services: { activeNodes$: getActiveNodes$() }, }); diff --git a/packages/shared-ux/chrome/navigation/__jest__/build_nav_tree.test.tsx b/packages/shared-ux/chrome/navigation/__jest__/build_nav_tree.test.tsx index 15baf09d04dc3..4196dd3eca21c 100644 --- a/packages/shared-ux/chrome/navigation/__jest__/build_nav_tree.test.tsx +++ b/packages/shared-ux/chrome/navigation/__jest__/build_nav_tree.test.tsx @@ -21,6 +21,7 @@ describe('builds navigation tree', () => { test('render reference UI and build the navigation tree', async () => { const { findByTestId } = renderNavigation({ navTreeDef: of({ + id: 'es', body: [ { id: 'group1', @@ -107,6 +108,7 @@ describe('builds navigation tree', () => { { const { findByTestId, unmount } = renderNavigation({ navTreeDef: of({ + id: 'es', body: [accordionNode], }), services: { navigateToUrl }, @@ -121,6 +123,7 @@ describe('builds navigation tree', () => { { const { findByTestId } = renderNavigation({ navTreeDef: of({ + id: 'es', body: [ { ...accordionNode, @@ -165,6 +168,7 @@ describe('builds navigation tree', () => { // Side nav is collapsed const { queryAllByTestId, unmount } = renderNavigation({ navTreeDef: of({ + id: 'es', body: [nodes], }), services: { isSideNavCollapsed: true }, @@ -180,6 +184,7 @@ describe('builds navigation tree', () => { // Side nav is not collapsed const { queryAllByTestId, unmount } = renderNavigation({ navTreeDef: of({ + id: 'es', body: [nodes], }), services: { isSideNavCollapsed: false }, // No conversion to accordion @@ -195,6 +200,7 @@ describe('builds navigation tree', () => { // Panel opener with a link const { queryAllByTestId, unmount } = renderNavigation({ navTreeDef: of({ + id: 'es', body: [ { ...nodes, @@ -238,6 +244,7 @@ describe('builds navigation tree', () => { const { findByTestId } = renderNavigation({ navTreeDef: of({ + id: 'es', body: [node], }), services: { navigateToUrl, eventTracker: new EventTracker({ reportEvent }) }, @@ -276,6 +283,7 @@ describe('builds navigation tree', () => { const { findByTestId } = renderNavigation({ navTreeDef: of({ + id: 'es', body: [node], }), services: { navigateToUrl }, @@ -290,6 +298,7 @@ describe('builds navigation tree', () => { test('should not render the group if it does not have children', async () => { const navTree: NavigationTreeDefinitionUI = { + id: 'es', body: [ { id: 'root', @@ -338,6 +347,7 @@ describe('builds navigation tree', () => { ]); const navTree: NavigationTreeDefinitionUI = { + id: 'es', body: [{ type: 'recentlyAccessed' }], }; @@ -364,6 +374,7 @@ describe('builds navigation tree', () => { ]); const navTree: NavigationTreeDefinitionUI = { + id: 'es', body: [{ type: 'recentlyAccessed' }], }; diff --git a/packages/shared-ux/chrome/navigation/__jest__/panel.test.tsx b/packages/shared-ux/chrome/navigation/__jest__/panel.test.tsx index 01a1112ca7d1a..59c3463fb7326 100644 --- a/packages/shared-ux/chrome/navigation/__jest__/panel.test.tsx +++ b/packages/shared-ux/chrome/navigation/__jest__/panel.test.tsx @@ -21,6 +21,7 @@ import { renderNavigation } from './utils'; describe('Panel', () => { test('should render group as panel opener', async () => { const navigationTree: NavigationTreeDefinitionUI = { + id: 'es', body: [ { id: 'root', @@ -60,6 +61,7 @@ describe('Panel', () => { test('should not render group if all children are hidden', async () => { const navigationTree: NavigationTreeDefinitionUI = { + id: 'es', body: [ { id: 'root', @@ -146,6 +148,7 @@ describe('Panel', () => { ]); const navTree: NavigationTreeDefinitionUI = { + id: 'es', body: [ { id: 'root', @@ -196,6 +199,7 @@ describe('Panel', () => { describe('auto generated content', () => { test('should rendre block groups with title', async () => { const navTree: NavigationTreeDefinitionUI = { + id: 'es', body: [ { id: 'root', @@ -262,6 +266,7 @@ describe('Panel', () => { test('should rendre block groups without title', async () => { const navTree: NavigationTreeDefinitionUI = { + id: 'es', body: [ { id: 'root', @@ -327,6 +332,7 @@ describe('Panel', () => { test('should rendre accordion groups', async () => { const navTree: NavigationTreeDefinitionUI = { + id: 'es', body: [ { id: 'root', diff --git a/packages/shared-ux/chrome/navigation/src/ui/components/feedback_btn.tsx b/packages/shared-ux/chrome/navigation/src/ui/components/feedback_btn.tsx index 3cc2fca2d8f81..182838d88b5d6 100644 --- a/packages/shared-ux/chrome/navigation/src/ui/components/feedback_btn.tsx +++ b/packages/shared-ux/chrome/navigation/src/ui/components/feedback_btn.tsx @@ -10,11 +10,20 @@ import { EuiButton, EuiCallOut, useEuiTheme, EuiText, EuiSpacer } from '@elastic/eui'; import React, { FC, useState } from 'react'; import { i18n } from '@kbn/i18n'; +import type { SolutionId } from '@kbn/core-chrome-browser'; -const feedbackUrl = 'https://ela.st/nav-feedback'; +const feedbackUrls: { [id in SolutionId]: string } = { + es: 'https://ela.st/search-nav-feedback', + oblt: 'https://ela.st/o11y-nav-feedback', + security: 'https://ela.st/security-nav-feedback', +}; const FEEDBACK_BTN_KEY = 'core.chrome.sideNav.feedbackBtn'; -export const FeedbackBtn: FC = () => { +interface Props { + solutionId: SolutionId; +} + +export const FeedbackBtn: FC = ({ solutionId }) => { const { euiTheme } = useEuiTheme(); const [showCallOut, setShowCallOut] = useState( sessionStorage.getItem(FEEDBACK_BTN_KEY) !== 'hidden' @@ -26,7 +35,7 @@ export const FeedbackBtn: FC = () => { }; const onClick = () => { - window.open(feedbackUrl, '_blank'); + window.open(feedbackUrls[solutionId], '_blank'); onDismiss(); }; diff --git a/packages/shared-ux/chrome/navigation/src/ui/navigation.stories.tsx b/packages/shared-ux/chrome/navigation/src/ui/navigation.stories.tsx index 6100dceaa2499..c90ec6a72152f 100644 --- a/packages/shared-ux/chrome/navigation/src/ui/navigation.stories.tsx +++ b/packages/shared-ux/chrome/navigation/src/ui/navigation.stories.tsx @@ -91,6 +91,7 @@ const NavigationWrapper: FC, 'c }; const groupExamplesNavigationTree: NavigationTreeDefinitionUI = { + id: 'es', body: [ // My custom project { @@ -257,6 +258,7 @@ export const GroupsExamples = (args: NavigationServices) => { }; const navigationTree: NavigationTreeDefinitionUI = { + id: 'es', body: [ // My custom project { @@ -568,6 +570,7 @@ const panelContentProvider: ContentProvider = (id: string) => { }; const navigationTreeWithPanels: NavigationTreeDefinitionUI = { + id: 'es', body: [ // My custom project { diff --git a/packages/shared-ux/chrome/navigation/src/ui/navigation.tsx b/packages/shared-ux/chrome/navigation/src/ui/navigation.tsx index 688ee1e709e15..80365bd16133f 100644 --- a/packages/shared-ux/chrome/navigation/src/ui/navigation.tsx +++ b/packages/shared-ux/chrome/navigation/src/ui/navigation.tsx @@ -52,7 +52,8 @@ const NavigationComp: FC = ({ navigationTree$, dataTestSubj, panelContent useNavigationService(); const activeNodes = useObservable(activeNodes$, []); - const navigationTree = useObservable(navigationTree$, { body: [] }); + const navigationTree = useObservable(navigationTree$, { id: 'es', body: [] }); + const { id: solutionId } = navigationTree; const isFeedbackBtnVisible = useObservable(isFeedbackBtnVisible$, false); const contextValue = useMemo( @@ -95,7 +96,7 @@ const NavigationComp: FC = ({ navigationTree$, dataTestSubj, panelContent {renderNodes(navigationTree.body)} {isFeedbackBtnVisible && ( - + )} diff --git a/src/plugins/navigation/public/plugin.test.ts b/src/plugins/navigation/public/plugin.test.ts index d05cf756f7178..3aa9ff8295f41 100644 --- a/src/plugins/navigation/public/plugin.test.ts +++ b/src/plugins/navigation/public/plugin.test.ts @@ -106,7 +106,7 @@ describe('Navigation Plugin', () => { await new Promise((resolve) => setTimeout(resolve)); const definition = { - id: 'es', + id: 'es' as const, title: 'Elasticsearch', navigationTree$: of({ body: [] }), }; diff --git a/src/plugins/navigation/public/plugin.tsx b/src/plugins/navigation/public/plugin.tsx index 9f41405a8438b..e7264efdf51d2 100644 --- a/src/plugins/navigation/public/plugin.tsx +++ b/src/plugins/navigation/public/plugin.tsx @@ -18,7 +18,7 @@ import { } from '@kbn/core/public'; import type { UnifiedSearchPublicPluginStart } from '@kbn/unified-search-plugin/public'; import type { Space } from '@kbn/spaces-plugin/public'; -import type { SolutionNavigationDefinition } from '@kbn/core-chrome-browser'; +import type { SolutionId, SolutionNavigationDefinition } from '@kbn/core-chrome-browser'; import { InternalChromeStart } from '@kbn/core-chrome-browser-internal'; import type { PanelContentProvider } from '@kbn/shared-ux-chrome-navigation'; import type { @@ -195,7 +195,7 @@ export class NavigationPublicPlugin } } - if (isProjectNav) { + if (isProjectNav && solutionView !== 'classic') { chrome.project.changeActiveSolutionNavigation(solutionView!); } } @@ -210,6 +210,6 @@ function getIsProjectNav(solutionView?: string) { return Boolean(solutionView) && isKnownSolutionView(solutionView); } -function isKnownSolutionView(solution?: string) { +function isKnownSolutionView(solution?: string): solution is SolutionId { return Boolean(solution) && ['oblt', 'es', 'security'].includes(solution!); } diff --git a/x-pack/plugins/cloud/common/index.ts b/x-pack/plugins/cloud/common/index.ts deleted file mode 100644 index 4aa6ce8d5edf0..0000000000000 --- a/x-pack/plugins/cloud/common/index.ts +++ /dev/null @@ -1,8 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -export type { OnBoardingDefaultSolution } from './types'; diff --git a/x-pack/plugins/cloud/common/parse_onboarding_default_solution.ts b/x-pack/plugins/cloud/common/parse_onboarding_default_solution.ts index 5b064eecce12d..483e6771394d2 100644 --- a/x-pack/plugins/cloud/common/parse_onboarding_default_solution.ts +++ b/x-pack/plugins/cloud/common/parse_onboarding_default_solution.ts @@ -5,7 +5,7 @@ * 2.0. */ -import type { OnBoardingDefaultSolution } from './types'; +import type { SolutionId } from '@kbn/core-chrome-browser'; /** * Cloud does not type the value of the "use case" that is set during onboarding for a deployment. Any string can @@ -14,12 +14,12 @@ import type { OnBoardingDefaultSolution } from './types'; * @param value The solution value set by Cloud. * @returns The default solution value for onboarding that matches Kibana naming. */ -export function parseOnboardingSolution(value?: string): OnBoardingDefaultSolution | undefined { +export function parseOnboardingSolution(value?: string): SolutionId | undefined { if (!value) return; const solutions: Array<{ cloudValue: 'search' | 'elasticsearch' | 'observability' | 'security'; - kibanaValue: OnBoardingDefaultSolution; + kibanaValue: SolutionId; }> = [ { cloudValue: 'search', diff --git a/x-pack/plugins/cloud/common/types.ts b/x-pack/plugins/cloud/common/types.ts index 0f72caf515058..b3a32270af6cc 100644 --- a/x-pack/plugins/cloud/common/types.ts +++ b/x-pack/plugins/cloud/common/types.ts @@ -5,8 +5,6 @@ * 2.0. */ -export type OnBoardingDefaultSolution = 'es' | 'oblt' | 'security'; - export interface ElasticsearchConfigType { elasticsearch_url?: string; } diff --git a/x-pack/plugins/cloud/public/types.ts b/x-pack/plugins/cloud/public/types.ts index 2a6140ba8e97e..91972b69ec4ef 100644 --- a/x-pack/plugins/cloud/public/types.ts +++ b/x-pack/plugins/cloud/public/types.ts @@ -5,8 +5,8 @@ * 2.0. */ +import type { SolutionId } from '@kbn/core-chrome-browser'; import type { FC, PropsWithChildren } from 'react'; -import type { OnBoardingDefaultSolution } from '../common'; export interface CloudStart { /** @@ -192,7 +192,7 @@ export interface CloudSetup { /** * The default solution selected during onboarding. */ - defaultSolution?: OnBoardingDefaultSolution; + defaultSolution?: SolutionId; }; /** * `true` when running on Serverless Elastic Cloud diff --git a/x-pack/plugins/cloud/server/plugin.ts b/x-pack/plugins/cloud/server/plugin.ts index 9f45b5398ac22..9821aa318e264 100644 --- a/x-pack/plugins/cloud/server/plugin.ts +++ b/x-pack/plugins/cloud/server/plugin.ts @@ -8,10 +8,10 @@ import type { Logger } from '@kbn/logging'; import type { CoreSetup, Plugin, PluginInitializerContext } from '@kbn/core/server'; import type { UsageCollectionSetup } from '@kbn/usage-collection-plugin/server'; +import type { SolutionId } from '@kbn/core-chrome-browser'; import { registerCloudDeploymentMetadataAnalyticsContext } from '../common/register_cloud_deployment_id_analytics_context'; import type { CloudConfigType } from './config'; import { registerCloudUsageCollector } from './collectors'; -import type { OnBoardingDefaultSolution } from '../common'; import { getIsCloudEnabled } from '../common/is_cloud_enabled'; import { parseDeploymentIdFromDeploymentUrl } from '../common/parse_deployment_id_from_deployment_url'; import { decodeCloudId, DecodedCloudId } from '../common/decode_cloud_id'; @@ -108,7 +108,7 @@ export interface CloudSetup { /** * The default solution selected during onboarding. */ - defaultSolution?: OnBoardingDefaultSolution; + defaultSolution?: SolutionId; }; /** * `true` when running on Serverless Elastic Cloud diff --git a/x-pack/plugins/cloud/tsconfig.json b/x-pack/plugins/cloud/tsconfig.json index fdf2ad6db58cd..dd25064897758 100644 --- a/x-pack/plugins/cloud/tsconfig.json +++ b/x-pack/plugins/cloud/tsconfig.json @@ -12,6 +12,7 @@ ], "kbn_references": [ "@kbn/core", + "@kbn/core-chrome-browser", "@kbn/usage-collection-plugin", "@kbn/config-schema", "@kbn/logging-mocks", diff --git a/x-pack/plugins/serverless/public/types.ts b/x-pack/plugins/serverless/public/types.ts index 4627d24659b8e..3a416a676ee92 100644 --- a/x-pack/plugins/serverless/public/types.ts +++ b/x-pack/plugins/serverless/public/types.ts @@ -10,6 +10,7 @@ import type { ChromeSetProjectBreadcrumbsParams, SideNavComponent, NavigationTreeDefinition, + SolutionId, } from '@kbn/core-chrome-browser'; import type { CloudSetup, CloudStart } from '@kbn/cloud-plugin/public'; import type { Observable } from 'rxjs'; @@ -26,7 +27,7 @@ export interface ServerlessPluginStart { ) => void; setProjectHome(homeHref: string): void; initNavigation( - id: string, + id: SolutionId, navigationTree$: Observable, config?: { dataTestSubj?: string; diff --git a/x-pack/plugins/serverless_search/public/plugin.ts b/x-pack/plugins/serverless_search/public/plugin.ts index 491252a6d9e9f..3d246e4be2929 100644 --- a/x-pack/plugins/serverless_search/public/plugin.ts +++ b/x-pack/plugins/serverless_search/public/plugin.ts @@ -149,7 +149,7 @@ export class ServerlessSearchPlugin serverless.setProjectHome(services.searchIndices.startRoute); const navigationTree$ = of(navigationTree()); - serverless.initNavigation('search', navigationTree$, { dataTestSubj: 'svlSearchSideNav' }); + serverless.initNavigation('es', navigationTree$, { dataTestSubj: 'svlSearchSideNav' }); const extendCardNavDefinitions = serverless.getNavigationCards( security.authz.isRoleManagementEnabled() diff --git a/x-pack/plugins/spaces/common/types/space/v1.ts b/x-pack/plugins/spaces/common/types/space/v1.ts index ebd841e914e69..3d7bb94cf65ab 100644 --- a/x-pack/plugins/spaces/common/types/space/v1.ts +++ b/x-pack/plugins/spaces/common/types/space/v1.ts @@ -5,11 +5,11 @@ * 2.0. */ -import type { OnBoardingDefaultSolution } from '@kbn/cloud-plugin/common'; +import type { SolutionId } from '@kbn/core-chrome-browser'; import type { SOLUTION_VIEW_CLASSIC } from '../../constants'; -export type SolutionView = OnBoardingDefaultSolution | typeof SOLUTION_VIEW_CLASSIC; +export type SolutionView = SolutionId | typeof SOLUTION_VIEW_CLASSIC; /** * A Space. diff --git a/x-pack/plugins/spaces/public/nav_control/solution_view_tour/solution_view_tour.tsx b/x-pack/plugins/spaces/public/nav_control/solution_view_tour/solution_view_tour.tsx index bf80bf92bdf4e..caa9cc17b053c 100644 --- a/x-pack/plugins/spaces/public/nav_control/solution_view_tour/solution_view_tour.tsx +++ b/x-pack/plugins/spaces/public/nav_control/solution_view_tour/solution_view_tour.tsx @@ -9,7 +9,7 @@ import { EuiButtonEmpty, EuiLink, EuiText, EuiTourStep } from '@elastic/eui'; import React from 'react'; import type { FC, PropsWithChildren } from 'react'; -import type { OnBoardingDefaultSolution } from '@kbn/cloud-plugin/common'; +import type { SolutionId } from '@kbn/core-chrome-browser'; import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n-react'; @@ -26,7 +26,7 @@ const LearnMoreLink = () => ( ); -const solutionMap: Record = { +const solutionMap: Record = { es: i18n.translate('xpack.spaces.navControl.tour.esSolution', { defaultMessage: 'Search', }), diff --git a/x-pack/plugins/spaces/server/default_space/create_default_space.ts b/x-pack/plugins/spaces/server/default_space/create_default_space.ts index 53658fd68a0f7..3c53543a756fb 100644 --- a/x-pack/plugins/spaces/server/default_space/create_default_space.ts +++ b/x-pack/plugins/spaces/server/default_space/create_default_space.ts @@ -5,9 +5,9 @@ * 2.0. */ -import type { OnBoardingDefaultSolution } from '@kbn/cloud-plugin/common'; import type { Logger, SavedObjectsRepository, SavedObjectsServiceStart } from '@kbn/core/server'; import { SavedObjectsErrorHelpers } from '@kbn/core/server'; +import type { SolutionId } from '@kbn/core-chrome-browser'; import { i18n } from '@kbn/i18n'; import { DEFAULT_SPACE_ID } from '../../common/constants'; @@ -15,7 +15,7 @@ import { DEFAULT_SPACE_ID } from '../../common/constants'; interface Deps { getSavedObjects: () => Promise>; logger: Logger; - solution?: OnBoardingDefaultSolution; + solution?: SolutionId; } export async function createDefaultSpace({ getSavedObjects, logger, solution }: Deps) { diff --git a/x-pack/plugins/spaces/server/default_space/default_space_service.ts b/x-pack/plugins/spaces/server/default_space/default_space_service.ts index 1faaf5490de89..9d537f93f63fc 100644 --- a/x-pack/plugins/spaces/server/default_space/default_space_service.ts +++ b/x-pack/plugins/spaces/server/default_space/default_space_service.ts @@ -19,9 +19,9 @@ import { timer, } from 'rxjs'; -import type { OnBoardingDefaultSolution } from '@kbn/cloud-plugin/common'; import type { CoreSetup, Logger, SavedObjectsServiceStart, ServiceStatus } from '@kbn/core/server'; import { ServiceStatusLevels } from '@kbn/core/server'; +import type { SolutionId } from '@kbn/core-chrome-browser'; import type { ILicense } from '@kbn/licensing-plugin/server'; import { createDefaultSpace } from './create_default_space'; @@ -33,7 +33,7 @@ interface Deps { license$: Observable; spacesLicense: SpacesLicense; logger: Logger; - solution?: OnBoardingDefaultSolution; + solution?: SolutionId; } export const RETRY_SCALE_DURATION = 100; diff --git a/x-pack/plugins/spaces/tsconfig.json b/x-pack/plugins/spaces/tsconfig.json index 97cd0d3d4fdc8..a997ef7b3d97a 100644 --- a/x-pack/plugins/spaces/tsconfig.json +++ b/x-pack/plugins/spaces/tsconfig.json @@ -51,7 +51,8 @@ "@kbn/logging", "@kbn/core-logging-browser-mocks", "@kbn/core-http-router-server-mocks", - "@kbn/core-application-browser-mocks" + "@kbn/core-application-browser-mocks", + "@kbn/core-chrome-browser" ], "exclude": [ "target/**/*",