Skip to content

Instantly share code, notes, and snippets.

@sebelga
Last active April 20, 2023 13:58
Show Gist options
  • Save sebelga/5996aa64b2fc58c1984bceb687a81c42 to your computer and use it in GitHub Desktop.
Save sebelga/5996aa64b2fc58c1984bceb687a81c42 to your computer and use it in GitHub Desktop.
/*
* 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 and the Server Side Public License, v 1; you may not use this file except
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/
import type { RecursiveReadonly } from '@kbn/utility-types';
import { BehaviorSubject, Observable } from 'rxjs';
// -------------------------------------------------------
// ------------------- URL SERVICE -----------------------
// -------------------------------------------------------
// List of all the pages that we can navigate to
const KIBANA_PAGE_IDS = [
'dashboard.home',
'dashboard.create',
'maps.home',
'management.home',
'management.indexManagement.dataStreams'
] as const;
// Semantic naming: <pluginName>.<page>
// Embedded plugin: <pluginName>.<pluginName>.<page> (e.g. "management.indexManagement.dataStreams")
type KibanaPageId = typeof KIBANA_PAGE_IDS[number];
interface UrlPageMeta { uri?: string; label: string }
interface PagesMeta {
pages: {
[key in KibanaPageId]: UrlPageMeta;
}
}
export const PAGES_META: PagesMeta = {
pages: {
'dashboard.home': {
uri: '/app/dashboards',
label: 'Dashboards',
},
'dashboard.create': {
// we don't know the URI, the dashboard app will let us know
label: 'Create dashboard',
},
'maps.home': {
uri: '/app/maps',
label: 'Maps',
},
'management.home': {
uri: '/app/management',
label: 'Stack management',
},
'management.indexManagement.dataStreams': {
// We don't know the URI, the indexManagement app will let us know
label: 'Data streams',
},
}
}
// Make a copy when initializing
// Quick and dirty code. Here we would probably add an "isActive" flag to each object item
const pages = new BehaviorSubject<PagesMeta>({ ...PAGES_META });
// Expose a handler to update the URIs and labels
const updatePageMeta = (pageId: KibanaPageId, meta: UrlPageMeta) => {
if (pages.getValue().pages[pageId].uri !== undefined) {
throw new Error(`Page [${pageId}] meta cannot be overriden.`);
}
pages.next({...pages.value, [pageId]: meta});
}
// Observable getter
const getPages$ = (pageId: KibanaPageId): Observable<PagesMeta> => {
return pages.asObservable();
}
// ----------------------------------------------------------
// ------------------- MENU / NAV SERVICE -------------------
// ----------------------------------------------------------
/**
* The Menu/Nav service subscribes to the getPages$() observable.
* It derives from it:
* - URIs for each menu item
* - Default label for each menu item (can be overriden in MenuDefinition)
* - The active page id
*/
export interface SectionItem {
name: string;
id?: KibanaPageId;
helpText?: string; // For possible tooltip
items?: RecursiveReadonly<MenuItem[]>;
}
export interface PageItem {
id: KibanaPageId;
label?: string; // Label can be overriden, otherwise uses the UrlPageMeta['label']
items?: RecursiveReadonly<MenuItem[]>;
}
type MenuItem = SectionItem | PageItem;
export type MenuDefinition = RecursiveReadonly<MenuItem[]>;
// The menu definition is a simple list of Kibana page ids and sections
const menu: MenuDefinition = [
{
// SECTION 1
name: 'Section 1',
helpText: 'Analyse your data',
items: [
{
id: 'dashboard.home',
items: [
{
id: 'dashboard.create',
label: 'Create dashboard now!', // Overrides the default label from PAGES_META constant
},
],
},
{
id: 'maps.home',
},
],
},
// SECTION 2
{
name: 'Section 2',
helpText: 'Some tooltip info',
id: 'management.home', // The section title points to management home page
items: [
{
id: 'management.indexManagement.dataStreams',
},
],
},
];
// public/plugin.ts
setup() {
/**
* Calling core.application.register will throw an error if
* there are ids in the KIBANA_PAGE_IDS constant whose id starts with the app id (e.g. "dashboard.")
* and the uri is empty ("").
*/
core.application.register({
id: DASHBOARD_APP_ID, // "dashboard"
title: 'Dashboard',
order: 2500,
...
});
/**
* To avoid that, the app must provide URIs for each of the KibanaPageId under its domain
*/
core.application.register({
id: DASHBOARD_APP_ID,
...
navItems: {
[`${DASHBOARD_APP_ID}.create`]: {
uri: '#create', // will be appened to "/app/dashboards" base path
label: 'Create dashboard', // Optional. Overrides the default label. Can still be overriden in the MenuDefinition
}
}
})
}
// At this stage the URL service can listen to URL changes and we know which KibanaPageId is active
// --> set its "isActive" flag to true
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment