Skip to main content

Plugins Functionality

Headlamp's plugins exist to change or add functionality related to the user interface and experience.

Plugins Lib​

The @kinvolk/headlamp-plugin module provides a library (@kinvolk/headlamp-plugin/lib) with Headlamp development modules.

The main ones are:

  • K8s: Kubernetes functionality.
  • Headlamp: To register plugins.
  • CommonComponents: Commonly used React components in the Headlamp UI.
  • Notification: This module exports two members: Notification and setNotificationsInStore. The Notification class creates notifications. The setNotificationsInStore function sends the notification to Headlamp to be displayed.
  • Router: To get or generate routes.

Shared Modules​

Headlamp shares many npm modules with plugins. It includes VSCode configuration files to find them.

These are:

  • react
  • @iconify-react
  • react-redux
  • @material-ui/core
  • @material-ui/styles
  • lodash
  • notistack
  • recharts

This means that plugins only need to install dependencies not already in Headlamp. If a plugin installs a dependency that Headlamp already has, make sure the versions are the same. The build process will not bundle these shared modules. Instead, they are replaced by the version in the pluginLib global object.

Older guides suggested using const React: window.pluginLib.React to access React. This is no longer needed.

Functionality​

The plugin registry makes functionality available to plugins.

The goal is to make more functionality available to plugins. Here is what we have so far:

App Bar Action​

Show a component in the top right of the app bar with registerAppBarAction.

screenshot of the header showing two actions

Change the logo in the top left with registerAppLogo.

screenshot of the logo being changed

App Menus​

Add menus when Headlamp runs as an app with Headlamp.setAppMenu.

screenshot of the logo being changed

Cluster Chooser​

Change the Cluster Chooser button in the top right of the app bar with registerClusterChooser.

screenshot of the cluster chooser button

Cluster Empty State​

Customize the Home page shown when no clusters are configured with registerClusterEmptyState. The registered component receives Headlamp's standard empty state as defaultContent. Render it to extend the default onboarding, or omit it to replace the empty state completely.

Details View Header Action​

Show a component in the top right of a detail view with registerDetailsViewHeaderAction.

screenshot of the header showing two actions

Details View Section​

Change sections in a Kubernetes resource's details view with registerDetailsViewSectionsProcessor. This lets you add, remove, update, or move sections.

Or, add a component to the bottom of a details view with registerDetailsViewSection.

screenshot of the appended Details View Section

Dynamic Clusters​

Set a cluster dynamically, instead of from a configuration file, with Headlamp.setCluster.

Secure Storage​

Desktop plugins can save small local credentials with the pluginSecureStorage argument that Headlamp injects when it runs the plugin. Values are encrypted by Electron safeStorage and scoped to the plugin's trusted installation identity. The plugin chooses only a key within its own storage area; it cannot choose or name another plugin's namespace.

Declare the injected argument in TypeScript and check every operation result:

interface PluginSecureStorage {
save(key: string, value: string): Promise<{ success: boolean; error?: string }>;
load(key: string): Promise<{ success: boolean; value?: string | null; error?: string }>;
delete(key: string): Promise<{ success: boolean; error?: string }>;
}

declare const pluginSecureStorage: PluginSecureStorage;

const saved = await pluginSecureStorage.save('oauth-token', token);
if (!saved.success) {
throw new Error(saved.error);
}

const loaded = await pluginSecureStorage.load('oauth-token');
if (!loaded.success) {
throw new Error(loaded.error);
}
const tokenOrNull = loaded.value ?? null;

const deleted = await pluginSecureStorage.delete('oauth-token');
if (!deleted.success) {
throw new Error(deleted.error);
}

load returns value: null when the key does not exist. A failed operation returns success: false and an error; plugins should not treat a failure as a missing value. Headlamp may reject an operation when the operating-system key store is unavailable, when persisted data cannot be read safely, or when an input or storage limit is exceeded.

This API is available only in the Headlamp desktop app. Check Headlamp.isRunningAsApp() before registering UI that uses it. It stores data on the computer running Headlamp and does not synchronize across computers or create a Kubernetes Secret. Use the Kubernetes API when a credential needs to be shared with workloads or other cluster users.

Route​

Show a component in the main area at a given URL with registerRoute.

Add items to the left sidebar with registerSidebarEntry. Filter items with registerSidebarEntryFilter. Filter items from the home (non-cluster) sidebar with registerHomeSidebarEntryFilter. Use entryType: 'subheader' with registerSidebarEntry to add a non-clickable section header that groups sidebar entries. Subheaders render as dividers when the sidebar is collapsed. Use sx to override the default subheader styles.

screenshot of the sidebar being changed

Tables​

Change tables in Headlamp with registerResourceTableColumnsProcessor. This lets you add, remove, update, or move table columns.

screenshot of the pods list with a context menu added by a plugin

Project Creation​

Add a project creation choice with registerCustomCreateProject. To replace one of Headlamp's built-in choices in the same position, use its ID from DefaultCreateProject:

import { DefaultCreateProject, registerCustomCreateProject } from '@kinvolk/headlamp-plugin/lib';

registerCustomCreateProject({
id: DefaultCreateProject.NEW_PROJECT,
name: 'Create Managed Project',
description: 'Create a project managed by the platform',
icon: 'mdi:folder-plus',
component: ManagedProjectForm,
});

Use DefaultCreateProject.NEW_PROJECT to replace the namespace-based project form, or DefaultCreateProject.FROM_YAML to replace the YAML creation flow. Use a unique ID to append another choice without replacing either built-in choice. The custom component receives an onBack callback for returning to the project creation menu.

Mobile (375 x 812)

Default choicesPlugin replacements
Default project creation choices on a mobile viewportProject creation choices replaced by a plugin on a mobile viewport

Headlamp Events​

Headlamp fires events when something important happens.

React to Headlamp events with registerHeadlampEventCallback.

screenshot of a snackbar notification when an event occurred

Plugin Settings​

Plugins can have user settings. Create them with registerPluginSettings.

screenshot of the plugin settings

App Theme​

Add a custom Headlamp theme with registerAppTheme. The theme name must be unique. You can specify 'light' or 'dark' as a base. The default is 'light'.

Check the AppTheme definition for all customizable properties.

After you register your theme, it will be in the 'Theme' selection in General Settings.

screenshot of the theme dropdown

To select a registered theme on first use, pass { default: true } as the second argument:

registerAppTheme(
{
name: 'My Product Theme',
base: 'light',
primary: '#ff0000',
secondary: '#333333',
},
{ default: true }
);

Headlamp selects this theme only when the user has no saved theme preference. An explicit selection in General Settings or an administrator-forced theme always takes precedence. A plugin default takes precedence over backend light and dark defaults regardless of whether plugins or backend configuration finish loading first. See AppThemeRegistrationOptions for the registration options.

The terminal/log surfaces (pod logs, exec, node shell) follow the active theme automatically. To override their colors, set the optional terminal field on AppTheme — background, foreground, cursor, and a 16-color ansi palette. Anything you leave out is auto-derived from the surrounding MUI palette and contrast-clamped to stay readable on the chosen background. See the custom-theme example for a working registerAppTheme({ ..., terminal: { ... } }) call.

pod log viewer in light theme

UI Panels​

Register a side panel with registerUIPanel. A side panel is a UI element on one side of the application. You can define more than one panel per side. Each panel needs a unique ID, a side (top, left, right, bottom), and a React component.

screenshot of the side panels

Check the example plugin for the full code.

Resource Map Relations​

Register a custom relation provider for the Resource Map graph with registerResourceRelationProvider. This enables plugins to define custom edges and surface implicit dependencies between resources. Each relation needs a globally unique id, a fromSource graph source ID, and a predicate that returns whether two graph nodes should be connected. Use a plugin-prefixed relation ID to avoid colliding with Headlamp's built-in relations.

import { registerResourceRelationProvider } from '@kinvolk/headlamp-plugin/lib';

registerResourceRelationProvider({
id: 'my-plugin.deployment-secret',
fromSource: 'apps/Deployment',
toSource: 'Secret',
label: 'Uses Secret',
predicate: (from, to) => {
// predicate receives GraphNode objects; access K8s data via kubeObject.
return (
from.kubeObject?.jsonData.metadata.name === 'my-deployment' &&
to.kubeObject?.jsonData.metadata.name === 'my-secret'
);
},
});

registerResourceRelationProvider({
id: 'my-plugin.custom-source-deployment',
fromSource: 'my-source',
toSource: 'apps/Deployment',
label: 'Depends On',
predicate: (from, to) => {
// `my-source` is the ID passed to registerMapSource.
return (
from.kubeObject?.jsonData.metadata.name === 'my-test-resource' &&
to.kubeObject?.jsonData.metadata.name === 'my-deployment'
);
},
});

See the customizing-map example for a complete relation provider registration.

Custom resource relation in the Resource Map

Projects customization​

Customize Headlamp's Projects feature with several registration functions:

Group namespaces into separate project entries with registerProjectGrouping. By default, Headlamp combines namespaces with the same project ID across clusters, which is useful when they form one logical application. Use custom grouping when clusters represent distinct environments, tenants, or ownership boundaries and users need separate resource counts, health, and actions for each entry. The callback receives each namespace and its labelled project ID, and returns an opaque key. Namespaces with the same project ID and key are shown as one project entry. Return the project ID to preserve Headlamp's default cross-cluster grouping.

Add custom tabs to the project details view with registerProjectDetailsTab. Each tab needs a unique ID, a label, and a React component that receives the project as a prop.

Add custom sections to the project overview page with registerProjectOverviewSection. Each section needs a unique id and a component. The component receives the current project and its loaded projectResources.

Use the optional asynchronous isEnabled callback to display a section only for matching projects. The callback receives { project } and returns a Promise<boolean>. Sections without the callback are displayed by default. A section is hidden when the callback resolves to false, rejects, or throws, and eligibility is checked again when the project changes.

registerProjectOverviewSection({
id: 'multi-cluster-summary',
component: ({ project, projectResources }) => (
<MultiClusterSummary project={project} resources={projectResources} />
),
isEnabled: async ({ project }) => project.clusters.length > 1,
});

Add action buttons to the project details header with registerProjectHeaderAction. The action component receives the current project and an optional setSelectedTab?: (tabId: string) => void callback. Call it with the ID of a registered, enabled tab to select that tab. Unknown tabs and tabs without a component are ignored.

registerProjectHeaderAction({
id: 'view-metrics',
component: ({ setSelectedTab }) => (
<Button onClick={() => setSelectedTab?.('my-plugin.metrics')}>View metrics</Button>
),
});

Register custom API resources (e.g. CRDs) for project resource tracking with registerProjectApiResource. Once registered, the CRD resources will appear in the project's resource count, health status, and Resources tab. Only namespaced resources can be registered, since Projects are scoped to namespaces.

Example plugin: How to customize projects, including conditionally displayed overview sections.

Activities​

Activity is a Headlamp feature that allows you to create resizable popup windows. For example when you click on a resource (like a Pod or ReplicaSet), the details will open in Activity.

screenshot of an activity example

You can create and update Actitivities from plugins using Activity API

Check the example plugin for the full code.