grid-creator について
grid-creatorは、ブランチ上でDatex Studioのグリッドを作成・変更するスキルです。データソース選定から設定、検証、登録までを案内し、エンティティ項目と動的フィルター設定の同期を重視します。
主な機能
- 01Datex Studioグリッドの作成と変更
- 02ODataまたはフローのデータソース選定
- 03グリッド内のエンティティ形状の同期
- 04フィルター、並べ替え、操作の設定
- 05dxsによる設定の検証と登録
活用シーン
- 01複数レコードの表形式ビューの作成
- 02グリッドへのフィルター、並べ替え、行操作の追加
- 03ブランチ上の既存グリッド設定の更新
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ datex/ skills --skill grid-creatorインストール後、Claude Code で/grid-creatorを入力して読み込まれたか確認します。
同梱ファイルevals/evals.jsonreferences/grids.md
詳細
グリッド作成
ブランチ上で Datex Studio のグリッド(configurationTypeId=3)を作成または変更します。グリッドは、プラットフォームの主要なデータ密度コンポーネントです。グリッドは、基盤となるデータソースの行を表形式で表示し、インライン編集、選択、ツールバー、動的なフィルターと並べ替え、行ごとおよびセルごとの操作を任意で設定できます。通常はハブのタブ内に配置され、他のどのコンポーネントよりも多くのロケーション間の不変条件を担います。ここでは、5 ロケーションのエンティティ形状ルール、動的なフィルターと並べ替えの 2 サイト間の登録ミラー、OData ランタイムの selects ロケーションを扱います。
参考資料
- ../datex-studio-shared/branch-setup.md — ブランチ/接続の選択(各スキルで共通)
- references/grids.md — グリッド作成の信頼できるリファレンス:ファイル構造、ランタイムグローバル、5 ロケーションルール、動的フィルター、セカンダリデータソース、命令型セル API、事前チェックリスト
- ../datex-studio-conventions/file-format.md —
configurationTypeIdの一覧と TypeScript 式のエンコード規則 - ../datex-studio-conventions/naming-conventions.md —
_gridサフィックス、ファイル名のベース名の一致、表示名の規則 - ../datex-studio-runtime/runtime-globals.md — グリッドコードで使用可能な、プラットフォームから注入されるグローバル(
$grid、$row、$flows、$apis、$utils、...) - ../datex-studio-runtime/calling-conventions.md — UI 階層の呼び出し規則(アクションではなく関数を呼び出すこと。CRUD には
$apis.<Package>.FootprintApi.extendedActions.<action_name>を使用) - ../datasource-creator/references/datasources.md — 行データの基盤となるデータソースの分類(バリアント × クエリタイプ)
- ../datasource-creator/references/flow-datasources.md — フロータイプのデータソース構造(ページネーション対応の
getListFlow/getByKeysFlow)。グリッドに埋め込むデータソース向け - ../component-wiring-check/references/component-wiring.md — ホスト参照の契約、vars を宣言するルール、moduleId ルール
- ../tailoring-overlay/references/tailoring.md — テーラリングされたグリッドバリアントとセカンダリデータソースによる拡張のオーバーレイモデル
- ../collection-filter-authoring/SKILL.md — オブジェクトコレクションを通じたスカラーリーフへの Any/All フィルター。検証済みの CLI 生成と、残りのライブ統合チェックを含む
依存関係
requirements-gatheringスキル — 会話のコンテキストに要件概要がまだ存在しない場合、要件概要を作成するために呼び出しますschema-explorerスキル — PascalCase の複数形名のグリッド(または行が OData エンティティのように見えるグリッド)を作成する前に呼び出し、Footprint スキーマにエンティティが存在するか確認します。間違ったデータソースに対してグリッドを作り直すより、5 秒で確認するほうが効率的ですdatasource-creatorスキル — グリッドに独立したデータソース(複数の利用者間で共有するもの)が必要な場合に呼び出します。グリッド専用のデータソースは別ファイルではなく、グリッド内の所有エントリとしてdatasources[]配列に作成します。この所有エントリを作成するには、../datasource-creator/references/datasources.md → Creating an Owned Datasource に従います。dxs datasource generate-flowでひな形を生成してから、組み込みます。ページネーションの件数はgetListFlow内に保持し、最上位コンポーネント/参照の出力は確定済みのデータソース契約に従いますform-creator/editor-creator/selector-creatorスキル — 要件が表形式の一覧ではなく、一時的な入力収集(フォーム)、単一エンティティの表示/編集画面(エディター)、またはドロップダウン/オートコンプリート(セレクター)に該当する場合に呼び出しますhub-creatorスキル — グリッドをマウントするために、グリッドをホストするハブのタブ/ボタンでconfigParameters契約を設定する必要がある場合に呼び出しますcomponent-wiring-checkスキル — プッシュする前に、グリッドのホスト側(外側)とグリッドに埋め込まれたデータソース側(内側)の両方で、configParametersと対象のinParamsの契約を監査するために呼び出しますtailoring-overlayスキル — グリッドのカスタマイズ版(baseConfigurationとonCustomization*FlowConfig)を作成または保守する場合、あるいは二次的なエンリッチメントデータソースがオーバーレイから取得される場合に呼び出しますgrid-validatorスキル — グリッドを編集するたびに、呼び出しが必須です。事前チェックリストを再実行し、5 か所にまたがる不整合、部分的な lookupcode/id の同期、ODataselectsの不足、動的フィルター登録のミラー間の不整合を検出します。このスキルのブロッカーは必ず修正してください
CLI のライフサイクル
グリッドの作成には dxs configuration を使用します。これは、すべてのプラットフォーム設定タイプに対応する汎用 CRUD プリミティブです。dxs grid サブコマンドやフィールド単位のパッチ適用はありません。JSON 本文全体を作成する(または取得して抽出する)必要があります。本文を編集した後、全体を再度プッシュします。CLI のタイプ識別子は grid(小文字。ConfigurationEndpoints.normalize_type の出力と一致)で、configurationTypeId: 3 に対応します。
新しいグリッドを作成する場合:
# 1. Build body.json from scratch (see references/grids.md → Minimal Valid Skeleton)
# 2. Validate — gates the push. Exit 1 = errors found (read validation_errors, fix, re-run), not a broken CLI
dxs configuration validate grid -b <branchId> -D body.json
# 3. Create
dxs configuration upsert grid -b <branchId> -D body.json
既存のグリッドを編集する場合:
# 1. Fetch — note the envelope wrapper
dxs configuration get grid <configId> -b <branchId> -O envelope.json
# 2. EXTRACT THE INNER BODY (round-trip footgun guard — see "Round-trip rule" below)
jq .json envelope.json > body.json
# 3. Edit body.json
# 4. Validate — gates the push. Exit 1 = errors found (read validation_errors, fix, re-run), not a broken CLI
dxs configuration validate grid -b <branchId> -D body.json
# 5. Push
dxs configuration upsert grid -b <branchId> -D body.json
ラウンドトリップのルール(重要)
既存の設定を編集する際、envelope.json を直接 dxs configuration upsert にパイプしてはいけません。設定内容がひそかに破壊されます。上記の修正済み手順のとおり、編集前に jq で内側の .json を抽出することが、ラウンドトリップのたびに必須です。標準のラウンドトリップ手順と根本的なバグについては、../datex-studio-shared/configuration-roundtrip.md を参照してください。
グリッドには、columns、datasourceConfig、埋め込みの datasources[] 配列(各エントリは完全なフロー型または OData 型のデータソースで、独自の getListFlow/getByKeysFlow とエンティティ形状の各配置箇所を持ちます)、flows/rowFlows(すべての executeCodeConfig ステップに code 文字列を含みます)、topToolbar/toolbar(多態的なコントロール記述子)、filters、およびグリッドレベルの inParams/outParams/vars/rowVars スキーマが含まれます。ラウンドトリップの手順(取得 → jq で抽出 → 編集 → 検証 → プッシュ)は必ず守ってください。エンティティ形状の各配置箇所の一部だけを同期する部分的な同期は、アップロード時の契約エラーの原因として最もよく見られます。
ワークフロー
[Phase 1: Setup + Requirements]
Follow branch-setup.md for branch/connection selection
|
[requirements brief in context?]
+-----+-----+
| |
YES NO -> invoke `requirements-gathering`
| |
+-----+------+
|
[Phase 2: Pre-author rows-source decision]
Consult references/grids.md → "Pre-Author Decision — What Backs the Rows?":
- PascalCase-plural name -> invoke `schema-explorer` (mandatory)
before defaulting to flow-type; if entity exists, build OData-backed
- snake_case name -> check the branch for a storage config
(`dxs source explore configs --type storage`) or treat as flow-type
- ambiguous -> invoke `schema-explorer` first
Owned vs standalone:
- grid-only datasource -> embedded entry in `datasources[]`
- shared across consumers -> standalone (invoke `datasource-creator`)
If requirement is single-entity view/edit -> invoke `editor-creator` and stop.
If requirement is transient input collection -> invoke `form-creator` and stop.
If requirement is a dropdown/autocomplete -> invoke `selector-creator` and stop.
|
[Phase 3: Author grid body]
Build body.json:
- File shape (configurationTypeId=3, *-grid.json suffix,
referenceName ends _grid, snake_case matches filename stem)
- Five-location entity-shape rule (flow-type) or five+selects (OData);
every entity field present at every site
- Two-site dynamic filter/sort registration mirror (datasources[0] and
datasourceConfig); per-column dynamicFilter/dynamicOrderBy/
dynamicFilterType/dynamicFilterControl; no $filter/$orderby in any
inParams or configParameters
- Dynamic filter/sort is all-or-nothing — flow-type backings either
fully wire (registrations + per-column + applyDynamicFilter/
applyDynamicOrderBy in getListFlow) or fully disable
- Toolbar items polymorphic — click handlers inside the type-specific
config block (buttonConfig.clickFlowConfig.flowId), siblings null;
destructive buttons get buttonDefaultStyleClass: "destructive";
selection-gated buttons seed readOnly: true statically AND gate
live in on_select_row
- Secondary enrichment datasources owned in same datasources[] array;
invoke from on_data_loaded; batch with Id in ${ids}; write via
imperative cell API ($row.cells.<col>.displayControl.text / value)
- Imperative cell API for post-load enrichment and change-guarded
saves; empty declarative bindings are legitimate when value is
populated imperatively — don't "fix" to $row.entity.<field>
- Text display bindings coerce non-string entity fields at the bind
site, not in the entity schema (entity type drives filter operators)
- Every $grid.vars.<id> / $row.vars.<id> written in flow code is
declared in top-level vars[] / rowVars[]
- Embedded datasource carries the full component-identity envelope
(referenceName matching datasourceConfig.configId, title, description,
hasKey, hasResult, accessModifier, ...)
- Invoke `schema-explorer` for OData entity / property / navigation
property validation before authoring OData-backed grids
- Invoke `component-wiring-check` to audit BOTH the outer host
contract AND the inner grid → embedded-datasource contract
(full_text_search and any inParam need explicit configParameters
entries)
|
[Phase 4: Validate + push]
dxs configuration validate grid -b <branchId> -D body.json
|
+----+----+
| |
CREATE MODIFY-EXISTING
| |
| use the corrected round-trip
| (get -O envelope -> jq .json -> body)
| |
+----+----+
|
v
dxs configuration upsert grid -b <branchId> -D body.json
(upsert creates or updates by referenceName — one command for both)
|
[Phase 5: Validate with `grid-validator` (MANDATORY)]
Delegate to `grid-validator` with the grid's file path / configId.
It re-runs the full Pre-Flight Checklist, catches five-location drift,
partial lookupcode/id syncs, OData `selects` misses, and registration
mirror drift. Treat its blockers as must-fix.
|
[invoke `post-edit-verification` for description/JSON/schema hygiene]
フェーズの詳細
フェーズ 1:セットアップと要件
- ブランチと接続の選択については、../datex-studio-shared/branch-setup.md に従ってください。ブランチ ID を決めつけないでください。ユーザーに確認を求めてください。
- 会話のコンテキストに要件ブリーフ(
requirements-gatheringまたは別の呼び出し元のスキルによって作成されたもの)がすでにあるか確認します。- ブリーフがある場合 — それを使用します。ブリーフでは、行エンティティ(または集約された行の形状)、グリッドに表示する列、フィルターや並べ替えが可能なフィールド、グリッドをマウントするホスト、および必要な行アクション/ツールバーアクションのフローが明確になっている必要があります。
- ブリーフがない場合 — まず
requirements-gatheringスキルを呼び出します。行の形状、フィルターの可否、ホストへのマウント方法を最初に正しく決めておけば、エンティティ形状の配置場所や動的フィルター登録を一から作り直さずに済みます。
フェーズ 2:行ソースの決定(作成前)
**グリッドを作成する前に、**行のデータソースを決定します。この判断によって、埋め込みデータソースの type(oDataQuery か flows か)が決まり、5 箇所ルールも変わります。ここを誤ると、データソース全体を間違ったソースに対して作成することになります。作成前に、references/grids.md(データソースの形式と5 箇所ルール)および以下のフェーズ 2 の行ソースの決定を確認してください。
フローデータソースの形式チェック:グリッドの行データソースは、キー付きコレクション形式である必要があります。つまり、resultIsCollection: true であり、getListFlow と getByKeysFlow の両方が設定され、keyDef が空でないことが条件です。getListFlow だけのフローデータソースではグリッドを構成できません。アクション後の単一行の更新では getByKeys が呼び出されますが、これは存在しないためです。接続する前に、実装済みのメソッドから適合性を判断してください。詳しくは
../datasource-creator/references/flow-datasources.md
→「既存のフローデータソースから適合性を判断する」を参照してください。これは実行時のリスクだけではありません。このブランチのサーバー側の使用ゲートは契約の検証時にこの条件を適用し、グリッドのデータソースに getList または getByKeys がない場合、公開をブロックします。
グリッド名は最も有力な手がかりです。
- PascalCase の複数形(
TaskStatuses、Orders、Shipments、Warehouses)— Footprint スキーマ内の OData エンティティである可能性があります。作成前にschema-explorerを実行し、describe entity <Name>(またはsearch <Name>)を確認してください。該当するエンティティが見つかった場合は、そのエンティティを使って OData ベースのグリッドを作成します。厳守事項:schema-explorerを実行せずに、PascalCase の複数形の名前に対してフロー型データソースをデフォルトとして使用しないでください。 - snake_case(
task_statuses、invoicing_rules、widget_options)— 機能が所有するストレージコンポーネントか、計算・集計されたソースである可能性があります。ブランチ内で該当するストレージ設定を確認するか(dxs source explore configs --branch <id> --type storage --search <name>)、機能コードを使用するフロー型データソースとして扱います。 - 曖昧/不明 — まず
schema-explorerを実行してください。5 秒の検索のほうが、後からユーザーにエンティティの存在を指摘され、グリッドを作り直すよりも手間がかかりません。
schema-explorer で該当するものが見つからない場合は、フロー型データソースに切り替えます。ただし、次の作成者が検索を繰り返さなくて済むよう、グリッドの description または埋め込みデータソースの近くに、この判断を記載してください。
所有型とスタンドアロン型。このグリッドの行へのデータ提供だけを目的とするデータソースは、独立した <name>-datasource 設定としてではなく、グリッドの datasources[] 配列内に所有型エントリーとして作成します。スタンドアロンのデータソースは、複数のグリッド/フォーム/エディター/アクションなど、複数の利用者で共有する場合に使用します。このグリッドの行形式のためだけに使うデータソースはグリッド内に置きます。これにより、5 箇所ルールを1つのファイル内に収め、行形式の編集を後から妨げる意図しない再利用を防げます。追加のエンリッチメント用データソース(フェーズ 3 を参照)も所有型です。要件で共有データソースが必要な場合は、代わりに datasource-creator を実行してください。これはプラットフォーム全体のデフォルトであり、グリッド固有の設定ではありません。このルールと、スタンドアロン型が妥当となる条件の全一覧については、../datasource-creator/references/datasources.md → デフォルトで所有型を参照してください。
**誤ったコンポーネントタイプの確認。**要件が単一エンティティの表示/編集である場合は、代わりに editor-creator を実行して終了します。outParams を返すダイアログなど、一時的な入力収集が必要な場合は form-creator を実行して終了します。ドロップダウン/オートコンプリートフィールドの場合は、selector-creator を実行して終了します。グリッドは複数レコードを表形式で一覧表示するためのものであり、他の3種類は代替として互換性があるわけではありません。
フェーズ 3:グリッド本体の作成
references/grids.md → 最小限の有効なスケルトンのスケルトンを基に body.json を作成します。主なポイントは次のとおりです。
-
ファイルの基本事項。
configurationTypeId: 3。referenceNameは_gridで終わります(例:task_statuses_grid-grid.json→task_statuses_grid)。ファイルのサフィックスは-grid.jsonです。さらに、共通のチェック項目も適用されます(../datex-studio-conventions/universal-checklist.md)。references/grids.md → ファイル構造の概要 と ../datex-studio-conventions/naming-conventions.md を参照してください。 -
ベースエンティティの形状を設定する5か所のルール。 グリッドに埋め込まれたフローデータソースでは、ベース行エンティティを独立した 5か所 に設定します。
datasources[0].queryOptionsObjectTypeDef、datasources[0].outParams[result].objectTypeDef、datasources[0].getListFlow.outParams[result].objectTypeDef、datasources[0].getByKeysFlow.outParams[result].objectTypeDef、およびdatasourceConfig.configOutParameters[result].objectTypeDefです。さらに、新しいフィールドに値を設定するgetListFlow/getByKeysFlow内のcode文字列も対象です。リンクフィールドやカスタムフィールドでは、派生フィールドをベースエンティティに追加せず、確定済みの出力コントラクトに従ってください。ベースエンティティの形状を編集した後は、ファイル全体で変更していない隣接フィールドの ID を grep してください。新しいフィールドは、それぞれの箇所に対応する出現箇所が必要です。OData バックエンドのグリッドではルールが変わります。 3番目と4番目の箇所はnullとなり、実行時のみ使用される6番目の箇所、つまりdatasources[0].queryOptions.selects(ネストされたフィールドでは適切なexpands[].queryOptions.selects)が重要になります。selectsがないと、型メタデータの各箇所が正しくても、実行時にエンティティが未定義になります。references/grids.md → データソースの配線 — 5か所を同期させる を参照してください。 -
動的フィルターと並べ替え — 4か所と列の配線。 フィルターや並べ替えに対応するフィールドを追加するには、次の作業が必要です。(a)上記の5か所すべてのエンティティ形状にフィールドを追加すること。(b)フィールドを
datasources[0].dynamicFilters/dynamicOrderBys(埋め込みデータソース側)とdatasourceConfig.dynamicFilters/dynamicOrderBys(コンシューマー側)の両方に同一の内容で登録すること。内容にずれがあると、インポート時にOutdated contract. Type mismatch for dynamic filtering/sortingが表示されます。(c)列ごとにdynamicFilter(ドット区切りパス)、dynamicOrderBy、dynamicFilterType(inParam 形式のリーフ型)、dynamicFilterControl(textBox/numberBox/dateBox)を設定すること。(d)いずれのinParamsリストにも$filter/$orderbyを絶対に宣言せず、datasourceConfig.configParametersにも追加しないこと。プラットフォームが登録内容から型付きの値を自動で挿入します。手動で宣言すると衝突します。references/grids.md → 動的フィルターと並べ替え を参照してください。 -
動的フィルター/並べ替えの適用は、すべて適用するか、まったく適用しないかのどちらかです。 フロー型のバックエンドでは、プラットフォームが
$filter/$orderbyを行セットに自動適用することはありません。フィルター/並べ替えの UI を登録しても、getListFlowのコードで入力値を適用しない場合、UI コントロールを操作しても何も起こりません。これが不具合の状態です。許容される最終状態は2つです。(A)完全に配線する — 登録と列ごとの配線を行い、getListFlow内で($flow.inParams as any).$filterと($flow.inParams as any).$orderbyを使ってフィルター/並べ替えを実行します。標準のapplyDynamicFilter/applyDynamicOrderByヘルパーはフラットなスカラーのパスに対応します。コレクションのフィルターには、collection-filter-authoring で説明されている評価処理が必要です。または(B)完全に無効化する — どちら側にもdynamicFilters/dynamicOrderBysを登録せず、列ごとの配線も行いません。OData 型のバックエンドでは、プラットフォームが登録内容を OData URL に宣言的に変換するため、状態 A が既定です。標準ヘルパーについては、references/grids.md → 適用はすべて適用するか、まったく適用しないか と 既定のインメモリ $filter / $orderby 適用 を参照してください。 -
配列フィールドに関する注意点。 プリミティブ型の配列をスカラーのフィルター/ソートの直接の対象にはできません。オブジェクトコレクションを経由して参照するスカラーのリーフには、代わりに collection-filter-authoring を使用してください。ソートは引き続きスカラーのみを対象とします。結合した配列表示をフィルタリングするには、隣にスカラーのサイドカーフィールドを追加します(例:
accounts_display=accounts.join(', '))。列では配列インデックスを使用した表示($row.entity.accounts[0])を維持し、dynamicFilterはサイドカーを対象にします。サイドカーはエンティティ形状の5つすべての箇所に記載し、フローコードで値を設定する必要があります。references/grids.md → 配列フィールドに関する注意点 — スカラーサイドカーパターンを参照してください。 -
ツールバー項目はポリモーフィックです。 各
topToolbar/toolbarエントリーのtypeによって、プラットフォームが読み取る兄弟の<type>Configブロックが決まります。たとえば、button→buttonConfig、selectBox→selectBoxConfigなどです。それ以外の兄弟設定ブロックはすべて、明示的にnullのままにします。セパレーター項目では、すべての設定をnullにします。クリックハンドラーはタイプ固有の設定ブロック内(buttonConfig.clickFlowConfig.flowId)に配置し、エントリーのトップレベルには配置しません。すべてのツールバーボタンが従うべき規約は3つあります。(a)破壊的な操作にはbuttonDefaultStyleClass: "destructive"を指定します。(b)選択状態に応じて有効化するボタンは、buttonConfigのreadOnly: trueで初期化します(最初のon_select_rowイベントより前に無効状態で表示されるようにするため)。また、on_select_rowで状態を切り替えます。(c)有用なツールチップがないボタンでは、tooltip: "''"(TS の空文字列リテラル)を設定して、プラットフォームによる表示ラベルへのフォールバックを抑止します。動的なツールチップは、宣言済みの$grid.vars.<name>を経由します。フローコードから.tooltipに直接代入しても何も起こりません。references/grids.md → ツールバー項目を参照してください。 -
セカンダリ(エンリッチメント)データソース。 グリッドの
datasources[]配列には、プライマリ以外の追加データソースを含めることができます。一般的な用途は、プライマリエンティティにないフィールド(UDF、外部システムのフィールド、外部キーの表示用解決値など)で各行を拡張することです。$grid.rowsの読み込み後にon_data_loadedから呼び出し、Id in ${ids}でクエリをまとめて実行し、結果を命令型セル APIで書き込みます。セカンダリデータソースにはdynamicFilters/dynamicOrderBysは含めません。これらはプライマリのフィルター UI のみに適用されます。セカンダリデータソースも、それぞれのエンティティ形状について5箇所ルールに従います。テーラリングされたグリッドではこのパターンを多用します。../tailoring-overlay/references/tailoring.mdを参照してください。 -
命令型セル API。 行フローとグリッドフローでは、個々のセルを変更できます。
$row.cells.<col>.displayControl.text = "..."(読み取りモードのテキスト)、$row.cells.<col>.displayControl.value = ...(checkBox / selectBox などの読み取りモード)、$row.cells.<col>.editControl.value = ...(編集モード)、およびプラットフォームが管理する$row.cells.<col>.editControl.isChangedのブール値を使用します。2つのイディオムがあります。on_data_loadedでの読み込み後のエンリッチメントでは、値を命令型で設定する列のdisplayControl.<cfg>.value文字列は空のままにします。エンティティに実際にそのフィールドがない限り、$row.entity.<field>に「修正」しないでください。on_save_existing_rowでの変更有無を確認した書き込みでは、最小限の PATCH ペイロードを作成するため、if ($row.cells.<col>.editControl.isChanged) { payload.<X> = $row.cells.<col>.editControl.value; }を使用します。references/grids.md → 命令型セル APIと空の宣言型バインディングも有効ですを参照してください。 -
テキスト表示のバインドでは、文字列以外のエンティティフィールドをバインド箇所で文字列に変換します。
displayControl.textConfig.valueの型はstringです。<Id>がEdm.Int32/boolean/date の場合に"$row.entity.<Id>"をバインドすると、Type '<number|boolean|...>' is not assignable to type 'string'というエラーが発生し、インポートに失敗します。変換はエンティティスキーマではなく、バインド箇所で行ってください("$row.entity.Id?.toString()"、"`${$row.entity.Id}`"、"$row.entity.Active ? 'Yes' : 'No'"、"$utils.date.format($row.entity.CreatedSysDateTime, 'MM/DD/YYYY')")。エンティティで宣言されたtypeは動的なフィルター/ソート演算子の選択に使用されます。references/grids.md → Text Display Bindings Need String Values を参照してください。 -
埋め込みデータソースのコンポーネント識別情報エンベロープ。 埋め込みの
datasources[]エントリーは単なるクエリ仕様ではなく、独立した-datasource.jsonが持つものと同じ識別情報フィールドを備えた、完全なデータソースコンポーネントです。datasources[0].referenceNameはdatasourceConfig.configId(検索キー)と完全に一致している必要があります。また、このエントリーにはtitle、100 文字以下の空でないdescription、ページネーション付き/コレクション型データソースの場合はhasKey: true、hasResult: true、新規作成時はid: null、未使用の場合は null のlinkedDatasources/customColumns、宣言済みのinParams/outParams/vars/events、およびaccessModifier: "private"が必要です。このエンベロープがない場合、Invalid contract. Referenced own configuration <name> does not exist or has been renamedが報告され、さらにCannot find name 'get' / 'getList' / 'inParams' / 'refresh'という TypeScript エラーにつながります(これらはすべて、1 つの参照を解決できないことによる派生エラーです)。references/grids.md → Embedded Datasource Component-Identity Envelope を参照してください。 -
fullTextSearchと内部のconfigParametersの契約。fullTextSearchは null 非許容の boolean です。trueにすると組み込みの検索ボックスが表示されます。その値がデータソースに$flow.inParams.full_text_searchとして渡されるのは、valueが"$grid.fullTextSearch"のdatasourceConfig.configParametersエントリーを使って接続した場合に限られます。自動接続はありません。埋め込みデータソースで宣言されたその他の inParam にも同じルールが適用されます。宣言済みの inParam に対応するconfigParametersエントリーがない場合、実行時にはバインドされず、それに依存するフィルターは一切実行されません。また、インポート時にグリッドとその埋め込みデータソースの間の契約不一致が報告されます。references/grids.md → datasourceConfig.configParameters — Feeding Inputs to the Datasource を参照してください。 -
$grid.vars/$row.varsの宣言。 フローコード内に記述するすべての$grid.vars.<id>はトップレベルのvars[]配列で宣言する必要があり、すべての$row.vars.<id>はrowVars[]で宣言する必要があります。プロパティ記述子の形式はinParams/outParamsと同じです。宣言がない場合、インポート時にProperty 'vars' does not exist on type 'IGrid'(またはIRow)というエラーが発生します。 -
兄弟の
*Configキーには明示的に null を指定します。 すべてのdisplayControl、editControl、ツールバーエントリー、フィルターエントリーでは、有効なサブ設定のみを入力し、それ以外は明示的にnullのままにします。構造差分の検出でもこの規約に従ってください。既存のグリッドコンポーネントでは、兄弟スロットがすべて存在し、null に設定されています。 -
呼び出し階層の規約。 グリッドコードでは、関数を
$flows.<Package>.<fn>経由で呼び出します。関数内では CRUD アクションの呼び出しを$apis.<Package>.FootprintApi.extendedActions.<action_name>({...})でラップします。Utilities の組み込みcrud_create_entity/crud_update_entity/crud_delete_entityが、一般的な永続化の方法です。グリッドコードからアクションを直接呼び出さないでください。../datex-studio-runtime/calling-conventions.md を参照してください。 -
ハブからのマウント。 ハブでは、グリッドは
tabs[].contentConfig内に埋め込まれます(contentType: "grid"の場合)。マウントには独自のconfigIdとmoduleIdが含まれます。moduleIdはホスティングするハブの機能フォルダーではなく、グリッドのパッケージです。マウントのconfigParametersはグリッド独自のinParamsに渡されます(グリッドが宣言するすべての inParam に、ホスト側でエントリーが必要です)。configEventsはグリッドが発行するイベントをサブスクライブします。component-wiring-checkを呼び出して、両側の参照コントラクト(外側のホスト → グリッドのコントラクトと、内側のグリッド → 埋め込みデータソースのコントラクト)を監査してください。../component-wiring-check/references/component-wiring.md と references/grids.md → ハブからのグリッドのマウントを参照してください。
フェーズ 4:検証してプッシュする
# Validate the body locally against the branch. Exit 1 = validation found errors
# (read validation_errors, fix body.json, re-run) — not a broken CLI. Do not push on exit 1.
dxs configuration validate grid -b <branchId> -D body.json
# For a new grid
dxs configuration upsert grid -b <branchId> -D body.json
# For modify-existing (round-trip — never skip the jq extract)
dxs configuration get grid <configId> -b <branchId> -O envelope.json
jq .json envelope.json > body.json
# ... edit body.json ...
dxs configuration upsert grid -b <branchId> -D body.json
検証では、必須フィールドの欠落、パラメーター記述子の不正な形式、未定義のフロー ID 参照、参照エラーがプッシュ前に検出されます。五箇所間の不整合、OData の selects の不足、datasources[0] と datasourceConfig 間の動的フィルター登録ミラーの不整合、lookupcode/id の同期漏れ、動的フィルター/ソートの未配線(状態 C)、ラップされていない TypeScript 式スロット、型変換が必要なテキスト表示バインディングは検出されません。これらは構造上または動作上の問題であり、アップロード時の検証または実行時にのみ表面化します。プッシュ前に以下のプリフライトチェックリストを確認し、必ず grid-validator を呼び出してください(フェーズ 5)。
フェーズ 5:grid-validator で検証する(必須)
グリッドに対するあらゆる編集(新規作成、エンティティ形状の変更、フィルター/ソート登録の変更、ツールバーの変更、セカンダリデータソースの変更、さらにはラベルの微調整も含む)の後には、対象のグリッドに対して grid-validator サブエージェントを必ず呼び出す必要があります。グリッドには、他のどのコンポーネントよりも多くの、気付きにくい失敗の落とし穴(五箇所ルール、二箇所の登録ミラー、OData の selects という第六の箇所、lookupcode/id の同期漏れ、フィルター/ソートが未配線のバグ状態)があり、汎用の component-validator はこれらを把握していません。
グリッドのファイルパスまたは configId を指定して、grid-validator サブエージェントに委任してください。サブエージェントは完全なプリフライトチェックリストを再実行し、見落とした可能性のある不整合(特に五箇所間の不整合)にフラグを立て、書き換えではなく修正項目のリストを返します。グリッドの作業完了を宣言する前に、ブロッカーは必ず修正してください。このステップを省略すると、同期漏れによるエラーがアップロード時の検証に到達します。
アプリが実行中で利用可能な場合は、通常のマウント経路(グリッドをホストするハブタブ)からグリッドも開き、次の点を確認してください。バックエンドのデータソースから行が読み込まれること、列が表示されること(命令型に追加された値が想定される箇所に空の列がないこと)、フィルター/ソートコントロールが行セットに適用されること(状態 C ではなく状態 A であること)、選択に応じて有効化されるボタンがツールバーに最初は無効状態でマウントされ、最初の選択時に有効になること、そして $grid.events.outParamsChange.emit() がホストに伝播することです。
アプリが実行中でない場合は、修正済みの jq .json 抽出パターンを使って設定を再取得し、body.json と差分を取り、プッシュが反映されたことを確認してください。
プリフライトチェックリスト
プッシュ前に、このプリフライトチェックリストを確認してください(グリッド固有の詳細なゲートとして grid-validator も呼び出してください)。簡易版は次のとおりです。
- ファイル名、拡張子、
referenceNameが一致していること。descriptionは空でなく、100 文字以下にします。accessModifierを設定します。 - グリッド固有のデータソースは単独ではなく、グリッドに組み込みます。 ブランチ上に単独で
<grid-specific-name>-datasource設定がある場合は問題の兆候です。グリッド内の所有エントリに移すか、別のコンポーネントが実際に使用していることを確認します。 - 組み込みデータソースには、コンポーネント ID の完全な一式を含めます。
referenceNameはdatasourceConfig.configIdと一致させます。title、description、hasKey: true、hasResult: true、新規作成時はid: null、linkedDatasources/customColumns(未使用の場合は null)、宣言済みのinParams/outParams/vars/events、accessModifier: "private"を含めます。 - テキスト表示のバインディングでは、文字列以外のエンティティフィールドをバインド箇所で型変換します。
Edm.Int32は?.toString()、booleanは三項演算子、Dateは$utils.date.format(...)を使います。表示用バインディングに合わせるために、エンティティスキーマで宣言されたtypeを変更してはいけません。 - 基本エンティティ形状の定義箇所を同期させます。 返された行から使用するフィールドについては、隣接フィールドの ID を grep し、新しいフィールドの出現回数が一致することを確認します。OData ベースのグリッドでは、
queryOptions.selectsにフィールドが含まれていることを確認します(箇所 3 と 4 はnullです)。ネストされたフィールドはexpands[].queryOptions.selectsに含めます。フィルター専用として明示された OData ナビゲーションは、展開されず出力にも含まれない場合があります。そのネストされたフィルターツリーは、メタデータを解決したうえで登録します。 - 動的なフィルター/ソートの配線: フィールドを両方の登録箇所(
datasources[0].dynamicFiltersとdatasourceConfig.dynamicFilters)に含めます。有効なフィルターには、列ごとにプレーンパスのdynamicFilter/dynamicFilterType/dynamicFilterControlを設定し、サポート対象のスカラーソートにのみdynamicOrderByを設定します。いずれのinParamsまたはconfigParametersにも$filter/$orderbyを含めてはいけません。 - 動的なフィルター/ソートの適用は、すべて有効にするか、すべて無効にします。 フロータイプのバックエンドでは、完全に配線する(登録 + 列ごとの設定 +
getListFlowでの適用)か、完全に無効にする(登録と列ごとの配線を削除する)必要があります。UI コントロールは登録されているものの、フローコードで適用されていない状態 C がバグです。 - プリミティブ配列では、結合表示のフィルター/ソートにスカラーのサイドカーを使用します。 オブジェクトコレクションのスカラーリーフには、量化子を考慮した実行を含め、collection-filter-authoring を使用します。ソートは引き続きスカラーのみです。
- ツールバーのクリックハンドラーは、エントリのトップレベルではなく、型固有の設定ブロック内に置きます。 兄弟の設定ブロックは明示的に
nullにします。セパレーターエントリでは、すべての設定をnullにします。 - 破壊的操作を行うボタンには
buttonDefaultStyleClass: "destructive"を設定します。ツールチップのないボタンにはtooltip: "''"(空の TS リテラル)を設定し、プラットフォームがラベルを代わりに表示しないようにします。 動的なツールチップは、宣言済みの$grid.vars.<name>にバインドします。 フローコードから.tooltipに直接代入しても何も起きません。 - 選択に依存するボタンでは、
on_select_rowでツールバーのreadOnlyを切り替えます(動的な切り替え)。 また、最初の選択イベントが発生する前に無効状態でマウントされるよう、これらのボタンはbuttonConfigに静的なreadOnly: trueも設定します。 - 命令的に値が設定されるセルでは、
displayControl.<cfg>.valueを空にします。 エンティティに実際にそのフィールドがない限り、$row.entity.<field>に「修正」してはいけません。 - フローコードで書き込むすべての
$grid.vars.<id>と$row.vars.<id>を、グリッドのトップレベルにあるvars[]/rowVars[]配列で宣言します。 - 外側のホストとの契約。 グリッドが宣言するすべての inParam に、ホストの
configParameters内のエントリを用意します。グリッドが宣言していないパラメーターのエントリは追加しません。ホストの参照にあるmoduleIdは、ホストではなくグリッドのパッケージを指定します。 - 内側のデータソースとの契約。 グリッド自身の
datasourceConfig.configParametersで、組み込みデータソースに宣言されたすべての inParam を網羅します。fullTextSearch: trueの場合のfull_text_searchも対象です(自動配線されないため、value: "$grid.fullTextSearch"を含むエントリを明示的に追加する必要があります)。 $grid.outParams.*への書き込み後、ホストが購読するものについては$grid.events.outParamsChange.emit()を呼び出します。- 呼び出し階層の遵守: グリッドコードでは
$flows.<Package>.<fn>を介して関数を呼び出します。関数では$apis.<Package>.FootprintApi.extendedActions.<action_name>({...})を介して CRUD アクションをラップします。グリッドからアクションを直接呼び出してはいけません。 grid-validatorを実行します。 必須です。以下の詳細を参照してください。
Common Mistakes
| 間違い | 修正 |
|---|---|
_lookupcode 列を追加したものの、5つのエンティティ形状の箇所に _id の対応項目を追加し忘れる | ストレージ列は通常、owner_id(数値)と owner_lookupcode(文字列)のペアです。表示列があるのが lookupcode だけでも、数値 ID は5つすべての箇所に含める必要があります。そうしないと、ID の有無について configOutParameters[result].objectTypeDef と outParams[result].objectTypeDef が食い違います。表示列がある項目だけでなく、新しいストレージ項目はすべて5つの箇所に追加してください。 |
| 5つあるエンティティ形状の箇所のうち、3つだけを修正する | getListFlow.outParams[result].objectTypeDef と getByKeysFlow.outParams[result].objectTypeDef は、無関係に見えるフロー定義の本体にネストされているため、見落としがちです。これらは無関係ではありません。フローが返す内容を宣言しており、データソース自身の outParams はここから取得します。 |
OData を使用するグリッドで、queryOptionsObjectTypeDef と configOutParameters にはフィールドを追加したものの、queryOptions.selects には追加していない | 型メタデータはフィールドを宣言しますが、実際に取得するのは selects です。6つ目の箇所を追加し忘れると、実行時にエンティティが未定義になります。グリッドのインポートは正常に完了し、空の列が表示されますが、バインディング式が未定義の値を参照すると、最初の行の描画時にエラーが発生する可能性があります。ネストされたフィールドは expands[].queryOptions.selects に追加してください。 |
動的フィルター UI を登録したものの、getListFlow で $filter/$orderby を適用していない(状態 C) | applyDynamicFilter/applyDynamicOrderBy を ($flow.inParams as any).$filter/$orderby に対して適用して完全に接続するか、登録と列ごとの設定を削除して完全に無効化してください。何もしない UI コントロールを中途半端に接続した状態が問題です。 |
datasources[0].dynamicFilters と datasourceConfig.dynamicFilters の不一致 | インポートエラー:Datasource <id>: Outdated contract. Type mismatch for dynamic filtering/sorting。登録箇所は両方とも同一でなければなりません。同じ編集で両方を更新してください。 |
$filter/$orderby を getListFlow.inParams または datasourceConfig.configParameters で宣言する | プラットフォームは登録内容から型付きの項目を自動で注入します。手動で宣言すると衝突します。宣言を削除し、適用箇所では ($flow.inParams as any).$filter のようにキャストしてください。 |
| スカラーのフィルター/ソートでプリミティブ配列を直接対象にする | 結合表示の照合にはスカラーのサイドカーを使用してください。オブジェクトコレクションのスカラーリーフには collection-filter-authoring を使用してください。数量化フィルタリングを有効にしても、コレクションのソートは有効になりません。 |
ツールバー項目の clickFlowConfig を項目の最上位に配置する | クリックハンドラーは、型固有の設定ブロック内(buttonConfig.clickFlowConfig.flowId)に配置します。最上位に配置しても、何も起こらず無視されます。 |
Id が Edm.Int32 の場合に、displayControl.textConfig.value: "$row.entity.Id" とする | インポートエラー:Type 'number' is not assignable to type 'string'。バインド箇所で型を変換してください("$row.entity.Id?.toString()")。動的フィルター/ソートの演算子選択が壊れるため、エンティティで宣言されている type を string に変更しないでください。 |
命令的に値を設定する列を、$row.entity.<field> に変更して「修正」する | この修正は、描画のたびに命令的な値の設定を上書きします。on_data_loaded による拡張処理で値を設定するセルでは、displayControl.<cfg>.value の文字列が空でも問題ありません。 |
| 選択状態に依存するツールバーボタンが有効な状態でマウントされ、行を選択する前にクリックできる | on_row_selected フローが実行されるのは、選択状態が変化した後だけです。buttonConfig に静的に readOnly: true を設定し、on_select_row で動的にも無効化してください。念には念を入れた対策です。 |
埋め込み先の datasources[0].referenceName が datasourceConfig.configId と一致しない | インポートエラー:Invalid contract. Referenced own configuration <name> does not exist or has been renamed。続いて Cannot find name 'get' / 'getList' / 'inParams' / 'refresh' という TS エラーが連鎖して発生します。識別情報の設定を修正すれば、一連のエラーはすべて解消されます。 |
fullTextSearch: true を設定し、データソースで full_text_search inParam を宣言したものの、グリッドに configParameters の項目がない | 検索ボックスは表示されますが、値はデータソースに渡されません。datasourceConfig.configParameters に { parameter: { id: "full_text_search", ... }, value: "$grid.fullTextSearch" } を追加してください。 |
vars: null/rowVars: null の状態で、フローコード内から $grid.vars.<id> = ... または $row.vars.<id> = ... を設定する | インポートエラー:Property 'vars' does not exist on type 'IGrid'/IRow。すべての var/rowVar を、inParams/outParams と同じプロパティ記述子の形で、最上位の配列に宣言してください。 |
フローコードで $grid.topToolbar.<id>.buttonConfig.tooltip(または列/フィルターの .tooltip)に代入しても、ツールチップが変わらない | .tooltip は宣言時のみ設定できます。$grid.vars.<name>(文字列)を宣言し、そのスロットを "$grid.vars.<name>" にバインドして、フローコードで var に値を設定してください。 |
Hub マウントの moduleId に、グリッドのパッケージではなく Hub の機能フォルダーを設定する | コンポーネント間参照のルールでは、moduleId は常に参照先のモジュールです。グリッドは登録されている場所にあります。../component-wiring-check/references/component-wiring.md を参照してください。 |
同階層の *Config スロットを削除する(例:列の displayControl で textConfig だけを設定し、ほかのサブ設定を省く) | 既存のグリッドでは、構造差分を確認できるよう、同階層のスロットをすべて残し、null に設定します。この慣例に従ってください。 |
rowSizingType/columnSizingType に、メンバーに存在しないリテラル("fill"、"Fill")を設定する | エラー:Error converting value '...' to type 'System.Nullable\1[...EGridColumnSizingType]'。メンバーはキャメルケースです。rowSizingTypeには"default"、"relaxed"、"compact"、columnSizingTypeには"cellsWidth"、"headersWidth"、"fixedWidth"、"fitedWidth"`(この綴りに注意)を指定してください。 |
fullTextSearch に null または { enabled: true } を設定する | サーバーは System.Boolean の値のみを想定しています。どちらの形式もインポートに失敗します。true または false を使用してください。 |
dxs configuration get -O envelope.json の出力を、そのまま dxs configuration upsert -D envelope.json に渡す | 設定内容が何も起こらず破壊されます。編集前に必ず jq .json envelope.json > body.json を実行してください。「往復ルール」を参照してください。 |
description が100文字を超える | SQL 列の上限により、プッシュ時の検証に失敗します。簡潔にしてください。 |
referenceName が _grid で終わっていない、またはファイル名のベース名と一致しない | インポートまたは検索に失敗します。snake_case にし、_grid のサフィックスを付け、ファイル名のベース名と一致させてください。 |
grid-validator を実行せずにグリッドの編集をプッシュする | 汎用の component-validator では、5つの箇所の不一致、OData の selects の不足、動的フィルター登録のミラー間の不一致、lookupcode/id の同期漏れを検出できません。必ず grid-validator を実行してください。これは必須です。 |
編集後にgrid-validatorを実行してください(必須です。グリッドには、汎用バリデーターでは検出できないエンベロープやテキスト表示に関する注意点があります)。説明文/JSON/スキーマの整合性を確認するため、post-edit-verificationも実行してください。 |