@kinvolk/headlamp-plugin
Version:
The needed infrastructure for building Headlamp plugins.
663 lines (662 loc) • 23.7 kB
TypeScript
import React, { ReactNode } from 'react';
import { AppLogoProps, AppLogoType } from '../components/App/AppLogo';
import { PluginManager } from '../components/App/pluginManager';
import { runCommand } from '../components/App/runCommand';
import { ClusterChooserProps, ClusterChooserType } from '../components/cluster/ClusterChooser';
import { TableColumnsProcessor } from '../components/common/Resource/resourceTableSlice';
import { DetailsViewSectionProps, DetailsViewSectionType } from '../components/DetailsViewSection';
import { DefaultDetailsViewSection, DetailsViewsSectionProcessor } from '../components/DetailsViewSection/detailsViewSectionSlice';
import { GraphSource } from '../components/resourceMap/graph/graphModel';
import { IconDefinition } from '../components/resourceMap/graphViewSlice';
import { DefaultSidebars, SidebarEntryProps } from '../components/Sidebar';
import { getHeadlampAPIHeaders } from '../helpers/getHeadlampAPIHeaders';
import { AppTheme } from '../lib/AppTheme';
import { KubeObject } from '../lib/k8s/KubeObject';
import { Route } from '../lib/router';
import { AppBarAction, AppBarActionProcessorType, AppBarActionsProcessor, AppBarActionType, DefaultAppBarAction, DefaultHeaderAction, HeaderActionsProcessor, HeaderActionType } from '../redux/actionButtonsSlice';
import { CallbackAction, CallbackActionOptions } from '../redux/clusterActionSlice';
import { ClusterProviderInfo, DialogComponent, MenuItemComponent } from '../redux/clusterProviderSlice';
import { CreateResourceEvent, DeleteResourceEvent, EditResourceEvent, ErrorBoundaryEvent, EventListEvent, HeadlampEvent, HeadlampEventCallback, HeadlampEventType, LogsEvent, PluginLoadingErrorEvent, PluginsLoadedEvent, PodAttachEvent, ResourceDetailsViewLoadedEvent, ResourceListViewLoadedEvent, RestartResourceEvent, ScaleResourceEvent, TerminalEvent } from '../redux/headlampEventSlice';
import { OverviewChartsProcessor } from '../redux/overviewChartsSlice';
import { UIPanel } from '../redux/uiSlice';
import { PluginSettingsComponentType, PluginSettingsDetailsProps } from './pluginsSlice';
export interface SectionFuncProps {
title: string;
component: (props: {
resource: any;
}) => ReactNode;
}
export type { AppLogoProps, AppLogoType, ClusterChooserProps, ClusterChooserType, DefaultSidebars, DetailsViewSectionProps, DetailsViewSectionType, SidebarEntryProps, HeadlampEventCallback, HeadlampEvent, ErrorBoundaryEvent, DeleteResourceEvent, EditResourceEvent, ScaleResourceEvent, RestartResourceEvent, LogsEvent, TerminalEvent, PodAttachEvent, CreateResourceEvent, PluginLoadingErrorEvent, PluginsLoadedEvent, ResourceDetailsViewLoadedEvent, ResourceListViewLoadedEvent, EventListEvent, PluginSettingsDetailsProps, PluginSettingsComponentType, GraphSource, IconDefinition, OverviewChartsProcessor, };
export declare const DefaultHeadlampEvents: typeof HeadlampEventType;
export declare const DetailsViewDefaultHeaderActions: typeof DefaultHeaderAction;
export type { AppBarActionProcessorType };
/**
* @deprecated please used DetailsViewSectionType and registerDetailViewSection
*/
export type sectionFunc = (resource: KubeObject) => SectionFuncProps | null | undefined;
export type DetailsViewHeaderActionType = HeaderActionType;
export type DetailsViewHeaderActionsProcessor = HeaderActionsProcessor;
export default class Registry {
/**
* @deprecated Registry.registerSidebarItem is deprecated. Please use registerSidebarItem.
*/
registerSidebarItem(parentName: string | null, itemName: string, itemLabel: string, url: string, opts?: Pick<SidebarEntryProps, 'sidebar' | 'useClusterURL' | 'icon'>): void;
/**
* @deprecated Registry.registerRoute is deprecated. Please use registerRoute.
*/
registerRoute(routeSpec: Route): void;
/**
* @deprecated Registry.registerDetailsViewHeaderAction is deprecated. Please use registerDetailsViewHeaderAction.
*/
registerDetailsViewHeaderAction(actionName: string, actionFunc: HeaderActionType): void;
/**
* @deprecated Registry.registerAppBarAction is deprecated. Please use registerAppBarAction.
*/
registerAppBarAction(actionName: string, actionFunc: (...args: any[]) => ReactNode): void;
/**
* @deprecated Registry.registerDetailsViewSection is deprecated. Please use registerDetailsViewSection.
*
* ```tsx
*
* register.registerDetailsViewSection('biolatency', resource => {
* if (resource?.kind === 'Node') {
* return {
* title: 'Block I/O Latency',
* component: () => <CustomComponent />,
* };
* }
* return null;
* });
*
* ```
*/
registerDetailsViewSection(sectionName: string, sectionFunc: (resource: KubeObject) => SectionFuncProps | null): void;
/**
* @deprecated Registry.registerAppLogo is deprecated. Please use registerAppLogo.
*/
registerAppLogo(logo: AppLogoType): void;
/**
* @deprecated Registry.registerClusterChooserComponent is deprecated. Please use registerClusterChooser.
*/
registerClusterChooserComponent(component: React.ComponentType<ClusterChooserProps> | null): void;
}
/**
* Add a Sidebar Entry to the menu (on the left side of Headlamp).
*
* @example
*
* ```tsx
* import { registerSidebarEntry } from '@kinvolk/headlamp-plugin/lib';
* registerSidebarEntry({ parent: 'cluster', name: 'traces', label: 'Traces', url: '/traces' });
*
* ```
*
* @see {@link http://github.com/kinvolk/headlamp/plugins/examples/sidebar/ Sidebar Example}
*/
export declare function registerSidebarEntry({ parent, name, label, url, useClusterURL, icon, sidebar, }: SidebarEntryProps): void;
/**
* Remove sidebar menu items.
*
* @param filterFunc - a function for filtering sidebar entries.
*
* @example
*
* ```tsx
* import { registerSidebarEntryFilter } from '@kinvolk/headlamp-plugin/lib';
*
* registerSidebarEntryFilter(entry => (entry.name === 'workloads' ? null : entry));
* ```
*/
export declare function registerSidebarEntryFilter(filterFunc: (entry: SidebarEntryProps) => SidebarEntryProps | null): void;
/**
* Remove routes.
*
* @param filterFunc - a function for filtering routes.
*
* @example
*
* ```tsx
* import { registerRouteFilter } from '@kinvolk/headlamp-plugin/lib';
*
* registerRouteFilter(route => (route.path === '/workloads' ? null : route));
* ```
*/
export declare function registerRouteFilter(filterFunc: (entry: Route) => Route | null): void;
/**
* Add a Route for a component.
*
* @param routeSpec - details of URL, highlighted sidebar and component to use.
*
* @example
*
* ```tsx
* import { registerRoute } from '@kinvolk/headlamp-plugin/lib';
*
* // Add a route that will display the given component and select
* // the "traces" sidebar item.
* registerRoute({
* path: '/traces',
* sidebar: 'traces',
* component: () => <TraceList />
* });
* ```
*
* @see {@link https://github.com/kinvolk/headlamp/blob/main/frontend/src/lib/router.tsx Route examples}
* @see {@link http://github.com/kinvolk/headlamp/plugins/examples/sidebar/ Sidebar Example}
*
*/
export declare function registerRoute(routeSpec: Route): void;
/**
* Add a component into the details view header.
*
* @param headerAction - The action (link) to put in the app bar.
*
* @example
*
* ```tsx
* import { ActionButton } from '@kinvolk/headlamp-plugin/lib/CommonComponents';
* import { registerDetailsViewHeaderAction } from '@kinvolk/headlamp-plugin/lib';
*
* function IconAction() {
* return (
* <ActionButton
* description="Launch"
* icon="mdi:comment-quote"
* onClick={() => console.log('Hello from IconAction!')}
* />
* )
* }
*
* registerDetailsViewHeaderAction(IconAction);
* ```
*/
export declare function registerDetailsViewHeaderAction(headerAction: DetailsViewHeaderActionType): void;
/**
* Add a processor for the details view header actions. Allowing the modification of header actions.
*
* @param processor - The processor to add. Receives a resource (for which we are processing the header actions) and the current header actions and returns the new header actions. Return an empty array to remove all header actions.
*
* @example
*
* ```tsx
* import { registerDetailsViewHeaderActionsProcessor, DetailsViewDefaultHeaderActions } from '@kinvolk/headlamp-plugin/lib';
*
* // Processor that removes the default edit action.
* registerDetailsViewHeaderActionsProcessor((resource, headerActions) => {
* return headerActions.filter(action => action.name !== DetailsViewDefaultHeaderActions.EDIT);
* });
*
* More complete detail view example in plugins/examples/details-view:
* @see {@link http://github.com/kinvolk/headlamp/plugins/examples/details-view/ Detail View Example}
*
*/
export declare function registerDetailsViewHeaderActionsProcessor(processor: DetailsViewHeaderActionsProcessor | DetailsViewHeaderActionsProcessor['processor']): void;
/**
* Add a processor for the resource table columns. Allowing the modification of what tables show.
*
* @param processor - The processor ID and function. See #TableColumnsProcessor.
*
* @example
*
* ```tsx
* import { registerResourceTableColumnsProcessor } from '@kinvolk/headlamp-plugin/lib';
*
* // Processor that adds a column to show how many init containers pods have (in the default pods' list table).
* registerResourceTableColumnsProcessor(function ageRemover({ id, columns }) {
* if (id === 'headlamp-pods') {
* columns.push({
* label: 'Init Containers',
* // return plain value to allow filtering and sorting
* getValue: (pod: Pod) => {
* return pod.spec.initContainers.length;
* }
* // (optional) customise how the cell value is rendered
* render: (pod: Pod) => <div style={{ color: "red" }}>{pod.spec.initContainers.length}</div>
* });
* }
*
* return columns;
* });
* ```
*/
export declare function registerResourceTableColumnsProcessor(processor: TableColumnsProcessor | TableColumnsProcessor['processor']): void;
/**
* Add a component into the app bar (at the top of the app).
*
* @param headerAction - The action (link) to put in the app bar.
*
* @example
*
* ```tsx
* import { registerAppBarAction } from '@kinvolk/headlamp-plugin/lib';
* import { Button } from '@mui/material';
*
* function ConsoleLogger() {
* return (
* <Button
* onClick={() => {
* console.log('Hello from ConsoleLogger!')
* }}
* >
* Print Log
* </Button>
* );
* }
*
* registerAppBarAction(ConsoleLogger);
* ```
*/
export declare function registerAppBarAction(headerAction: AppBarActionType | AppBarAction | AppBarActionsProcessor | AppBarActionProcessorType): void;
/**
* Append a component to the details view for a given resource.
*
* @param viewSection - The section to add on different view screens.
*
* @example
*
* ```tsx
* import {
* registerDetailsViewSection,
* DetailsViewSectionProps
* } from '@kinvolk/headlamp-plugin/lib';
*
* registerDetailsViewSection(({ resource }: DetailsViewSectionProps) => {
* if (resource.kind === 'Pod') {
* return (
* <SectionBox title="A very fine section title">
* The body of our Section for {resource.kind}
* </SectionBox>
* );
* }
* return null;
* });
* ```
*/
export declare function registerDetailsViewSection(viewSection: DetailsViewSectionType): void;
/**
* Add a processor for the details view sections. Allowing the modification of what sections are shown.
*
* @param processor - The processor to add. Receives a resource (for which we are processing the sections) and the current sections and returns the new sections. Return an empty array to remove all sections.
*
* @example
*
* ```tsx
* import { registerDetailsViewSectionsProcessor } from '@kinvolk/headlamp-plugin/lib';
*
* registerDetailsViewSectionsProcessor(function addTopSection( resource, sections ) {
* // Ignore if there is no resource.
* if (!resource) {
* return sections;
* }
*
* // Check if we already have added our custom section (this function may be called multiple times).
* const customSectionId = 'my-custom-section';
* if (sections.findIndex(section => section.id === customSectionId) !== -1) {
* return sections;
* }
*
* return [
* {
* id: 'my-custom-section',
* section: (
* <SectionBox title="I'm the top of the world!" />
),
* },
* ...sections,
* ];
* });
* ```
*/
export declare function registerDetailsViewSectionsProcessor(processor: DetailsViewsSectionProcessor | DetailsViewsSectionProcessor['processor']): void;
/**
* Add a logo for Headlamp to use instead of the default one.
*
* @param logo is a React Component that takes two required props
* `logoType` which is a constant string literal that accepts either
* of the two values `small` or `large` depending on whether
* the sidebar is in shrink or expanded state so that you can change your logo
* from small to large and the other optional prop is the `themeName`
* which is a string with two values 'light' and 'dark' base on which theme is selected.
*
* @example
*
* ```tsx
* import { registerAppLogo } from '@kinvolk/headlamp-plugin/lib';
*
* registerAppLogo(<p>my logo</p>)
* ```
*
* More complete logo example in plugins/examples/change-logo:
* @see {@link http://github.com/kinvolk/headlamp/plugins/examples/change-logo/ Change Logo Example}
*
*/
export declare function registerAppLogo(logo: AppLogoType): void;
/**
* Use a custom cluster chooser button
*
* @param chooser is a React Component that takes one required props ```clickHandler``` which is the
* action handler that happens when the custom chooser button component click event occurs
*
* @example
*
* ```tsx
* import { ClusterChooserProps, registerClusterChooser } from '@kinvolk/headlamp-plugin/lib';
*
* registerClusterChooser(({ clickHandler, cluster }: ClusterChooserProps) => {
* return <button onClick={clickHandler}>my chooser Current cluster: {cluster}</button>;
* })
* ```
*
* @see {@link http://github.com/kinvolk/headlamp/plugins/examples/cluster-chooser/ Cluster Chooser example}
*
*/
export declare function registerClusterChooser(chooser: ClusterChooserType): void;
/**
* Override headlamp setToken method
* @param override - The setToken override method to use.
*
* @example
*
* ```ts
* registerSetTokenFunction((cluster: string, token: string | null) => {
* // set token logic here
* });
* ```
*/
export declare function registerSetTokenFunction(override: (cluster: string, token: string | null) => void): void;
/**
* Override headlamp getToken method
* @param override - The getToken override method to use.
*
* @example
*
* ```ts
* registerGetTokenFunction(() => {
* // set token logic here
* });
* ```
*/
export declare function registerGetTokenFunction(override: (cluster: string) => string | undefined): void;
/**
* Add a callback for headlamp events.
* @param callback - The callback to add.
*
* @example
*
* ```ts
* import {
* DefaultHeadlampEvents,
* registerHeadlampEventCallback,
* HeadlampEvent,
* } from '@kinvolk/headlamp-plugin/lib';
*
* registerHeadlampEventCallback((event: HeadlampEvent) => {
* if (event.type === DefaultHeadlampEvents.ERROR_BOUNDARY) {
* console.error('Error:', event.data);
* } else {
* console.log(`Headlamp event of type ${event.type}: ${event.data}`)
* }
* });
* ```
*/
export declare function registerHeadlampEventCallback(callback: HeadlampEventCallback): void;
/**
* Register a plugin settings component.
*
* @param name - The name of the plugin.
* @param component - The component to use for the settings.
* @param displaySaveButton - Whether to display the save button.
* @returns void
*
* @example
*
* ```tsx
* import { registerPluginSettings } from '@kinvolk/headlamp-plugin/lib';
* import { TextField } from '@mui/material';
*
* function MyPluginSettingsComponent(props: PluginSettingsDetailsProps) {
* const { data, onDataChange } = props;
*
* function onChange(value: string) {
* if (onDataChange) {
* onDataChange({ works: value });
* }
* }
*
* return (
* <TextField
* value={data?.works || ''}
* onChange={e => onChange(e.target.value)}
* label="Normal Input"
* variant="outlined"
* fullWidth
* />
* );
* }
*
* const displaySaveButton = true;
* // Register a plugin settings component.
* registerPluginSettings('my-plugin', MyPluginSettingsComponent, displaySaveButton);
* ```
*
* More complete plugin settings example in plugins/examples/change-logo:
* @see {@link https://github.com/kubernetes-sigs/headlamp/tree/main/plugins/examples/change-logo Change Logo Example}
*/
export declare function registerPluginSettings(name: string, component: PluginSettingsComponentType, displaySaveButton?: boolean): void;
/**
* Add a processor for the overview charts section. Allowing the addition or modification of charts.
*
* @param processor - The processor to add. Returns the new charts to be displayed.
*
* @example
*
* ```tsx
* import { registerOverviewChartsProcessor } from '@kinvolk/headlamp-plugin/lib';
*
* registerOverviewChartsProcessor(function addFailedPodsChart(charts) {
* return [
* ...charts,
* {
* id: 'failed-pods',
* component: () => <FailedPodsChart />
* }
* ];
* });
* ```
*/
export declare function registerOverviewChartsProcessor(processor: OverviewChartsProcessor): void;
/**
* Registers a new graph source in the store.
*
* @param {GraphSource} source - The graph source to be registered.
* @example
*
* ```tsx
* const mySource = {
* id: 'my-source',
* label: 'Sample source',
* useData() {
* return {
* nodes: [{ id: 'my-node', type: 'kubeObject', data: { resource: myCustomResource } }],
* edges: []
* };
* }
* }
*
* registerMapSource(mySource);
* ```
*/
export declare function registerMapSource(source: GraphSource): void;
/**
* Register Icon for a resource kind
*
* @param kind - Resource kind
* @param {IconDefinition} definition - icon definition
* @param definition.icon - React Element of the icon
* @param definition.color - Color for the icon, optional
*
* @example
*
* ```tsx
* registerKindIcon("MyCustomResource", { icon: <MyIcon />, color: "#FF0000" })
* ```
*/
export declare function registerKindIcon(kind: string, definition: IconDefinition): void;
/**
* Register a new cluster action menu item.
* @param item - The item to add to the cluster action menu.
*
* @example
*
* ```tsx
* import { registerClusterProviderMenuItem } from '@kinvolk/headlamp-plugin/lib';
* import { MenuItem, ListItemText } from '@mui/material';
* registerClusterProviderMenuItem(({cluster, setOpenConfirmDialog, handleMenuClose}) => {
* const isMinikube =
* cluster.meta_data?.extensions?.context_info?.provider === 'minikube.sigs.k8s.io';
* if (!isElectron() !! !isMinikube) {
* return null;
* }
* return (
* <MenuItem
* onClick={() => {
* setOpenConfirmDialog('deleteMinikube');
* handleMenuClose();
* }}
* >
* <ListItemText>{t('translation|Delete')}</ListItemText>
* </MenuItem>
* );
* )}
* ```
*
*/
export declare function registerClusterProviderMenuItem(item: MenuItemComponent): void;
/**
* Register a new cluster provider dialog.
*
* These dialogs are used to show actions that can be performed on a cluster.
* For example, starting, stopping, or deleting a cluster.
*
* @param item - The item to add to the cluster provider dialog.
* @param item.cluster - The cluster to show the dialog for.
* @param item.openConfirmDialog - The name of the dialog to open. Null if no dialog is open.
* @param item.setOpenConfirmDialog - The function to set the dialog to open.
* Call it with null when dialog is closed.
*
* @example
*
* ```tsx
* import { registerClusterProviderDialog } from '@kinvolk/headlamp-plugin/lib';
* import { CommandCluster } from './CommandCluster';
*
* registerClusterProviderDialog(({cluster, openConfirmDialog, setOpenConfirmDialog}) => {
*
* const isMinikube =
* cluster.meta_data?.extensions?.context_info?.provider === 'minikube.sigs.k8s.io';
* if (!isElectron() !! !isMinikube) {
* return null;
* }
*
* return (
* <CommandCluster
* initialClusterName={cluster.name}
* open={openConfirmDialog === 'startMinikube'}
* handleClose={() => setOpenConfirmDialog(null)}
* onConfirm={() => {
* setOpenConfirmDialog(null);
* }}
* command={'start'}
* finishedText={'Done! kubectl is now configured'}
* />
* );
* });
*
* ```
*
*/
export declare function registerClusterProviderDialog(item: DialogComponent): void;
/**
* For adding a card to the Add Cluster page in the providers list.
* @param item - The iformation to add to the Add Cluster page.
*
* @example
*
* ```tsx
* import { useTranslation } from 'react-i18next';
* import { registerAddClusterProvider } from '@kinvolk/headlamp-plugin/lib';
* import { Card, CardHeader, CardContent, Typography, Button } from '@mui/material';
* import { MinikubeIcon } from './MinikubeIcon';
* const { t } = useTranslation();
*
* registerAddClusterProvider({
* title: 'Minikube',
* icon: MinikubeIcon,
* description:
* 'Minikube is a lightweight tool that simplifies the process of setting up a Kubernetes environment on your local PC. It provides a localStorage, single-node Kubernetes cluster that you can use for learning, development, and testing purposes.',
* url: '/create-cluster-minikube',
* });
*
* ```
*
*/
export declare function registerAddClusterProvider(item: ClusterProviderInfo): void;
/**
* Add a new theme that will be available in the settings.
* Theme name should be unique
*
* @param theme - App Theme definition
*
* @example
*
* ```ts
* registerAppTheme({
* name: "My Custom Theme",
* base: "light",
* primary: "#ff0000",
* secondary: "#333",
* })
*
*/
export declare function registerAppTheme(theme: AppTheme): void;
/**
* Starts an action after a period of time giving the user an opportunity to cancel the action.
*
* @param callback - called after some time.
* @param actionOptions - options for text messages and callbacks.
*
* @example
*
* ```tsx
* clusterAction(() => runFunc(clusterName), {
* startMessage: `About to "${command}" cluster "${clusterName}"…`,
* cancelledMessage: `Cancelled "${command}" cluster "${clusterName}".`,
* successMessage: `Cluster "${command}" of "${clusterName}" begun.`,
* errorMessage: `Failed to "${command}" ${clusterName}.`,
* cancelCallback: () => {
* setActing(false);
* setRunning(false);
* handleClose();
* setOpenDialog(false);
* })
* ```
*
*/
export declare function clusterAction(callback: CallbackAction['callback'], actionOptions?: CallbackActionOptions): void;
/**
* Registers a UI panel in the application's UI.
*
* See {@link UIPanel} for more details on Panel definition
*
* @param panel - The UI panel configuration object to be registered
* @example
* ```tsx
* registerUIPanel({
* id: 'my-panel',
* location: 'right'
* component: () => <div style={{ width: '100px', flexShrink: 0 }}>Hello world</div>,
* });
* ```
*/
export declare function registerUIPanel(panel: UIPanel): void;
export { DefaultAppBarAction, DefaultDetailsViewSection, getHeadlampAPIHeaders, runCommand, PluginManager, };