@cosmicdrift/kumiko-types 0.413.1 → 0.414.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/access-predicates.d.ts +1 -0
- package/dist/access-predicates.js +3 -3
- package/dist/config.d.ts +1 -2
- package/dist/db-connection.d.ts +0 -3
- package/dist/define-handler.d.ts +1 -1
- package/dist/delivery-attempt-types.d.ts +22 -0
- package/dist/delivery-attempt-types.js +31 -0
- package/dist/entity-table-meta-types.d.ts +2 -0
- package/dist/event-store-executor-types.d.ts +4 -1
- package/dist/feature.d.ts +1 -0
- package/dist/fields.d.ts +2 -0
- package/dist/handler-context-facets.d.ts +5 -2
- package/dist/handler-context-services.d.ts +3 -1
- package/dist/handlers.d.ts +16 -15
- package/dist/handlers.js +4 -32
- package/dist/hooks.d.ts +1 -0
- package/dist/identifiers.d.ts +7 -0
- package/dist/identifiers.js +20 -0
- package/dist/minor-units.d.ts +3 -0
- package/dist/minor-units.js +11 -0
- package/dist/named-list-filters.d.ts +26 -0
- package/dist/observability/provider.d.ts +0 -2
- package/dist/screen-dashboard.d.ts +139 -22
- package/dist/screen-entity-edit.d.ts +2 -0
- package/dist/screen-entity-list.d.ts +75 -19
- package/dist/screen-list-table.d.ts +23 -3
- package/dist/screen-list-table.js +8 -1
- package/dist/screen-projection.d.ts +48 -4
- package/dist/screen-record-guidance.d.ts +88 -0
- package/dist/screen-record-guidance.js +1 -0
- package/dist/screen.d.ts +9 -5
- package/dist/screen.js +1 -1
- package/package.json +9 -1
- package/src/changes.json +6 -0
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { SelectOptionTone } from "./fields.ts";
|
|
1
2
|
import type { AccessRule, AgentScreenHints } from "./handlers.ts";
|
|
2
3
|
import type { PlatformComponent, ScreenNavSugar, ScreenSlots } from "./screen.ts";
|
|
3
4
|
import type { ListColumnSpec, RowAction } from "./screen-entity-list.ts";
|
|
@@ -56,7 +57,14 @@ export type DashboardPanelQueryOptions = {
|
|
|
56
57
|
export type DashboardPanelGate = {
|
|
57
58
|
readonly visibleWhen?: DashboardPanelVisibility;
|
|
58
59
|
};
|
|
59
|
-
|
|
60
|
+
/** Phone layout switch shared by every panel kind. */
|
|
61
|
+
export type DashboardPanelNarrow = {
|
|
62
|
+
/** Leaves the panel out below the `sm` breakpoint (phone). Not valid on a stat-group child: hide the group. */
|
|
63
|
+
readonly hideOnNarrow?: true;
|
|
64
|
+
/** Position below `sm`, like CSS `order`: panels are laid out by ascending value, a panel without one counts as 0, equal values keep the declared order. Integer ≥ 0. Desktop keeps the declared order. */
|
|
65
|
+
readonly narrowOrder?: number;
|
|
66
|
+
};
|
|
67
|
+
export type DashboardPanelSpan = "half" | "full" | "third" | "two-thirds";
|
|
60
68
|
export type DashboardPanelEmptyState = {
|
|
61
69
|
readonly span?: DashboardPanelSpan;
|
|
62
70
|
readonly emptyLabel?: string;
|
|
@@ -65,7 +73,7 @@ export type DashboardPanelEmptyState = {
|
|
|
65
73
|
};
|
|
66
74
|
export declare const DASHBOARD_STAT_TONES: readonly ["default", "positive", "ok", "warn", "negative"];
|
|
67
75
|
export type DashboardStatTone = (typeof DASHBOARD_STAT_TONES)[number];
|
|
68
|
-
export type DashboardStatPanel = DashboardPanelQueryOptions & DashboardPanelGate & {
|
|
76
|
+
export type DashboardStatPanel = DashboardPanelQueryOptions & DashboardPanelGate & DashboardPanelNarrow & {
|
|
69
77
|
readonly kind: "stat";
|
|
70
78
|
/** Stable id: kebab-case, unique within the panel set. */
|
|
71
79
|
readonly id: string;
|
|
@@ -73,6 +81,10 @@ export type DashboardStatPanel = DashboardPanelQueryOptions & DashboardPanelGate
|
|
|
73
81
|
readonly label: string;
|
|
74
82
|
readonly query: string;
|
|
75
83
|
readonly valueField: string;
|
|
84
|
+
/** Field of the query answer holding the label text, e.g. "Contracts ending by 31.01.2027"; it replaces the static `label` while it holds a non-empty string. The static `label` stays the fallback and the loading/error title. */
|
|
85
|
+
readonly labelField?: string;
|
|
86
|
+
/** i18n key shown instead of the label in the one-line phone strip of a titled stat-group ("2 requests"). Only used for stats inside a stat-group. */
|
|
87
|
+
readonly narrowLabel?: string;
|
|
76
88
|
readonly subField?: string;
|
|
77
89
|
readonly toneField?: string;
|
|
78
90
|
/** Formats a numeric value as currency (minor units) or, with `relativeTime`, as
|
|
@@ -110,6 +122,8 @@ export type DashboardStatPanel = DashboardPanelQueryOptions & DashboardPanelGate
|
|
|
110
122
|
readonly navigate?: {
|
|
111
123
|
readonly screen: string;
|
|
112
124
|
readonly namedFilter?: string;
|
|
125
|
+
/** Search params for the target list, e.g. { tab: "failed" }; merged with the namedFilter param. */
|
|
126
|
+
readonly params?: Readonly<Record<string, string>>;
|
|
113
127
|
};
|
|
114
128
|
};
|
|
115
129
|
export type DashboardChartKind = "timeseries" | "stacked-bars" | "segment-bars" | "stacked-area";
|
|
@@ -134,7 +148,7 @@ export type DashboardChartRanges = {
|
|
|
134
148
|
readonly options: readonly DashboardChartRangeOption[];
|
|
135
149
|
readonly default: string;
|
|
136
150
|
};
|
|
137
|
-
export type DashboardChartPanel = DashboardPanelQueryOptions & DashboardPanelEmptyState & DashboardPanelGate & {
|
|
151
|
+
export type DashboardChartPanel = DashboardPanelQueryOptions & DashboardPanelEmptyState & DashboardPanelGate & DashboardPanelNarrow & {
|
|
138
152
|
readonly kind: "chart";
|
|
139
153
|
readonly id: string;
|
|
140
154
|
readonly label: string;
|
|
@@ -175,77 +189,181 @@ export type DashboardChartPanel = DashboardPanelQueryOptions & DashboardPanelEmp
|
|
|
175
189
|
/** Only for chart "stacked-area": true writes each marker label vertically next to its guide line on wide panels; narrow panels keep the pins. Default false. */
|
|
176
190
|
readonly markerLabels?: boolean;
|
|
177
191
|
};
|
|
178
|
-
export type DashboardListPanel = DashboardPanelQueryOptions & DashboardPanelEmptyState & DashboardPanelGate & {
|
|
192
|
+
export type DashboardListPanel = DashboardPanelQueryOptions & DashboardPanelEmptyState & DashboardPanelGate & DashboardPanelNarrow & {
|
|
179
193
|
readonly kind: "list";
|
|
180
194
|
readonly id: string;
|
|
181
195
|
readonly label: string;
|
|
182
196
|
readonly query: string;
|
|
183
197
|
readonly columns: readonly ListColumnSpec[];
|
|
198
|
+
/** Row field holding a SelectOptionTone; tints the row and is the default tone of `hint` columns. */
|
|
199
|
+
readonly rowToneField?: string;
|
|
200
|
+
/** How `rowToneField` marks a table row from `sm` up: "bar" (default) draws a stripe at the left edge, "dot" a small dot in front of the first cell. Cards below `sm` always get the stripe. */
|
|
201
|
+
readonly rowToneMarker?: DashboardListRowToneMarker;
|
|
202
|
+
/** Icon left of the one-line phone variant (`narrow.layout: "line"`); not drawn from `sm` up. Resolved like `DashboardStatGroupPanel.icon`. */
|
|
203
|
+
readonly icon?: PlatformComponent;
|
|
204
|
+
/** `false` drops the column header row; default true. */
|
|
205
|
+
readonly showHeader?: boolean;
|
|
206
|
+
/** i18n key, a line under `label`; with `showTotal` it stands before the count. */
|
|
207
|
+
readonly subtitle?: string;
|
|
208
|
+
/** Adds "n of m" to the subtitle from the rows shown and the query's `total`. An object sets the text: `text` is an i18n key with `{shown}` and `{total}` ("the {shown} most urgent of {total} items"), `narrowText` replaces it below `sm`. */
|
|
209
|
+
readonly showTotal?: true | DashboardListShowTotal;
|
|
210
|
+
/** Link under the table to the full list; with a known `total` above the rows shown, "k more" stands before it. */
|
|
211
|
+
readonly footerLink?: DashboardListFooterLink;
|
|
212
|
+
/** Phone layout below `sm`; the table stays from `sm` up. */
|
|
213
|
+
readonly narrow?: DashboardListNarrow;
|
|
214
|
+
/** Makes each table row a link to a screen; a small icon at the right edge marks it. The cards below `sm` get no extra icon. */
|
|
215
|
+
readonly rowLink?: DashboardListRowLink;
|
|
216
|
+
};
|
|
217
|
+
/** "bar": stripe at the left edge of the row. "dot": small tone dot in front of the first cell. */
|
|
218
|
+
export type DashboardListRowToneMarker = "bar" | "dot";
|
|
219
|
+
/** Row link of a list panel: one fixed target screen (`screen`) or, when the rows point to different places, the screen named by each row (`screenField`). */
|
|
220
|
+
export type DashboardListRowLink = {
|
|
221
|
+
/** "arrow" (default) draws ↗ for a jump to another place, "chevron" draws › for opening the row. */
|
|
222
|
+
readonly icon?: "arrow" | "chevron";
|
|
223
|
+
} & ({
|
|
224
|
+
/** Target screen, `feature:screen:name` or the short id in the same feature. */
|
|
225
|
+
readonly screen: string;
|
|
226
|
+
/** Row field holding the params object of the target (`entityId` opens that record, other keys become search params). */
|
|
227
|
+
readonly paramField?: string;
|
|
228
|
+
readonly screenField?: never;
|
|
229
|
+
readonly paramsField?: never;
|
|
230
|
+
} | {
|
|
231
|
+
/** Row field holding the qualified screen name of the target; a row without one is no link. */
|
|
232
|
+
readonly screenField: string;
|
|
233
|
+
/** Row field holding the params object of the target, like `paramField`. */
|
|
234
|
+
readonly paramsField?: string;
|
|
235
|
+
readonly screen?: never;
|
|
236
|
+
readonly paramField?: never;
|
|
237
|
+
});
|
|
238
|
+
/** Texts of the "n of m" count in a list panel's subtitle; without `text` the default i18n text stands. */
|
|
239
|
+
export type DashboardListShowTotal = {
|
|
240
|
+
/** i18n key, placeholders `{shown}` and `{total}`. */
|
|
241
|
+
readonly text?: string;
|
|
242
|
+
/** i18n key used instead of `text` below `sm`. */
|
|
243
|
+
readonly narrowText?: string;
|
|
244
|
+
};
|
|
245
|
+
/** "cards": one card per row (tone stripe; badge column and `hint.detailField` on top, the hint sentence bold, button column bottom right,
|
|
246
|
+
* `showOnNarrowOnly` columns bottom left; the button column bottom right). "line": a single clickable line "<label> · <value of the first row> · k more" to `footerLink`, which it needs;
|
|
247
|
+
* k is the total of the list (the query's `total`, else the rows loaded) minus one.
|
|
248
|
+
* Default "cards". `limit` shows only the first n rows; subtitle count and footer follow it. */
|
|
249
|
+
export type DashboardListNarrow = {
|
|
250
|
+
readonly limit?: number;
|
|
251
|
+
readonly layout?: "cards" | "line";
|
|
252
|
+
/** Query output field whose value of the first row stands behind the label in the "line" layout; it need not be a column of the panel. Default: the first text column. */
|
|
253
|
+
readonly field?: string;
|
|
254
|
+
/** i18n key replacing "k more" in the "line" layout; `{count}` is the total minus the first row. */
|
|
255
|
+
readonly moreText?: string;
|
|
256
|
+
/** Row field replacing the card title (the hint sentence) in the "cards" layout, e.g. a shorter sentence for the phone. Needs a hint column. */
|
|
257
|
+
readonly titleField?: string;
|
|
258
|
+
};
|
|
259
|
+
/** Link to a screen from a panel; `label` is an i18n key, `namedFilter` only for list screens. */
|
|
260
|
+
export type DashboardListFooterLink = {
|
|
261
|
+
readonly label: string;
|
|
262
|
+
/** i18n key of the text before the link when more rows exist than shown; `{count}` is the rest. Default "k more". */
|
|
263
|
+
readonly moreText?: string;
|
|
264
|
+
/** i18n key used instead of `moreText` below `sm`. */
|
|
265
|
+
readonly narrowMoreText?: string;
|
|
266
|
+
/** Draw the link only below `sm`, where it is the target of the "line" layout; from `sm` up the panel shows no footer link. */
|
|
267
|
+
readonly narrowOnly?: boolean;
|
|
268
|
+
readonly screen: string;
|
|
269
|
+
readonly namedFilter?: string;
|
|
270
|
+
readonly params?: Readonly<Record<string, string>>;
|
|
271
|
+
};
|
|
272
|
+
/** Link at the right edge of a stat-group panel; `label` is an i18n key. */
|
|
273
|
+
export type DashboardStatGroupLink = {
|
|
274
|
+
readonly label: string;
|
|
275
|
+
readonly screen: string;
|
|
276
|
+
readonly params?: Readonly<Record<string, string>>;
|
|
184
277
|
};
|
|
185
|
-
export type
|
|
278
|
+
export type DashboardStatGroupLayout = "cards" | "strip";
|
|
279
|
+
export type DashboardStatGroupPanel = DashboardPanelGate & DashboardPanelNarrow & {
|
|
186
280
|
readonly kind: "stat-group";
|
|
187
281
|
readonly id: string;
|
|
188
282
|
readonly label?: string;
|
|
189
283
|
/** i18n key, a line under `label`; the boot validator requires `label`. */
|
|
190
284
|
readonly subtitle?: string;
|
|
191
285
|
readonly span?: DashboardPanelSpan;
|
|
286
|
+
/** Default: "strip" without `label`, "cards" with. "strip" with a `label` puts label and subtitle
|
|
287
|
+
* left, then one box per stat (number large, label bold, sub line small) and the link at the right edge; under sm it collapses to
|
|
288
|
+
* one line "<title> · <n> <narrowLabel ?? label> · …" with a chevron, clickable to the `link`. */
|
|
289
|
+
readonly layout?: DashboardStatGroupLayout;
|
|
290
|
+
/** Icon left of the one-line phone strip (below `sm`); not drawn on wider screens. Resolved like `DashboardStatPanel.icon`. */
|
|
291
|
+
readonly icon?: PlatformComponent;
|
|
292
|
+
/** Link at the right edge of the panel (label + chevron). */
|
|
293
|
+
readonly link?: DashboardStatGroupLink;
|
|
294
|
+
/** Phone look of the one-line strip; needs a label and layout "strip". */
|
|
295
|
+
readonly narrow?: DashboardStatGroupNarrow;
|
|
296
|
+
/** Tiles per row from `md` up, only with `layout: "cards"`; one column below `sm`. Default: follows the number of tiles. */
|
|
297
|
+
readonly columns?: 2 | 3 | 4;
|
|
192
298
|
readonly stats: readonly DashboardStatPanel[];
|
|
193
299
|
};
|
|
194
|
-
export type
|
|
300
|
+
export type DashboardStatGroupNarrow = {
|
|
301
|
+
/** Tints the one-line phone strip (background and border) in this tone, e.g. "accent" for a promo-blue inbox line. */
|
|
302
|
+
readonly tone?: SelectOptionTone;
|
|
303
|
+
};
|
|
304
|
+
export type DashboardFeedPanel = DashboardPanelQueryOptions & DashboardPanelEmptyState & DashboardPanelGate & DashboardPanelNarrow & {
|
|
195
305
|
readonly kind: "feed";
|
|
196
306
|
readonly id: string;
|
|
197
307
|
readonly label: string;
|
|
198
308
|
readonly query: string;
|
|
199
309
|
};
|
|
200
310
|
export type DashboardProgressTone = "default" | "danger";
|
|
201
|
-
export type DashboardProgressListPanel = DashboardPanelQueryOptions & DashboardPanelEmptyState & DashboardPanelGate & {
|
|
311
|
+
export type DashboardProgressListPanel = DashboardPanelQueryOptions & DashboardPanelEmptyState & DashboardPanelGate & DashboardPanelNarrow & {
|
|
202
312
|
readonly kind: "progress-list";
|
|
203
313
|
readonly id: string;
|
|
204
314
|
readonly label: string;
|
|
205
315
|
readonly query: string;
|
|
206
316
|
};
|
|
207
|
-
export type DashboardCustomPanel = {
|
|
317
|
+
export type DashboardCustomPanel = DashboardPanelNarrow & {
|
|
208
318
|
readonly kind: "custom";
|
|
209
319
|
readonly id: string;
|
|
210
320
|
readonly component: PlatformComponent;
|
|
321
|
+
/** Grid width like the other panels; default is the full row. */
|
|
322
|
+
readonly span?: DashboardPanelSpan;
|
|
211
323
|
/** Static author values laid over the screen's filterParams, like
|
|
212
324
|
* `DashboardPanelQueryOptions.params`; the panel wins on a name clash. */
|
|
213
325
|
readonly params?: Readonly<Record<string, unknown>>;
|
|
214
326
|
};
|
|
215
327
|
export type DashboardTextBlock = {
|
|
216
328
|
readonly kind: "heading";
|
|
217
|
-
readonly text:
|
|
329
|
+
readonly text: DashboardText;
|
|
218
330
|
} | {
|
|
219
331
|
readonly kind: "paragraph";
|
|
220
|
-
readonly text:
|
|
221
|
-
/** Default "muted", like body copy inside panels. */
|
|
222
|
-
readonly emphasis?: "muted" | "strong";
|
|
332
|
+
readonly text: DashboardText;
|
|
333
|
+
/** Default "muted", like body copy inside panels. "lead" is the larger serif opening sentence of a briefing. */
|
|
334
|
+
readonly emphasis?: "muted" | "strong" | "lead";
|
|
223
335
|
} | {
|
|
224
336
|
readonly kind: "list";
|
|
225
|
-
readonly items: readonly
|
|
337
|
+
readonly items: readonly DashboardText[];
|
|
226
338
|
} | {
|
|
227
339
|
readonly kind: "code";
|
|
228
340
|
readonly code: string;
|
|
229
341
|
} | {
|
|
230
342
|
readonly kind: "hint";
|
|
231
|
-
readonly text:
|
|
343
|
+
readonly text: DashboardText;
|
|
232
344
|
} | {
|
|
233
345
|
readonly kind: "link";
|
|
234
|
-
/** Link label (i18n key). */
|
|
235
|
-
readonly text:
|
|
346
|
+
/** Link label (i18n key or DashboardI18nText). */
|
|
347
|
+
readonly text: DashboardText;
|
|
236
348
|
/** Same-feature short id or cross-feature QN `<feature>:screen:<id>`. */
|
|
237
349
|
readonly screen: string;
|
|
238
350
|
/** Show the link only to users holding one of these roles. Display
|
|
239
351
|
* gate only: the target screen's own `access` stays the enforcement. */
|
|
240
352
|
readonly roles?: readonly string[];
|
|
241
353
|
};
|
|
242
|
-
export type DashboardTextPanel = DashboardPanelGate & {
|
|
354
|
+
export type DashboardTextPanel = DashboardPanelGate & DashboardPanelQueryOptions & DashboardPanelNarrow & {
|
|
243
355
|
readonly kind: "text";
|
|
244
356
|
readonly id: string;
|
|
245
357
|
/** Panel title (i18n key). */
|
|
246
358
|
readonly label?: string;
|
|
247
359
|
readonly span?: DashboardPanelSpan;
|
|
248
|
-
|
|
360
|
+
/** Query answering `{ blocks: DashboardTextBlock[] }`; its blocks replace the static ones.
|
|
361
|
+
* Static blocks show while it loads, on error and when it answers empty. It may add
|
|
362
|
+
* `narrowBlocks`, which the renderer shows below `sm` instead of `blocks`. */
|
|
363
|
+
readonly query?: string;
|
|
364
|
+
readonly blocks?: readonly DashboardTextBlock[];
|
|
365
|
+
/** Shown instead of `blocks` below `sm`; a query answering `{ blocks, narrowBlocks }` replaces both. Needs `blocks`. */
|
|
366
|
+
readonly narrowBlocks?: readonly DashboardTextBlock[];
|
|
249
367
|
};
|
|
250
368
|
export type DashboardPanelVisibility = {
|
|
251
369
|
readonly query: string;
|
|
@@ -257,7 +375,7 @@ export type ScreenVisibility = DashboardPanelVisibility & {
|
|
|
257
375
|
* the gate query runs with an empty payload. */
|
|
258
376
|
readonly idParam?: string;
|
|
259
377
|
};
|
|
260
|
-
export type DashboardScreenPanel = {
|
|
378
|
+
export type DashboardScreenPanel = DashboardPanelNarrow & {
|
|
261
379
|
readonly kind: "screen";
|
|
262
380
|
readonly id: string;
|
|
263
381
|
/** Same-feature short id or cross-feature QN `<feature>:screen:<id>`. */
|
|
@@ -355,9 +473,8 @@ export type DashboardScreenDefinition = {
|
|
|
355
473
|
readonly timeRange?: DashboardTimeRangeDefinition;
|
|
356
474
|
/** Marks the screen as spanning more than the caller's own scope. */
|
|
357
475
|
readonly scope?: DashboardScopeDefinition;
|
|
358
|
-
/** Show
|
|
359
|
-
* dashboards that host forms rather than live metrics
|
|
360
|
-
* next to the form reads as stale data. */
|
|
476
|
+
/** Show today's date (server clock, weekday and day, no time) in the top bar next to the title; hidden below `sm`.
|
|
477
|
+
* Default true; turn off for dashboards that host forms rather than live metrics. */
|
|
361
478
|
readonly showUpdatedAt?: boolean;
|
|
362
479
|
readonly slots?: ScreenSlots;
|
|
363
480
|
readonly access?: AccessRule;
|
|
@@ -440,6 +440,8 @@ export type EntityEditScreenDefinition = {
|
|
|
440
440
|
readonly entity: string;
|
|
441
441
|
/** Entity field whose value names the loaded record in the header breadcrumb (edit mode only). */
|
|
442
442
|
readonly recordTitleField?: string;
|
|
443
|
+
/** Focused shell while the record is open: the app header actions leave the shell header, and on phones a top bar with the record title, a back arrow to the parent list and the page-header overflow menu replaces it. Default off. */
|
|
444
|
+
readonly focus?: boolean;
|
|
443
445
|
/** Screen title (i18n key) with `{field}` placeholders filled from the
|
|
444
446
|
* current form values, so the title follows what the user types (create
|
|
445
447
|
* wizard: "Add {make} {model}"). Falls back to the plain title while the
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { FieldCondition } from "./fields.ts";
|
|
2
2
|
import type { AccessRule, AgentScreenHints } from "./handlers.ts";
|
|
3
|
-
import type { NamedListFilterRef } from "./named-list-filters.ts";
|
|
3
|
+
import type { ListSortDir, ListSortOption, ListSortSpec, NamedFilterFacetOptions, NamedListFilterRef } from "./named-list-filters.ts";
|
|
4
4
|
import type { IconKey } from "./nav-icon.ts";
|
|
5
5
|
import type { FieldRenderer, PlatformComponent, ScreenNavSugar, ScreenSlots } from "./screen.ts";
|
|
6
6
|
import type { ActionFormRedirect } from "./screen-action-form.ts";
|
|
@@ -9,7 +9,7 @@ import type { ListEmptyStateSpec } from "./screen-entity-edit.ts";
|
|
|
9
9
|
import type { EntityListExpandableRow } from "./screen-expandable-row.ts";
|
|
10
10
|
import type { ScreenFallback } from "./screen-fallback.ts";
|
|
11
11
|
import type { ListBulkAction } from "./screen-list-bulk.ts";
|
|
12
|
-
import type { ListColumnPin, ListTableOptions } from "./screen-list-table.ts";
|
|
12
|
+
import type { ListColumnPin, ListNarrowFacets, ListTableOptions } from "./screen-list-table.ts";
|
|
13
13
|
export type ListColumnSpec = string | {
|
|
14
14
|
readonly field: string;
|
|
15
15
|
readonly renderer?: FieldRenderer;
|
|
@@ -45,47 +45,81 @@ export type ListColumnSpec = string | {
|
|
|
45
45
|
* `sortable` on. Ignored on `entityList` columns, where the entity
|
|
46
46
|
* field's own `sortable` flag wins. */
|
|
47
47
|
readonly sortable?: boolean;
|
|
48
|
-
/** Value type of a relatedList column, which has no `EntityDefinition`
|
|
48
|
+
/** Value type of a projectionList or relatedList column, which has no `EntityDefinition`
|
|
49
49
|
* field to derive it from. Numeric types right-align the column and its
|
|
50
50
|
* header with tabular figures, like an entityList column of that field
|
|
51
51
|
* type. Ignored on entityList columns, where the field's own type wins. */
|
|
52
52
|
readonly valueType?: "number" | "decimal" | "bigInt" | "money";
|
|
53
|
+
/** `false` leaves an empty cell blank instead of drawing the "—" placeholder. Not combinable with `hint`, whose empty sentence is `hint.emptyLabel`. */
|
|
54
|
+
readonly emptyPlaceholder?: false;
|
|
53
55
|
/** Leaves the column out of the compact card layout used below the
|
|
54
56
|
* `md` breakpoint (tables keep it). For columns that only make sense
|
|
55
57
|
* next to the others, like a sort key. */
|
|
56
58
|
readonly hideOnNarrow?: boolean;
|
|
59
|
+
/** Counterpart of `hideOnNarrow`: the column shows only in the compact card layout and not in the table.
|
|
60
|
+
* Not combinable with `hideOnNarrow`, `hidden` or `pinned`. */
|
|
61
|
+
readonly showOnNarrowOnly?: true;
|
|
57
62
|
/** Start state for the column picker: the column begins hidden and the
|
|
58
63
|
* user can show it. Only valid together with `table.columnPicker`. */
|
|
59
64
|
readonly hidden?: boolean;
|
|
60
65
|
/** Start pin for the column: it sticks to this edge while the table scrolls
|
|
61
66
|
* horizontally. Only valid together with `table.pinning`. */
|
|
62
67
|
readonly pinned?: ListColumnPin;
|
|
63
|
-
/** Start width in px.
|
|
68
|
+
/** Start width in px. Needs `table.resizing`, except on a hint column, which sizes itself. */
|
|
64
69
|
readonly width?: number;
|
|
65
|
-
/** Smallest width in px the user can resize to.
|
|
70
|
+
/** Smallest width in px the user can resize to. Needs `table.resizing`, except on a hint column. */
|
|
66
71
|
readonly minWidth?: number;
|
|
67
|
-
/**
|
|
68
|
-
* as bar + percent. "badge": field holds a label,
|
|
69
|
-
* tone comes from `badgeToneField
|
|
70
|
-
*
|
|
71
|
-
*
|
|
72
|
+
/** One of "bar" | "badge" | "datetime" | "button". "bar": field holds a 0..1 fraction,
|
|
73
|
+
* drawn as bar + percent (dashboard list panels only). "badge": field holds a label,
|
|
74
|
+
* drawn as a pill whose tone comes from `badgeToneField` (dashboard list panels and the
|
|
75
|
+
* RenderList tables of entityList and projectionList). "datetime": field holds an ISO
|
|
76
|
+
* string or epoch ms, shown in the user's locale and time zone (dashboard list panels
|
|
77
|
+
* only). "button": a column with a screen link (linkScreenField or refEntity) draws the
|
|
78
|
+
* link as a small outline button, in dashboard list panels only; a row button in an
|
|
79
|
+
* entityList or projectionList table is a rowAction with display "button" (boot-rejected
|
|
80
|
+
* on columns there). Other list renderers ignore `display`. */
|
|
72
81
|
readonly display?: ListColumnDisplay;
|
|
73
82
|
/** Row field naming the badge tone; only with `display: "badge"`. */
|
|
74
83
|
readonly badgeToneField?: string;
|
|
84
|
+
/** `false` draws the badge pill without its leading dot; only with `display: "badge"`. */
|
|
85
|
+
readonly badgeDot?: false;
|
|
75
86
|
/** Row field holding a screen QN (`<feature>:screen:<id>`): the cell links
|
|
76
87
|
* to that screen when the row sets it and the user may open it. For
|
|
77
88
|
* query-backed lists (projectionList, relatedList), whose rows can point
|
|
78
89
|
* at a different screen each. */
|
|
79
90
|
readonly linkScreenField?: string;
|
|
91
|
+
/** Row field holding a params object for the linkScreenField target: `entityId` opens that record, the other keys become search params (e.g. actionForm prefill). Only with linkScreenField. */
|
|
92
|
+
readonly linkParamsField?: string;
|
|
93
|
+
/** "To do" cell: the column's field holds a sentence, shown emphasized in the row tone; an empty value shows `emptyLabel`. Owns the cell rendering, so no `renderer`. */
|
|
94
|
+
readonly hint?: ListColumnHint;
|
|
80
95
|
};
|
|
81
|
-
export type
|
|
96
|
+
export type ListColumnHint = {
|
|
97
|
+
/** Row field with a second, muted line (e.g. the due date as text). */
|
|
98
|
+
readonly detailField?: string;
|
|
99
|
+
/** Row field shown as the detail line below `sm` instead of `detailField` (a shorter line, e.g. "5 days · Anna Schneider"). Needs `detailField`. */
|
|
100
|
+
readonly narrowDetailField?: string;
|
|
101
|
+
/** Row field holding a SelectOptionTone; defaults to the screen's `rowToneField`. Tone `neutral` draws the sentence muted and not bold, like `emptyLabel`, and no stripe on the phone card. */
|
|
102
|
+
readonly toneField?: string;
|
|
103
|
+
/** Row field with a longer reason, shown behind a "Why?" toggle in the cell. */
|
|
104
|
+
readonly reasonField?: string;
|
|
105
|
+
/** Row field (boolean): while true, the `reasonField` text stands open as a box under the row, over the full row width, in the table view (entity/projection lists from `md` up, dashboard lists from `sm` up); the (i) stays and closes it. Cards and narrower views keep the plain toggle. Needs `reasonField`. */
|
|
106
|
+
readonly reasonOpenField?: string;
|
|
107
|
+
/** Row field with a bold lead-in of the reason paragraph ("Rule 10 · Case open."); without it the reason has none. Needs `reasonField`. */
|
|
108
|
+
readonly reasonTitleField?: string;
|
|
109
|
+
/** i18n key for an empty sentence; default `kumiko.list.hint.empty`. */
|
|
110
|
+
readonly emptyLabel?: string;
|
|
111
|
+
/** The sentence keeps the normal text color (still bold); the tone stays on the row stripe, a badge and the detail line. */
|
|
112
|
+
readonly plainSentence?: true;
|
|
113
|
+
};
|
|
114
|
+
/** Computed fields for the loaded rows: one `query` call per page answer with `{ ...params, ids }`, answering `{ rows: [{ id, ...fields }] }`. Fields are merged into the rows and win over same-named row fields. */
|
|
115
|
+
export type ListRowDecoration = {
|
|
116
|
+
readonly query: string;
|
|
117
|
+
readonly params?: Readonly<Record<string, unknown>>;
|
|
118
|
+
};
|
|
119
|
+
export type ListColumnDisplay = "bar" | "badge" | "datetime" | "button";
|
|
82
120
|
export type ListBadgeTone = "positive" | "warn" | "negative" | "neutral";
|
|
83
121
|
export type ListPaginationMode = "pages" | "infinite" | false;
|
|
84
|
-
export type ListSortDir
|
|
85
|
-
export type ListSortSpec = {
|
|
86
|
-
readonly field: string;
|
|
87
|
-
readonly dir: ListSortDir;
|
|
88
|
-
};
|
|
122
|
+
export type { ListSortDir, ListSortOption, ListSortSpec };
|
|
89
123
|
export type ScreenFilterOp = "eq" | "ne" | "lt" | "gt" | "lte" | "gte" | "in";
|
|
90
124
|
export type ScreenFilter = {
|
|
91
125
|
readonly field: string;
|
|
@@ -116,8 +150,11 @@ export type RowFieldExtractor = {
|
|
|
116
150
|
export type RowActionDisplay = "button" | "link" | "icon" | "responsive";
|
|
117
151
|
/** Row-action column layout. `"adaptive"` (default): primary action as link,
|
|
118
152
|
* the rest in a kebab menu — except actions with an explicit `display`, which
|
|
119
|
-
* stay inline. `"inline"`: every action inline, no kebab.
|
|
120
|
-
|
|
153
|
+
* stay inline. `"inline"`: every action inline, no kebab. `"menu"`: every
|
|
154
|
+
* action in the kebab menu at the row end, none inline, the row opener
|
|
155
|
+
* (`rowClick: true`) included as an entry, so every row has a kebab; phone
|
|
156
|
+
* cards draw no kebab. */
|
|
157
|
+
export type RowActionMode = "adaptive" | "inline" | "menu";
|
|
121
158
|
export type RowAction = RowActionWriteHandler | RowActionNavigate | RowActionDrawer | RowActionClientAction;
|
|
122
159
|
export type RowActionWriteHandler = {
|
|
123
160
|
/** Default for RowActions without an explicitly set `kind` —
|
|
@@ -330,6 +367,8 @@ export type ToolbarAction = ({
|
|
|
330
367
|
/** Line under the drawer heading (i18n key). */
|
|
331
368
|
readonly subtitle?: string;
|
|
332
369
|
}) & {
|
|
370
|
+
/** Icon of the button, in every list (entityList, projectionList, relatedList). Without it the id-derived default applies (`create` → plus). */
|
|
371
|
+
readonly icon?: IconKey;
|
|
333
372
|
/** Shown only while the query's `field` equals `eq` (live, empty payload). Hidden while the
|
|
334
373
|
* query loads and when it fails. Named like the screen and panel gates because it is
|
|
335
374
|
* query-based; a list toolbar has no record to evaluate a row condition against. */
|
|
@@ -414,8 +453,11 @@ export type EntityListScreenDefinition = {
|
|
|
414
453
|
/** `false` hides this list's "+ New" button (and the empty-state create CTA) while the entity's edit screen keeps its create branch for other entry points, e.g. a prefilled action. Default `true`. */
|
|
415
454
|
readonly allowCreate?: boolean;
|
|
416
455
|
readonly columns: readonly ListColumnSpec[];
|
|
456
|
+
/** Row field holding a SelectOptionTone; the row is toned like relatedList `rowTone`, other values leave it untoned. */
|
|
457
|
+
readonly rowToneField?: string;
|
|
458
|
+
/** Computed row fields from an app query, readable by `rowToneField`, column `hint`, `linkScreenField`/`linkParamsField` and rowAction `visible`/`params`/`payload`; a column may name a decoration field. */
|
|
459
|
+
readonly rowDecoration?: ListRowDecoration;
|
|
417
460
|
readonly rowRenderer?: PlatformComponent;
|
|
418
|
-
readonly cardRenderer?: PlatformComponent;
|
|
419
461
|
/** Per-row actions, rendered as an actions column on the right.
|
|
420
462
|
* Adaptive (default, see `rowActionMode`): the primary action as a link,
|
|
421
463
|
* the rest in the kebab menu; actions with an explicit `display` stay
|
|
@@ -444,6 +486,8 @@ export type EntityListScreenDefinition = {
|
|
|
444
486
|
/** Opt-in table behaviour: remembered state, reset, column picker, density. */
|
|
445
487
|
readonly table?: ListTableOptions;
|
|
446
488
|
readonly defaultSort?: ListSortSpec;
|
|
489
|
+
/** Choices of the "Sorted by" select in the toolbar (and the narrow-width sort control) instead of one entry per column; every field must be sortable. */
|
|
490
|
+
readonly sortOptions?: readonly ListSortOption[];
|
|
447
491
|
/** Initial facet selection, per filterable field: option values (string
|
|
448
492
|
* facets) or a boolean. Applies only while the URL carries no value for
|
|
449
493
|
* that field, so a link or the user's own choice wins; picking "no filter"
|
|
@@ -459,10 +503,22 @@ export type EntityListScreenDefinition = {
|
|
|
459
503
|
* `label` an i18n key. Selected through the `<screenId>.filter` URL key; a dashboard stat's
|
|
460
504
|
* `navigate.namedFilter` links here. While one is active `defaultFilters` are not applied. */
|
|
461
505
|
readonly namedFilters?: readonly NamedListFilterRef[];
|
|
506
|
+
/** Presentation of `namedFilters` in the toolbar; needs `namedFilters`. */
|
|
507
|
+
readonly namedFilterFacet?: NamedFilterFacetOptions;
|
|
462
508
|
/** Replaces the default empty-list title/hint; the create button stays when the list can create. */
|
|
463
509
|
readonly emptyState?: ListEmptyStateSpec;
|
|
464
510
|
/** i18n key for the primary create button label (default `kumiko.actions.create`). */
|
|
465
511
|
readonly createLabel?: string;
|
|
512
|
+
/** "toolbar": from `sm` up the create button ends the filter row instead of standing in the header. Default "header". Needs a create button (no `allowCreate: false`). */
|
|
513
|
+
readonly createPlacement?: "header" | "toolbar";
|
|
514
|
+
/** From `sm` up, a "Sorted by" select in the filter row (same options as the narrow sort control); column headers stay sortable. */
|
|
515
|
+
readonly toolbarSort?: true;
|
|
516
|
+
/** "pills": below `sm` the select facets render as rounded pill triggers with a stronger border; from `sm` up unchanged. */
|
|
517
|
+
readonly narrowFacets?: ListNarrowFacets;
|
|
518
|
+
/** "toolbar": from `md` up the `toolbarActions` end the filter row, after the "Sorted by" select and the create button, instead of standing in the page header. Below `md` they stay in the header. Default "header". Needs `toolbarActions`. */
|
|
519
|
+
readonly toolbarActionsPlacement?: "header" | "toolbar";
|
|
520
|
+
/** i18n key of the plural noun for the list size in the phone sort line (`{count}` pluralised). Default `<feature>:entity:<entity>:noun`. */
|
|
521
|
+
readonly itemNounKey?: string;
|
|
466
522
|
/** i18n key for the search field placeholder (default `kumiko.list.search-placeholder`). */
|
|
467
523
|
readonly searchPlaceholder?: string;
|
|
468
524
|
readonly searchable?: boolean;
|
|
@@ -1,9 +1,16 @@
|
|
|
1
1
|
import type { ListAggregateMeasureKind } from "./list-aggregate-types.ts";
|
|
2
|
-
export declare const LIST_TABLE_DENSITIES: readonly ["comfortable", "compact"];
|
|
2
|
+
export declare const LIST_TABLE_DENSITIES: readonly ["comfortable", "compact", "relaxed"];
|
|
3
3
|
export type ListTableDensity = (typeof LIST_TABLE_DENSITIES)[number];
|
|
4
|
+
/** Upper bound for a list column width in pixels; the renderer clamps to it, the boot validator rejects above it. */
|
|
5
|
+
export declare const LIST_COLUMN_MAX_WIDTH_PX = 2000;
|
|
4
6
|
export declare const LIST_COLUMN_PINS: readonly ["left", "right"];
|
|
5
7
|
export type ListColumnPin = (typeof LIST_COLUMN_PINS)[number];
|
|
6
|
-
export declare const LIST_TABLE_OPTION_KEYS: readonly ["rememberState", "resetAll", "columnPicker", "density", "pinning", "resizing", "keyboardNavigation", "export", "grouping", "totals", "compactHeader"];
|
|
8
|
+
export declare const LIST_TABLE_OPTION_KEYS: readonly ["rememberState", "resetAll", "columnPicker", "density", "pinning", "resizing", "keyboardNavigation", "export", "grouping", "totals", "summaryRow", "compactHeader", "frame"];
|
|
9
|
+
export declare const LIST_TABLE_FRAMES: readonly ["card"];
|
|
10
|
+
export type ListTableFrame = (typeof LIST_TABLE_FRAMES)[number];
|
|
11
|
+
export declare const LIST_NARROW_FACETS: readonly ["pills"];
|
|
12
|
+
export type ListNarrowFacets = (typeof LIST_NARROW_FACETS)[number];
|
|
13
|
+
export declare const LIST_TABLE_SUMMARY_ROW_KEYS: readonly ["query", "params"];
|
|
7
14
|
export declare const LIST_TABLE_GROUPING_KEYS: readonly ["field", "label", "labels", "collapsedWhen", "userChoice", "fields"];
|
|
8
15
|
export declare const LIST_TABLE_TOTAL_KEYS: readonly ["field", "kind"];
|
|
9
16
|
export declare const LIST_TABLE_EXPORT_KEYS: readonly ["xlsx", "maxRows"];
|
|
@@ -27,8 +34,10 @@ export type ListTableOptions = {
|
|
|
27
34
|
readonly keyboardNavigation?: boolean;
|
|
28
35
|
/** Renders the header row smaller (12px) and semibold. */
|
|
29
36
|
readonly compactHeader?: boolean;
|
|
37
|
+
/** "card": from `sm` up the table, summary row and pager sit in one bordered, rounded card (toolbar and description stay above it); below `sm` the cards of the card layout are bordered, rounded cards with a gap. Default: the table runs frameless over the page width. */
|
|
38
|
+
readonly frame?: ListTableFrame;
|
|
30
39
|
readonly density?: {
|
|
31
|
-
/** Row density on first visit. Default "comfortable". */
|
|
40
|
+
/** Row density on first visit. Default "comfortable"; "relaxed" gives the body cells 12px vertical padding from sm, the header row stays as is. */
|
|
32
41
|
readonly default?: ListTableDensity;
|
|
33
42
|
/** Shows the density choice in the view menu and remembers it per session. */
|
|
34
43
|
readonly userChoice?: boolean;
|
|
@@ -39,6 +48,17 @@ export type ListTableOptions = {
|
|
|
39
48
|
readonly grouping?: ListTableGrouping;
|
|
40
49
|
/** Footer row under the rows, computed by the server over all rows matching the current filters and search. In grouped mode the same measures show in each group header. */
|
|
41
50
|
readonly totals?: readonly ListTableTotal[];
|
|
51
|
+
/** One line under the rows (above `totals`), computed by a query of your own: "label value · label value"; an item without `label` shows its value alone. */
|
|
52
|
+
readonly summaryRow?: ListTableSummaryRow;
|
|
53
|
+
};
|
|
54
|
+
/** The query receives the list's current search, filters and named filter (no paging, no sort) plus `params`, and answers `{ items: [{ label?, value, tone?, column? }] }`.
|
|
55
|
+
* When an item names a `column` (a column field of the list), the table draws the row as a table row: the values stand in the cells under their columns, without labels; items without `column` go to the first column.
|
|
56
|
+
* Without any `column` the row stays one line "label value · label value". */
|
|
57
|
+
export type ListTableSummaryRow = {
|
|
58
|
+
/** Qualified query name, e.g. `feature:query:order:summary`. Its Zod schema accepts every list key the screen sends (search, filters, namedFilter, ...). */
|
|
59
|
+
readonly query: string;
|
|
60
|
+
/** Extra payload keys merged over the list's own. */
|
|
61
|
+
readonly params?: Readonly<Record<string, unknown>>;
|
|
42
62
|
};
|
|
43
63
|
export type ListTableGrouping = {
|
|
44
64
|
/** Start grouping. Without it the list starts ungrouped and the user picks from `fields`. */
|
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
export const LIST_TABLE_DENSITIES = ["comfortable", "compact"];
|
|
1
|
+
export const LIST_TABLE_DENSITIES = ["comfortable", "compact", "relaxed"];
|
|
2
|
+
/** Upper bound for a list column width in pixels; the renderer clamps to it, the boot validator rejects above it. */
|
|
3
|
+
export const LIST_COLUMN_MAX_WIDTH_PX = 2000;
|
|
2
4
|
export const LIST_COLUMN_PINS = ["left", "right"];
|
|
3
5
|
export const LIST_TABLE_OPTION_KEYS = [
|
|
4
6
|
"rememberState",
|
|
@@ -11,8 +13,13 @@ export const LIST_TABLE_OPTION_KEYS = [
|
|
|
11
13
|
"export",
|
|
12
14
|
"grouping",
|
|
13
15
|
"totals",
|
|
16
|
+
"summaryRow",
|
|
14
17
|
"compactHeader",
|
|
18
|
+
"frame",
|
|
15
19
|
];
|
|
20
|
+
export const LIST_TABLE_FRAMES = ["card"];
|
|
21
|
+
export const LIST_NARROW_FACETS = ["pills"];
|
|
22
|
+
export const LIST_TABLE_SUMMARY_ROW_KEYS = ["query", "params"];
|
|
16
23
|
export const LIST_TABLE_GROUPING_KEYS = [
|
|
17
24
|
"field",
|
|
18
25
|
"label",
|