Headlamp 集群选择器覆盖示例插件:用 registerClusterChooser 替换顶栏集群切换按钮
2026/9/17 3:45:24 网站建设 项目流程

Headlamp 集群选择器覆盖示例插件:用 registerClusterChooser 替换顶栏集群切换按钮

【免费下载链接】headlampA Kubernetes web UI that is fully-featured, user-friendly and extensible项目地址: https://gitcode.com/GitHub_Trending/he/headlamp

本文以 Headlamp 官方示例插件plugins/examples/cluster-chooser为主体,讲解如何通过插件机制覆盖 Headlamp 顶栏默认的集群选择按钮(cluster chooser),包括完整的本地运行步骤、示例源码逐段解析,以及框架侧 registerClusterChooser 与 useClustersConf 的实现原理。读完后你可以掌握:如何注册自定义集群选择组件、如何利用K8s工具类读取集群配置、如何扩展“无集群”空状态页面,以及如何为该插件编写单元测试。

示例插件的定位

该示例插件的目标只有一个:把 Headlamp 顶栏中央的默认集群选择按钮替换为自定义按钮。默认情况下,这个按钮由内置组件 ClusterChooser 渲染,显示当前集群名称及图标;覆盖后,它会被插件提供的组件取代,点击后仍会弹出 Headlamp 原有的集群选择弹窗。

插件目录结构如下,核心代码全部位于src/index.tsx

plugins/examples/cluster-chooser/ ├── src/ │ ├── headlamp-plugin.d.ts # 引入 @kinvolk/headlamp-plugin 的类型声明 │ ├── index.tsx # 插件主代码 │ └── index.test.tsx # 组件单元测试 ├── package.json ├── tsconfig.json └── README.md

本地运行插件

在已安装 Node.js 的环境中,进入仓库中的插件目录执行以下命令即可启动(插件会由headlamp-plugin脚手架工具构建并以开发模式加载):

cd headlamp/plugins/examples/cluster-chooser/ npm install npm start

运行成功后,在 Headlamp 顶栏中央可以看到被替换的集群选择按钮。

从 package.json 可以看到,该插件的全部脚本都委托给headlamp-pluginCLI:startbuildlinttsctesti18nstorybook等,开发依赖仅@kinvolk/headlamp-plugin一项,并将 TypeScript 锁定为5.6.2。这种单依赖结构是 Headlamp 插件的标准形态,插件开发入门可参考仓库内的 插件构建文档。

核心实现:registerClusterChooser 覆盖集群按钮

下面是插件主文件 src/index.tsx 的关键代码,逐段说明:

import { ClusterChooserProps, ClusterEmptyStateProps, K8s, registerClusterChooser, registerClusterEmptyState, } from '@kinvolk/headlamp-plugin/lib'; import { Button } from '@mui/material';

插件统一从@kinvolk/headlamp-plugin/lib导入注册函数与工具类,这是所有 Headlamp 插件的入口约定。

自定义按钮组件

/** Props for the ClusterChooserButton component. */ export interface ClusterChooserButtonProps { /** Handler called when the button is clicked. */ clickHandler: ClusterChooserProps['clickHandler']; /** Currently selected cluster name. */ cluster: ClusterChooserProps['cluster']; } /** A button that shows the current cluster and total cluster count using useClustersConf. */ 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> ); }

组件要点:

  • clickHandler:框架注入的点击回调。插件不需要自己实现“打开集群选择弹窗”的逻辑,只需在按钮的onClick中调用该回调,Headlamp 会照常弹出集群选择界面。
  • cluster:当前已选中集群的名称,由框架通过 props 传入,示例中直接展示为Cluster: minikube这类文本。
  • K8s.useClustersConf():Headlamp 提供给插件的 Hook,用于读取当前所有集群的配置对象。示例通过Object.keys(clusters)统计集群数量并显示在按钮上(例如(3 clusters))。

注册覆盖

// Replaces the default cluster chooser in the top bar with a button that shows // the current cluster name and total number of configured clusters (e.g. "Cluster: minikube (3 clusters)"). registerClusterChooser(({ clickHandler, cluster }: ClusterChooserProps) => ( <ClusterChooserButton clickHandler={clickHandler} cluster={cluster} /> ));

registerClusterChooser接受一个 React 组件(或元素),其 props 类型由 ClusterChooserProps 定义:

字段类型说明
clickHandler(event?: React.MouseEvent) => void点击按钮时由框架触发的处理器,用于打开默认集群选择弹窗
clusterstring?当前选中的集群名称
selectedClustersstring[]?多选模式下已选中的集群列表
iconstring?集群徽标图标(默认按钮用于ClusterBadge展示)
accentColorstring?集群主题强调色,可用于自定义按钮配色

