画面を1枚定義する
どの画面にも要る4つのキーと、レコードを1件に絞る key。
どの画面も、まず「どの種別か」「どのデータを扱うか」を書く。ここが決まれば、あとはその種別が持てるものを足していくだけになる。
dsl_version: "1.0"
page:
type: master # 画面の種別
id: dept_master # 画面の識別子(遷移先の指定に使う)
title: 部門マスタ # 画面に出る名前
repository: deptRepository # データの出し入れ先の名前
key: code # 1件を特定する項目repository は「名前」であって実装ではない
repository に書くのは名前だけ。その名前で実際に何をするか(HTTP を叩く、DB を見る、メモリに持つ)は自分のコードで書いて、アプリ起動時に名前と結びつける。Framework は HTTP も DB も知らない。
key を書く画面と書かない画面
key は「この1件」を決めるための項目。詳細表示・編集・削除は、これが無いとどのレコードを触るのか決まらない。
逆に、1件を触らない画面(dashboard / report)には key を書かない。集計しか出さないので特定する対象が無い。
1つの列で決まらないとき
受注明細は受注番号だけでは1件に決まらない。行番号と合わせて初めて1件を指す。明細ビュー・履歴表・年度別の実績表と、業務では普通に出てくる形。項目を並べて書く。
key: [orderNo, lineNo]並べた順に意味がある。 その順がそのまま REST の道の順になるので(/api/orderLines/SO-1/2)、並べ替えると別の1件を指してしまう。定義の並びは URL の一部だと思って扱う。
画面から画面へ渡すときは、鍵の項目を1つずつ渡す。行き先は自分の key の名前で受け取るので、名前を合わせておけば届く。1つでも欠けていたら取りに行かない ── 欠けたまま組み立てると別の1件が開くので、そろうまで画面は空のまま待つ。
Repository を書き直す必要は無い。1件を指す項目が1つの画面には、いままでどおり素の値("SO-1")が渡る。複合キーの画面だけ、項目名と値の組が渡る。
どの type を選ぶか
迷ったら、扱う対象が「一覧か1件か」「読むだけか書くか」で切る。
| やりたいこと | type |
|---|---|
| 探して一覧に出して、その場で登録・修正・削除まで | crud / master |
| 探して一覧に出すだけ(照会) | search |
| 1件を読み取り専用で見せる | detail |
| 1件を入力・編集する(一覧なし) | form |
| 長い入力を数ステップに分ける | wizard |
| 数字とグラフを並べる | dashboard |
| 印刷・PDF 向けに出す | report |
判断に迷う場合の対照表は ページ種別の選び方 にある。
書けるキー
| キー | 書く場所 | 型 | 必須 | 既定値 | 有効なページ種別 | 説明 |
|---|---|---|---|---|---|---|
type | action | string (create / edit / delete / navigate / plugin / export / print ほか) | 必須 | — | crud dashboard detail form master report search wizard | Action type (open string). Built-ins: create, edit, delete, navigate, plugin, export, print. |
type | column | string (text / number / badge / boolean / date / dateTime ほか) | 任意 | "text" | crud dashboard detail form master report search wizard | Render type (open string). Built-ins: text, number, badge, boolean, date, dateTime. |
type | crudPage | string (crud) | 必須 | — | crud | Page kind. |
type | dashboardItem | string (metric / table / chart ほか) | 任意 | "metric" | dashboard | Card kind. Open string; built-ins below. |
type | dashboardPage | string (dashboard) | 必須 | — | dashboard | Page kind. |
type | detailPage | string (detail) | 必須 | — | detail | Page kind. |
type | field | string (text / textarea / number / select / multiSelect / checkbox / radio / date / dateTime / time / subTable ほか) | 任意 | "text" | crud dashboard detail form master report search wizard | Field type (open string). Built-ins: text, textarea, number, select, multiSelect, checkbox, radio, date, dateTime, time, subTable. A subTable holds child rows — see columns / fields / source. |
type | filter | string (text / textarea / number / select / multiSelect / checkbox / radio / date / dateTime / time ほか) | 任意 | "text" | crud dashboard master report search | Input type (open string). Built-ins: text, textarea, number, select, multiSelect, checkbox, radio, date, dateTime, time. |
type | formPage | string (form) | 必須 | — | form | Page kind. |
type | masterPage | string (master) | 必須 | — | master | Page kind. |
type | reportPage | string (report) | 必須 | — | report | Page kind. |
type | searchPage | string (search) | 必須 | — | search | Page kind. |
type | validator | string (required / maxLength / minLength / pattern / min / max / email / postalCode / compare / unique ほか) | 必須 | — | crud dashboard detail form master report search wizard | Validator type (open string). Built-ins: required, maxLength, minLength, pattern, min, max, email, postalCode, compare, unique. compare is the cross-field one (it reads another field of the same record) and unique is the cross-row one (it reads every row of a subTable, so it belongs on the subTable field itself); see the node description for their parameters. |
type | wizardPage | string (wizard) | 必須 | — | wizard | Page kind. |
id | action | string | 必須 | — | crud dashboard detail form master report search wizard | — |
id | app | string | 必須 | — | すべて | — |
id | crudPage | string | 必須 | — | crud | Stable page identifier. |
id | dashboardItem | string | 必須 | — | dashboard | Card identifier. |
id | dashboardPage | string | 必須 | — | dashboard | — |
id | detailPage | string | 必須 | — | detail | — |
id | formPage | string | 必須 | — | form | — |
id | masterPage | string | 必須 | — | master | — |
id | menuItem | string | 任意 | — | すべて | Route key for a leaf (defaults to page). |
id | reportPage | string | 必須 | — | report | — |
id | searchPage | string | 必須 | — | search | — |
id | wizardPage | string | 必須 | — | wizard | — |
id | wizardStep | string | 必須 | — | wizard | Step identifier. |
title | actionPrompt | string | 任意 | — | crud dashboard detail form master report search wizard | Dialog heading. Defaults to the action's label. |
title | app | string | 必須 | — | すべて | — |
title | confirm | string | 任意 | — | crud dashboard detail form master report search wizard | Dialog heading. Omit for the renderer's default. May carry {count}. |
title | crudPage | string | 必須 | — | crud | Page title. |
title | dashboardItem | string | 必須 | — | dashboard | Card heading. |
title | dashboardPage | string | 必須 | — | dashboard | — |
title | detailPage | string | 必須 | — | detail | — |
title | formPage | string | 必須 | — | form | — |
title | masterPage | string | 必須 | — | master | — |
title | reportPage | string | 必須 | — | report | — |
title | searchPage | string | 必須 | — | search | — |
title | section | string | 任意 | — | crud detail form master | — |
title | wizardPage | string | 必須 | — | wizard | — |
title | wizardStep | string | 必須 | — | wizard | Step heading. |
repository | crudPage | string | 必須 | — | crud | Key resolving the user-provided Repository implementation. |
repository | dashboardItem | string | 任意 | — | dashboard | Repository key. Falls back to the page's. |
repository | dashboardPage | string | 任意 | — | dashboard | Default repository key for cards that omit one. |
repository | detailPage | string | 必須 | — | detail | — |
repository | formPage | string | 必須 | — | form | — |
repository | masterPage | string | 必須 | — | master | — |
repository | optionsSource | string | 必須 | — | crud dashboard detail form master report search wizard | Repository key holding the choices. |
repository | reportPage | string | 必須 | — | report | — |
repository | searchPage | string | 必須 | — | search | — |
repository | subTableSource | string | 必須 | — | crud dashboard detail form master report search wizard | Repository key for the child rows. |
repository | wizardPage | string | 必須 | — | wizard | — |
key | crudPage | object → crudPage.key / crudPage.key | 任意 | — | crud | Which field identifies one record. A list names a composite key ([orderNo, lineNo]): the parts are read in the order written, and that order is part of the REST path (<collection>/<orderNo>/<lineNo>), so reordering them addresses a different record. Default id. |
key | detailPage | object → detailPage.key / detailPage.key | 任意 | — | detail | Which field identifies one record. A list names a composite key ([orderNo, lineNo]): the parts are read in the order written, and that order is part of the REST path (<collection>/<orderNo>/<lineNo>), so reordering them addresses a different record. Default id. |
key | formPage | object → formPage.key / formPage.key | 任意 | — | form | Which field identifies one record. A list names a composite key ([orderNo, lineNo]): the parts are read in the order written, and that order is part of the REST path (<collection>/<orderNo>/<lineNo>), so reordering them addresses a different record. Default id. |
key | masterPage | object → masterPage.key / masterPage.key | 任意 | — | master | Which field identifies one record. A list names a composite key ([orderNo, lineNo]): the parts are read in the order written, and that order is part of the REST path (<collection>/<orderNo>/<lineNo>), so reordering them addresses a different record. Default id. |
key | searchPage | object → searchPage.key / searchPage.key | 任意 | — | search | Which field identifies one record. A list names a composite key ([orderNo, lineNo]): the parts are read in the order written, and that order is part of the REST path (<collection>/<orderNo>/<lineNo>), so reordering them addresses a different record. Default id. |
key | subTableSource | object → subTableSource.key / subTableSource.key | 任意 | — | crud dashboard detail form master report search wizard | Which field identifies one child row. A list names a composite key; the order is part of the REST path, as on a page. |
key | wizardPage | object → wizardPage.key / wizardPage.key | 任意 | — | wizard | Which field identifies one record. A list names a composite key ([orderNo, lineNo]): the parts are read in the order written, and that order is part of the REST path (<collection>/<orderNo>/<lineNo>), so reordering them addresses a different record. Default id. |
この表は spec/reference.json から生成している(JSON Schema が正)。手元では npx -p @hatake-fw/api hatake reference <キー名> で同じものが引ける。
近い例
例は丸ごと写して直すのが一番速い。以下は CI で検証済み(そのまま動く形)。
| ファイル | 種別 | 画面 | どういうときに使うか |
|---|---|---|---|
customer_detail.yaml | detail | 顧客詳細 | 1件の内容を読み取り専用で表示したい(一覧から開く先) |
order_lines.yaml | app | 受注明細 | 受注番号だけでは1件に決まらない表を出したい(明細・履歴・年度別の実績) |
よくある間違い
dashboard / report に key を書く
なぜ駄目か key は「1件のレコードの主キー項目名」。ダッシュボードと帳票は単一レコードを指さないので持たない。
こう直す 消す。行から1件を開きたいなら navigate アクションで detail ページへ渡す(params: { id: "$row.id" })。
page:
type: report
id: sales_report
title: 売上明細表
repository: orderRepository
key: id
table:
columns:
- { field: amount, label: 金額, type: number }page:
type: report
id: sales_report
title: 売上明細表
repository: orderRepository
table:
columns:
- { field: amount, label: 金額, type: number }spec/pitfalls.json から生成。各項目は CI で検証済み(間違いは本当に落ち、正しい方は本当に通る)。手元では npx -p @hatake-fw/api hatake pitfalls <キー名>。
実物を見る
デモアプリの「顧客マスタ」がこれを使っている。 デモを開く