mcpField
O
objectstack-ui

objectstack-ui

github.com/objectstack-aiデザイン・UI76229 回インストール今日更新
リポジトリ

objectstack-ui について

objectstack-uiは、ObjectStack仕様に沿ったUI設計を支援するスキルです。ビュー、ナビゲーション、ダッシュボード、レポート、ページ、アクションを扱います。

主な機能

  1. 01リスト・フォームビューの設計ガイド
  2. 02マスターディテールフォームのパターン
  3. 03アプリナビゲーション構成
  4. 04ダッシュボードとレポートの設定
  5. 05ページとアクションの設計

活用シーン

  1. 01メタデータ駆動のCRM UI設計
  2. 02子レコードを含む親フォームの設定
  3. 03アプリナビゲーションとカスタムページの構成

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/objectstack-ai/objectstack --skill objectstack-ui

インストール後、Claude Code で/objectstack-uiを入力して読み込まれたか確認します。

同梱ファイル

SKILL.md と一緒にインストールされる参考資料やスクリプト。

evals/
README.md
analytics-inline-vs-dataset.json
views-apps-actions-pages.json
references/
_index.md
react-blocks.md
rules/
actions.md
list-views.md
dashboards.md
navigation.md
pages.md

詳細

UI デザイン — ObjectStack UI プロトコル

ObjectStack 仕様を使用してユーザーインターフェースを設計するための専門家向け指示です。このスキルでは、ビュー(リスト、フォーム、カンバン、カレンダー、…)、アプリのナビゲーション、ダッシュボード、レポート、アクションを扱います。


ビューの種類

リストビュー
種類使用する場面
grid標準的なデータテーブル — ほとんどのオブジェクトでデフォルト
kanban列を使ったビジュアルボード(ステータス主導のワークフロー)
galleryカードベースの石積みレイアウト(ビジュアルカタログ、連絡先)
calendar日付ベースのスケジュール管理(イベント、タスク、予約)
timeline時系列のアクティビティストリーム
gantt依存関係を追跡するプロジェクト管理
maplocation フィールドを持つ地理空間レコード
chartオブジェクト全体の集計を視覚化(ミニチャートビュー)
tree自己参照型の階層構造(ツリーグリッド)
フォームビュー
種類使用する場面
simple1 ページのフォーム — フィールドが 15 個以下のオブジェクトに適しています
tabbedタブ付きセクション — 多くのフィールドグループを持つ複雑なオブジェクト向け
wizardステップ形式のフロー — ガイド付きデータ入力(オンボーディング、申請)
マスターディテールフォーム(親+子明細行)

ユーザーがレコードを子明細行と一緒に(請求書+明細行、プロジェクト+タスク)入力し、アトミックに保存できるようにする場合、カスタムページやフォーム設定が必要になることはほとんどありません。次の順に優先してください。

  1. リレーションシップの inlineEdit(デフォルト、UI 設定不要)。 データモデルで宣言します。親を参照する子の master_detail フィールドに inlineEdit を設定してください。親の標準的な新規作成/編集フォーム(モーダル、ドロワー、全画面)には子が自動的に表示され、親と子が 1 回のアトミックな /api/v1/batch で保存されます。ビューのメタデータは不要です。 true / 'grid' / 'form' の段階と、それぞれの値で選ばれる内容については、objectstack-data → Relationships → Inline Editing を参照してください。

  2. フォームビューの subforms(上書き/調整)。 派生した列や順序を上書きする場合、またはリレーションシップでインライン表示に指定されていない子を表示する場合にのみ、フォームビューに追加してください。

    form: {
      type: 'simple',
      sections: [{ group: 'invoice_header' }],  // a declared fieldGroup
      subforms: [
        { childObject: 'invoice_line', // relationshipField + columns are
          title: 'Line Items',         // derived from the child object;
          addLabel: 'Add line' },      // set `columns` here only to override.
      ],
    },
    
  3. object-master-detail-form ページブロック(独自レイアウト)。 自由形式のレイアウトが必要な場合にのみページを使用してください。同じ details: [{ childObject }] の省略記法を使えます。

