diff --git a/src/core/server/legacy/plugins/__snapshots__/get_nav_links.test.ts.snap b/src/core/server/legacy/plugins/__snapshots__/get_nav_links.test.ts.snap new file mode 100644 index 0000000000000..4b6ee8f19b882 --- /dev/null +++ b/src/core/server/legacy/plugins/__snapshots__/get_nav_links.test.ts.snap @@ -0,0 +1,66 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[` 1`] = ` +Array [ + Object { + "category": undefined, + "disableSubUrlTracking": undefined, + "disabled": false, + "euiIconType": undefined, + "hidden": false, + "icon": undefined, + "id": "link-a", + "linkToLastSubUrl": false, + "order": 0, + "subUrlBase": "/some-custom-url", + "title": "AppA", + "tooltip": "", + "url": "/some-custom-url", + }, + Object { + "category": undefined, + "disableSubUrlTracking": true, + "disabled": false, + "euiIconType": undefined, + "hidden": false, + "icon": undefined, + "id": "link-b", + "linkToLastSubUrl": false, + "order": 0, + "subUrlBase": undefined, + "title": "link-b", + "tooltip": "", + "url": "/app/link-b", + }, + Object { + "category": undefined, + "disableSubUrlTracking": undefined, + "disabled": false, + "euiIconType": undefined, + "hidden": false, + "icon": undefined, + "id": "app-a", + "linkToLastSubUrl": false, + "order": 0, + "subUrlBase": undefined, + "title": "AppA", + "tooltip": "", + "url": "/app/app-a", + }, + Object { + "category": undefined, + "disableSubUrlTracking": undefined, + "disabled": false, + "euiIconType": undefined, + "hidden": false, + "icon": undefined, + "id": "app-b", + "linkToLastSubUrl": false, + "order": 0, + "subUrlBase": undefined, + "title": "AppB", + "tooltip": "", + "url": "/app/app-b", + }, +] +`; diff --git a/src/core/server/legacy/plugins/get_nav_links.test.ts b/src/core/server/legacy/plugins/get_nav_links.test.ts index e88524d9b378b..5fd394cba636a 100644 --- a/src/core/server/legacy/plugins/get_nav_links.test.ts +++ b/src/core/server/legacy/plugins/get_nav_links.test.ts @@ -123,5 +123,165 @@ describe('getNavLinks', () => { ); }).toThrowErrorMatchingInlineSnapshot(`"Unknown plugin id \\"notExistingPlugin\\""`); }); + + it('uses all known properties of the navlink', () => { + const navlinks = getNavLinks( + createLegacyExports({ + uiAppSpecs: [ + { + id: 'app-a', + title: 'AppA', + category: { + label: 'My Category', + }, + order: 42, + url: '/some-custom-url', + subUrlBase: '/some-custom-url/sub', + disableSubUrlTracking: true, + icon: 'fa-snowflake', + euiIconType: 'euiIcon', + linkToLastSubUrl: true, + hidden: false, + tooltip: 'My tooltip', + }, + ], + }), + [] + ); + expect(navlinks.length).toBe(1); + expect(navlinks[0]).toEqual({ + id: 'app-a', + title: 'AppA', + category: { + label: 'My Category', + }, + order: 42, + url: '/some-custom-url', + subUrlBase: '/some-custom-url/sub', + disableSubUrlTracking: true, + icon: 'fa-snowflake', + euiIconType: 'euiIcon', + linkToLastSubUrl: true, + hidden: false, + disabled: false, + tooltip: 'My tooltip', + }); + }); + }); + + describe('generating from navLinkSpecs', () => { + it('generates navlinks from legacy navLink specs', () => { + const navlinks = getNavLinks( + createLegacyExports({ + navLinkSpecs: [ + { + id: 'link-a', + title: 'AppA', + url: '/some-custom-url', + }, + { + id: 'link-b', + disableSubUrlTracking: true, + }, + ], + }), + createPluginSpecs('pluginA') + ); + + expect(navlinks.length).toEqual(2); + expect(navlinks[0]).toEqual( + expect.objectContaining({ + id: 'link-a', + title: 'AppA', + url: '/some-custom-url', + hidden: false, + disabled: false, + }) + ); + expect(navlinks[1]).toEqual( + expect.objectContaining({ + id: 'link-b', + title: 'link-b', + url: '/app/link-b', + disableSubUrlTracking: true, + }) + ); + }); + + it('uses all known properties of the navlink', () => { + const navlinks = getNavLinks( + createLegacyExports({ + navLinkSpecs: [ + { + id: 'link-a', + title: 'AppA', + category: { + label: 'My Second Cat', + }, + order: 72, + url: '/some-other-custom', + subUrlBase: '/some-other-custom/sub', + disableSubUrlTracking: true, + icon: 'fa-corn', + euiIconType: 'euiIconBis', + linkToLastSubUrl: false, + hidden: false, + tooltip: 'My other tooltip', + }, + ], + }), + [] + ); + expect(navlinks.length).toBe(1); + expect(navlinks[0]).toEqual({ + id: 'link-a', + title: 'AppA', + category: { + label: 'My Second Cat', + }, + order: 72, + url: '/some-other-custom', + subUrlBase: '/some-other-custom/sub', + disableSubUrlTracking: true, + icon: 'fa-corn', + euiIconType: 'euiIconBis', + linkToLastSubUrl: false, + hidden: false, + disabled: false, + tooltip: 'My other tooltip', + }); + }); + }); + + describe('generating from both apps and navlinks', () => { + const navlinks = getNavLinks( + createLegacyExports({ + uiAppSpecs: [ + { + id: 'app-a', + title: 'AppA', + }, + { + id: 'app-b', + title: 'AppB', + }, + ], + navLinkSpecs: [ + { + id: 'link-a', + title: 'AppA', + url: '/some-custom-url', + }, + { + id: 'link-b', + disableSubUrlTracking: true, + }, + ], + }), + [] + ); + + expect(navlinks.length).toBe(4); + expect(navlinks).toMatchSnapshot(); }); }); diff --git a/src/core/server/legacy/plugins/get_nav_links.ts b/src/core/server/legacy/plugins/get_nav_links.ts index 26c17347eeb36..3d05f284a88d2 100644 --- a/src/core/server/legacy/plugins/get_nav_links.ts +++ b/src/core/server/legacy/plugins/get_nav_links.ts @@ -17,62 +17,51 @@ * under the License. */ -import { LegacyUiExports, LegacyNavLink, LegacyPluginSpec } from '../types'; +import { + LegacyUiExports, + LegacyNavLink, + LegacyPluginSpec, + LegacyNavLinkSpec, + LegacyAppSpec, +} from '../types'; -const REMOVE_FROM_ARRAY: LegacyNavLink[] = []; - -function getUiAppsNavLinks({ uiAppSpecs = [] }: LegacyUiExports, pluginSpecs: LegacyPluginSpec[]) { - return uiAppSpecs.flatMap(spec => { - if (!spec) { - return REMOVE_FROM_ARRAY; - } +function convertToNavLink(spec: LegacyNavLinkSpec | LegacyAppSpec): LegacyNavLink { + if (!spec.id) { + throw new Error('Every app must specify an id'); + } + return { + id: spec.id, + category: spec.category, + title: spec.title ?? spec.id, + order: typeof spec.order === 'number' ? spec.order : 0, + url: spec.url ?? `/app/${spec.id}`, + subUrlBase: spec.subUrlBase ?? spec.url, + disableSubUrlTracking: spec.disableSubUrlTracking, + icon: spec.icon, + euiIconType: spec.euiIconType, + linkToLastSubUrl: spec.linkToLastSubUrl ?? false, + hidden: spec.hidden ?? false, + disabled: spec.disabled ?? false, + tooltip: spec.tooltip ?? '', + }; +} - const id = spec.id; +function isHidden(app: LegacyAppSpec) { + return app.listed === false || app.hidden === true; +} - if (!id) { - throw new Error('Every app must specify an id'); - } +export function getNavLinks(uiExports: LegacyUiExports, pluginSpecs: LegacyPluginSpec[]) { + const navLinkSpecs = uiExports.navLinkSpecs || []; + const appSpecs = (uiExports.uiAppSpecs || []).filter( + app => app !== undefined && !isHidden(app) + ) as LegacyAppSpec[]; - if (spec.pluginId && !pluginSpecs.some(plugin => plugin.getId() === spec.pluginId)) { + const pluginIds = (pluginSpecs || []).map(spec => spec.getId()); + appSpecs.forEach(spec => { + if (spec.pluginId && !pluginIds.includes(spec.pluginId)) { throw new Error(`Unknown plugin id "${spec.pluginId}"`); } - - const listed = typeof spec.listed === 'boolean' ? spec.listed : true; - - if (spec.hidden || !listed) { - return REMOVE_FROM_ARRAY; - } - - return { - id, - category: spec.category, - title: spec.title, - order: typeof spec.order === 'number' ? spec.order : 0, - icon: spec.icon, - euiIconType: spec.euiIconType, - url: spec.url || `/app/${id}`, - linkToLastSubUrl: spec.linkToLastSubUrl, - }; }); -} -export function getNavLinks(uiExports: LegacyUiExports, pluginSpecs: LegacyPluginSpec[]) { - return (uiExports.navLinkSpecs || []) - .map(spec => ({ - id: spec.id, - category: spec.category, - title: spec.title, - order: typeof spec.order === 'number' ? spec.order : 0, - url: spec.url, - subUrlBase: spec.subUrlBase || spec.url, - disableSubUrlTracking: spec.disableSubUrlTracking, - icon: spec.icon, - euiIconType: spec.euiIconType, - linkToLastSub: 'linkToLastSubUrl' in spec ? spec.linkToLastSubUrl : false, - hidden: 'hidden' in spec ? spec.hidden : false, - disabled: 'disabled' in spec ? spec.disabled : false, - tooltip: spec.tooltip || '', - })) - .concat(getUiAppsNavLinks(uiExports, pluginSpecs)) - .sort((a, b) => a.order - b.order); + return [...navLinkSpecs, ...appSpecs].map(convertToNavLink).sort((a, b) => a.order - b.order); } diff --git a/src/core/server/legacy/types.ts b/src/core/server/legacy/types.ts index d51058ca561c6..6b05f3853cb16 100644 --- a/src/core/server/legacy/types.ts +++ b/src/core/server/legacy/types.ts @@ -131,16 +131,16 @@ export type VarsReplacer = ( * @internal * @deprecated */ -export type LegacyNavLinkSpec = Record & ChromeNavLink; +export type LegacyNavLinkSpec = Partial; /** * @internal * @deprecated */ -export type LegacyAppSpec = Pick< - ChromeNavLink, - 'title' | 'order' | 'icon' | 'euiIconType' | 'url' | 'linkToLastSubUrl' | 'hidden' | 'category' -> & { pluginId?: string; id?: string; listed?: boolean }; +export type LegacyAppSpec = Partial & { + pluginId?: string; + listed?: boolean; +}; /** * @internal