Metabase Embedded Analytics SDK 的 SdkQuestionTitleProps 类型详解:控制与自定义问题标题
【免费下载链接】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
导读
SdkQuestionTitleProps是 Metabase Embedded Analytics SDK 中用于控制“问题(Question)标题”显示方式的核心类型别名。它定义在 frontend/src/embedding-sdk-bundle/types/question.ts,并被InteractiveQuestion、StaticQuestion、CreateQuestion、EditableDashboard等多个 SDK 组件共用的title?属性引用。本篇文章将带你完整掌握该类型的四种合法取值形态、各自的渲染行为与优先级、在实际嵌入场景中的使用方式,并结合仓库源码与单元测试逐层印证其底层实现。
类型定义:一个属性,四种形态
关联文档 SdkQuestionTitleProps.md 给出了该类型的精确定义:
type SdkQuestionTitleProps = | boolean | undefined | ReactNode | () => ReactNode;从源码 question.ts 中可以确认,这与 SDK 内部embedding-sdk-bundle包中导出的类型完全一致,其注释还保留了一条待办事项:未来会将该函数形态改为接收question: Question参数(对应内部 issue metabase#50487),目前函数调用时不传入任何参数。
这四种形态分别代表四种使用场景:
| 取值形态 | 语义 | 典型用途 |
|---|---|---|
boolean(true/false) | 显式控制标题是否显示 | 隐藏标题或强制显示默认标题 |
undefined | 不传该属性,走默认行为 | 大多数场景,保持 SDK 默认外观 |
ReactNode | 用任意 React 节点替换默认标题 | 传入字符串、<h1>等 JSX 元素实现自定义标题 |
() => ReactNode | 用渲染函数动态生成标题 | 根据运行状态计算标题内容 |
属性来源:哪些组件接受该类型
SdkQuestionTitleProps是一个“共享的公共属性类型”。在 SDK 的 API 文档中,它出现在多个组件的title?属性上,例如:
- InteractiveQuestionProps.md:
title?的类型即为SdkQuestionTitleProps,说明是"Determines whether the question title is displayed, and allows a custom title to be displayed instead of the default question title. Shown by default."(决定问题标题是否显示,并允许用自定义标题替代默认标题,默认显示。) - SdkQuestionProps.md
- CreateQuestionProps.md
- StaticQuestionProps.md
- DrillThroughQuestionProps.md
- EditableDashboardProps.md 中同样出现
也就是说,只要是在 SDK 中渲染单个问题(Question)视图的组件,几乎都会透传这个title?属性,其行为语义是一致的:控制标题显隐,或自定义标题内容。
在内部实现上,SdkQuestionDefaultView.tsx 的SdkQuestionDefaultViewProps接口也定义了同名的title?: SdkQuestionTitleProps属性,并被实际渲染在顶部工具栏区域(SdkQuestionDefaultView.tsx)。
渲染原理:DefaultViewTitle 的分支逻辑
标题最终由 DefaultViewTitle.tsx 组件负责渲染。从源码结构看,它依据title的值走完全不同的分支:
title === false:直接返回null,即彻底隐藏标题(DefaultViewTitle.tsx)。title === undefined或title === true:调用getQuestionTitle(question, tc)从问题对象中取出默认标题文本,若取不到(null)则同样不渲染;否则渲染为加粗大号Text(fw={700}、fz="xl"),颜色使用主题变量--mb-color-text-primary(DefaultViewTitle.tsx)。title为字符串:将该字符串通过useTranslateContent的tc()做内容翻译后渲染为标题文本(DefaultViewTitle.tsx)。title为函数:将其视为组件直接调用<CustomTitle />渲染,函数返回值即标题内容(DefaultViewTitle.tsx)。- 其他情况(如 React 元素):原样渲染该节点(DefaultViewTitle.tsx)。
由此可以推断出完整的决策优先级:false优先于一切,之后才是undefined/true的默认标题、字符串、函数与任意 React 节点。
使用示例:四种形态全覆盖
以下示例均基于 SDK 的InteractiveQuestion组件(同样适用于StaticQuestion、CreateQuestion等),假设你的应用已按 quickstart.md 完成 SDK 初始化。
1. 默认行为(不传 title)
不传title属性时,组件显示问题本身的默认标题:
import { InteractiveQuestion } from "@metabase/embedding-sdk-react"; export const DefaultTitle = () => { return <InteractiveQuestion questionId={1} />; };2. 隐藏标题(title={false})
export const HideTitle = () => { return <InteractiveQuestion questionId={1} title={false} />; };适合标题信息冗余、希望最大化可视化区域空间的场景。
3. 使用字符串自定义标题
export const CustomTitleText = () => { return <InteractiveQuestion questionId={1} title="2024 年度销售分析" />; };此时标题被固定为你提供的文案,且字符串会经过useTranslateContent处理,在启用了内容翻译的环境下会显示对应的翻译文本。
4. 使用 React 元素自定义标题
export const CustomTitleElement = () => { return ( <InteractiveQuestion questionId={1} title={ <div style={{ display: "flex", alignItems: "center", gap: "8px" }}> <span>📊</span> <h1 style={{ margin: 0 }}>销售驾驶舱</h1> </div> } /> ); };React 节点形态让开发者可以完全掌控标题的 DOM 结构与样式,突破默认标题的样式限制。
5. 使用渲染函数动态生成标题
export const DynamicTitle = () => { const userName = "Alice"; return ( <InteractiveQuestion questionId={1} title={() => <h2>{userName} 的个性化报表</h2>} /> ); };函数形态每次渲染都会重新调用,适合需要根据上下文(如当前用户、日期、权限等)动态计算标题内容的场景。需要注意:按照当前源码实现,该函数被调用时不会传入question参数(见 question.ts 中的 TODO 注释),如需读取问题信息需通过其他途径获取。
单元测试:行为即规格
SDK 的单元测试文件 SdkQuestion.unit.spec.tsx 用一张参数化用例表完整覆盖了title属性的所有形态(SdkQuestion.unit.spec.tsx):
it.each([ // shows the question title by default [undefined, "My Question"], // hides the question title when title={false} [false, null], // shows the default question title when title={true} [true, "My Question"], // customizes the question title via strings ["Foo Bar", "Foo Bar"], // customizes the question title via React elements [<h1 key="foo">Foo Bar</h1>, "Foo Bar"], // customizes the question title via React components. [() => <h1>Foo Bar</h1>, "Foo Bar"], ])( "shows the question title according to the title prop", async (titleProp, expectedTitle) => { await setup({ title: titleProp }); const element = screen.queryByText(expectedTitle ?? "My Question"); expect(element?.textContent ?? null).toBe(expectedTitle); }, );这些用例验证的行为可以总结为一张事实对照表:
传入的title值 | 页面呈现的标题 | 依据 |
|---|---|---|
undefined(不传) | 问题的默认标题(如 "My Question") | 默认显示 |
false | 无标题 | 隐藏 |
true | 问题的默认标题 | 强制显示 |
"Foo Bar"(字符串) | 文本 "Foo Bar" | 自定义字符串 |
<h1>Foo Bar</h1>(React 元素) | 元素内容 "Foo Bar" | 自定义节点 |
() => <h1>Foo Bar</h1>(函数) | 函数返回的元素内容 | 自定义渲染函数 |
测试同时通过screen.queryByText断言了标题的显示/隐藏状态,这意味着标题的行为完全由title属性驱动,与SdkQuestionDefaultView中RenderIfHasContent的布局逻辑配合,空标题时顶部工具栏会自动收缩,不会残留空白区域。
与自定义布局(Custom Layout)配合使用
SDK 支持通过 children 自定义InteractiveQuestion的内部布局。在 SdkQuestion.unit.spec.tsx 中可以看这样一个自定义布局示例:
function InteractiveQuestionCustomLayout({ title }: { title?: SdkQuestionTitleProps }) { const { resetQuestion } = useSdkQuestionContext(); return ( <div> <button onClick={resetQuestion}>Run Query</button> <SdkQuestionDefaultView title={title} /> </div> ); }title属性由外层传入、透传给SdkQuestionDefaultView,最终由DefaultViewTitle消费。也就是说,无论你是否使用默认布局,title的四种形态语义都保持一致。开发者也可以完全不使用默认视图,而在自己的布局中直接渲染自定义标题元素。
小结
SdkQuestionTitleProps虽是一个仅四行的类型别名,却承担了 Metabase Embedded Analytics SDK 中问题标题的全部控制逻辑:
boolean/undefined控制标题的显隐与默认行为;ReactNode支持任意自定义标题内容(字符串、JSX 元素);() => ReactNode支持动态计算标题。
通过阅读 DefaultViewTitle.tsx 的分支实现与 SdkQuestion.unit.spec.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),仅供参考