scene-menu-bar について
PostHog のシーンメニューバーを設計・移行するための開発スキルです。メニュー構成、コンポーネントの使い方、操作ルール、移行時の確認事項をまとめています。
主な機能
- 01File、Edit、View、Metadata のメニュー規則
- 02破壊的操作と切り替え項目の指針
- 03リッチなフォーム入力向けポップオーバー
- 04キーボード操作とレイアウトの指針
- 05移行とシーン監査のチェックリスト
活用シーン
- 01ScenePanel のメニューバーへの移行
- 02シーン操作のメニュー分類
- 03タグなどのリッチ入力の追加
- 04メニューの操作性とアクセシビリティの確認
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ posthog/ posthog --skill scene-menu-barインストール後、Claude Code で/scene-menu-barを入力して読み込まれたか確認します。
詳細
SceneMenuBar の規約
PostHog のシーンは <SceneTitleSection> の上に Mac 風のメニューバーをレンダリングし、ScenePanel のアクションを発見しやすくキーボードで操作可能なサーフェスに集約します。このスキルでは、分類体系、利用可能なプリミティブ、および配線ルールについて説明します。
バー全体は SCENE_MENU_BAR 機能フラグによって制御されます(lib/constants.tsx を参照)。
コンポーネント
すべてのプリミティブは frontend/src/layout/scenes/components/SceneMenuBar.tsx にあります。
| コンポーネント | 用途 |
|---|---|
<SceneMenuBar> | トップレベルのラッパー。<SceneTitleSection> の上にレンダリングされます。共通の右側クラスター(PostHog AI / Docs / Support)を含みます。 |
<SceneMenuBarMenu label> | トップレベルメニュー(File / Edit / View / Metadata / Staff のみ)。 |
<SceneMenuBarSubMenu label> | SceneMenuBarMenu 内のネストされたサブメニュー(例: Create、Export、Add to notebook)。トリガーに空のアイコンスロットを自動的に先頭追加し、ラベルがアイコン付きの兄弟要素と揃うようにします — オプトアウトするには withIconBlank={false} を渡します。 |
<SceneMenuBarItem> | 標準のメニュー項目(アクション / ナビゲーション)。 |
<SceneMenuBarCheckboxItem> | トグル項目 — チェックマークで真偽状態を反映します。 |
<SceneMenuBarRadioGroup> + <SceneMenuBarRadioItem> | 多数の中から 1 つを選ぶ排他的なオプション。 |
<SceneMenuBarSeparator> | グループ間の水平方向の区切り線。 |
<SceneMenuBarShortcut> | 右揃えのキーボードショートカットのヒント。 |
<SceneMenuBarPopover label> | コンテンツにリッチなフォームコントロール(テキスト入力、コンボボックス)が必要な場合に SceneMenuBarMenu の代わりにそのまま使える選択肢。内部的に Popover を使用します — Menu.Popup はキーストロークを横取りして入力をブロックします。トリガーは CompositeRoot のキーボードナビゲーションに参加しません。 |
正規のメニューセット(順序どおり)
| メニュー | 項目 |
|---|---|
| File | + Create サブメニュー(先頭)、── 、プロジェクトツリー項目(Open / Move / Star)、別のプロジェクトへコピー、Terraform で管理、シーン固有のファイル操作、Export サブメニュー、──、Delete / Archive / Restore(破壊的項目は最下部) |
| Edit | Duplicate、Rename、SQL エディターで編集、シーン固有の編集、状態変更(Pause/Resume、Activate/Deactivate)、──、トグルグループ(チェックボックス/ラジオ項目。通常項目とは <SceneMenuBarSeparator> で区切る) |
| View (条件付き) | クロスリソース表示 — View recordings、View metalytics、View related insights など。現在のリソースに間接的に関連するものを 見る ためにナビゲートするものはすべてここに含めます。空の場合はスキップします。 |
Metadata (SceneMenuBarPopover を使用) | Tags、Evaluation contexts、Stage、Activity indicator、External references、Comments など。 |
| Staff only (条件付き) | デバッグパネル、スタッフ専用トグル。スタッフ / superpowers / なりすまし中 / 非クラウドユーザーにのみレンダリングします。 |
状態は Edit にあります。 Pause/Resume、Activate/Deactivate、Favorite/Pin トグルなどの 状態変更はすべて Edit メニューの内部にあります — 通常は最下部で、トグルグループがある場合は
<SceneMenuBarSeparator>の後ろです。独立したStateメニューを作成しないでください。
右側のクラスターは固定で共通です: PostHog AI · Docs · Support。ここには何も追加しないでください。
ルール
破壊的なアクション(Delete / Archive / Restore)
- File の最下部に配置し、上にあるファイル操作とは
<SceneMenuBarSeparator>で区切ります。 - 視覚的な表現のために
variant="destructive"を渡します(赤いテキスト + アイコン)。 - 確認ダイアログを開く場合でも、破壊的な項目には
opensFloatingUiを 追加しないでください — 破壊的バリアントと明確なラベルで十分なシグナルになります。 - リソースにアクセス制御レベルがある場合は
<AccessControlAction>でラップします。
トグルグループ
- すべての
<SceneMenuBarCheckboxItem>と<SceneMenuBarRadioGroup>項目をまとめてグループ化します。 - 通常のアクション項目とは
<SceneMenuBarSeparator>で区切ります(上に、そしてさらに項目が続く場合は下にも)。 - 安定したラベルを使用します — チェックマークが状態を伝えます:
Pin/UnpinではなくPinned、Show/Hide debug panelではなくShow debug panel。 - 相互排他的な選択肢にはラジオを使用します(
<SceneMenuBarRadioGroup value onValueChange>)。
opensFloatingUi プロップ
追加のフローティング UI を開く項目には、Mac スタイルのアフォーダンスとして項目ラベルの末尾に … を追加します:
- ✅ 使用する: モーダル、ポップオーバー、ダイアログ、サイドパネルのオープナー
- ❌ スキップする: 同一ページ内ナビゲーション、直接アクション、破壊的な項目(破壊的なスタイルがすでに結果を示しています)、トグル項目
+ Create クロスセル
- File の先頭にある
<SceneMenuBarSubMenu label="Create">の中にネストします。 - Create と File の残りの間に
<SceneMenuBarSeparator>を配置します。 - クロスセル: Cohort、Survey、Dashboard、Notebook、Endpoint、Subscription、Alert、Share or embed。
空のメニュー
SceneMenuBarMenu は、コンパイル時に子要素が何もレンダリングしない場合(例:{false && <Item/>}、{null}、空のフラグメント)、トリガーを自動的に無効にします。トリガーは表示されたまま(グレー表示で、cursor-not-allowed)になるため、メニューセットを通じてユーザーにバーの機能を伝えられます。
子要素が実行時に null をレンダリングする可能性があるメニュー(最も一般的な例は <SceneMenuBarFileItems> です。プロジェクトツリーのエントリが登録されていない場合、または Today レイアウトが有効な場合に sceneFileLogic.hasFileItems が false となり、null を返します)では、親はポップアップが空になることを検知できません。次のいずれかを行ってください。
-
子要素が依存する値と同じ値に基づいて、
disabledを明示的に渡します。例:const { hasFileItems } = useValues(sceneFileLogic) <SceneMenuBarMenu label="File" disabled={!hasFileItems}> {hasFileItems && <SceneMenuBarFileItems dataAttrKey="…" />} </SceneMenuBarMenu> -
有用なものを何もレンダリングできない場合は、親でメニュー全体の表示を制御します。
{ hasAnyEditItem && <SceneMenuBarMenu label="Edit">…</SceneMenuBarMenu> }
メニューの存在がシーンのアイデンティティの一部である場合(無効でも File は常に表示するなど)は(1)を優先し、メニューが本当に任意の場合(View、Staff のみなど)は(2)を優先してください。
タグ/評価コンテキスト/その他のリッチ入力
<SceneMenuBarMenu>ではなく、<SceneMenuBarPopover>の内側に配置する必要があります。メニューのポップアップはキーストロークを横取り(タイプアヘッド、矢印キーによる移動)し、テキスト入力が入力を受け取れないようにします。- 複数選択のチップ入力には
<TagsCombobox>(lib/components/Scenes/TagsCombobox.tsx)を使用します。デフォルトでは選択のみ可能です。末尾に「新しい {noun} '...' を作成」という項目を表示するには、allowCustomValuesを渡します。 <SceneTagsCombobox>(lib/components/Scenes/SceneTagsCombobox.tsx)は、SCENE_MENU_BARのときに<SceneTags>と置き換えて使える、すぐに利用可能なラッパーです。
デバウンスを使った楽観的な保存
メニューバーの入力(タグ、切り替え)を自動保存する場合は、次の処理を行う kea リスナーを使用します。
- API 呼び出しの前に、
setXとupdateXで楽観的に更新します。 - 連続した変更をデバウンスするため、
await breakpoint(250)を実行します。 - より新しい呼び出しによって古くなった処理を中断できるよう、API 応答の後に
breakpoint()を実行します。 - サーバーから返された値の順序が異なる場合に並べ替えが発生しないよう、反映する前に集合の等価性を確認します。
error.isBreakpointを再スローして、kea がエラーを通知せずに処理できるようにします。
frontend/src/scenes/feature-flags/featureFlagLogic.ts の saveTagsInline を参照してください。
File メニュー — プロジェクトツリーの項目
File の末尾(破壊的操作の区切り線の前)に <SceneMenuBarFileItems dataAttrKey={RESOURCE_TYPE} /> を使用すると、プロジェクトツリーで開く、フォルダーに移動、スターに追加/スターから削除を表示できます。sceneFileLogic.hasFileItems が false の場合は自動的に非表示になります。
右側のクラスター
実際のメニューで CompositeRoot のキーボードナビゲーションを機能させるため、<Menubar> ラッパーの外側に配置します。UX レビューなしにここへ項目を追加しないでください。
レイアウトに応じたはみ出し
<SceneMenuBar> は sceneLayoutLogic.sceneLayoutConfig.layout を読み取り、レイアウトにパディングがある場合にのみシーンコンテナーのパディングを越えてはみ出します(-mx-4 -mt-4)。対象となるのは app、app-container、app-full-scene-height です。パディングのないレイアウト(app-raw、app-raw-no-header、plain)では、負の値を設定すると必要以上にはみ出し、ヘッダーの見た目が崩れるため適用されません。シーン側で特別な対応は不要です。適切な SceneConfig.layout を登録するだけで、バーが自動的に調整されます。デバッグ用に、ラッパーには data-scene-layout 属性が設定されます。
移行済みのシーン
- Feature Flag —
frontend/src/scenes/feature-flags/FeatureFlag.tsx - Insight —
products/product_analytics/frontend/insights/insightScene/sidePanel/InsightSceneMenuBar.tsx - Dashboard —
frontend/src/scenes/dashboard/DashboardSceneMenuBar.tsx
新しいシーンを移行する際は、<Scene>SceneMenuBar.tsx のパターンに従ってください(featureFlagLogic を読み込み、フラグがオフなら早期に null を返し、オンならバーをレンダリングするコンポーネント)。<SceneTitleSection> のすぐ上に直接マウントしてください。
シーンの監査
シーンを移行する際は、既存の ScenePanel を取得し、すべての項目を次のようにマッピングします。
- どのメニューに属するか(File / Edit / View / Metadata / Staff only)。
variant="destructive"が必要かどうか(delete/archive/remove)。opensFloatingUiが必要かどうか(モーダル/ポップオーバー/ダイアログ/サイドパネルを開く)。- トグルかどうか(
SceneMenuBarCheckboxItemを使用)。 - どのようなゲートが適用されるか(保存状態、FF、AccessControl、マルチプロジェクト)。
PostHog 全体にわたるすべての ScenePanel 項目と、それらに対して提案されたメニュー配置の最新の一覧については、/Users/adamleithp/Desktop/scene-menu-bar-grouping.md を参照してください。