Headlamp 插件开发常见模式(Common Plugin Patterns)实战指南:基于官方示例的 UI 扩展、主题定制与高级集成
Headlamp 是一个功能完整、用户友好且可扩展的 Kubernetes Web UI,其插件机制允许开发者以 JavaScript/TypeScript 模块的形式深度定制界面。本文以官方文档《Common Plugin Patterns》为核心骨架,结合仓库内 plugins/examples 目录下的 12 个可直接运行的示例插件,系统讲解顶部导航栏、侧边栏、详情页、表格、应用菜单、动态集群、插件设置、主题、Logo、图表、UI 面板与集群选择器等常见开发模式。读完本文,你将掌握 Headlamp 插件 API(registerAppBarAction、registerSidebarEntry、registerDetailsViewSection、registerAppTheme 等)的使用方法,并能够照抄示例快速落地自己的插件功能。
快速上手:如何运行官方示例
所有模式都在仓库的 plugins/examples/ 目录下配有可运行的完整示例。文档给出的标准运行流程如下:
# 1. 进入某个示例插件目录
cd plugins/examples/[example-name]
# 2. 安装依赖
npm install
# 3. 启动插件开发服务器
npm start
npm start 由 headlamp-plugin 工具提供。以 plugins/examples/pod-counter/package.json 为例,其 scripts 段暴露了一整套开发命令,而不仅是 start:
"scripts": {
"start": "headlamp-plugin start",
"build": "headlamp-plugin build",
"format": "headlamp-plugin format",
"lint": "headlamp-plugin lint",
"tsc": "headlamp-plugin tsc",
"storybook": "headlamp-plugin storybook",
"storybook-build": "headlamp-plugin storybook-build",
"test": "headlamp-plugin test",
"i18n": "headlamp-plugin i18n"
}
其中 start 会在开发模式下监听文件变化、自动重新构建插件;build 产出可直接分发的构建产物。运行后打开 Headlamp(桌面端会自动发现处于开发模式的插件,或按 development 指南 启动开发服务器),即可在界面中看到插件效果。若想从零创建一个新插件,可参考 Getting Started 中的脚手架命令:
npx --yes @kinvolk/headlamp-plugin create my-first-plugin
下文所有 API 均可在 @kinvolk/headlamp-plugin/lib 中导入(部分公共组件从 @kinvolk/headlamp-plugin/lib/CommonComponents 导入,例如 SectionBox、Table、NameValueTable、ActionButton、TileChart)。
UI 扩展模式
UI 扩展是插件最常用的场景,覆盖顶部导航栏、侧边栏、资源详情页、资源表格与应用菜单五大区域。
1. 向顶部导航栏(App Bar)添加内容
典型用途:集群统计信息、系统健康状态、快捷操作、全局信息。
示例插件 plugins/examples/pod-counter 通过 registerAppBarAction 在顶部导航栏展示集群中的 Pod 总数,并使用 K8s.ResourceClasses.Pod.useList() 获取实时数据(见 src/index.tsx):
import {
DefaultAppBarAction,
K8s,
registerAppBarAction,
registerPluginSettings,
} from '@kinvolk/headlamp-plugin/lib';
import Message from './Message';
function PodCounter() {
const [pods, error] = K8s.ResourceClasses.Pod.useList();
const msg = pods === null ? 'Loading…' : pods.length.toString();
return <Message msg={msg} error={error !== null} />;
}
registerAppBarAction(PodCounter);
代码要点:
useList()返回[数据, 错误]二元组;pods === null表示仍在加载,从而自然地处理加载中状态;- 传入的组件收到错误后由
Message组件渲染错误样式,即文档所述的“处理加载与错误”; - 组件直接复用 Headlamp 的 K8s 数据层,无需自行封装请求。
registerAppBarAction 还可以接收一个“重排函数”,对导航栏中的既有操作按钮重新排序或移除。示例演示了如何将“通知”按钮移到末尾:
registerAppBarAction(function reorderNotifications({ actions }) {
if (!actions) {
return actions;
}
// 移除默认的通知按钮
const newActions = actions.filter(action => action.id !== DefaultAppBarAction.NOTIFICATION);
// 也可以 push 一个自定义按钮:newActions.push({action: <PodCounter />, id: 'pod-counter'});
const notificationAction = actions.find(action => action.id === DefaultAppBarAction.NOTIFICATION);
if (notificationAction) {
newActions.push(notificationAction);
}
return newActions;
});
运行该示例后,顶部栏会显示类似“# Pods: 9”的统计信息,效果见下图(截图位于 docs/development/plugins/images/podcounter_screenshot.png):
2. 自定义侧边栏导航
典型用途:自定义仪表盘、外部工具链接、特殊资源视图、管理工具、甚至全新的侧边栏。
示例插件 plugins/examples/sidebar 是侧边栏能力的“百科全书”,其入口文件 src/index.tsx 展示了 registerSidebarEntry、registerSidebarEntryFilter、registerRoute、registerRouteFilter、registerHomeSidebarEntryFilter 的完整用法。下图是该示例的运行效果(截图位于 docs/development/plugins/images/sidebar.png):
添加顶级侧边栏项:通过 registerSidebarEntry 传入 parent: null 的条目即成为顶级项;url、icon 分别控制跳转地址与图标(图标使用 MDI 图标集,如 mdi:comment-quote):
registerSidebarEntry({
parent: null,
name: 'feedback',
label: 'Feedback',
url: '/feedback',
icon: 'mdi:comment-quote',
});
添加子级(嵌套)项:用 parent 指向父条目名称即可;若父条目尚未创建,parent 会先创建它:
registerSidebarEntry({
parent: 'feedback2', // 挂到 feedback2 下
name: 'feedback3',
label: 'More Feedback',
url: '/feedback3',
});
添加不可点击的分组标题:设置 entryType: 'subheader',并可用 sx 调整字号与大小写:
registerSidebarEntry({
parent: null,
name: 'feedback-section',
label: 'Feedback Tools',
entryType: 'subheader',
sx: { fontSize: '0.8rem', textTransform: 'none' },
});
创建全新的侧边栏:只需在条目中给出一个尚不存在的 sidebar 名称,Headlamp 会为该名称创建全新侧边栏并放入条目。示例创建了名为 myplugin 的独立侧边栏,并为它注册了“Back to Clusters”和“Special Area”两个入口:
registerSidebarEntry({
name: 'backtoclusters',
label: 'Back to Clusters',
url: '/',
icon: 'mdi:hexagon',
sidebar: 'myplugin', // 全新侧边栏
});
registerSidebarEntry({
name: 'mypluginarea',
label: 'Special Area',
url: '/mypluginarea',
icon: 'mdi:comment-quote',
sidebar: 'myplugin',
});
同时用 registerRoute 为每个 URL 注册对应的页面组件。路由支持几个关键选项:
sidebar:指定该路由对应的侧边栏条目(也可传{item, sidebar}对象);useClusterURL: false:URL 中不包含/c/<cluster>/前缀;noAuthRequired: true:该视图无需认证即可访问;hideAppBar: true:隐藏顶部 AppBar;exact: true:精确匹配路径。
例如“我的插件区”路由同时启用了前三项:
registerRoute({
path: '/mypluginarea',
sidebar: { item: 'mypluginarea', sidebar: 'myplugin' },
useClusterURL: false,
noAuthRequired: true,
name: 'mypluginarea',
exact: true,
component: () => (
<SectionBox title="Special Plugin Area" textAlign="center" paddingTop={2}>
<Typography>See how the home sidebar is completely new?</Typography>
</SectionBox>
),
});
移除侧边栏项与路由:registerSidebarEntryFilter 与 registerRouteFilter 接收“过滤函数”,返回 null 即删除该项。示例把内置的 Workloads、Namespaces 入口及其路由一并移除,并在 Home 侧边栏(HOME)中移除“settings”:
registerSidebarEntryFilter(entry => (entry.name === 'workloads' ? null : entry));
registerRouteFilter(route => (route.path === '/workloads' ? null : route));
registerSidebarEntryFilter(entry => (entry.name === 'namespaces' ? null : entry));
registerRouteFilter(route => (route.path === '/namespaces' ? null : route));
registerHomeSidebarEntryFilter(entry => (entry.name === 'settings' ? null : entry));
注意:registerSidebarEntryFilter 也可在组件内部动态调用(如在 useEffect 中移除“Click me and I will disappear”条目),从而实现运行期动态增删。
3. 增强资源详情页
典型用途:附加资源元数据、外部系统链接、自定义操作按钮、关联资源信息。
示例插件 plugins/examples/details-view 的 src/index.tsx 演示了 registerDetailsViewSection 与 registerDetailsViewHeaderAction(以及更进阶的 registerDetailsViewSectionsProcessor、registerDetailsViewHeaderActionsProcessor)。下图展示了详情页中新增自定义子标题的运行效果(截图位于 docs/development/plugins/images/details-view.jpeg):
向详情页添加自定义章节:registerDetailsViewSection 接收一个回调,回调返回 React 元素则渲染,返回 null 则跳过。示例只针对 ConfigMap 资源渲染自定义区块:
registerDetailsViewSection(({ resource }: DetailsViewSectionProps) => {
if (resource && resource.kind === 'ConfigMap') {
return (
<SectionBox title="A custom very fine section title">
The body of our custom Section for {resource.kind}
</SectionBox>
);
}
return null;
});
向头部添加操作按钮:registerDetailsViewHeaderAction 注册的组件会出现在详情页头部操作区:
function IconAction() {
return (
<ActionButton
description="Our action button"
icon="mdi:comment-quote"
onClick={() => console.log('Hello from IconAction!')}
/>
);
}
registerDetailsViewHeaderAction(IconAction);
调整章节顺序与替换默认按钮(进阶):
registerDetailsViewSectionsProcessor(resource, sections):拿到当前章节数组,可插入、删除或重排章节。示例借助DefaultDetailsViewSection.MAIN_HEADER定位主头部,并在其后插入自定义章节;registerDetailsViewHeaderActionsProcessor(resource, actions):拿到当前头部操作按钮数组,可替换默认按钮。示例使用DetailsViewDefaultHeaderActions.DELETE定位删除按钮,移除它并替换为自定义按钮(默认按钮还包括 EDIT、RESTART、SCALE 等)。
registerDetailsViewHeaderActionsProcessor(function replaceDeleteAction(resource, actions) {
if (!resource || !actions.find(action => action.id === DetailsViewDefaultHeaderActions.DELETE)) {
return actions; // 没有删除按钮就不做任何事
}
const actionsDeleteRemoved = actions.filter(action => action.id !== DetailsViewDefaultHeaderActions.DELETE);
return [
...actionsDeleteRemoved,
{
id: 'my-custom-delete-action',
action: (
<ActionButton
description="Useless button from a plugin example from details-view example plugin"
icon="mdi:delete"
onClick={() => alert(`One cannot simply delete a ${resource.kind}!`)}
/>
),
},
];
});
4. 定制资源表格
典型用途:表格行的上下文菜单、自定义表格列、行级操作、更好的数据展示。
示例插件 plugins/examples/tables 通过 registerResourceTableColumnsProcessor 为 Pods 列表的每一行追加一个三点“上下文菜单”(Details / Delete),代码见 src/index.tsx:
registerResourceTableColumnsProcessor(function setupContextMenuForPodsList({ id, columns }) {
if (id === 'headlamp-pods') {
const podColumns = columns as ResourceTableColumn<Pod>[];
podColumns.push({
label: '',
getValue: (pod: Pod) => pod.getDetailsLink(),
render: (pod: Pod) => <ContextMenu detailsLink={pod.getDetailsLink()} />,
});
}
return columns;
});
使用要点:
- 表格 ID 约定:资源列表表格的 ID 遵循
headlamp-${资源复数名}的约定,例如 Pods 列表是headlamp-pods、Namespaces 列表是headlamp-namespaces;而集群总览中的事件表是headlamp-cluster.overview.events。开发期可以在 processor 里打印id以确认目标表格; - 若不判断
id,则所有资源表格都会被修改;插件自己创建的表格也可以使用带自身前缀的 ID; - 新增列对象包含
label、getValue与render三个字段,render负责渲染自定义组件(此处为ContextMenu,一个使用 MUIMenu/MenuItem实现的下拉菜单)。
运行效果见下表截图(位于 docs/development/plugins/images/table-context-menu.png):
5. 应用集成(桌面端菜单)
典型用途:运行本地命令、桌面端菜单、外部工具快捷键、系统集成。
示例插件 plugins/examples/app-menus 通过 Headlamp.setAppMenu 在桌面端顶部菜单栏新增“Chat with us”菜单,代码见 src/index.tsx。它演示了基于 Plugin 基类的插件写法:
import { Headlamp, Plugin } from '@kinvolk/headlamp-plugin/lib';
class AppMenuDemo extends Plugin {
initialize(): boolean {
console.log('app-menus plugin initialized');
if (!Headlamp.isRunningAsApp()) {
window.alert('app-menus plugin: Headlamp is running as an app. This plugin will not do anything!');
return;
}
Headlamp.setAppMenu(menus => {
let chatMenu = menus?.find(menu => menu.id === 'custom-menu-item') || null;
if (!chatMenu) {
chatMenu = {
label: 'Chat with us',
id: 'custom-menu-item',
submenu: [
{ label: 'This menu is an example from the app-menus plugin', enabled: false },
{ label: 'Open Headlamp Slack', url: 'https://kubernetes.slack.com/messages/headlamp' },
],
};
menus.push(chatMenu);
}
return menus;
});
}
}
Headlamp.registerPlugin('app-menus', new AppMenuDemo());
要点:
Headlamp.isRunningAsApp()用于判断是否运行在桌面应用中(应用菜单只在桌面端生效);Headlamp.setAppMenu接收一个“变换函数”:入参是当前菜单数组,返回修改后的数组;菜单项结构为{label, id, submenu},子菜单项可设置enabled: false(置灰)或url(点击后打开外部链接);- 使用
Plugin子类时,在initialize()中完成注册,并通过Headlamp.registerPlugin(name, instance)挂载。运行效果见 docs/development/plugins/images/app-menus.png。
6. 动态集群管理
典型用途:自定义集群发现、动态集群注册、集群管理 UI、多集群部署。
示例插件 plugins/examples/dynamic-clusters 在顶部栏注册一个“New cluster”按钮,弹窗中根据后端是否开启动态集群(stateless)能力,提供两种接入方式,代码见 src/index.tsx:
// 挂载时向后端询问动态集群是否开启
useEffect(() => {
request('/config', {}, false, false).then((response: any) => {
setIsDynamicClusterEnabled(response.isDynamicClusterEnabled);
});
}, []);
- 动态集群开启时:要求用户粘贴 base64 编码的 kubeconfig,插件先用
atob解码并用js-yaml校验(apiVersion: v1且kind: Config),随后调用Headlamp.setCluster({ kubeconfig })注册集群; - 未开启时:退化为
Headlamp.setCluster({ name, server })的经典方式。
两种方式成功后都会 window.location.reload() 刷新界面;失败则通过 catch 捕获并回显错误信息。这展示了插件如何与后端 /config 接口联动,并结合 ApiProxy.request 与 Headlamp.setCluster 完成动态集群生命周期管理。
7. 插件设置(Plugin Settings)
典型用途:用户偏好、功能开关、配置表单、持久化设置。
示例插件 plugins/examples/pod-counter 与 plugins/examples/change-logo 都演示了 registerPluginSettings。
以 pod-counter 为例,registerPluginSettings('@kinvolk/headlamp-pod-counter', Settings, true) 将 Settings 组件注册到“插件设置”面板。Settings 组件接收 {data, onDataChange} 两个 props:data 是当前配置,onDataChange 用于提交新配置:
function Settings(props) {
const { data, onDataChange } = props;
const handleChange = event => {
onDataChange?.({ ...data, errorMessage: event.target.value });
};
const settingsRows = [
{
name: 'Custom Error Message',
value: (
<TextField
fullWidth
helperText="Enter the custom error message to display when the pod count cannot be retrieved."
value={data?.errorMessage ?? 'Uh... pods!?'}
onChange={handleChange}
variant="standard"
/>
),
},
];
return (
<Box width={'80%'}>
<NameValueTable rows={settingsRows} />
</Box>
);
}
change-logo 示例则展示了基于 ConfigStore 的持久化方案(见 settings.tsx):new ConfigStore<pluginConfig>('change-logo') 创建配置存储,store.get() 读取、store.set() 写入;设置表单里的 AutoSaveInput 组件对输入做 1000ms 防抖后自动保存,实现“边输入边持久化”的体验。
样式与主题模式
1. 自定义主题
典型用途:企业品牌定制、自定义配色、无障碍(可访问性)、深色/浅色主题。
示例插件 plugins/examples/custom-theme 通过 registerAppTheme 注册主题,入口 src/index.tsx 只有两行:
import { registerAppTheme } from '@kinvolk/headlamp-plugin/lib';
import { customTheme, customThemeWithTerminal } from './themes';
registerAppTheme(customTheme);
registerAppTheme(customThemeWithTerminal);
主题对象(AppTheme)的结构在 src/themes.ts 中有完整示例,包含 name、base('light'/'dark')、primary、secondary、text、background、sidebar(背景、前景、选中态背景/前景、操作按钮背景)、navbar、buttonTextTransform、radius 等字段:
export const customTheme: AppTheme = {
name: 'my custom theme',
base: 'light',
primary: '#414141',
secondary: '#eff2f5',
text: { primary: '#44444f' },
background: { muted: '#f5f5f5' },
sidebar: {
background: '#f0f0f0',
color: '#605e5c',
selectedBackground: '#f2e600',
selectedColor: '#292827',
actionBackground: '#414141',
},
navbar: { background: '#f0f0f0', color: '#292827' },
buttonTextTransform: 'none',
radius: 6,
};
注册后,用户可在 Settings → General 的下拉框中看到并切换“my custom theme”。示例还演示了可选的 terminal 字段:用于覆盖 xterm.js 终端(Pod 日志查看器、Pod exec 终端、Node shell)的配色,例如在浅色主题内保持深色终端:
export const customThemeWithTerminal: AppTheme = {
name: 'my custom theme with terminal',
base: 'light',
primary: '#414141',
text: { primary: '#44444f' },
background: { muted: '#f5f5f5' },
terminal: {
background: '#1e1e1e',
foreground: '#f5f5f5',
cursor: '#ffcc00',
ansi: {
red: '#ff5555',
green: '#50fa7b',
yellow: '#f1fa8c',
blue: '#8be9fd',
magenta: '#ff79c6',
cyan: '#8be9fd',
},
},
};
主题代码中的注释还给出了可访问性建议:终端 foreground 与 background 之间应保持 4.5:1 的对比度(WCAG 2.1 AA),以保证日志可读。
2. 自定义应用 Logo
典型用途:企业品牌、自定义视觉识别、主题感知的 Logo、响应式 Logo。
示例插件 plugins/examples/change-logo 演示了 registerAppLogo 的三种用法(见 src/index.tsx):
- 纯文本 Logo:只需两行代码:
import { registerAppLogo } from '@kinvolk/headlamp-plugin/lib';
registerAppLogo(() => <p>My Logo</p>);
- SVG 响应式 Logo:接收
AppLogoProps(含logoType、themeName、className、sx)。logoType为'small'(移动端)或'large'(桌面/平板端);themeName为'dark'或'light',据此可返回主题感知的 Logo:
export function ReactiveLogo(props: AppLogoProps) {
const { logoType, themeName } = props;
if (logoType === 'small' && themeName === 'dark') return <p>small dark theme logo</p>;
if (logoType === 'small' && themeName === 'light') return <p>small light theme logo</p>;
if (logoType === 'large' && themeName === 'dark') return <p>large dark theme logo</p>;
return <p>large light theme logo</p>;
}
- 图片 + 文本组合:
SimpleLogo在用户通过设置面板配置了 Logo URL 时渲染Avatar图片,否则回退到两个 SVG 文件(大图icon-large-light.svg、小图icon-small-light.svg):
function SimpleLogo(props: AppLogoProps) {
const { logoType, className, sx } = props;
const config = store.useConfig()();
return config?.url ? (
<Avatar src={config?.url} alt="logo" className={className} sx={sx} />
) : (
<SvgIcon
className={className}
component={logoType === 'large' ? LogoWithTextLight : LogoLight}
viewBox="0 0 auto 32"
sx={sx}
/>
);
}
配合前文提到的 ConfigStore 与 registerPluginSettings,用户可以在设置面板中输入 Logo URL 并自动保存,实现“可配置的 Logo”。运行效果见 docs/development/plugins/images/change-logo.png。
高级模式
1. 数据可视化(图表)
典型用途:资源用量图表、集群健康仪表盘、性能指标、自定义监控。
示例插件 plugins/examples/resource-charts 在集群总览页(Overview)上新增“Pods Failed”图表,代码见 src/index.tsx。核心是 registerOverviewChartsProcessor 与 TileChart 组件的组合:
function PodFailureChart() {
const [pods, error] = K8s.ResourceClasses.Pod.useList();
const theme = useTheme();
const failedPods = (pods || []).filter(pod => {
const phase = pod.status?.phase;
return phase === 'Failed' || phase === 'Unknown';
});
if (error) {
return (
<Box p={2}>
<Paper>
<Box p={2}>{`Error loading pods: ${error}`}</Box>
</Paper>
</Box>
);
}
const totalPods = pods?.length || 0;
const failedCount = failedPods.length;
return (
<TileChart
title="Pods Failed"
data={[{ name: 'failed', value: failedCount, fill: theme.palette.error.main }]}
total={totalPods}
label={totalPods === 0 ? '0' : `${((failedCount / totalPods) * 100).toFixed(1)}%`}
legend={totalPods === 0 ? 'No pods found' : `${failedCount} failed / ${totalPods} total`}
/>
);
}
registerOverviewChartsProcessor({
id: 'pod-failed',
processor: charts => {
return [
...charts,
{ id: 'pod-failed', component: () => <PodFailureChart /> },
];
},
});
要点:useList() 提供实时数据;错误时渲染错误卡片;TileChart 接收 title、data(含 name/value/fill)、total、label、legend,颜色可直接取自 MUI 主题(theme.palette.error.main),与 Headlamp 视觉体系保持一致。
2. UI 面板(UIPanel)
典型用途:自定义仪表盘、专用视图、可复用 UI 组件、复杂数据展示。
示例插件 plugins/examples/ui-panels 通过 registerUIPanel 在界面的上、下、左、右四个方向各注册一个面板,代码见 src/index.tsx:
registerUIPanel({
id: 'top-panel',
side: 'top',
component: () => (
<div
role="region"
aria-label="top panel"
style={{
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
height: '50px',
flexShrink: 0,
border: '1px solid green',
}}
>
Top Panel
</div>
),
});
registerUIPanel({ id: 'bottom-panel', side: 'bottom', component: () => /* ... */ });
registerUIPanel({ id: 'left-panel', side: 'left', component: () => /* ... */ });
registerUIPanel({ id: 'right-panel', side: 'right', component: () => /* ... */ });
side 支持 'top' | 'bottom' | 'left' | 'right',组件内可自由组合 MUI 组件或自定义内容,是搭建自定义布局与可复用面板的基础设施。
3. 自定义集群选择器
典型用途:自定义集群发现、增强集群元数据、专用集群视图、多环境管理。
示例插件 plugins/examples/cluster-chooser 同时替换了顶部栏的集群选择器与“无集群”空状态界面,代码见 src/index.tsx:
export function ClusterChooserButton({ clickHandler, cluster }: ClusterChooserButtonProps) {
const clusters = K8s.useClustersConf();
const clusterNames = clusters ? Object.keys(clusters) : [];
return (
<Button onClick={clickHandler}>
Our Cluster Chooser button. Cluster: {cluster} ({clusterNames.length} clusters)
</Button>
);
}
registerClusterChooser(({ clickHandler, cluster }: ClusterChooserProps) => (
<ClusterChooserButton clickHandler={clickHandler} cluster={cluster} />
));
registerClusterEmptyState(CustomClusterEmptyState);
要点:
registerClusterChooser接收一个渲染函数,props 提供clickHandler(点击后打开默认集群选择面板)与cluster(当前集群名);- 通过
K8s.useClustersConf()可读取全部已配置集群,从而展示“当前集群 + 集群总数”; registerClusterEmptyState用于定制“没有集群”时的引导页,其 props 中的defaultContent是默认内容,可在其基础上包裹自定义文案(如“Choose a cluster provider”),实现既保留原生能力又叠加品牌信息。
运行效果见 docs/development/plugins/images/cluster-chooser.png。
模式速查与选型建议
| 目标区域 | 核心 API | 参考示例(仓库内路径) |
|---|---|---|
| 顶部导航栏 | registerAppBarAction | plugins/examples/pod-counter |
| 侧边栏 / 路由 | registerSidebarEntry、registerRoute、registerSidebarEntryFilter、registerRouteFilter | plugins/examples/sidebar |
| 资源详情页 | registerDetailsViewSection、registerDetailsViewHeaderAction | plugins/examples/details-view |
| 资源表格 | registerResourceTableColumnsProcessor | plugins/examples/tables |
| 桌面应用菜单 | Headlamp.setAppMenu、Plugin 基类 | plugins/examples/app-menus |
| 动态集群 | Headlamp.setCluster、ApiProxy.request | plugins/examples/dynamic-clusters |
| 插件设置 | registerPluginSettings、ConfigStore | plugins/examples/pod-counter、plugins/examples/change-logo |
| 自定义主题 | registerAppTheme | plugins/examples/custom-theme |
| 自定义 Logo | registerAppLogo | plugins/examples/change-logo |
| 图表可视化 | registerOverviewChartsProcessor、TileChart | plugins/examples/resource-charts |
| UI 面板 | registerUIPanel | plugins/examples/ui-panels |
| 集群选择器 | registerClusterChooser、registerClusterEmptyState | plugins/examples/cluster-chooser |
选型建议:需要全局信息或快捷入口时优先考虑 App Bar;需要承载一组独立页面时使用侧边栏 + 路由;对单个资源做增值展示(元数据、操作)时使用详情页扩展;需要行级操作时扩展表格列;品牌化场景则同时考虑自定义主题与 Logo。若需要了解插件的构建、打包与发布,可继续阅读 Building 与 Publishing 指南;插件的国际化支持可参考 i18n。上述所有模式均有可运行示例支撑,直接以对应示例为起点进行二次开发,是上手 Headlamp 插件开发最高效的路径。
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考