リレーションシップの外部キーとグリッド列は、いずれの場合も子オブジェクトのメタデータから派生します。選択肢とルックアップも引き継がれます。親の summary フィールドでは、子の値をサーバー側で集計できます(objectstack-data を参照)。

明細行グリッドの動作(grid モード)。 編集可能なグリッドは、実際のスプレッドシート形式の明細エディター(QuickBooks / Stripe / NetSuite のパターン)です。計算列、カタログのタイプアヘッドによる自動入力、保存されるドラッグ並べ替え、リアルタイムの小計 → 税 → 合計の連鎖など、すべての動作はデータモデルから派生します。objectstack-data → Relationships → Inline Editing を参照してください。この側で設定するのは 3 つです。末尾には常にゴースト行が存在するため、「明細行を追加」ボタンは追加しないでください(ゴースト行に入力すると行が作成され、何も入力されていない行は保存されません)。autofill: false を指定すると、対象の列はタイプアヘッドによるコピーから除外されます。また、フォームの taxRateField で、合計の計算に使用する親フィールドを上書きできます。

読み取り側 — 詳細ページの関連リスト。 inlineEdit に対応するのは、親レコードの詳細ページにある関連リストです。関連リストを独自に定義する必要はありません。すべての子リレーションシップはデフォルトで関連リストとして表示されます(所有する master_detail の子が最初に表示されます)。リレーションシップで次のように調整できます。

  • relatedList: 'primary' — 重要なリレーションシップとして指定します。詳細ページでは独立したタブに昇格します(下記のレイアウトを参照)。これはレイアウトを切り替える指定ではなく、重要度を示す意図です(ADR-0085)。
  • relatedList: false — 詳細ページから、不要な子の表示を抑制します。
  • relatedListTitle / relatedListColumns — 派生したタイトル/列を上書きします(どちらも任意です。列は、指定がなければ子オブジェクトの highlightFields から自動的に派生します)。objectstack-data → Relationships → Detail-page related lists を参照してください。

関連リストのレイアウト。 生成されるレコード詳細ページでは、relatedList: 'primary' の子はそれぞれ独立したタブになり、それ以外の関連リストはすべて 1 つの共通の Related タブに積み重ねて表示されます。そのため、子テーブルを第一級のタブに昇格するには、リレーションシップを 1 語変更するだけです。カスタムページは必要ありません。オブジェクトでは、画面ごとのレイアウトヒントを宣言しません。以前の detail.relatedLayout 切り替え設定とオブジェクトレベルの detail: {...} ブロックは削除済みです(ADR-0085)。relatedLayout: 'tabs' | 'stack' は、アプリレベルのデフォルト上書きとしてのみ残り、オブジェクトのキーとしては使えません。リレーションシップ層では表現できない配置(例:Open と Closed を分けたタブ、チャート/レポートのタブ、厳密なタブ順序)が必要な場合は、オブジェクトにカスタムレコードページを割り当て、record:related_list(またはインライン編集可能な line_items)ブロックで明示的にレイアウトしてください。

フォームのフィールド条件ルール

フィールドのライフサイクルに属する条件である visibleWhen、readonlyWhen、 requiredWhen は、フォームビューではなく データモデルのフィールド に宣言します。 ObjectUI フォームはこれらを使用します。セマンティクスとサーバーの動作については、 objectstack-data → Conditional Field Rules を参照してください。

UI 側では、インラインのマスター・詳細グリッドは、各子行に対して行ごとにこれらのルールを評価します。 requiredWhen を使用してください。conditionalRequired エイリアスはプロトコル 17 で 削除され、現在は解析エラーになります。複雑な CEL を記述する場合は objectstack-formula を読み込んでください。


詳細ルール


アプリのナビゲーション

