@cosmicdrift/kumiko-types 0.383.1 → 0.385.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/config.d.ts +2 -2
- package/dist/fields.d.ts +17 -1
- package/dist/screen-action-form.d.ts +302 -0
- package/dist/screen-action-form.js +1 -0
- package/dist/screen-custom-config.d.ts +122 -0
- package/dist/screen-custom-config.js +1 -0
- package/dist/screen-dashboard.d.ts +348 -0
- package/dist/screen-dashboard.js +10 -0
- package/dist/screen-entity-edit.d.ts +493 -0
- package/dist/screen-entity-edit.js +8 -0
- package/dist/screen-entity-list.d.ts +427 -0
- package/dist/screen-entity-list.js +1 -0
- package/dist/screen-projection.d.ts +217 -0
- package/dist/screen-projection.js +1 -0
- package/dist/screen.d.ts +27 -1885
- package/dist/screen.js +2 -18
- package/dist/where-clause-types.d.ts +3 -0
- package/package.json +1 -1
- package/src/changes.json +6 -0
package/dist/config.d.ts
CHANGED
|
@@ -2,7 +2,7 @@ import type { ZodType } from "zod";
|
|
|
2
2
|
import type { ConcurrencyMode } from "./concurrency-mode.ts";
|
|
3
3
|
import type { ConfigScope } from "./config-scope.ts";
|
|
4
4
|
import type { DbConnection } from "./db-connection.ts";
|
|
5
|
-
import type {
|
|
5
|
+
import type { EntityFieldDefinition, OptionsQueryPayload } from "./fields.ts";
|
|
6
6
|
import type { EscapeHatchDeclaration, JobContext, JobDeferral } from "./handlers.ts";
|
|
7
7
|
import type { PostDeleteHookFn, PostSaveHookFn, PreDeleteHookFn, PreQueryHookFn, PreSaveHookFn } from "./hooks.ts";
|
|
8
8
|
import type { TenantId } from "./identifiers.ts";
|
|
@@ -289,7 +289,7 @@ export type UiExtensionDef = {
|
|
|
289
289
|
};
|
|
290
290
|
export type RegistrarExtensionDef = {
|
|
291
291
|
readonly onRegister?: (entityName: string, options?: Record<string, unknown>) => void;
|
|
292
|
-
readonly extendSchema?: (entityName: string) => Record<string,
|
|
292
|
+
readonly extendSchema?: (entityName: string) => Record<string, EntityFieldDefinition>;
|
|
293
293
|
readonly hooks?: RegistrarExtensionHooks;
|
|
294
294
|
readonly extendSearch?: (entityName: string) => Record<string, unknown>;
|
|
295
295
|
readonly uiExtension?: UiExtensionDef;
|
package/dist/fields.d.ts
CHANGED
|
@@ -739,7 +739,23 @@ export type EntityIndexDef = {
|
|
|
739
739
|
*/
|
|
740
740
|
readonly where?: unknown;
|
|
741
741
|
};
|
|
742
|
-
export type
|
|
742
|
+
export type ResolvedPiiStance = {
|
|
743
|
+
readonly pii: true;
|
|
744
|
+
} | {
|
|
745
|
+
readonly userOwned: NonNullable<ResolvedPiiFlags["userOwned"]>;
|
|
746
|
+
} | {
|
|
747
|
+
readonly tenantOwned: true;
|
|
748
|
+
} | {
|
|
749
|
+
readonly recordOwned: true;
|
|
750
|
+
} | {
|
|
751
|
+
readonly allowPlaintext: string;
|
|
752
|
+
} | {
|
|
753
|
+
readonly subjectRef: true;
|
|
754
|
+
};
|
|
755
|
+
export type EntityTextFieldDef = TextFieldDef & ResolvedPiiStance;
|
|
756
|
+
export type EntityLongTextFieldDef = LongTextFieldDef & ResolvedPiiStance;
|
|
757
|
+
export type EntityFieldDefinition = Exclude<FieldDefinition, TextFieldDef | LongTextFieldDef> | EntityTextFieldDef | EntityLongTextFieldDef;
|
|
758
|
+
export type FieldsMap = Readonly<Record<string, EntityFieldDefinition>>;
|
|
743
759
|
export type ParentRefDef = {
|
|
744
760
|
/** Field holding the name of the host entity this row hangs off. */
|
|
745
761
|
readonly entityTypeField: string;
|
|
@@ -0,0 +1,302 @@
|
|
|
1
|
+
import type { FormFieldDefinition } from "./fields.ts";
|
|
2
|
+
import type { AccessRule, AgentScreenHints } from "./handlers.ts";
|
|
3
|
+
import type { IconKey } from "./nav-icon.ts";
|
|
4
|
+
import type { ScreenNavSugar, ScreenSlots } from "./screen.ts";
|
|
5
|
+
import type { DashboardPanelVisibility } from "./screen-dashboard.ts";
|
|
6
|
+
import type { EditLayout } from "./screen-entity-edit.ts";
|
|
7
|
+
/** A form field computed from other fields of the same form. `listSum` adds one
|
|
8
|
+
* numeric cell over all rows of an embedded list field; its `whenEmpty`
|
|
9
|
+
* fallback applies while the list has no rows (it must not be a `listSum`). */
|
|
10
|
+
export type FormFieldDerivation = {
|
|
11
|
+
readonly op: "sum" | "subtract" | "multiply" | "percent";
|
|
12
|
+
readonly from: readonly string[];
|
|
13
|
+
} | {
|
|
14
|
+
readonly op: "listSum";
|
|
15
|
+
readonly list: string;
|
|
16
|
+
readonly cell: string;
|
|
17
|
+
readonly whenEmpty?: FormFieldDerivationWithoutList;
|
|
18
|
+
};
|
|
19
|
+
export type FormFieldDerivationWithoutList = Extract<FormFieldDerivation, {
|
|
20
|
+
from: unknown;
|
|
21
|
+
}>;
|
|
22
|
+
export type ActionFormScreenDefinition = {
|
|
23
|
+
readonly id: string;
|
|
24
|
+
readonly type: "actionForm";
|
|
25
|
+
/** Default true: the screen fills the shell content height, its body scrolls
|
|
26
|
+
* inside and the pager / action bar stays pinned. `false` restores page
|
|
27
|
+
* scroll (table grows with its rows, pager below the last row, form footer
|
|
28
|
+
* in the flow). */
|
|
29
|
+
readonly fillHeight?: boolean;
|
|
30
|
+
readonly nav?: ScreenNavSugar;
|
|
31
|
+
readonly detailFor?: string;
|
|
32
|
+
readonly description?: string;
|
|
33
|
+
readonly agent?: AgentScreenHints;
|
|
34
|
+
/** Screen has no nav entry by design (opened via link or navved by the
|
|
35
|
+
* app); exempts it from the nav-area boot check. */
|
|
36
|
+
readonly dormant?: boolean;
|
|
37
|
+
/** UI-only gate, also on direct URL access; handlers still enforce access. Unmet or failed renders `fallback`. */
|
|
38
|
+
readonly visibleWhen?: DashboardPanelVisibility;
|
|
39
|
+
/** Same-feature short id or cross-feature QN `<feature>:screen:<id>` shown when `visibleWhen` is unmet (default: standard notice). */
|
|
40
|
+
readonly fallback?: string;
|
|
41
|
+
/** Derived by buildAppSchema — see EntityEditScreenDefinition.urlPrefillFields. */
|
|
42
|
+
readonly urlPrefillFields?: readonly string[];
|
|
43
|
+
/** Derived by buildAppSchema from the `excludedFields` of the called `handler`; the form
|
|
44
|
+
* shows these fields read-only, not required and never in the payload. An authored value is overwritten. */
|
|
45
|
+
readonly writeExcludedFields?: readonly string[];
|
|
46
|
+
/** Submit is enabled without edits: values seeded from navigate `params` count as the
|
|
47
|
+
* user's intent. Every required field the layout hides with `visible: false` must hold a
|
|
48
|
+
* value, otherwise submit stays disabled (boot-checked against navigate `params`). */
|
|
49
|
+
readonly submitPrefilled?: boolean;
|
|
50
|
+
/** Write-handler QN called on submit. The form object lands 1:1 as the
|
|
51
|
+
* payload — the handler schema (Zod) keeps validating. */
|
|
52
|
+
readonly handler: string;
|
|
53
|
+
/** Form shape: field map by name. Uses the same FieldDefinitions as
|
|
54
|
+
* entity fields. At least one field is required (boot
|
|
55
|
+
* validator).
|
|
56
|
+
*
|
|
57
|
+
* A `money` field here must name its own currency source: this screen
|
|
58
|
+
* has no entity whose `defaultCurrency` it could inherit (fw#2839). */
|
|
59
|
+
readonly fields: Readonly<Record<string, FormFieldDefinition>>;
|
|
60
|
+
/** Fields computed from other fields, shown read-only and recomputed on every
|
|
61
|
+
* change. A `listSum` over an empty list without `whenEmpty` leaves the field
|
|
62
|
+
* a normal input, and then the client value counts. Otherwise the client value
|
|
63
|
+
* is never trusted: the handler must wrap its schema with
|
|
64
|
+
* `withFormDerivations(schema, screen)`, which the boot validator enforces.
|
|
65
|
+
* A field read only as `whenEmpty` operand is read-only while every such list has rows. */
|
|
66
|
+
readonly derive?: Readonly<Record<string, FormFieldDerivation>>;
|
|
67
|
+
/** Layout analogous to EntityEditScreen: sections with fields from the
|
|
68
|
+
* fields map above. */
|
|
69
|
+
readonly layout: EditLayout;
|
|
70
|
+
/** Per-field label i18n key override, same type/semantics as
|
|
71
|
+
* `EntityEditScreenDefinition.fieldLabels`. Falls back to the convention when absent. */
|
|
72
|
+
readonly fieldLabels?: Readonly<Record<string, string>>;
|
|
73
|
+
/** i18n key for the submit button. Default: the renderer's i18n default
|
|
74
|
+
* (typically "actions.submit"). */
|
|
75
|
+
readonly submitLabel?: string;
|
|
76
|
+
/** Extra buttons in the form footer next to the submit button. A click
|
|
77
|
+
* applies `patch` to the form values, then submits the form (same
|
|
78
|
+
* validation, same handler) — e.g. a "Mark as posted" button that sets
|
|
79
|
+
* `posted: true`. The patched field need not be rendered by the layout.
|
|
80
|
+
* Order in the array = order in the footer, before the submit button. */
|
|
81
|
+
readonly footerActions?: readonly ActionFormFooterAction[];
|
|
82
|
+
/** Context box above the fields (i18n keys). `{name}` placeholders resolve from the
|
|
83
|
+
* drawer prefill (`params` of the opening row action), formatted for display. */
|
|
84
|
+
readonly summary?: {
|
|
85
|
+
readonly title: string;
|
|
86
|
+
readonly subtitle?: string;
|
|
87
|
+
};
|
|
88
|
+
/** Visual style of the submit button. "danger" renders it red — for a form
|
|
89
|
+
* whose handler is destructive (terminate, revoke, delete), so the warning
|
|
90
|
+
* isn't lost on the way from the calling screen to this one. Default "primary". */
|
|
91
|
+
readonly submitStyle?: "primary" | "danger";
|
|
92
|
+
/** i18n key of a confirmation shown above the form after a successful submit
|
|
93
|
+
* when the screen stays put (no `redirect`, not drawer-hosted). `{field}`
|
|
94
|
+
* placeholders resolve from the submitted values; a `reference` field shows
|
|
95
|
+
* the chosen record's label (its `labelField`), not the id — so a
|
|
96
|
+
* cross-tenant admin form can name the record it just changed. */
|
|
97
|
+
readonly successMessage?: string;
|
|
98
|
+
/** Navigate to this screen ID after a successful submit: either a short
|
|
99
|
+
* ID (e.g. "item-list" — same feature, the nav-router resolves to the
|
|
100
|
+
* full path) or a fully-qualified cross-feature QN
|
|
101
|
+
* (`<feature>:screen:<id>`). If not set, the user stays on the form
|
|
102
|
+
* screen. Boot-validator checks that the target resolves to a
|
|
103
|
+
* registered screen. A cross-feature QN hard-couples this feature to
|
|
104
|
+
* the target at boot time — an app that doesn't mount the target
|
|
105
|
+
* feature fails the boot-validator; only use this form in a reusable
|
|
106
|
+
* feature when the target feature is guaranteed to be mounted
|
|
107
|
+
* alongside it.
|
|
108
|
+
*
|
|
109
|
+
* The object form additionally names the success-payload field the
|
|
110
|
+
* navigation id comes from (`ActionFormRedirect.idFrom`) — needed when
|
|
111
|
+
* the handler creates a child record but the target screen is the
|
|
112
|
+
* parent's detail screen (fw#2670). */
|
|
113
|
+
readonly redirect?: string | ActionFormRedirect;
|
|
114
|
+
/** Links shown in the success box after a successful submit while the
|
|
115
|
+
* screen stays put. Targets resolve like `redirect` (the id comes from the
|
|
116
|
+
* handler's success payload); a link without a string id is hidden.
|
|
117
|
+
* Mutually exclusive with `redirect`. */
|
|
118
|
+
readonly successLinks?: readonly ActionFormSuccessLink[];
|
|
119
|
+
/** Key figures from the handler's success payload, shown in the success box
|
|
120
|
+
* while the screen stays put (e.g. charged/skipped/failed of a batch run).
|
|
121
|
+
* Mutually exclusive with `redirect`. */
|
|
122
|
+
readonly successFacts?: readonly ActionFormSuccessFact[];
|
|
123
|
+
/** Reset the form to its initial values after a successful submit (prefill
|
|
124
|
+
* kept, typed values cleared). Only applies while the screen stays put,
|
|
125
|
+
* i.e. without `redirect`. */
|
|
126
|
+
readonly resetOnSuccess?: boolean;
|
|
127
|
+
/** Load the initial values from a query. The record id comes from the route
|
|
128
|
+
* (or the drawer row id) and is sent as `{ [idParam]: id }`; the result,
|
|
129
|
+
* picked to `fields`, becomes the initial values. Turns URL prefill off:
|
|
130
|
+
* search params never reach the form. */
|
|
131
|
+
readonly load?: ActionFormLoad;
|
|
132
|
+
/** Target of the Cancel button. Default: `redirect` (historical
|
|
133
|
+
* behavior — Cancel and the submit-redirect then land in the same
|
|
134
|
+
* place). `false` = no Cancel button; correct for single-action
|
|
135
|
+
* screens with no discardable state (e.g. "Send test mail"), where
|
|
136
|
+
* Cancel would just be a second path to the same target. Accepts the
|
|
137
|
+
* same string targets as `redirect` (short ID or cross-feature QN);
|
|
138
|
+
* boot-validator checks it. A cross-feature QN hard-couples this
|
|
139
|
+
* feature to the target at boot time — an app that doesn't mount the
|
|
140
|
+
* target feature fails the boot-validator; only use this form in a
|
|
141
|
+
* reusable feature when the target feature is guaranteed to be
|
|
142
|
+
* mounted alongside it. */
|
|
143
|
+
readonly cancelTarget?: string | false;
|
|
144
|
+
/** Parent list screen (short id) for breadcrumb + nav highlighting when
|
|
145
|
+
* this screen has no nav entry of its own. Same field/semantics as on
|
|
146
|
+
* `custom`/`projectionDetail`/`entityEdit`; an explicit value here wins
|
|
147
|
+
* over the rowAction heuristic. */
|
|
148
|
+
readonly listScreenId?: string;
|
|
149
|
+
readonly slots?: ScreenSlots;
|
|
150
|
+
readonly access?: AccessRule;
|
|
151
|
+
};
|
|
152
|
+
export type ActionFormFooterAction = {
|
|
153
|
+
/** Stable id (kebab-case), used for the test id. */
|
|
154
|
+
readonly id: string;
|
|
155
|
+
/** i18n key. */
|
|
156
|
+
readonly label: string;
|
|
157
|
+
readonly icon?: IconKey;
|
|
158
|
+
/** Button style. Default "secondary". */
|
|
159
|
+
readonly variant?: "primary" | "secondary" | "danger";
|
|
160
|
+
/** Form values set before the submit. JSON-safe literals only. */
|
|
161
|
+
readonly patch: Readonly<Record<string, string | number | boolean | null>>;
|
|
162
|
+
};
|
|
163
|
+
/** Redirect target plus the success-payload field carrying the navigation
|
|
164
|
+
* id. The write-handler reports the id of what it wrote (`data.id`); when
|
|
165
|
+
* that record is a child and the target screen shows its parent, the
|
|
166
|
+
* parent id has to be read from a different field instead of forcing the
|
|
167
|
+
* handler to misreport its own result (fw#2670). */
|
|
168
|
+
export type ActionFormRedirect = {
|
|
169
|
+
/** Same target forms as the string `redirect`: short screen ID
|
|
170
|
+
* (same-feature) or a fully-qualified cross-feature screen QN. */
|
|
171
|
+
readonly screen: string;
|
|
172
|
+
/** Flat field name in the handler's success payload, e.g. "leaseId".
|
|
173
|
+
* Only used when the target screen type carries an id (`entityEdit`,
|
|
174
|
+
* `projectionDetail`); a non-string or missing value navigates without
|
|
175
|
+
* an id, same as a payload without `id` does today. */
|
|
176
|
+
readonly idFrom: string;
|
|
177
|
+
/** Section id to open on the target `projectionDetail` with `layout.mode:
|
|
178
|
+
* "tabs"` (the `tab` search param, same as `ToolbarAction` navigate `tab`).
|
|
179
|
+
* Boot rejects other targets and unknown section ids. */
|
|
180
|
+
readonly tab?: string;
|
|
181
|
+
};
|
|
182
|
+
export type ActionFormLoad = {
|
|
183
|
+
/** Query QN that returns the record. */
|
|
184
|
+
readonly query: string;
|
|
185
|
+
/** Payload key carrying the record id (default "id"). */
|
|
186
|
+
readonly idParam?: string;
|
|
187
|
+
/** The query picks the row from the caller's tenant/session context, so the
|
|
188
|
+
* form loads without a record id and the query is called WITHOUT `idParam`
|
|
189
|
+
* (same semantics as `ProjectionDetailScreenDefinition.singleton`). Boot
|
|
190
|
+
* rejects declaring `idParam` alongside it. */
|
|
191
|
+
readonly singleton?: boolean;
|
|
192
|
+
};
|
|
193
|
+
/** One key figure of the success box, read from the handler's success payload. */
|
|
194
|
+
export type ActionFormSuccessFact = {
|
|
195
|
+
/** Flat field name in the handler's success payload. A number or string is
|
|
196
|
+
* shown as one value, an array a comma-separated list (numbers, strings and
|
|
197
|
+
* `{ label }` objects). A missing field hides the fact. */
|
|
198
|
+
readonly field: string;
|
|
199
|
+
/** Label (i18n key). */
|
|
200
|
+
readonly label: string;
|
|
201
|
+
};
|
|
202
|
+
/** A redirect target rendered as a link in the success box. */
|
|
203
|
+
export type ActionFormSuccessLink = Omit<ActionFormRedirect, "idFrom"> & {
|
|
204
|
+
/** Success-payload field carrying the navigation id. Required for a record
|
|
205
|
+
* target (`entityEdit`, `projectionDetail`); omit it for a list, dashboard
|
|
206
|
+
* or form target, which opens without an id. */
|
|
207
|
+
readonly idFrom?: string;
|
|
208
|
+
/** Link text (i18n key). */
|
|
209
|
+
readonly label: string;
|
|
210
|
+
};
|
|
211
|
+
/** Author-declared field shown once after a mint-form submit — API token,
|
|
212
|
+
* recovery codes, similar one-time secrets. */
|
|
213
|
+
export type SecretRevealField = {
|
|
214
|
+
/** Flat field name in the handler's success payload. */
|
|
215
|
+
readonly field: string;
|
|
216
|
+
/** i18n key for this value's label. */
|
|
217
|
+
readonly label: string;
|
|
218
|
+
/** "code" (default) renders one monospaced value; "list" renders a
|
|
219
|
+
* string-array payload one value per line (recovery codes); "qr" renders
|
|
220
|
+
* the value as a scannable QR code (otpauth://-style enrollment URI) —
|
|
221
|
+
* platforms without a QR-capable SecretReveal primitive fall back to the
|
|
222
|
+
* monospaced text display. */
|
|
223
|
+
readonly display?: "code" | "list" | "qr";
|
|
224
|
+
/** Default true — offer a copy-to-clipboard control next to the value. */
|
|
225
|
+
readonly copyable?: boolean;
|
|
226
|
+
};
|
|
227
|
+
/** Post-reveal proof-of-receipt step. A mint whose effect is only armed once
|
|
228
|
+
* the user proves they received the secret (TOTP enrollment: scan the code,
|
|
229
|
+
* then enter one) declares it here — the reveal card renders this form in
|
|
230
|
+
* place of the bare acknowledge button. */
|
|
231
|
+
export type SecretMintConfirmStep = {
|
|
232
|
+
/** Write-handler QN dispatched when the confirm form is submitted. */
|
|
233
|
+
readonly handler: string;
|
|
234
|
+
readonly fields: Readonly<Record<string, FormFieldDefinition>>;
|
|
235
|
+
readonly layout: EditLayout;
|
|
236
|
+
/** Mint success-payload fields merged into the confirm payload (e.g. a
|
|
237
|
+
* short-lived setup token). Held in component state only — never rendered,
|
|
238
|
+
* never in the URL, a query cache, nav or a persisted draft. */
|
|
239
|
+
readonly carry?: readonly string[];
|
|
240
|
+
readonly submitLabel?: string;
|
|
241
|
+
/** i18n key for the banner shown after a successful confirm when the screen
|
|
242
|
+
* declares no `redirect`. Default "kumiko.secretMint.done". */
|
|
243
|
+
readonly doneMessage?: string;
|
|
244
|
+
};
|
|
245
|
+
export type SecretReveal = {
|
|
246
|
+
readonly fields: readonly SecretRevealField[];
|
|
247
|
+
/** i18n key. Default "kumiko.secretMint.title". */
|
|
248
|
+
readonly title?: string;
|
|
249
|
+
/** i18n key for the "this is the only time you see it" warning.
|
|
250
|
+
* Default "kumiko.secretMint.warning". */
|
|
251
|
+
readonly warning?: string;
|
|
252
|
+
/** i18n key for the acknowledge button. Default "kumiko.secretMint.confirm". */
|
|
253
|
+
readonly confirmLabel?: string;
|
|
254
|
+
/** i18n key for a checkbox on the reveal card ("I have saved my recovery
|
|
255
|
+
* codes"). While unchecked, the confirm step's submit or the acknowledge
|
|
256
|
+
* button stays disabled. The tick is UI-only and never part of a payload. */
|
|
257
|
+
readonly acknowledge?: string;
|
|
258
|
+
};
|
|
259
|
+
/** Mint form → one-time reveal → explicit confirm. The secret (API token,
|
|
260
|
+
* recovery codes) lives only in the write-handler's own success payload —
|
|
261
|
+
* no stored value backs it, so no query can redisplay it later. That gap
|
|
262
|
+
* is why this needs its own screen type instead of a flag on `actionForm`,
|
|
263
|
+
* which discards the success payload after extracting the navigation id. */
|
|
264
|
+
export type SecretMintScreenDefinition = {
|
|
265
|
+
readonly id: string;
|
|
266
|
+
readonly type: "secretMint";
|
|
267
|
+
readonly nav?: ScreenNavSugar;
|
|
268
|
+
readonly detailFor?: string;
|
|
269
|
+
readonly description?: string;
|
|
270
|
+
readonly agent?: AgentScreenHints;
|
|
271
|
+
/** Screen has no nav entry by design (opened via link or navved by the
|
|
272
|
+
* app); exempts it from the nav-area boot check. */
|
|
273
|
+
readonly dormant?: boolean;
|
|
274
|
+
/** UI-only gate, also on direct URL access; handlers still enforce access. Unmet or failed renders `fallback`. */
|
|
275
|
+
readonly visibleWhen?: DashboardPanelVisibility;
|
|
276
|
+
/** Same-feature short id or cross-feature QN `<feature>:screen:<id>` shown when `visibleWhen` is unmet (default: standard notice). */
|
|
277
|
+
readonly fallback?: string;
|
|
278
|
+
/** Derived by buildAppSchema — see EntityEditScreenDefinition.urlPrefillFields. */
|
|
279
|
+
readonly urlPrefillFields?: readonly string[];
|
|
280
|
+
/** Submit is enabled without edits: values seeded from navigate `params` count as the
|
|
281
|
+
* user's intent. Every required field the layout hides with `visible: false` must hold a
|
|
282
|
+
* value, otherwise submit stays disabled (boot-checked against navigate `params`). */
|
|
283
|
+
readonly submitPrefilled?: boolean;
|
|
284
|
+
/** Write-handler QN dispatched on submit. */
|
|
285
|
+
readonly handler: string;
|
|
286
|
+
readonly fields: Readonly<Record<string, FormFieldDefinition>>;
|
|
287
|
+
readonly layout: EditLayout;
|
|
288
|
+
/** Navigate here after the reveal is confirmed. Short id (same-feature) or
|
|
289
|
+
* a fully-qualified cross-feature screen QN — no result-id navigation
|
|
290
|
+
* form exists here (unlike `ActionFormScreenDefinition.redirect`), since
|
|
291
|
+
* the confirmed screen carries no entity id to thread through. */
|
|
292
|
+
readonly redirect?: string;
|
|
293
|
+
readonly cancelTarget?: string | false;
|
|
294
|
+
readonly listScreenId?: string;
|
|
295
|
+
readonly access?: AccessRule;
|
|
296
|
+
readonly reveal: SecretReveal;
|
|
297
|
+
/** i18n-key for the mint button. Default: renderer's own default. */
|
|
298
|
+
readonly submitLabel?: string;
|
|
299
|
+
/** Proof-of-receipt step rendered on the reveal card in place of the bare
|
|
300
|
+
* acknowledge button — see `SecretMintConfirmStep` doc. */
|
|
301
|
+
readonly confirm?: SecretMintConfirmStep;
|
|
302
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
import type { FieldDefinition } from "./fields.ts";
|
|
2
|
+
import type { AccessRule, AgentScreenHints } from "./handlers.ts";
|
|
3
|
+
import type { PlatformComponent, ScreenNavSugar, ScreenSlots } from "./screen.ts";
|
|
4
|
+
import type { DashboardPanelVisibility } from "./screen-dashboard.ts";
|
|
5
|
+
import type { EditLayout } from "./screen-entity-edit.ts";
|
|
6
|
+
export type CustomScreenRoute = {
|
|
7
|
+
readonly path: string;
|
|
8
|
+
readonly component: PlatformComponent;
|
|
9
|
+
};
|
|
10
|
+
export type CustomScreenDefinition = {
|
|
11
|
+
readonly id: string;
|
|
12
|
+
readonly type: "custom";
|
|
13
|
+
readonly nav?: ScreenNavSugar;
|
|
14
|
+
readonly detailFor?: string;
|
|
15
|
+
readonly description?: string;
|
|
16
|
+
readonly agent?: AgentScreenHints;
|
|
17
|
+
readonly renderer: PlatformComponent;
|
|
18
|
+
readonly routes?: readonly CustomScreenRoute[];
|
|
19
|
+
/** Parent list screen for breadcrumb when this detail is not in nav. */
|
|
20
|
+
readonly listScreenId?: string;
|
|
21
|
+
readonly access?: AccessRule;
|
|
22
|
+
/** This screen is registered without a self-owned `r.nav()` entry by
|
|
23
|
+
* design — an app opts in by navving it explicitly (e.g. a settings-area
|
|
24
|
+
* self-service screen). `createKumikoApp`'s boot diagnostic
|
|
25
|
+
* (kumiko-framework#2025) skips dormant screens instead of flagging
|
|
26
|
+
* every consumer that doesn't mount the client plugin as a false
|
|
27
|
+
* positive (kumiko-framework#2034). Only set this on screens the
|
|
28
|
+
* feature itself never navs — a screen the feature DOES nav still needs
|
|
29
|
+
* its client plugin mounted by every consumer, and should keep
|
|
30
|
+
* triggering the diagnostic if it's missing. Also gates the
|
|
31
|
+
* boot-validator's nav-area check, same as `dormant` on other screens. */
|
|
32
|
+
readonly dormant?: boolean;
|
|
33
|
+
/** UI-only gate, also on direct URL access; handlers still enforce access. Unmet or failed renders `fallback`. */
|
|
34
|
+
readonly visibleWhen?: DashboardPanelVisibility;
|
|
35
|
+
/** Same-feature short id or cross-feature QN `<feature>:screen:<id>` shown when `visibleWhen` is unmet (default: standard notice). */
|
|
36
|
+
readonly fallback?: string;
|
|
37
|
+
};
|
|
38
|
+
export type ConfigEditScreenDefinition = {
|
|
39
|
+
readonly id: string;
|
|
40
|
+
readonly type: "configEdit";
|
|
41
|
+
/** Default true: the form fills the shell content height with a pinned
|
|
42
|
+
* footer. `false` restores the card layout with the footer in the flow. */
|
|
43
|
+
readonly fillHeight?: boolean;
|
|
44
|
+
readonly nav?: ScreenNavSugar;
|
|
45
|
+
readonly detailFor?: string;
|
|
46
|
+
readonly description?: string;
|
|
47
|
+
readonly agent?: AgentScreenHints;
|
|
48
|
+
/** Screen has no nav entry by design (opened via link or navved by the
|
|
49
|
+
* app); exempts it from the nav-area boot check. */
|
|
50
|
+
readonly dormant?: boolean;
|
|
51
|
+
/** UI-only gate, also on direct URL access; handlers still enforce access. Unmet or failed renders `fallback`. */
|
|
52
|
+
readonly visibleWhen?: DashboardPanelVisibility;
|
|
53
|
+
/** Same-feature short id or cross-feature QN `<feature>:screen:<id>` shown when `visibleWhen` is unmet (default: standard notice). */
|
|
54
|
+
readonly fallback?: string;
|
|
55
|
+
/** scope for config:write:set calls. Must match the scope declaration of
|
|
56
|
+
* the keys referenced in `configKeys` — the boot validator checks that
|
|
57
|
+
* against the registry. */
|
|
58
|
+
readonly scope: "tenant" | "system" | "user";
|
|
59
|
+
/** Map: form field name (short, as referenced in the layout) → fully
|
|
60
|
+
* qualified config key (`<feature>:config:<short>`). The boot validator
|
|
61
|
+
* checks that every qualified key is known in the registry. */
|
|
62
|
+
readonly configKeys: Readonly<Record<string, string>>;
|
|
63
|
+
/** Field name → qualified secret key (`<feature>:secret:<short>`), tenant scope only.
|
|
64
|
+
* Such a field is a writeOnly text field with no `configKeys` entry; the same save
|
|
65
|
+
* writes it through secrets:write:set (or secrets:write:delete on removal). */
|
|
66
|
+
readonly secretKeys?: Readonly<Record<string, string>>;
|
|
67
|
+
/** Form shape per field name. Same FieldDefinitions as on
|
|
68
|
+
* entities/ActionForm. Field names match the keys in `configKeys`
|
|
69
|
+
* — the boot validator pins that. */
|
|
70
|
+
readonly fields: Readonly<Record<string, FieldDefinition>>;
|
|
71
|
+
/** Layout: sections with field refs. Identical to entityEdit/
|
|
72
|
+
* actionForm. */
|
|
73
|
+
readonly layout: EditLayout;
|
|
74
|
+
/** Optional per-field label i18n key (field name → key). The settings
|
|
75
|
+
* hub sets the respective config key's `mask.title` here, so the label
|
|
76
|
+
* declared on the key shows up on the generated field — without
|
|
77
|
+
* duplicating it under the `__config-edit__` convention. A missing
|
|
78
|
+
* entry falls back to the convention. */
|
|
79
|
+
readonly fieldLabels?: Readonly<Record<string, string>>;
|
|
80
|
+
/** Per-field help text i18n key (Field-Name → Key), from `mask.description`. */
|
|
81
|
+
readonly fieldDescriptions?: Readonly<Record<string, string>>;
|
|
82
|
+
/** Field names whose config key declares `required: true` — drives the
|
|
83
|
+
* "Not set. Required." origin line, not form validation. */
|
|
84
|
+
readonly requiredFields?: readonly string[];
|
|
85
|
+
/** i18n key for the submit button. Default: "kumiko.actions.save". */
|
|
86
|
+
readonly submitLabel?: string;
|
|
87
|
+
readonly slots?: ScreenSlots;
|
|
88
|
+
readonly access?: AccessRule;
|
|
89
|
+
};
|
|
90
|
+
export type SecretsEditSection = {
|
|
91
|
+
readonly title?: string;
|
|
92
|
+
readonly fields: readonly string[];
|
|
93
|
+
};
|
|
94
|
+
export type SecretsEditScreenDefinition = {
|
|
95
|
+
readonly id: string;
|
|
96
|
+
readonly type: "secretsEdit";
|
|
97
|
+
readonly nav?: ScreenNavSugar;
|
|
98
|
+
readonly detailFor?: string;
|
|
99
|
+
readonly description?: string;
|
|
100
|
+
readonly agent?: AgentScreenHints;
|
|
101
|
+
/** Screen has no nav entry by design (opened via link or navved by the
|
|
102
|
+
* app); exempts it from the nav-area boot check. */
|
|
103
|
+
readonly dormant?: boolean;
|
|
104
|
+
/** UI-only gate, also on direct URL access; handlers still enforce access. Unmet or failed renders `fallback`. */
|
|
105
|
+
readonly visibleWhen?: DashboardPanelVisibility;
|
|
106
|
+
/** Same-feature short id or cross-feature QN `<feature>:screen:<id>` shown when `visibleWhen` is unmet (default: standard notice). */
|
|
107
|
+
readonly fallback?: string;
|
|
108
|
+
/** field id -> qualified secret name (`<feature>:secret:<kebab>`). */
|
|
109
|
+
readonly secretKeys: Readonly<Record<string, string>>;
|
|
110
|
+
/** field id -> i18n key for the label. */
|
|
111
|
+
readonly fieldLabels: Readonly<Record<string, string>>;
|
|
112
|
+
/** field id -> i18n key for the hint, only where the declaration carries one. */
|
|
113
|
+
readonly fieldHints?: Readonly<Record<string, string>>;
|
|
114
|
+
/** field ids whose declaration set `required: true`. */
|
|
115
|
+
readonly requiredFields?: readonly string[];
|
|
116
|
+
/** field id -> write access derived from the key's `writeRoles`. The screen
|
|
117
|
+
* hides fields the viewer fails; UI only, the secrets write gate stays
|
|
118
|
+
* authoritative. */
|
|
119
|
+
readonly fieldAccess?: Readonly<Record<string, AccessRule>>;
|
|
120
|
+
readonly sections: readonly SecretsEditSection[];
|
|
121
|
+
readonly access?: AccessRule;
|
|
122
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|