Metabase 嵌入 SDK 点击行为定制:MetabaseClickAction 类型与 mapQuestionClickActions 插件完全指南
Metabase 嵌入 SDK 点击行为定制:MetabaseClickAction 类型与 mapQuestionClickActions 插件完全指南
Metabase 的模块化嵌入 SDK(Modular Embedding SDK)允许你在自己的 React 应用中直接嵌入交互式图表与仪表盘。当用户点击图表中的数据点时,Metabase 默认会弹出一个操作菜单(如"查看详情""钻取""自动洞察"等)。MetabaseClickAction 就是描述这些菜单操作项(以及自定义操作项)的核心类型,而 mapQuestionClickActions 插件则是对其进行接管、追加或替换的入口。读完本文,你将理解 MetabaseClickAction 的类型骨架与 name 字段的含义、MetabaseClickActionPluginsConfig 的函数签名,并掌握如何在 MetabaseProvider 全局或 InteractiveQuestion 组件级别定制点击行为。
一、MetabaseClickAction 类型定义解析
该类型定义位于 docs/embedding/sdk/api/snippets/MetabaseClickAction.md,其完整声明如下:
type MetabaseClickAction = {
name: string;
} & Record<string, any>;
类型声明表:
| Name | Type |
|---|---|
name |
string |
这是一个非常"宽松"的类型:唯一强制字段是 name,其余字段全部通过 Record<string, any> 放开。这种设计带来的两个直接推论:
- 每个点击操作项都必须有一个字符串类型的
name,用于在操作项集合中标识该动作; - 其余属性(如标题、图标、按钮形态、点击回调等)均不强制,可按需附加,SDK 不会在类型层面阻止你扩展任何字段。
与源码 ClickAction 的关系
从 SDK 源码看,SDK 暴露给应用侧的 MetabaseClickActionPluginsConfig 实际操作的是来自 metabase/visualizations/types 的 ClickAction(见 frontend/src/metabase/embedding-sdk/types/plugins.ts)。MetabaseClickAction 可以理解为面向 SDK 使用者的、对外文档化的简化视图:它以 name 为强制锚点,其余信息对应用开放。因此在实际代码中,一个操作项通常还会携带 title(菜单标题)、onClick(点击回调)等字段,这些字段正是通过 Record<string, any> 部分被接纳的。
二、name 字段:操作项的标识锚点
name 是 MetabaseClickAction 唯一强制字段,其作用主要有三点:
- 唯一标识:在
clickActions数组中区分不同的操作项,便于插件对既有操作做增删改; - 保证可扩展性:有了
name这个稳定的锚点,其余字段可以被自由扩展而不破坏类型结构; - 序列化友好:
string类型保证操作项可以被安全地序列化、比对与记录。
三、使用场景:mapQuestionClickActions 插件
MetabaseClickAction 不会独立出现,它总是作为 mapQuestionClickActions 插件的输入与输出类型被消费。该插件的类型定义见 MetabaseClickActionPluginsConfig.md:
type MetabaseClickActionPluginsConfig = (
clickActions: MetabaseClickAction[],
clickedDataPoint: MetabaseDataPointObject,
) =>
| MetabaseClickAction[]
| {
onClick: () => void;
};
参数表:
| Parameter | Type |
|---|---|
clickActions |
MetabaseClickAction[] |
clickedDataPoint |
MetabaseDataPointObject |
返回值:
MetabaseClickAction[]:返回一组操作项(可原样返回、追加或替换);{ onClick: () => void }:返回一个立即执行的回调对象,表示"不弹菜单,直接执行"。
官方文档(docs/embedding/sdk/plugins.md)对它的定位是:自定义用户点击仪表盘或图表数据点时发生的行为;既可以在全局使用,也可以在组件级别使用。
四、clickedDataPoint 参数:被点击数据点的完整信息
第二个参数 clickedDataPoint 的类型是 MetabaseDataPointObject(见 MetabaseDataPointObject.md),它把"用户点到了哪里"完整地带给插件:
type MetabaseDataPointObject = {
column?: {
display_name?: string;
name?: string;
};
data?: Record<string, string | number | null | boolean | object>;
event?: MouseEvent;
question?: MetabaseQuestion;
raw?: {
column?: Record<string, any>;
data?: {
col: Record<string, any> | null;
value: string | number | null | boolean;
}[];
event?: MouseEvent;
value?: string | number | null | boolean;
};
value?: string | number | null | boolean | object;
};
关键字段速览:
| 字段 | 含义 |
|---|---|
value |
被点击单元格的值(字符串/数字/布尔/对象等) |
column |
被点击列的信息,含 name(列名)与 display_name(显示名) |
data |
以列名为键的整行数据记录 |
event |
触发点击的原生 MouseEvent |
question |
当前查询对应的 MetabaseQuestion 对象 |
raw |
底层未加工的数据与事件信息,data 为 { col, value }[] 数组 |
在编写自定义逻辑时,最常见的判据就是 clicked?.column?.display_name(按列名区分行为)或 clicked?.value(按单元格值区分行为)。
五、三种返回形态:默认菜单、追加操作、立即执行
根据 docs/embedding/chart.md 的说明,mapQuestionClickActions 允许三种行为:
- 打开默认菜单:原样返回
clickActions,保持 Metabase 默认行为; - 追加自定义操作:返回
[...clickActions, customAction],在默认菜单基础上增加自定义项; - 立即执行:返回
{ onClick: () => void },点击后不展示菜单,直接触发回调。
需要注意的是,该功能目前仅适用于模块化嵌入 SDK(Modular Embedding SDK)。
六、完整实战示例
仓库提供的可运行示例位于 docs/embedding/sdk/snippets/questions/interactive-question-click-actions.tsx,它演示了全部三种形态的组合使用:
import {
defineMetabaseAuthConfig,
InteractiveQuestion,
MetabaseProvider,
} from "@metabase/embedding-sdk-react";
const authConfig = defineMetabaseAuthConfig({
metabaseInstanceUrl: "http://localhost:3000",
});
const Example = () => {
return (
<MetabaseProvider
authConfig={authConfig}
pluginsConfig={{
mapQuestionClickActions: (clickActions, clicked) => {
if (clicked?.column?.display_name === "Last Name") {
// 在 "Last Name" 列上追加一个自定义菜单项
return [
...clickActions,
{
buttonType: "horizontal",
name: "custom",
title: "This is the Last Name column",
onClick: () => alert("You clicked the Last Name column!"),
},
];
}
if (clicked?.column?.display_name === "Plan") {
// 在 "Plan" 列上不弹菜单,立即执行
return {
onClick: () => alert("You clicked the Plan column!"),
};
}
// 其他列保持 Metabase 默认点击菜单
return clickActions;
},
}}
>
<InteractiveQuestion questionId={1} />
</MetabaseProvider>
);
};
这个示例展示了 MetabaseClickAction 的实际形态:自定义操作项 { buttonType, name, title, onClick } 中,name 是强制字段,title 决定菜单中展示的文案,buttonType 控制按钮的布局形态,onClick 承载实际业务逻辑。以 name 为锚点、其余字段自由扩展的结构在这里体现得淋漓尽致。
七、源码级印证:插件类型在 SDK 中的真实定义
在 frontend/src/metabase/embedding-sdk/types/plugins.ts 中,插件的真实定义为:
export type MetabaseClickActionPluginsConfig = (
clickActions: ClickAction[],
clickedDataPoint: MetabaseDataPointObject,
) => ClickAction[] | { onClick: () => void };
可以确认:
- 源码中的
MetabaseClickActionPluginsConfig与文档 snippet 的签名完全一致,仅将对外文档化的MetabaseClickAction映射为内部的ClickAction; - 该插件被挂在全局插件配置
MetabasePluginsConfig的mapQuestionClickActions字段下(同文件 plugins.ts),与仪表盘卡片菜单dashboard.dashboardCardMenu并列,属于 SDK 全局插件体系的一部分。
在 SDK 内部,点击菜单由 frontend/src/metabase/querying/click-actions 模块驱动,mapQuestionClickActions 会在点击事件触发时被调用,从而在默认行为之前插入你的定制逻辑。
八、全局配置与组件级配置
mapQuestionClickActions 可以在两个层面注入:
- 全局层面:通过
MetabaseProvider的pluginsConfig.mapQuestionClickActions传入(如上面的示例),对所有嵌入组件生效; - 组件层面:通过
InteractiveQuestion等组件的插件配置单独传入,仅对当前组件生效。
官方文档(docs/embedding/sdk/plugins.md)明确说明其"可以全局使用,也可以在组件级别使用",并进一步指向图表定制章节 docs/embedding/chart.md 获取更多示例。两种层级叠加时,组件级配置优先于全局配置,这为"全局兜底 + 局部特化"的嵌入场景提供了灵活的组合空间。
总结
MetabaseClickAction 以 { name: string } & Record<string, any> 这样极简而开放的类型,成为 Metabase 嵌入 SDK 点击行为定制体系的基石:name 保证每个操作项可被稳定标识,Record<string, any> 则允许你在不破坏类型结构的前提下自由扩展业务字段。配合 mapQuestionClickActions 插件,你可以对交互式图表与仪表盘的点击行为进行三种粒度的定制——保留默认菜单、追加自定义操作项、或完全绕过菜单立即执行,从而把嵌入应用的数据交互体验完全握在自己手中。