PostHog 仪表盘 Widget 布局与 UX 技术指南:Catalog 栅格体系、编辑交互与实战配置

发布时间:2026/9/10 13:33:35
PostHog 仪表盘 Widget 布局与 UX 技术指南:Catalog 栅格体系、编辑交互与实战配置 PostHog 仪表盘 Widget 布局与 UX 技术指南Catalog 栅格体系、编辑交互与实战配置【免费下载链接】posthog:hedgehog: PostHog is the leading platform for building self-driving products. Our developer tools – AI observability, analytics, session replay, flags, experiments, error tracking, logs, and more – capture all the context agents need to diagnose problems, uncover opportunities, and ship fixes. Steer it all from Slack, web, desktop, or the MCP.项目地址: https://gitcode.com/GitHub_Trending/po/posthogPostHog 的 Dashboard Widget仪表盘小组件体系允许把 Error Tracking、Session Replay、Experiments、Surveys、Logs 等不同产品的上下文汇聚到同一个看板。本文以仓库内.agents/skills/manage-dashboard-widgets/references/layout-and-ux.md为骨架结合 tileLayouts.ts、catalog.ts、widget_layouts.py 等源码实现完整讲解栅格尺寸min/max的单一事实来源与传递链路、Add Widget 弹窗的多选与底部堆叠放置逻辑、NEW 徽标、⋯ 菜单、头布局选择、日期范围配置与描述展示等全部 UX 细节。读完你可以精准定位该改哪个文件、改哪一行而不必在错误层次如 Widget Component里浪费排查时间。栅格尺寸总览三层职责划分Dashboard 的排版由三层各司其职DASHBOARD_WIDGET_CATALOG[].defaultLayout ← 你编辑的对象默认尺寸 缩放下限 ↓ tileLayouts.ts :: calculateLayouts() ← 按 tile.widget.widget_type 读取 catalog ↓ react-grid-layout minW / minH on each item ← 编辑模式下缩放时被强制约束几个关键约定全部可在源码中验证栅格固定 12 列w/minW的单位是列数。前端BREAKPOINT_COLUMN_COUNTS.sm与后端 constants.py 中的DASHBOARD_GRID_COLUMN_COUNT 12保持一致文件头还专门注释了Keep in sync with frontend BREAKPOINT_COLUMN_COUNTS.sm。高度用行单位h/minH不是像素而是栅格行数。用户说3 行高即 3 个 grid rows。行高常量BASE_ROW_HEIGHT 80px定义在 DashboardItems.tsx同处还有BASE_MARGIN [16, 16]、CONTAINER_PADDING [0, 0]。因此minH: 3意味着最小高度约3 × 80 240px另加 margin。编辑模式下还会乘以layoutZoom得到effectiveZoom见DashboardItems.tsx中rowHeight BASE_ROW_HEIGHT * effectiveZoom。宽表格如列表类 widget在WidgetCardContent内部横向滚动而不是让 dashboard 栅格整体横向滚动——这是内容层与栅格层的边界划分。Tile 最小/最大尺寸唯一的权威修改入口改动 widget 最小尺寸的正确位置是catalog tileLayouts.ts而不是 widget 的Component。Agent 或开发者经常第一个就找错层在组件 SCSS 里调高度请直接使用本小节。单一事实来源Single Source of Truth在 catalog 条目上设置最小尺寸例如 catalog.ts 中error_tracking_list的写法// products/dashboards/frontend/widget_types/catalog.ts defaultLayout: { w: 6, h: 5, minW: 3, minH: 3 },字段含义w,h添加widget 时的默认尺寸dashboardLogic.addWidgetTiles会读取它们minW,minH在 dashboard 上缩放时允许的最小尺寸下限在DASHBOARD_WIDGET_CATALOG中多数列表类 widgeterror_tracking_list、session_replay_list、experiments_list、experiment_results、survey_results、activity_events_list、logs_list均采用{ w: 6, h: 5, minW: 3, minH: 3 }而conversations_recent_tickets用{ w: 6, h: 6, minW: 3, minH: 4 }——这印证了不同类型可以有不同下限的设计。最小尺寸如何到达栅格传递链路calculateLayouts(tiles) 在每次 dashboard 加载或 tile 变化时执行为每个断点sm/xs取自BREAKPOINT_COLUMN_COUNTS计算布局。对 widget tile调用getWidgetCatalogLayout(widget_type)tileLayouts.ts→ 返回DASHBOARD_WIDGET_CATALOG[key].defaultLayout若 widget_type 缺失或未知则返回undefined由调用方使用场景级回退。getTileMinDimensions()tileLayouts.ts根据 tile 类型image / text / button / widget / default为每个布局项设置 RGL 的minW/minH。widget 类型优先取 catalog 值缺失时回退到MIN_TILE_DIMENSIONS.widget。这些minW/minH会随布局对象一并传给 react-grid-layout在编辑模式缩放时强制生效。同一文件的其余逻辑也值得了解calculateLayouts会先按sm排序建立referenceOrderxs断点忽略存储布局、仅跟随sm顺序推导对y Infinity的脏tile 采用最低段贪心放置lowestSegments这与后端 widget_layouts.py 的_pack_at_bottom逐列放置算法互相镜像。持久化与无需迁移的设计持久化的 tile JSONtile.layouts.sm只存x、y、w、h不存 min。最小尺寸每次都从 catalog 重新计算因此修改 catalog 的minH会立即作用于所有现存 dashboard无需任何数据迁移——这是catalog 是唯一权威带来的关键红利。回退值catalog 省略 min 时当 catalog 条目没有给出minW/minH时由 tileLayouts.ts 中的MIN_TILE_DIMENSIONS提供回退场景 / 概念常量值何时生效Widget tile 无minWMIN_WIDGET_TILE_WIDTH_COLS3widget tilecatalog 未定义minWWidget tile 无minHMIN_WIDGET_TILE_HEIGHT_ROWS4widget tilecatalog 未定义minHInsight tileMIN_TILE_HEIGHT_ROWS2insight tiledefault类型Text tileMIN_TEXT_TILE_HEIGHT_ROWS1text tile含 image / button 为 1×2 / 1×1踩坑提示如果新 widget 类型忘了写minH用户只能缩到4 行而不是 3 行。务必在 catalog 条目上显式设置minH/minW。哪些地方不控制 dashboard 最小尺寸位置为什么无关WidgetComponent/ SCSS只负责内容布局外层 tile 尺寸由 RGL 决定widget_catalog.py的get_default_widget_layouts()后端添加辅助函数——只返回w/h没有 min 概念见 widget_layouts.py 中defaults[sm][w]的用法StorybookwidgetCardStoryFixtures的TILE_HEIGHT只是 story 的固定画框不是 RGLDashboardWidgetsOverview.stories.tsx的高度总览展示的缩放比例与真实 min 无关全局修改MIN_WIDGET_TILE_HEIGHT_ROWS只影响未知widget 类型优先用每类型的 catalogminH变更检查清单Change checklist在 catalog.ts 中按widget_type修改defaultLayout.minH/minW。扩展 tileLayouts.test.ts为对应widget_type增加参数化用例断言expectedMinH/expectedMinW。仓库已有范例——error_tracking_list、session_replay_list均断言minH: 3, minW: 3而unknown_widget断言回退minH: 4, minW: 3测试同时校验sm与xs两个断点。运行hogli test frontend/src/scenes/dashboard/tileLayouts.test.ts。在 dashboard编辑模式下手动缩放该 tile确认下限生效。可选添加一个MinimumSizestory——画框高度取minH * 80px并限制 demo 数据量以保证内容不溢出。Storybook 与真实 dashboard 的关系Dashboardmin 从 catalog →tileLayouts.ts→ RGL是生产行为。Storybook tile stories使用可选的固定画框widgetCardStoryFixtures或 story 级 wrapper。MinimumSizestory 只是记录下限不会改变生产行为——不要把 story 高度当成真实 min。Add widget 弹窗多选、批量接口与底部堆叠标题为Add widget描述为Bring context from your different PostHog products into one dashboard.AddWidgetModal支持多选可勾选一个或多个 catalog 变体然后点击 Add N widgetsN1 时dashboardLogic会 toastAdded N widgets。前端动作链dashboardLogic.addWidgetTilesdashboardLogic.tsx→POST api/environments/:teamId/dashboards/:dashboardId/widgets/batch/单次 1–10 个 tile后端 constants.py 的MAX_WIDGETS_BATCH_SIZE 10与弹窗限制对应。后端放置锚定最高列、向下堆叠后端放置由widget_layouts.stack_widget_layout_at_bottom实现widget_layouts.py核心算法在_find_bottom_row_placementL29-L53先按列计算每列底部max(y h)新 tile 放在y max(heights)并锚定在最高的那列tallest_column上为什么要锚定最高列因为栅格渲染时会做纵向压缩vertical compaction——只有列跨度覆盖了定义底部的列tile 才能留在底部否则会被压缩抬升到较矮列的空隙里这就是历史上落到第二行类 bug 的成因批量添加向下堆叠pending_sm_layouts让第 2 个 tile 把第 1 个计入高度依次往下排。注释明确说明横向一行在阶梯状 dashboard 上无法在压缩中存活所以批量为串行堆叠而非并排。放置完成后dashboardLogic会调用requestScrollToBottom()将#main-content滚动到底部保证新 tile 可见。值得注意前端支持内联插入pendingInsertion——单 widget 添加时若用户指定了插入槽位会带上layouts: { sm: { x, y, w, h } }走同一 batch 接口多选添加因只 reposition 单个 tile故不做内联插入一律追加到底部见 dashboardLogic.tsx。布局缺失 tile 的高度合成防掉进中部空隙后端放置会统计没有布局的 tilecollect_dashboard_sm_layouts_for_dashboardwidget_layouts.py遍历dashboard.tiles.exclude(deletedTrue)注意deleted为 NULL 的存活 tile 必须显式排除因为filter(deletedFalse)会漏掉 NULL对每个layouts {}的 tile 合成一个底部放置默认 6×5与前端DEFAULT_INSERTED_TILE_SIZE { w: 6, h: 5 }对齐让它们参与高度计算。典型场景通过insight API添加的 insight其layouts为空前端渲染时才临时排到底部、仅在保存布局时持久化。若后端只读持久化布局就会低估看板高度把新 widget 丢进页面中部的空隙——即注释中描述的 lands in the 2nd row bug。REST / MCP 添加REST 与 MCP 添加走dashboard-widgets-batch-add与前端共用同一个 batch 端点单个 tile 即widgets数组的单个元素。细节见 mcp.md。NEW 徽标Add 菜单在 Add 菜单中把 Widget 入口标记为新功能已填充的 dashboardDashboardHeaderActions中LemonMenu项加tag: new。空 dashboardEmptyDashboardComponent中在 Widget 菜单项旁内联LemonTag typesuccess sizesmallNEW/LemonTag。注意不要给AddWidgetModal内的单个 catalog 变体加 NEW 徽标——徽标只属于菜单入口不属于弹窗内的条目。配置更新Config updates运行时配置采用 PATCH 流程并带有保存守卫详见 managing-existing-widgets.md § Config update flow编辑弹窗的字段布局见同文档 § Edit modal layout。移除与撤销Remove and undo移除无确认弹窗直接执行通过undo toast提供反悔入口。相关逻辑在dashboardLogic.tsx的removeTileSuccesscache.removedTileForUndo缓存被移除的 tiledashboardLogic.tsx撤销时取回。Toast 文案widget removed Undo。⋯ 菜单对齐DashboardWidgetItem每个 widget tile 的 ⋯ 菜单提供以下能力菜单项行为说明View若配置了titleHref标题链接行为见 composition.md § Header title navigationEdit打开 widget 设置弹窗Duplicate复制 tile前端calculateDuplicateLayout优先放右侧、空间不足则放下方并下移可能重叠的 tile见 tileLayouts.tsShow/hide description切换描述可见性编辑文案在设置弹窗中完成Dashboard section复制 / 移动到另一个 dashboard、移除Refresh data直接点击刷新可选带 Last computed 副标题dashboard_tile头布局未知 widget 类型则省略头布局选择Header layout choice新 widget 优先使用headerLayout: dashboard_tile——与 insight tile 的外壳chrome一致Refresh data 是 ⋯ 菜单的直接项可选 Last computed 副标题体验与 insight tile 对齐。代码层面catalog.ts 定义了DASHBOARD_WIDGET_HEADER_LAYOUTS [simple, dashboard_tile]且DEFAULT_DASHBOARD_WIDGET_HEADER_LAYOUT dashboard_tilesatisfies语法保证它是合法枚举值headerMeta默认{ showWidgetType: true, showDateRange: true }可被 catalog 条目覆盖如experiments_list、experiment_results设showDateRange: false避免显示无意义的默认日期。完整头布局细节见 composition.md。配置中的日期范围Date range in config时间区间存放在config.dateRange中形状与 insight 一致{ date_from, date_to?, explicitDate? }。支持的相对date_from取值由短到长定义在后端 constants.py 的WIDGET_DATE_FROM_VALUES_ORDERED与 PydanticWidgetDateFromwidget_specs/common.py中值含义值含义-1MLast minute-7dLast 7 days-30MLast 30 minutes-14dLast 14 days-1hLast hour-30dLast 30 days-3hLast 3 hours-90dLast 90 days-24hLast 24 hours注意M表示分钟、m表示月见 constants.py 注释对应posthog.utils相对日期解析widget 只接受这些预设相对区间不接受任意 HogQL 日期字符串date_from可省略即不限制起始。后端测试 test_run_widgets.py 用参数化用例覆盖了各 widget 类型接受-1h/-3h/-24h短区间的校验。代码生成hogli build:openapi重新生成widget-date-from-options.json前端widgetConfigShared.ts再导出WIDGET_DATE_RANGE_SELECT_OPTIONS含 label并从生成的 Zod schema 推断值类型。显示WidgetCardHeader读取config.dateRange catalog 的headerMeta用dateFilterToText格式化为可读文本如 Last 7 days。描述展示Description display当show_description开启时卡片头部在标题下方渲染 markdown 描述WidgetCardHeader/CardMeta容器样式为max-h-24 overflow-y-auto——即最多约 6 行高、超出滚动避免描述撑爆 tile 高度。参考资源汇总布局计算与 min 回退tileLayouts.ts行高与 margin 常量DashboardItems.tsxWidget 目录defaultLayout / headerMeta / titleHrefcatalog.ts添加 widget 的前端动作链dashboardLogic.tsx后端底部堆叠与布局合成widget_layouts.py后端日期/批量常量constants.py布局单测含 min 参数化用例tileLayouts.test.ts、后端放置测试test_widget_layouts.py同系列参考architecture.md、composition.md、managing-existing-widgets.md、mcp.md【免费下载链接】posthog:hedgehog: PostHog is the leading platform for building self-driving products. Our developer tools – AI observability, analytics, session replay, flags, experiments, error tracking, logs, and more – capture all the context agents need to diagnose problems, uncover opportunities, and ship fixes. Steer it all from Slack, web, desktop, or the MCP.项目地址: https://gitcode.com/GitHub_Trending/po/posthog创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考