HyperDX 页面布局指南:深入解析 PageHeader 与 PageLayout 共享页头体系
2026/9/24 16:58:19 网站建设 项目流程
  • 可观测性
  • 云原生
  • 运维

【免费下载链接】hyperdx

Resolve production issues, fast. An open source observability platform unifying session replays, logs, metrics, traces and errors powered by ClickHouse and OpenTelemetry.

项目地址:https://gitcode.com/gh_mirrors/hy/hyperdx
点击查看免费下载

HyperDX 的 App 页面共用一套「粘性顶栏 + 可滚动内容区」的页面骨架:左导航(AppNav)+ 统一滚动容器之上,是吸顶的PageHeader页头,页头下方才是各自页面的内容区。本文以 agent_docs/page_layout.md 为骨架,结合 PageHeader.tsx、PageLayout.tsx 及 Alerts、Service Map、Kubernetes Dashboard、Sessions、Dashboard 等真实页面源码,系统讲解两个共享布局原语(primitive)的完整 API、三种页面形态的选型规则、常见反模式与迁移步骤。读完本文,你将掌握在 HyperDX 中新增或改造页面时,如何用一致的方式组织标题、面包屑、来源选择器、时间范围与主操作按钮,保证 Search、列表页与工具页(Service Map、Kubernetes、Chart Explorer)的视觉与交互一致。

为什么需要统一的页头体系

HyperDX App 的所有受保护页面都运行在同一套外壳中。查看 packages/app/src/layout.tsx,withAppNav负责把页面包装进HDXSpotlightProviderPageWrapperPageWrapper左侧渲染AppNav,右侧是带有APP_CONTENT_SCROLL_CONTAINER_ID的滚动容器(overflowY: 'scroll'),所有页面内容都在这个容器内滚动。

这意味着页面的"吸顶"是相对于这个滚动容器而言的,而非整个浏览器窗口;任何页面若各自用Text size="xl"写一个标题、再手动拼一个Group justify="space-between"工具条,都会在边距、字号、吸顶层级和滚动行为上与相邻页面产生肉眼可见的差异。统一页头(page chrome)的职责由此而来:让标题、控件与间距在 Search、列表页和工具页之间保持一致

两个核心组件:PageHeader 与 PageLayout

page_layout.md 给出了两个组件的选型结论,仓库中两个组件相邻位于packages/app/src/components/

组件路径使用场景
PageHeaderpackages/app/src/components/PageHeader.tsx只需要页头栏(页面已有自己的内容包装器)
PageLayoutpackages/app/src/components/PageLayout.tsx需要"页头 + flex 内容列"一个包装器搞定(新页面推荐)

两者都位于withAppNav(packages/app/src/layout.tsx)之下,后者提供左侧导航与滚动容器。从源码看,PageLayout本质上是PageHeader的薄封装:PageLayoutProps通过Pick<PageHeaderProps, 'title' | 'leading' | 'actions' | 'breadcrumbs' | 'children'>透传页头插槽,未传入自定义header时,内部自动构造一个<PageHeader>(PageLayout.tsx)。因此插槽语义完全继承自PageHeader

PageHeader API 详解

PageHeader.tsx 的类型定义中,PageHeaderProps提供了两种组合形式,源码注释按优先级明确标注:

  1. 结构化插槽title/leading/actions/breadcrumbs。适用于标题(或面包屑轨迹)+ 水平工具条能清晰拆成"左侧组 + 右侧组"的标准页头;
  2. 自定义children:用于工具条无法表达为leading + actions的页面(例如 Sessions 全宽混合控件行),仅在结构化插槽会歪曲预期布局时才使用。

基础用法

<PageHeader title="Alerts" /> {/* 粘性栏包含输入控件时:不传 `title`,把面包屑传进页头 */} <PageHeader breadcrumbs={<Breadcrumbs>...</Breadcrumbs>} leading={<SourceSelectControlled ... />} actions={<TimePicker ... />} /> <PageHeader> {/* 自定义标题行,例如 Team 设置里可编辑的团队名 */} </PageHeader>

Props 语义对照表

Prop用途
title纯文本页面标题(<h1>)。仅当粘性栏没有输入控件时使用(列表/设置页)。如果栏上有选择器、搜索、滑块或 Run 按钮,必须省略title,改用breadcrumbs(或仅靠导航 + 文档标题表达位置)。源码中toolbarInner仅在title != null时渲染<h1 className={styles.title}>(PageHeader.tsx)
breadcrumbs粘性页头内部的位置轨迹,当leading/actions存在时渲染在工具条上方。使用 MantineBreadcrumbs(如Dashboards→ 当前页)。不要与title重复同一页面名称。渲染逻辑见hasBreadcrumbs && hasToolbar分支,此时页头应用headerStacked样式(PageHeader.tsx)
leading左侧簇:来源选择器、徽章或其他控件。存在输入控件时,不要与同一页面名的title配对
actions右侧簇:时间范围、Run/Save、采样、刷新
children插槽不够用时的完整自定义页头。除非走纯面包屑分支,否则不要与title/leading/actions/breadcrumbs混用
growing启用"块级内边距只在工具条超过min-height时出现"的行为。Sessions 的多行搜索使用它;纯标题页省略它
stickyRow指定页头中唯一吸顶的行,其余页头 chrome 随页面滚动消失(用于 Dashboard 这类"面包屑 + 可编辑名 + 查询工具条"的高页头,见下文进阶章节)
className/data-testid页头样式类与 E2E 测试定位锚点