App は、オブジェクト、ダッシュボード、レポート、カスタムページを構造化された ナビゲーションツリーにまとめます。@objectstack/spec/ui の App.create({...}) で構築し、defineStack({ apps: [...] }) に登録します。

⛔ type: 'app' のパッケージにつき App は 1 つだけです — ADR-0019 (app-as-consumer-unit)D3 に基づき、defineStack は読み込み時に 2 つ目の App を拒否します。 対象者を増やす場合は、2 つ目の App を作成せず、1 つの App 内 に requiredPermissions で制御するグループを追加してください。

ナビゲーション項目の種類
種類プロパティ用途
grouplabel、icon、expanded、children[]折りたたみ可能な項目グループ
objectobjectName、viewName?、recordId?、filters?、label、iconオブジェクトのリスト、名前付きビュー、レコードへのディープリンク、または基本データサーフェス上の filters スライスへのリンク
dashboarddashboardName、label、iconダッシュボードへのリンク
reportreportName、label、iconレポートへのリンク
pagepageName、label、iconカスタムページへのリンク
urlurl、label、icon外部 URL またはカスタム URL
actionactionDef({ actionName, params? })、label、iconナビゲーションの代わりにアクションを実行
componentcomponentRef、params?、label、icon組み込みのプラットフォームコンポーネント。componentRef はコロンで連結したレジストリキー(metadata:resource)です
docbook? / doc?(いずれか必須)、label、iconパッケージドキュメント。ドキュメントの対象者設定を継承
separator—視覚的な区切り

requiresObject / requiresService: オプションのシステムオブジェクトまたはカーネルサービスに依存する項目には、これらを使用してください。依存対象がない場合、ナビゲーション項目は自動的に非表示になります。条件付き UI をハードコードしないでください。


レポートの種類

種類使用する場面
tabular列とフィルターを含むフラットなデータテーブル
summary小計を含むグループ化データ(例:地域別の売上)
matrixクロス集計/ピボットテーブル(rows が縦方向 × columns が横方向)
joined複数ブロックからなる分析サーフェス(複数のサブレポートを組み合わせる)

chart レポートタイプはありません。レポートの視覚化には、埋め込みの chart: 設定を使用します。


CRM UI ブループリント(メタデータ優先)

この CRM スタイルの構造を、UI を構築する際の標準リファレンスとして使用します。

