Metabase Embedding SDK 实战指南:EditableDashboard 可编辑仪表盘组件
【免费下载链接】metabaseThe easy-to-use open source Business Intelligence and Embedded Analytics tool that lets everyone work with data :bar_chart:项目地址: https://gitcode.com/GitHub_Trending/me/metabase
导读
EditableDashboard是 Metabase Embedding SDK 提供的可编辑仪表盘组件:它在InteractiveDashboard(支持钻取、点击行为、查看问题)的全部能力之上,额外允许最终用户在嵌入应用中添加、更新问题(question)、调整布局与内容。本文将以 EditableDashboard.md 为核心,完整讲解其函数签名、EditableDashboardProps全部参数语义,并结合仓库源码剖析其"可编辑"能力的底层实现与受控参数机制,帮助你正确选用仪表盘组件并把可编辑能力安全、可控地嵌入到自己的产品中。
组件定位:三种仪表盘组件的能力分层
在 Metabase Embedding SDK 中,仪表盘(Dashboard)组件族分为三档能力层级,从 API 索引 的 "Dashboard" 分组可以清晰看到它们的定位:
| 组件 | 定位 |
|---|---|
| StaticDashboard | 轻量级只读仪表盘组件 |
| InteractiveDashboard | 支持钻取、点击行为、可查看并点击进入问题的仪表盘 |
| EditableDashboard | 具备InteractiveDashboard全部特性,且可添加/更新问题、布局与内容 |
从源码 EditableDashboard.tsx 可以看到,EditableDashboard并不是从零实现,而是基于通用底座SdkDashboard定制而来:
export type EditableDashboardProps = SdkDashboardProps & EditableDashboardOwnProps; export const EditableDashboard = Object.assign( withPublicComponentWrapper(EditableDashboardInner, { supportsGuestEmbed: false, // 可编辑仪表盘不支持游客嵌入 }), { schema: editableDashboardSchema, }, );其中supportsGuestEmbed: false是一个关键事实:可编辑仪表盘不支持匿名游客(guest)嵌入模式,因为编辑仪表盘必然涉及写操作,需要真实的已认证用户身份。
函数签名与返回类型
原文档给出组件签名如下:
function EditableDashboard(props: EditableDashboardProps): Element;- 参数:唯一的入参是
props,其完整类型为EditableDashboardProps。 - 返回值:一个 React
Element,即渲染后的嵌入组件节点。
组件自身的静态schema
除了作为组件渲染外,EditableDashboard还通过Object.assign挂载了一个静态schema属性(见 EditableDashboard.schema.ts),它基于 Yup 定义了可接受 props 的白名单结构:
const propsSchema: Yup.SchemaOf<EditableDashboardProps> = Yup.object({ children: Yup.mixed().optional(), className: Yup.mixed().optional(), dashboardId: Yup.mixed().required(), // 唯一必填项 token: Yup.mixed().optional(), dataPickerProps: Yup.object({ entityTypes: Yup.mixed().optional() }) .optional() .noUnknown(), // 拒绝 schema 未声明的字段 // ... drillThroughQuestionProps、hiddenParameters、initialParameters、 // parameters、onParametersChange、onLoad、onLoadWithoutCards、 // plugins、renderDrillThroughQuestion、style、autoRefreshInterval、 // withCardTitle、withDownloads、withSubscriptions、withTitle、 // onVisualizationChange、enableEntityNavigation }).noUnknown();从 schema 结构可以推断:dashboardId是唯一必填属性,且.noUnknown()校验策略意味着传入未声明字段会被拒绝——这对于确保嵌入参数可预测、避免误传是重要的约束。
EditableDashboardProps 完整参数详解
EditableDashboardProps.md 定义了组件的全部可配置项。下面按功能域分组展开(标?为可选属性)。
基础标识与样式
| 属性 | 类型 | 说明 |
|---|---|---|
dashboardId | string \| number | 必填。仪表盘 ID,二选一:数字 ID(访问链接如http://localhost:3000/dashboard/1-my-dashboard中的1);或通过 API / SDK Collection Browser 拿到的entity_id字符串。底层类型别名见 SdkDashboardId(number \| string \| SdkEntityId) |
token? | string \| null | 覆盖默认的嵌入令牌(原文档未展开说明,schema 中声明为可选) |
className? | string | 追加到根元素的自定义类名 |
style? | CSSProperties | 追加到根元素的自定义样式对象 |
仪表盘渲染控制
| 属性 | 类型 | 说明 |
|---|---|---|
withTitle? | boolean | 是否显示仪表盘标题 |
withCardTitle? | boolean | 是否显示卡片(card)标题 |
withDownloads? | boolean | 是否隐藏下载按钮 |
withSubscriptions? | boolean | 是否显示订阅按钮 |
autoRefreshInterval? | number | 仪表盘自动刷新间隔,单位为秒 |
enableEntityNavigation? | boolean | 为true时保留内部点击行为(跳转仪表盘/问题链接);为false(SDK 默认值)时过滤掉这些点击行为 |
这些展示控制项在源码中直接参与组件挂载埋点(见 EditableDashboard.tsx):
useTrackSdkComponentMount("EditableDashboard", dashboardId, { with_title: withTitle, with_downloads: withDownloads, with_subscriptions: withSubscriptions, auto_refresh: autoRefreshInterval != null, enable_entity_navigation: enableEntityNavigation, });参数(Parameters)相关
SDK 对仪表盘参数(filter)的支持分为"一次性初始值"与"受控值"两种模式,均以 slug 作为键:
initialParameters?— 类型ParameterValues。挂载时一次性应用的初始参数值,用户之后在控件上的编辑不会回传宿主。每个参数的取值规则:
- 设为值(单选为字符串、多选为字符串数组):应用该值;
- 设为
null:严格清空,忽略参数自身默认值; - 省略(或设为
undefined):回退到参数默认值(无默认值则为null)。
parameters?— 类型ParameterValues。受控参数值:每次渲染时用该对象整体替换仪表盘参数值。规则与initialParameters一致,但它是持续受控的——应配合onParametersChange同步用户编辑,形成"单向数据流 + 回传"的闭环。
hiddenParameters?—string[]。需要隐藏的参数列表。
- 安全提示(原文档明确警告):用
initialParameters/parameters组合hiddenParameters在前端过滤数据属于安全风险(每个终端用户都必须有自己的 Metabase 账号),不应这样用; - 仅用于整理界面(如隐藏不想展示的过滤控件)则没有问题。
onParametersChange?—(payload: ParameterChangePayload) => void。参数变化回调,payload 的source字段区分三类事件(见 ParameterChangePayload 与 index.md 中的 ParameterChangeSource):
initial-state:加载时首次应用快照,每次仪表盘加载触发一次;manual-change:用户在 UI 中编辑参数;auto-change:自动更新场景(例如把归一化后的值回传给父组件)。
payload 结构:{ defaultParameters, lastUsedParameters, parameters, source },其中parameters为当前生效值,defaultParameters为默认值,lastUsedParameters为最近一次使用的值。
生命周期回调
| 属性 | 类型 | 说明 |
|---|---|---|
onLoad? | (dashboard: MetabaseDashboard \| null) => void | 仪表盘加载完成后回调 |
onLoadWithoutCards? | (dashboard: MetabaseDashboard \| null) => void | 仪表盘无卡片加载完成时回调 |
onVisualizationChange? | (visualization: ... ) => void | 从仪表盘卡片打开问题,或用户更换问题可视化类型时触发;类型为 21 种可视化名称的联合:"object" \| "table" \| "bar" \| "line" \| "pie" \| "scalar" \| "row" \| "area" \| "combo" \| "pivot" \| "smartscalar" \| "gauge" \| "progress" \| "funnel" \| "map" \| "scatter" \| "boxplot" \| "waterfall" \| "sankey" \| "treemap" \| "list" |
onLoad回调收到的dashboard对象是 MetabaseDashboard 实体,包含id、entity_id、name、description、collection、created_at、updated_at以及last-edit-info(email、first_name、last_name、id、timestamp)等字段——其中last-edit-info对"可编辑仪表盘"场景尤其有用,可用于展示"上次由谁编辑"的信息。
钻取(Drill-through)与插件扩展
| 属性 | 类型 | 说明 |
|---|---|---|
drillThroughQuestionHeight? | Height<string \| number> | 从仪表盘钻取到问题层级时,问题组件的高度 |
drillThroughQuestionProps? | DrillThroughQuestionProps | 钻取到问题层级时问题组件的 props(其plugins字段会被用于构造点击行为模式,见下方源码) |
renderDrillThroughQuestion? | () => ReactNode | 自定义问题布局的 React 组件,应使用带命名空间的InteractiveQuestion组件来构建布局 |
plugins? | MetabasePluginsConfig | 用于覆盖或新增钻取菜单的 mapper 函数(详见"实现自定义 actions"相关章节) |
在源码 EditableDashboard.tsx 中,钻取行为被显式装配为"SDK 嵌入模式":
const clickActionMode = useMemo( () => getEmbeddingMode({ queryMode: createEmbeddingSdkMode({ pushNavigation }), plugins: props.drillThroughQuestionProps?.plugins, }), [pushNavigation, props.drillThroughQuestionProps?.plugins], );新建问题时的数据选择器
dataPickerProps?—Pick<SdkQuestionProps, "entityTypes">。透传给新建仪表盘问题时由InteractiveQuestion渲染的查询构建器(query builder)的附加 props,目前只开放entityTypes(限制可选择的数据实体类型)。schema 中也仅放行dataPickerProps.entityTypes单个字段。
源码视角:"可编辑"是如何实现的
编辑态与非编辑态的头部动作
EditableDashboard与InteractiveDashboard最本质的差异体现在 dashboardActions 工厂函数:
const dashboardActions: SdkDashboardInnerProps["dashboardActions"] = ({ isEditing, }) => isEditing ? DASHBOARD_EDITING_ACTIONS : [ DASHBOARD_ACTION.EDIT_DASHBOARD, DASHBOARD_ACTION.DASHBOARD_SUBSCRIPTIONS, DASHBOARD_ACTION.DOWNLOAD_PDF, DASHBOARD_ACTION.REFRESH_INDICATOR, ];- 非编辑态:提供"编辑仪表盘"入口(
EDIT_DASHBOARD)、订阅(DASHBOARD_SUBSCRIPTIONS)、导出 PDF(DOWNLOAD_PDF)与刷新指示器(REFRESH_INDICATOR); - 编辑态(
isEditing为真):切换为完整的仪表盘编辑动作集合DASHBOARD_EDITING_ACTIONS(常量定义见 constants.ts),这就是"添加/更新问题、调整布局与内容"能力的 UI 入口。
内嵌导航与受控参数
- 内嵌导航:
EditableDashboardInner使用SdkInternalNavigationProvider包裹内容(见 EditableDashboard.tsx),为仪表盘内部跳转提供pushNavigation上下文; - 受控参数:底层
SdkDashboard(见 SdkDashboard.tsx)通过useSdkControlledParameters等 hooks 处理parameters/initialParameters的合并语义,并有useWarnConflictingParameterProps对相互冲突的参数 props 给出告警;getEffectiveParameterValues负责计算最终生效的参数值。这也解释了原文档中initialParameters与parameters两种模式的差异。
最小使用示例
组件需要先由 MetabaseProvider 提供认证与主题上下文,之后即可在任意页面级组件中渲染:
import { EditableDashboard, MetabaseProvider } from "@metabase/embedding-sdk-react"; export function AdminDashboard() { return ( <MetabaseProvider authConfig={{ metabaseInstanceUrl: "https://metabase.example.com", ... }}> <EditableDashboard dashboardId="mY-dAsHbOaRd-eNtItY" withTitle={true} withCardTitle={true} withDownloads={false} enableEntityNavigation={false} initialParameters={{ region: "APAC" }} onLoad={(dashboard) => console.log("loaded:", dashboard?.name)} onParametersChange={(payload) => console.log(payload.source, payload.parameters)} /> </MetabaseProvider> ); }要点提醒:
dashboardId支持数字 ID 与entity_id字符串(见 SdkDashboardId);- 编辑能力需要当前用户具备对应权限;
supportsGuestEmbed: false意味着游客嵌入下不可用; - 若需"受控 + 回传"的参数闭环,请同时使用
parameters与onParametersChange;若仅需初始值,使用initialParameters; - 不要把
parameters/initialParameters与hiddenParameters组合用于前端数据过滤(存在安全风险),只能用于界面整理。
与 InteractiveDashboard 的选型对比
| 维度 | InteractiveDashboard | EditableDashboard |
|---|---|---|
| 钻取、点击行为、查看问题 | ✅ | ✅(完整继承) |
| 编辑态(新增/更新问题、改布局与内容) | ❌ | ✅ |
编辑入口动作(EDIT_DASHBOARD等) | ❌ | ✅ |
| 游客嵌入支持 | 视版本而定 | ❌(supportsGuestEmbed: false) |
从 InteractiveDashboard 文档 的签名可见其能力止步于"drill downs, click behaviors, and the ability to view and click into questions";而 EditableDashboard.md 明确定义其差异为"as well as the ability to add and update questions, layout, and content within your dashboard"。因此,只读展示选StaticDashboard,需要交互分析选InteractiveDashboard,需要终端用户自助维护仪表盘内容时再选EditableDashboard。
总结
EditableDashboard是 Embedding SDK 中能力最完整的仪表盘组件:它复用InteractiveDashboard的交互与钻取体系,通过注入DASHBOARD_EDITING_ACTIONS编辑动作集合获得"添加/更新问题、调整布局与内容"的能力,并通过SdkInternalNavigationProvider、useSdkControlledParameters等基础设施保证嵌入场景下的导航与受控参数语义。使用前请务必注意:编辑能力意味着写操作,需要真实认证用户(不支持游客嵌入),且参数过滤必须依赖后端权限而非前端隐藏控件。相关源码入口:EditableDashboard.tsx、EditableDashboard.schema.ts、SdkDashboard.tsx。
【免费下载链接】metabaseThe easy-to-use open source Business Intelligence and Embedded Analytics tool that lets everyone work with data :bar_chart:项目地址: https://gitcode.com/GitHub_Trending/me/metabase
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考