样式与行为细节(源码级)

样式定义在 PageHeader.module.scss:

  • 吸顶与分隔.header设置position: sticky; top: 0,带border-bottom: 1px solid var(--color-border),与 Search 页的px="sm"对齐,水平内边距为var(--mantine-spacing-sm)
  • 最小高度:单行页头保持min-height: 60px;堆叠页头(面包屑 + 工具条)通过.headerStacked改为纵向布局(flex-direction: column)、min-height: auto,随内容生长;
  • 层级z-index: 2,源码注释明确说明该应用顶层抽屉渲染在contextZIndex + 10(即 10),页头保持比抽屉低 8 层,保证抽屉遮罩始终覆盖页面 chrome,同时页头仍浮于普通滚动内容之上(PageHeader.module.scss);
  • growing行为.header.growing:not(.notSticky)增加padding-block: var(--mantine-spacing-xs)。块级内边距在静止时被吸收,只有当行超过页头高度(Sessions 的多行搜索)才显现,避免查询框贴边;而纯标题页保持零块内边距,60px 单行不产生位移(PageHeader.module.scss);
  • 行内排版.start(标题 + leading)flex: 1.actions固定不收缩且gap: 12px.title继承字号/字重、white-space: nowrap,避免标题换行破坏单行布局。

PageLayout API 详解

<PageLayout ><PageLayout >// ❌ 在页面主体里临时写标题 <Group justify="space-between"> <Text size="xl">Service Map</Text> <TimePicker ... /> </Group> // ✅ 工具页:面包屑进页头、输入控件在同一个粘性块中(无 `title`) <PageLayout breadcrumbs={<Breadcrumbs>...</Breadcrumbs>} leading={<SourceSelect ... />} actions={<TimePicker ... />} content={<>...</>} /> // ❌ title 与面包屑重复同一页面名 <PageLayout title="Kubernetes Dashboard" breadcrumbs={<Breadcrumbs>… Kubernetes</Breadcrumbs>} /> // ❌ 用 Box 把整个页面(包括标题)包一层重复 padding <Box p="sm"> <Text size="xl">Alerts</Text> ... </Box> // ✅ 页头在 padding 区之外 <PageHeader title="Alerts" /> <Container py="lg">...</Container>

几点原理补充:

  • 禁止主体内Text size="xl"标题:这样的标题不在粘性页头内、不参与统一排版,滚动时也不会吸顶,破坏跨页一致性;
  • 禁止titlebreadcrumbs文案重复:两者表达同一定位信息会产生冗余;若栏上有输入控件,title还会导致<h1>与工具条争夺单行空间;
  • 禁止重复 padding 包裹PageHeader自带--mantine-spacing-sm水平内边距,页面主体再包一层p="sm"会造成双重留白;正确做法是页头在 padding 区之外,内容用Container/padded自行控制。

迁移现有页面:六步走

  1. PageLayoutPageHeader插槽替换Text size="xl"标题 +Group justify="space-between"
  2. 把时间选择器与主操作按钮移到actions
  3. 把来源选择器和徽章移到leading
  4. 如果粘性栏有输入控件,不要设置title;当路由存在层级时,把breadcrumbs传给PageLayout(面包屑渲染在粘性PageHeader内部,而不是content里);
  5. PageLayout/ 页面根节点保留data-testid供 E2E 测试使用——例如 AlertsPage.tsx 的data-testid="alerts-page"被 tests/e2e/page-objects/AlertsPage.ts 的page.locator('[data-testid="alerts-page"]')引用,Service Map 的data-testid="service-map-page"与 Kubernetes Dashboard 的data-testid="kubernetes-dashboard-page"同理;
  6. 运行受影响的 Playwright 测试(packages/app/tests/e2e/)。

变更后记得跑 Knip

packages/app的 Knip 入口根是pages/scripts/和 e2e 测试。新增或移动PageLayout导入后,请从仓库根目录运行yarn knip(若packages/app单独配置了则在其目录下执行yarn knip),确保新增的消费方仍然被正确接线、没有未使用或未声明的导入残留。

小结

  • 选型一句话:只差页头用PageHeader,页头 + 内容一体的新页面用PageLayout
  • 输入控件决定 title 取舍:粘性栏有任何输入控件就省略title,用breadcrumbs(在页头内部)表达位置;
  • 全局控件在actions、上下文控件在leading,全高画布加fillViewport
  • 复杂形态走自定义槽:Search/Chart Explorer 保留定制工具条;Sessions 用header承载单行工具条;Dashboard 用stickyRow钉住查询工具条;
  • 保持可测性与可维护性data-testid落在布局根节点,改动后跑 e2e 与yarn knip

这套体系的源码、样式与全部真实用例都集中在packages/app/src/components/PageHeader.tsxpackages/app/src/components/PageLayout.tsx与各自.module.scss中,新增页面时直接对照上述规则即可与既有页面保持一致。

  • 可观测性
  • 云原生
  • 运维

【免费下载链接】hyperdx

Resolve production issues, fast. An open source observability platform unifying session replays, logs, metrics, traces and errors powered by ClickHouse and OpenTelemetry.

项目地址:https://gitcode.com/gh_mirrors/hy/hyperdx
点击查看免费下载
上一篇:本地离线语音转文字工具TMSpeech上手指南:让电脑声音实时变字幕,会议记录提速3倍
下一篇:NumPy 1.17.5 补丁版本技术解析:关键 Bug 修复、构建改进与升级注意事项

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

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

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

立即咨询