UI サーフェス一般的な場所従うパターン
複数ビューのオブジェクト UIsrc/views/*.view.tsデフォルトの list と form を定義し、シナリオ別に名前付きの listViews / formViews を定義します
公開フォームsrc/views/*.view.ts(sharing: { enabled: true, allowAnonymous: true, publicLink: 'slug' } を含む formView)GET/POST /api/v1/forms/:slug の Web-to-Lead
アプリナビゲーションsrc/apps/*.app.tsグループ化したナビゲーションツリー、viewName ショートカット、機能に応じた表示制御のための requiresObject を使用します
アナリティクスデータセットsrc/datasets/*.dataset.tsレポート対象にするオブジェクトごとに 1 つ定義します — ダッシュボードとレポートは名前で宣言済みデータセットにバインドされるため、データセットのないオブジェクトにはアナリティクスの表示手段がありません
ダッシュボードsrc/dashboards/*.dashboard.tsKPI、チャート、テーブルのウィジェットを、共通の dateRange と globalFilters と組み合わせます
レポートsrc/reports/*.report.tsそのデータセットから rows(ディメンション)と values(メジャー)を選択します。形式は表形式/サマリー/マトリックス/結合です
レコードページsrc/pages/*.page.tsregions とコンポーネント(page:header、record:highlights、関連リスト、タブ)を組み合わせます
ユーザーアクションsrc/actions/*.actions.tsオーケストレーションには flow を、パラメーター化された一括変更には script を使用します

このブループリントは、「メタデータアプリの UI 全体を構築する」タスクのデフォルトです。


日付マクロ — フィルタープレースホルダー

リストビュー、ダッシュボード、レポート、ページのフィルター値では、相対日付トークン({today}、{current_month_start}、{30_days_ago})と、セッショントークン {current_user_id} / {current_org_id} を使用できます。トークンの語彙、受け付ける 2 つの表記、2 つのリゾルバー、およびよく似た誤りの一覧は objectstack-query の rules/filters.md で管理されています — フィルタートークンを書く前に読み込んでください。 認識されないトークンはビルドエラーとなり、実行時にも例外が発生します。リテラルとして黙って扱われることはありません。

このパッケージが管理するルールは、トークンの語彙ではなく UI サーフェスに関する次の 2 つです。

  • フィルタートークンは表示範囲であり、セキュリティではありません。サーフェスに何が表示されるかを決めるのはフィルタートークンであり、呼び出し元が何を読み取れるかを決めるのは RLS です。{current_user_id} フィルターを削除するとビューの範囲は広がりますが、ユーザーが他のユーザーのデータにアクセスできるかどうかを左右する要素にしてはなりません。
  • AppContextSelector の ID(例:{active_package})は、ナビゲーションの recordId / params でのみ解決されます。フィルターの評価では、サイドバーのセレクター状態は使用されません。

アクション

アクションは、オブジェクトまたはビューに関連付けられた、ユーザーが起動する操作です。 defineStack({ actions: [...] }) の下に登録します。

アクションの種類
type目的必須フィールド
scriptサーバー上でインラインの L2 フック本体(サンドボックス化された JS)を実行しますbody(または target = 登録済み関数名)
url内部ルートまたは外部 URL に移動しますtarget
modaltarget で指定されたページを開きます。body が実行されるのは script の場合のみですtarget
flow名前で画面フローまたは自動起動フローを起動しますtarget
api登録済みの API エンドポイントを呼び出しますtarget
form名前で FormView を開きます(/_console/forms/:name にルーティングされます)target

よくある落とし穴

  1. グリッドビューに列を詰め込みすぎること。 通常、ユーザーがデフォルトで表示する列は 6~8 列までで十分です。補助的な列には hidden を使用してください。

  2. 主列に link: true を設定し忘れること。 最初の意味のある列(通常は名前/件名)を、レコード詳細への ナビゲーションリンクにしてください。

  3. ウィジェットのグリッド配置を position に設定すること。 グリッド配置フィールドは layout: { x, y, w, h } です。position は ウィジェットのキーではなく、クローズドスキーマでは名前で拒否されます(プロトコル 17 より前は警告なく 削除されていました)。layout は省略可能です。省略するとウィジェットは自動的に 配置されます(Studio デザイナーはこれを前提としています)。明示的なグリッド位置を指定したい 場合にのみ設定してください。


作業の検証

*.view.ts / *.action.ts / *.dashboard.ts を作成した後、完了を報告する前に 作成時の検証を実行してください。

os validate     # CEL predicates (record.<field>) + widget bindings + schema
# or: os build  # the same gates, plus emits dist/

実行時にはどちらも警告なしに問題が起きる、UI 固有の落とし穴を 2 つ検出します。

  • アクション/フィールドの述語 — アクションの visible / disabled やフィールドの visibleWhen にフィールド参照のみを指定すると( record.done ではなく done)、評価結果が null となり、すべてのレコードで コントロールが非表示になります(「ボタンが表示されない」落とし穴)。
  • ダッシュボードのウィジェットバインディング — 宣言済みのデータセット/フィールドに解決できない dataset / dimensions / values をウィジェットに指定すると、空のグラフが 表示されます(ADR-0021)。

os validate が成功するまで、ビュー/アクション/ダッシュボードの作業完了を報告しないでください。スキャフォールド済みのプロジェクトでは、検証コマンドは npm run validate です。


参考資料

Zod スキーマの全一覧(各項目に 1 行の説明を付記)については、references/_index.md を参照してください。各項目は node_modules/@objectstack/spec/src/ 内の該当箇所を示しています。フィールドの正確な 構造は必ずソースを Read して確認し、プロパティ名の記憶に頼らないでください。

コメント