
PostHog SceneMenuBar 场景菜单栏迁移指南从 ScenePanel 到 Mac 风格菜单栏的双写改造实践【免费下载链接】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/posthogfrontend/src/layout/scenes/AGENTS.md是 PostHog 前端为 AI 编码 Agent如 Claude Code、Cursor 等撰写的场景操作面板Scene action surface开发规范。它定义了一项正处于迁移中期的 UI 改造工程将传统ScenePanel侧边操作面板中的场景级操作按钮、开关、链接、破坏性操作、元数据输入等逐步收敛到 Mac 风格、由SCENE_MENU_BAR功能开关feature flag控制的SceneMenuBar顶部菜单栏。读完本文你将掌握两个操作面如何共存与保持同步、如何为一个尚无菜单栏的场景新建ResourceSceneMenuBar、如何遵循 File / Edit / View / Metadata / Staff only 的规范菜单集构建菜单、以及自动化埋点约定。一、背景两个并存的场景操作面在 PostHog 前端架构中每个业务场景Scene如 Cohorts 人群、Dashboards 仪表盘、Notebooks 笔记等都有自己的操作入口。当前仓库中存在两代操作面ScenePanel旧操作面定义在 SceneLayout.tsx 中的每场景操作/信息侧边面板。场景通过ScenePanelActionsSection、ScenePanelInfoSection、ScenePanelLabel、ScenePanelDivider这些原语填充面板。实现上ScenePanel通过sceneLayoutLogic的scenePanelElement使用 React Portal 将内容渲染到挂载点并借助setScenePanelIsPresent标记面板是否在 DOM 中。SceneMenuBar新操作面定义在 components/SceneMenuBar.tsx是渲染在SceneTitleSection上方的 Mac 风格菜单栏把散落在面板里的操作整合进 File / Edit / View / Metadata / Staff only 等菜单受SCENE_MENU_BAR功能开关门控。正如文档所强调的项目正处于ScenePanel到SceneMenuBar的中期迁移状态在功能开关全量上线之前两个操作面必须保持同步both surfaces must stay in sync。功能开关的定义可以在 lib/constants 的FEATURE_FLAGS.SCENE_MENU_BAR中找到可用SCENE_MENU_BAR字符串检索确认并在 Navigation.tsx 中通过useFeatureFlag(SCENE_MENU_BAR)消费用于导航层判断是否启用该 UI。二、核心规则每个场景操作都必须同时写入 SceneMenuBar文档中最重要、必须无条件遵守的规则是When you add, edit, or remove any action/feature on a scenesScenePanel按钮、开关、链接、破坏性操作、元数据输入ScenePanelActionsSection/ScenePanelInfoSection中的任何内容你必须在对应场景的SceneMenuBar中做同样的修改。一个只存在于ScenePanel的功能对任何开启SCENE_MENU_BAR的用户都是不可见的。需要特别强调的是这是一次双写dual-write而不是移动move保留ScenePanel中的条目flag-off 路径新增菜单栏条目flag-on 路径在功能开关仍在灰度发布期间不要删除ScenePanel的既有操作。这样做的原因很直接SCENE_MENU_BAR尚未全量覆盖所有用户删掉旧面板操作会让关闭该 flag 的用户失去功能入口。双写是迁移期的安全网。三、为没有 SceneMenuBar 的场景新建一个含参考实现如果一个场景还没有对应的菜单栏组件你需要为它创建同目录co-located的ResourceSceneMenuBar组件命名遵循CohortSceneMenuBar、DashboardSceneMenuBar、NotebookSceneMenuBar等模式。文档给出了三步流程下面结合仓库中的参考实现 CohortSceneMenuBar.tsx 展开说明。第 1 步创建门控组件新建ResourceSceneMenuBar.tsx放在场景目录中组件在功能开关关闭时返回nullexport function CohortSceneMenuBar({ id }: { id?: CohortType[id] }): JSX.Element | null { const { featureFlags } useValues(featureFlagLogic) if (!featureFlags[FEATURE_FLAGS.SCENE_MENU_BAR]) { return null } return CohortSceneMenuBarInner id{id} / }这正是CohortSceneMenuBar的实际写法useValues(featureFlagLogic)读取featureFlags[FEATURE_FLAGS.SCENE_MENU_BAR]未开启时提前返回null开启时渲染内部的CohortSceneMenuBarInner。将门控逻辑与真实菜单实现分离既保证了 flag-off 时零渲染开销也便于内部组件专注菜单构建。第 2 步用基础原语构建菜单从~/layout/scenes/components/SceneMenuBar导入基础原语把场景ScenePanel上已有的操作镜像到规范菜单集中。CohortSceneMenuBarInner的实例展示了完整用法SceneMenuBar最外层容器data-attrscene-menu-barSceneMenuBarMenu labelFile顶层菜单dataAttr形如${RESOURCE_TYPE}-menubar-fileSceneMenuBarItem单个操作项破坏性操作传variantdestructive如Delete点击时通过LemonDialog.open弹出确认框data-attr为${RESOURCE_TYPE}-menubar-deleteSceneMenuBarSubMenu labelCreate子菜单如添加到笔记本SceneMenuBarSeparator菜单分隔线条件渲染也完全遵循场景状态新人群id new不显示 Create/Delete已删除cohort.deleted显示Restore而隐藏 Edit 菜单动态人群才能Duplicate as dynamic cohort等。菜单项还通过tooltip解释禁用原因如Save the cohort first、通过disabled表达当前不可用状态——这些细节在双写时也要同步到ScenePanel侧。第 3 步在场景中渲染将组件渲染在SceneTitleSection正上方与既有的ScenePanel并列CohortSceneMenuBar id{id} / ScenePanel…/ScenePanel SceneTitleSection … /其他可以参考的参考实现包括CohortSceneMenuBar.tsxDashboardSceneMenuBar.tsxNotebookSceneMenuBar.tsx此外仓库中已落地的还有 ExperimentSceneMenuBar.tsx、InsightSceneMenuBar.tsx 等可从这些实现中归纳出稳定的迁移模式。四、动手写菜单之前先读 /scene-menu-bar skill文档明确划分了职责边界这份 AGENTS.md 讲的是何时/为什么when/why而/scene-menu-barskill 讲的是怎么做how。skill 文件位于仓库根目录的.agents/skills/scene-menu-bar/SKILL.md.agents目录下还有 adding-activity-logging、adding-inbox-sources 等一系列同类技能文档PostHog 用这种方式为 Agent 沉淀可复用的工程规范。SKILL.md中覆盖了组件分类component taxonomy、规范菜单顺序、破坏性操作样式、opensFloatingUi用法、富输入SceneMenuBarPopoverTagsCombobox接线、空菜单处理以及乐观保存optimistic-save模式等完整约定。在添加或移动菜单项之前必须先调用该 skill。如果你作为 Agent在编码前缺少这些约定很可能在菜单顺序、键盘导航、富输入拦截等细节上出错。五、基础组件 API 速览源自 SceneMenuBar.tsx为了让你在双写时有据可依这里梳理 SceneMenuBar.tsx 导出的组件族组件用途关键 Props / 说明SceneMenuBar菜单栏容器右侧固定渲染 Settings / Docs / Support / PostHog AI 链接簇SceneMenuBarRightLinks并把被跳过的产品空状态提醒SetupReminderContext渲染在栏下方SceneMenuBarMenu顶层菜单label规范标签、dataAttr、align、contentClassName、disabled子元素为空时触发器自动禁用SceneMenuBarItem菜单操作项opensFloatingUi追加 Mac 风格尾部省略号…提示会打开浮层 UI、tooltip禁用原因提示、variantdestructiveSceneMenuBarCheckboxItem开关型项目渲染反映checked状态的勾选指示Pin/Favorite/Show debug panel 等SceneMenuBarRadioGroup/SceneMenuBarRadioItem互斥单选组通过valueonValueChange绑定SceneMenuBarSeparator分隔线—SceneMenuBarShortcut快捷键提示—SceneMenuBarSubMenu子菜单label、withIconBlank默认 true为触发器预留前导图标槽位以对齐兄弟项SceneMenuBarPopover富表单菜单渲染 Popover 而非 Menu用于 Tags、Evaluation contexts、Stage、Activity 等元数据面板可容纳文本输入与 combobox代价是不参与 Menubar 的 CompositeRoot 键盘导航SceneMenuBarItem对opensFloatingUi的处理值得一提它通过-ms-2负外边距抵消父级 flex 的gap-2让省略号紧贴标签尾部而不是被完整间距隔开——这是实现 Mac 风格视觉细节的源码级证据。规范菜单集canonical menu set组件文件中的注释明确定义了菜单顺序File → Edit → View → Metadata → Staff only各菜单职责如下File顶部放SceneMenuBarSubMenu labelCreate然后是文件/项目级操作、Export 子菜单、分隔线最后是破坏性操作Delete / Archive / Restore放在底部EditDuplicate、Rename、场景专属编辑、状态变更Pause/Resume、Activate/Deactivate分隔线后是成组开关Pin/Fullscreen/Favorite 等用SceneMenuBarCheckboxItemView条件性跨资源查看类操作View recordings、View metalytics、View related X 等导航类操作没有可看的内容时整菜单可跳过Metadata用SceneMenuBarPopoverTags、Evaluation contexts、Stage、Activity 指示器、ExternalReferencesStaff only条件性调试面板、内部开关。右侧固定簇包含 PostHog AI、Docs、Support以及当场景所属产品配置了对应设置页时的 Settings。SETTINGS_SECTION_BY_PRODUCT映射见 SceneMenuBar.tsx把ProductKeyPRODUCT_ANALYTICS、WEB_ANALYTICS、SESSION_REPLAY、FEATURE_FLAGS、EXPERIMENTS、SURVEYS、AI_OBSERVABILITY、LOGS、WORKFLOWS映射到SettingSectionId再经urls.settings(section)生成设置链接。布局细节负边距与边缘出血SceneMenuBar会依据当前场景布局决定是否出血到容器边缘const PADDED_LAYOUTS new Set([app, app-container, app-full-scene-height])只有PADDED_LAYOUTS中的布局容器本身带水平/垂直内边距才应用-mx-4 -mt-4负边距以撑满全宽app-raw、plain等无内边距布局若也加负边距就会溢出因此被排除。另外当相邻前置兄弟节点是LemonTabs时通过[.LemonTabs]:-mt-6把菜单栏上提与已经用-mt-6出血的 Tabs 齐平避免浮在 flexgap-y-*空隙中。六、埋点自动化零成本获得全场景行为数据这是迁移工程最省心的部分埋点由SceneMenuBar.tsx集中完成每个场景无需单独接线。核心是captureSceneMenuBar辅助函数见 SceneMenuBar.tsxfunction captureSceneMenuBar(event: string, properties: Recordstring, unknown {}): void { posthog.capture(event, { scene: sceneLogic.findMounted()?.values.activeSceneId ?? null, ...properties, }) }它统一捕获三个事件scene menu bar shown菜单栏挂载时见useEffect、menu openedSceneMenuBarMenu的onOpenChange中附menu标签、item clickedSceneMenuBarItem的点击处理中附item。场景 ID 通过sceneLogic.findMounted()?.values.activeSceneId读取且不订阅不触发重渲染右侧链接点击则上报scene menu bar right link clicked并携带link字段settings/docs/support/ai。因此你作为开发者只需做一件事给菜单项一个稳定的data-attr命名规范为${RESOURCE_TYPE}-menubar-action例如cohort-menubar-file、cohort-menubar-edit菜单触发器cohort-menubar-delete、cohort-menubar-restore、cohort-menubar-duplicate-dynamic、cohort-menubar-copy-to-project、cohort-menubar-calculation-history操作项。这样被捕获的item才有业务语义分析报表才能区分具体动作。data-attr同时也被测试引用是菜单在自动化测试中的选择器锚点。七、迁移期实操清单总结结合文档与源码给正在实施迁移的开发者一份可执行的 checklist读 skill 再动手先查看.agents/skills/scene-menu-bar/SKILL.md获取组件分类、菜单顺序、破坏性样式、opensFloatingUi、富输入接线、空菜单与乐观保存等约定保持双写ScenePanel的任何增删改都同步到SceneMenuBarflag 未全量前不删除面板入口没有就新建创建ResourceSceneMenuBar.tsx用 flag 门控关闭返回null用SceneMenuBar组件族镜像面板操作到 File / Edit / View / Metadata / Staff only 规范菜单渲染位置放在SceneTitleSection正上方、ScenePanel旁边稳定 contenteditable="false">【免费下载链接】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),仅供参考