其中clickHandler是框架要求的必填项:注册函数内部会将其分发给 Redux 状态,顶栏在渲染时把该回调与当前集群信息一起传给插件组件。

框架侧的覆盖机制

从源码结构看,覆盖流程可以分为三段:

  1. 注册入口。registerClusterChooser 的实现非常直接:

    export function registerClusterChooser(chooser: ClusterChooserType) { store.dispatch(uiSlice.actions.setClusterChooserButton(chooser)); }

    它把插件提供的组件写入uiSlice中的clusterChooserButton状态,因此后注册的插件会覆盖先前的注册结果。函数文档注释中也给出了最小示例:registerClusterChooser(({ clickHandler, cluster }) => <button onClick={clickHandler}>...</button>)

  2. 默认按钮。未被覆盖时,顶栏渲染内置的 ClusterChooser。它是一个React.forwardRef组件,使用 MUIButtonClusterBadge渲染集群名称,并处理了多选场景:选中多个集群时若不超过 2 个则内联展示名称,否则显示{{count}} clusters文案。插件组件注册后,顶栏改为渲染插件组件,因此插件只需要负责“长什么样”,弹窗交互仍由框架接管。

  3. 兼容旧 APIRegistry类上保留了registerClusterChooserComponent方法,但已被标记@deprecated,会打印警告并转发到函数式 API(见 registry.tsx 第 306-311 行)。新插件应直接使用registerClusterChooser

useClustersConf 的数据来源

示例按钮统计的集群数量来自K8s.useClustersConf()。其框架侧实现在 frontend/src/lib/k8s/index.ts:该 Hook 从 Redux 的configstate 中读取clustersallClusters并深拷贝合并;若存在statelessClusters(无状态集群,例如通过 URL token 注入的集群),也会合并进结果中。也就是说,插件按钮上显示的集群总数同时包含常规配置集群与无状态集群。

扩展空状态:registerClusterEmptyState

示例插件同时演示了第二个覆盖点:当用户尚未配置任何集群时,Headlamp 展示的“无集群”空状态页面。插件代码:

/** Demonstrates how a product can extend Headlamp's no-cluster experience. */ export function CustomClusterEmptyState({ defaultContent }: ClusterEmptyStateProps) { return ( <section> <p>Choose a cluster provider</p> {defaultContent} </section> ); } registerClusterEmptyState(CustomClusterEmptyState);

对应框架 API 在 registry.tsx 第 994 行:registerClusterEmptyState接收一个产品方提供的组件,该组件会拿到 Headlamp 的默认内容defaultContent,产品可以将其包裹在自定义文案或布局中,而不是完全丢弃原有内容;再次注册会替换此前的组件。这个 API 面向的产品化场景是:在默认的连接引导之上追加厂商自己的集群提供者入口(如云厂商一键接入)。

测试验证

插件的 index.test.tsx 用 Vitest + Testing Library 验证了按钮的核心行为,值得参考:

  • 集群未加载时显示 0:构造一个clusters: null的 Redux store 渲染组件,断言出现0 clusters,覆盖useClustersConf()返回空值的分支;
  • 展示集群数量:store 中放入 1 个集群my-cluster,断言出现Cluster: my-cluster1 clusters
  • 计入无状态集群:store 中同时包含 1 个常规集群与 1 个statelessClusters集群,断言总数为2 clusters,验证了上面提到的合并逻辑。

测试的关键技巧是:ClusterChooserButton通过K8s.useClustersConf()读取的是 Reduxconfigslice,因此测试只需configureStore一个伪造的configreducer,再用<Provider store={...}>包裹组件,即可完全脱离真实 Headlamp 环境运行。

小结与进一步阅读

  • 覆盖顶栏集群选择按钮只需调用registerClusterChooser,传入实现ClusterChooserProps的组件,并把框架传入的clickHandler绑定到自身按钮的点击事件上;
  • 需要读取集群配置时使用K8s.useClustersConf(),它会合并常规集群与无状态集群;
  • 需要定制“无集群”页面时使用registerClusterEmptyState,并保留defaultContent
  • 相关源码入口:registerClusterChooser 实现、默认 ClusterChooser 组件、useClustersConf 实现;
  • 插件开发通用流程见 docs/development/plugins/building.md,同类覆盖式示例还可参考 change-logo 插件 与 ui-panels 插件。

【免费下载链接】headlampA Kubernetes web UI that is fully-featured, user-friendly and extensible项目地址: https://gitcode.com/GitHub_Trending/he/headlamp

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询