@happyvertical/smrt-svelte 0.55.22 → 0.55.24
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/AGENTS.md +2 -2
- package/README.md +2 -2
- package/agents/overview-surfaces.md +108 -4
- package/agents/screens.md +171 -5
- package/dist/components/overview/index.d.ts +4 -1
- package/dist/components/overview/index.d.ts.map +1 -1
- package/dist/components/overview/index.js +3 -0
- package/dist/components/overview/record.d.ts +51 -0
- package/dist/components/overview/record.d.ts.map +1 -0
- package/dist/components/overview/record.js +146 -0
- package/dist/components/overview/server.d.ts +4 -0
- package/dist/components/overview/server.d.ts.map +1 -1
- package/dist/components/overview/server.js +4 -0
- package/dist/components/overview/types.d.ts +12 -0
- package/dist/components/overview/types.d.ts.map +1 -1
- package/dist/components/overview/widgets/LineItemsWidget.svelte +144 -0
- package/dist/components/overview/widgets/LineItemsWidget.svelte.d.ts +6 -0
- package/dist/components/overview/widgets/LineItemsWidget.svelte.d.ts.map +1 -0
- package/dist/components/overview/widgets/RecordListWidget.svelte +67 -3
- package/dist/components/overview/widgets/RecordListWidget.svelte.d.ts.map +1 -1
- package/dist/components/overview/widgets/RecordTable.svelte +167 -0
- package/dist/components/overview/widgets/RecordTable.svelte.d.ts +21 -0
- package/dist/components/overview/widgets/RecordTable.svelte.d.ts.map +1 -0
- package/dist/components/overview/widgets/RelatedWidget.svelte +117 -0
- package/dist/components/overview/widgets/RelatedWidget.svelte.d.ts +6 -0
- package/dist/components/overview/widgets/RelatedWidget.svelte.d.ts.map +1 -0
- package/dist/components/overview/widgets/core.d.ts +13 -2
- package/dist/components/overview/widgets/core.d.ts.map +1 -1
- package/dist/components/overview/widgets/core.js +43 -2
- package/dist/components/overview/widgets/data.d.ts +97 -8
- package/dist/components/overview/widgets/data.d.ts.map +1 -1
- package/dist/components/overview/widgets/line-totals.d.ts +48 -0
- package/dist/components/overview/widgets/line-totals.d.ts.map +1 -0
- package/dist/components/overview/widgets/line-totals.js +91 -0
- package/dist/components/overview/widgets/record-loaders.d.ts +63 -0
- package/dist/components/overview/widgets/record-loaders.d.ts.map +1 -0
- package/dist/components/overview/widgets/record-loaders.js +150 -0
- package/dist/components/overview/widgets/record-table.d.ts +45 -0
- package/dist/components/overview/widgets/record-table.d.ts.map +1 -0
- package/dist/components/overview/widgets/record-table.js +201 -0
- package/dist/components/overview/widgets/record-widgets.d.ts +27 -0
- package/dist/components/overview/widgets/record-widgets.d.ts.map +1 -0
- package/dist/components/overview/widgets/record-widgets.js +100 -0
- package/dist/components/screens/DetailScreen.svelte +105 -6
- package/dist/components/screens/DetailScreen.svelte.d.ts.map +1 -1
- package/dist/components/screens/EditForm.svelte +39 -3
- package/dist/components/screens/EditForm.svelte.d.ts.map +1 -1
- package/dist/components/screens/RecipeScreens.svelte +18 -18
- package/dist/components/screens/RecipeScreens.svelte.d.ts.map +1 -1
- package/dist/components/screens/RecordHeader.svelte +238 -0
- package/dist/components/screens/RecordHeader.svelte.d.ts +26 -0
- package/dist/components/screens/RecordHeader.svelte.d.ts.map +1 -0
- package/dist/components/screens/RecordScreen.svelte +511 -0
- package/dist/components/screens/RecordScreen.svelte.d.ts +5 -0
- package/dist/components/screens/RecordScreen.svelte.d.ts.map +1 -0
- package/dist/components/screens/columns.d.ts +29 -0
- package/dist/components/screens/columns.d.ts.map +1 -0
- package/dist/components/screens/columns.js +115 -0
- package/dist/components/screens/fields.d.ts +12 -2
- package/dist/components/screens/fields.d.ts.map +1 -1
- package/dist/components/screens/fields.js +37 -5
- package/dist/components/screens/index.d.ts +7 -2
- package/dist/components/screens/index.d.ts.map +1 -1
- package/dist/components/screens/index.js +6 -1
- package/dist/components/screens/record-header.d.ts +51 -0
- package/dist/components/screens/record-header.d.ts.map +1 -0
- package/dist/components/screens/record-header.js +118 -0
- package/dist/components/screens/relations.d.ts +49 -0
- package/dist/components/screens/relations.d.ts.map +1 -0
- package/dist/components/screens/relations.js +98 -0
- package/dist/components/screens/roles.d.ts +56 -0
- package/dist/components/screens/roles.d.ts.map +1 -0
- package/dist/components/screens/roles.js +174 -0
- package/dist/components/screens/types.d.ts +182 -1
- package/dist/components/screens/types.d.ts.map +1 -1
- package/dist/components/screens/values.d.ts +23 -1
- package/dist/components/screens/values.d.ts.map +1 -1
- package/dist/components/screens/values.js +80 -4
- package/dist/i18n/strings.overview.d.ts +25 -0
- package/dist/i18n/strings.overview.d.ts.map +1 -1
- package/dist/i18n/strings.overview.js +25 -0
- package/dist/i18n/strings.screens.d.ts +8 -0
- package/dist/i18n/strings.screens.d.ts.map +1 -1
- package/dist/i18n/strings.screens.js +8 -0
- package/package.json +16 -16
package/AGENTS.md
CHANGED
|
@@ -15,12 +15,12 @@ subpath you are editing. This file keeps what holds in every module.
|
|
|
15
15
|
| `src/test-support/` + `__tests__/` | the golden-test harness and pattern for Svelte component tests | [agents/testing.md](agents/testing.md) |
|
|
16
16
|
| `src/components/import-export/` (`./import-export`) | `ImportExport` CSV/TSV import (column mapping, validation preview, error report) and export (column selection) driven by collection definitions + resolved field policy, over a pure Node-tested CSV layer (#3715) | [agents/import-export.md](agents/import-export.md) |
|
|
17
17
|
| `src/components/settings/` (`./settings`) | `SettingsCatalog`, `paginateSettingsCatalog`, and the summary-vs-detail scalability contract | [agents/settings.md](agents/settings.md) |
|
|
18
|
-
| `src/components/screens/` (`./screens`) | `RecipeScreens` / `ListScreen` / `DetailScreen` / `EditForm`: list, view, create and edit derived from a generated web definition plus resolved field policy; pure `deriveScreenFields` selection, minor-unit money handling, transport-neutral source (#3718) | [agents/screens.md](agents/screens.md) |
|
|
18
|
+
| `src/components/screens/` (`./screens`) | `RecipeScreens` / `ListScreen` / `RecordScreen` / `DetailScreen` / `EditForm`: list, view, create and edit derived from a generated web definition plus resolved field policy; pure `deriveScreenFields` selection, `deriveFieldRoles` (title / identifier / status / money / totals roles) and `deriveScreenRelations` (children / items / reference); the record page's header (identifier, status, key facts, overflow Delete), details card and overview, select / derived fields and an items slot in inline (desktop) or sheet (phone) editing; minor-unit money handling, transport-neutral source (#3718) | [agents/screens.md](agents/screens.md) |
|
|
19
19
|
| `src/components/app/` (`./app`) | `AppShell` (Provider + ThemeProvider + theme CSS + AdminShell + nav/dock slots), `OwnerSetupForm` (props-driven first-run owner form), `ShellSettingsPage`, `RuntimeDiagnosticsWebMcp`. Browser-only; no `$app/*` or server imports | [agents/workspace.md](agents/workspace.md#app-shell-and-owner-setup-app) |
|
|
20
20
|
| `src/components/workspace/` (`./workspace` + `./web`) | the AdminShell family and its principles, the legacy ToolsDock surface, the `./web` activity-feed and `updateAvailable` adapters, and server-side dock gates | [agents/workspace.md](agents/workspace.md) |
|
|
21
21
|
| `src/components/command-palette/` (`./command-palette`) | `CommandPalette` trigger + dialog, `PaletteProvider` contract, nav and manifest providers (#3713) | [agents/command-palette.md](agents/command-palette.md) |
|
|
22
22
|
| `src/components/cookbook/` (`./cookbook` + `./cookbook/server`) | cookbook-driven app shell: pure `buildCookbookShell` (cookbook + recipe catalog to `AppShell` sections, entries, layout, theme, section overviews, recipe surfaces), `CookbookApp` / `CookbookSectionPage`, and the server `loadCookbookApp` (file + installed manifests + validation); ported from smrt-planner (#3749) | [agents/cookbook-shell.md](agents/cookbook-shell.md) |
|
|
23
|
-
| `src/components/overview/` (`./overview` + `./overview/server`) | customizable overview surfaces: `OverviewGrid` flow grid (span 1-4, keyboard reorder/resize) joined to the shell's layout edit mode, host-owned `createOverview` controller, widget registry with versioned option schemas validated on save and load, the server `load(options, ctx)` contract (`loadOverview`), the metric/chart/records/shortcuts/note core widgets, and `registerRecipeWidgets` (recipe `widget` surfaces to registry registrations, injected module resolver) (#3727); production persistence is `@happyvertical/smrt-preferences` (kind `overview`) | [agents/overview-surfaces.md](agents/overview-surfaces.md) |
|
|
23
|
+
| `src/components/overview/` (`./overview` + `./overview/server`) | customizable overview surfaces: `OverviewGrid` flow grid (span 1-4, keyboard reorder/resize) joined to the shell's layout edit mode, host-owned `createOverview` controller, widget registry with versioned option schemas validated on save and load, the server `load(options, ctx)` contract (`loadOverview`), the metric/chart/records/shortcuts/note core widgets (records as a role-column table with a `DataTable` summaries footer), the record-page `related` (tabbed) and `line-items` (totals block) widgets, and `registerRecipeWidgets` (recipe `widget` surfaces to registry registrations, injected module resolver) (#3727); production persistence is `@happyvertical/smrt-preferences` (kind `overview`) | [agents/overview-surfaces.md](agents/overview-surfaces.md) |
|
|
24
24
|
| `src/web/remote-query.svelte.ts` | Svelte 5 binding for query-shaped remote pages: rows, page, totals, loading/refreshing/stale/error, retry, last-updated, and query-scoped live subscriptions (#2445) | — |
|
|
25
25
|
| `src/web/list-data-surface.svelte.ts` (`mountListDataSurface`) | Registers an existing non-`DataTable` list (mirroring a `DataTableController`) as a mounted `DataSurfaceDescriptor`; a same-behavior port of `registerContentListDataSurface`, not yet unified behind smrt-ui (#2917). The module doc comment is the authoritative list of divergences (#2906) | — |
|
|
26
26
|
| `src/web/webmcp-provider.ts` | Provider config for generated data/model WebMCP tools: definitions, effect policy, namespace, budget, legacy/canonical filters, and fetcher seams (#2520) | — |
|
package/README.md
CHANGED
|
@@ -708,13 +708,13 @@ importable, even if it appears in `dist/`.
|
|
|
708
708
|
| `@happyvertical/smrt-svelte/forms` | Form inputs (TextInput, Select, MoneyInput, DateTimeInput, Toggle, etc.) |
|
|
709
709
|
| `@happyvertical/smrt-svelte/import-export` | `ImportExport` (CSV/TSV import with column mapping, validation preview and error report; export with column selection), `createCollectionImportExport`, `fieldsFromCollectionDefinition`, and the pure CSV layer |
|
|
710
710
|
| `@happyvertical/smrt-svelte/settings` | Server-paged settings search, selection, and list/detail layout (`SettingsCatalog`, `paginateSettingsCatalog`) |
|
|
711
|
-
| `@happyvertical/smrt-svelte/screens` | List, view, create and edit screens derived from a generated web definition and resolved field policy (`RecipeScreens`, `ListScreen`, `DetailScreen`, `EditForm`) |
|
|
711
|
+
| `@happyvertical/smrt-svelte/screens` | List, view, create and edit screens derived from a generated web definition and resolved field policy (`RecipeScreens`, `ListScreen`, `RecordScreen`, `DetailScreen`, `EditForm`); `RecordScreen` is the record view with a customizable related-records overview and inline (desktop) or sheet (phone) editing, `deriveScreenRelations` its relation rule |
|
|
712
712
|
| `@happyvertical/smrt-svelte/workspace` | AdminShell, ShellState, tenant nav, focus tools, settings, activities, and system/app panels |
|
|
713
713
|
| `@happyvertical/smrt-svelte/app` | `AppShell` (Provider + themes + AdminShell + nav/dock slots, `dockToggles` buttons and host `slots` for the header/footer/sidebar regions), `OwnerSetupForm` (first-run owner setup), `ShellSettingsPage`, `RuntimeDiagnosticsWebMcp` |
|
|
714
714
|
| `@happyvertical/smrt-svelte/app/runtime-diagnostics` | Svelte-free diagnostics WebMCP registration and its tool name/endpoint constants, importable from server routes |
|
|
715
715
|
| `@happyvertical/smrt-svelte/command-palette` | Global search and command palette: `CommandPalette` (shell-slot trigger plus dialog), `createCommandPalette`, the provider contract, and the navigation and manifest-driven model providers |
|
|
716
716
|
| `@happyvertical/smrt-svelte/overview` | Customizable overview surfaces: `OverviewGrid` (flow grid with keyboard reorder and resize), `createOverview` (host-owned controller), the widget registry (`registerWidget`), `registerCoreWidgets` (metric, chart, record list, shortcuts, note) and `shortcutsFromNav` |
|
|
717
|
-
| `@happyvertical/smrt-svelte/overview/server` | Svelte-free half of the overview surface: the data model (`resolveOverview`, `checkOverviewOverride`), option-schema validation, `WidgetRegistry`, and `loadOverview` for a page's server load |
|
|
717
|
+
| `@happyvertical/smrt-svelte/overview/server` | Svelte-free half of the overview surface: the data model (`resolveOverview`, `checkOverviewOverride`), option-schema validation, `WidgetRegistry`, and `loadOverview` for a page's server load; `recordOverview` / `recordOverviewId` (the record view's default overview, per model kind) |
|
|
718
718
|
| `@happyvertical/smrt-svelte/workspace/legacy` | Opt-in ToolsDock compatibility surface for applications migrating to AdminShell |
|
|
719
719
|
| `@happyvertical/smrt-svelte/workspace/server` | Server-side workspace helpers (Node only) |
|
|
720
720
|
| `@happyvertical/smrt-svelte/workspace/live` | `systemFeed` — the AdminShell system scope (jobs/schedules/dispatch) polled from an app status endpoint; deliberately carries no `smrt-web` dependency |
|
|
@@ -113,10 +113,26 @@ return { overview }; // LoadedOverview: JSON, serializable
|
|
|
113
113
|
|
|
114
114
|
- A widget's `load(options, ctx)` receives **validated options only** and a
|
|
115
115
|
`WidgetLoadContext` the host built from the request principal: `overviewId`, an
|
|
116
|
-
abort `signal`, `locale`,
|
|
116
|
+
abort `signal`, `locale`, the optional core `record` key (below), and any host
|
|
117
|
+
capabilities (index keys). It must
|
|
117
118
|
authorize through `ctx` (the user's permissions and tenant filters), never
|
|
118
119
|
through option values. Reports-backed chart loaders call the runtime-report
|
|
119
120
|
compiler with this context; this package does not depend on it.
|
|
121
|
+
- **`ctx.record = { model, id }`** is a core capability key: the record a
|
|
122
|
+
record overview is rendered on (`RecordScreen` sets it from the screen's
|
|
123
|
+
definition `objectRef` and the record's id; a host's server load sets it the
|
|
124
|
+
same way for a record page). With it comes the **parent-filter vocabulary**
|
|
125
|
+
of the core `records` and `metric` loaders: `filter: 'parent'` plus `field`
|
|
126
|
+
(the FK field on `options.model`) mean "rows of `model` whose `field` equals
|
|
127
|
+
`ctx.record.id`" — a count for `metric`, the newest rows for `records`
|
|
128
|
+
(`sort` / `direction` / `limit` as usual). A `metric` with `parentField`
|
|
129
|
+
uses that as the FK and measures `field` (`measure: 'sum'`, `field:
|
|
130
|
+
'totalAmount'`, `parentField: 'customerId'`: the record's order total). A
|
|
131
|
+
`records` load may carry `columns` (comma-separated keys; fill each row's
|
|
132
|
+
`cells`). A loader given `filter: 'parent'`
|
|
133
|
+
without `ctx.record` or `field` must return an empty result, never the
|
|
134
|
+
unfiltered model. The shell's own loaders need no data access: hosts
|
|
135
|
+
implement it, the same way they implement every other named filter.
|
|
120
136
|
- Loads run in parallel with a per-widget timeout (default 8 s; the signal
|
|
121
137
|
aborts). A thrown error, a timeout or non-serializable / oversized data
|
|
122
138
|
(default 256 KB of JSON) becomes a per-widget error tile
|
|
@@ -197,9 +213,9 @@ shape. Data shapes are in `widgets/data.ts`.
|
|
|
197
213
|
|
|
198
214
|
| Type | Options | Data |
|
|
199
215
|
|---|---|---|
|
|
200
|
-
| `metric` | `title`, `model`*, `measure`, `field`, `filter` | `{ value, format?, currency?, label?, change?, href? }` (money = integer minor units) |
|
|
216
|
+
| `metric` | `title`, `model`*, `measure`, `field`, `filter`, `parentField` | `{ value, format?, currency?, label?, change?, href? }` (money = integer minor units) |
|
|
201
217
|
| `chart` | `title`, `model`*, `groupBy`, `measure`, `field`, `period`, `style` (bar/line/table/pie/stat), `filter` | `{ points: [{ label, value }], format?, currency?, href?, delta? }`, one measure of a runtime report |
|
|
202
|
-
| `records` | `title`, `model`*, `sort`, `direction`, `limit`, `filter` | `{ rows: [{ id, title, subtitle?, meta?, href? }], total?, href? }`; the loader chooses the title field and the visible records |
|
|
218
|
+
| `records` | `title`, `model`*, `sort`, `field`, `direction`, `limit`, `filter`, `columns`, `summaries` | `{ rows: [{ id, title, subtitle?, meta?, href?, cells? }], total?, href?, columns?, currency?, timeZone?, summaries? }`; the loader chooses the title field and the visible records; `field` is the FK for `filter: 'parent'`; with columns (the option, else `data.columns`) the rows are a table — see "Records tables" |
|
|
203
219
|
| `shortcuts` | `title`, `section` | `{ items: [{ id, label, href, icon?, description?, count? }] }` (`count` draws as "N records"; widgets also receive the grid's `presentation` and the shortcuts widget drops its entry frame under `plain`); `shortcutsFromNav(sections, sectionId)` maps `resolveShellNavModel` / `useShellLayout().sections` (visible entries, user renames) |
|
|
204
220
|
| `note` | `title`, `body` (Markdown) | none |
|
|
205
221
|
|
|
@@ -219,6 +235,64 @@ else derived from the last two points). Motion honours `prefers-reduced-motion`.
|
|
|
219
235
|
The chart option schema is **version 2**: v1 (`style` bar or line, or no version)
|
|
220
236
|
migrates by identity (`migrateChartOptions`), so saved overviews keep validating.
|
|
221
237
|
|
|
238
|
+
## Records tables (`widgets/RecordTable.svelte`, `widgets/record-table.ts`)
|
|
239
|
+
|
|
240
|
+
The `records` widget with columns, each `related` tab and `line-items` render
|
|
241
|
+
one internal `RecordTable`: smrt-ui `DataTable` (dense, `phoneLayout="cards"`)
|
|
242
|
+
with cells by `RecordListColumn.role` — `identifier` monospace, `status` a
|
|
243
|
+
`Badge` (`statusTone`), `date` date-only in `data.timeZone` (default UTC, so
|
|
244
|
+
SSR and the browser agree; a non-ISO string is shown as sent), `money` from
|
|
245
|
+
integer minor units in `data.currency`, `quantity` a number — and the first
|
|
246
|
+
column linking to the row's `href`. The footer is `DataTable`'s `summaries`
|
|
247
|
+
(no per-widget footer code): the count (`total`, else the rows) in the first
|
|
248
|
+
column and the sum of every `money` / `quantity` column unless
|
|
249
|
+
`summarize: false` (a unit price). **A partial page is never summed**: when
|
|
250
|
+
`total` exceeds the rows, a sum cell is empty unless the loader sent
|
|
251
|
+
`summaries` (totals over every matching record, money in minor units). The
|
|
252
|
+
`columns` option is a comma-separated list because options are flat JSON
|
|
253
|
+
primitives (`parseColumnsOption` / `formatColumnsOption`, at most 6 keys);
|
|
254
|
+
labels and roles come from `data.columns`, else a humanized key. Pure,
|
|
255
|
+
Node-tested helpers: `formatRecordCell`, `statusTone` /
|
|
256
|
+
`DEFAULT_STATUS_TONES`, `statusLabel`, `resolveRecordColumns`,
|
|
257
|
+
`readRecordRows`, `isSummedColumn`.
|
|
258
|
+
|
|
259
|
+
## Record-page widgets (`related`, `line-items`; `widgets/record-loaders.ts`)
|
|
260
|
+
|
|
261
|
+
Built from the record's relations, so they register per record view —
|
|
262
|
+
`registerRecordWidgets(registry, { relations, records, viewAllHref?,
|
|
263
|
+
totals?, currency? })`; `RecordScreen` does it on its own registry when
|
|
264
|
+
`loaders.records` is given. **Loader contract: no new loader.** Each tab /
|
|
265
|
+
the lines are one call of the host's core `records` loader with the
|
|
266
|
+
parent-filter vocabulary (`model`, `field`, `filter: 'parent'`, `sort`,
|
|
267
|
+
`direction`, `limit`, `columns`), so a host that implements parent-filtered
|
|
268
|
+
`records` implements both. Loaders are Svelte-free on both entries
|
|
269
|
+
(`createRelatedLoader`, `createLineItemsLoader`, `relatedRelations`,
|
|
270
|
+
`relatedTabOptions`, `lineItemsRelation`, `lineItemsOptions`).
|
|
271
|
+
|
|
272
|
+
| Type | Options | Data |
|
|
273
|
+
|---|---|---|
|
|
274
|
+
| `related` | `title`, `relations` (relation keys `Order-customerId`, comma-separated; empty = every `children` relation, at most 20), `limit` (5) | `{ tabs: [{ key, label, rows, total?, columns, href?, currency?, timeZone?, summaries? }] }` |
|
|
275
|
+
| `line-items` | `title`, `relation` (an `items` relation key; empty = the first), `limit` (50, the max) | `{ rows, columns, total?, totals?: { subtotal?, discount?, tax?, total? }, currency?, summaries?, href? }` |
|
|
276
|
+
|
|
277
|
+
- `related`: one tab per relation with the count in the tab ("Orders 6"),
|
|
278
|
+
each a records table with a totals footer and that tab's one "View all"
|
|
279
|
+
(`viewAllHref`, else the loaded `href`). Relations with no rows are hidden;
|
|
280
|
+
all empty is one empty state. A failing tab is dropped; all failing fails
|
|
281
|
+
the widget. Never lists `items` relations.
|
|
282
|
+
- `line-items` (the contract's `lineItems`; widget type ids are lowercase
|
|
283
|
+
kebab): the lines in `sort` order, then the totals block
|
|
284
|
+
(`lineItemTotals`, pure). The record's own subtotal / discount / tax /
|
|
285
|
+
total are authoritative and shown as they are; one it lacks is computed
|
|
286
|
+
from the lines (subtotal = sum of the line amounts, total = subtotal -
|
|
287
|
+
discount + tax) and marked "(from the lines)"; discount and tax show when
|
|
288
|
+
present and non-zero. When the record's subtotal (or, without one, its
|
|
289
|
+
total) disagrees with the lines, a visible flag says "Lines add up to $X."
|
|
290
|
+
beside the recorded figure — never a silent override. A partial page of
|
|
291
|
+
lines is not compared.
|
|
292
|
+
- Tests: `__tests__/record-table.test.ts`, `__tests__/record-widgets.test.ts`,
|
|
293
|
+
`__tests__/line-items.test.ts` (axe on both components), the records cases
|
|
294
|
+
in `__tests__/widgets.test.ts`.
|
|
295
|
+
|
|
222
296
|
## Recipe widgets (`recipe-widgets.ts`)
|
|
223
297
|
|
|
224
298
|
A package contributes a widget with a `widget` surface on a recipe
|
|
@@ -250,7 +324,8 @@ turns the manifest's widget surfaces into `registry.register(...)` calls:
|
|
|
250
324
|
- **`enabled(recipeId)`** keeps widgets of recipes that are off out of the add
|
|
251
325
|
list. Call the helper again (after `dispose()`) when the set changes.
|
|
252
326
|
- Widget types share one registry namespace with the core widgets
|
|
253
|
-
(`metric`, `chart`, `records`, `shortcuts`, `note`)
|
|
327
|
+
(`metric`, `chart`, `records`, `shortcuts`, `note`) and the record-page
|
|
328
|
+
widgets (`related`, `line-items`). Pages still confine what
|
|
254
329
|
can appear with `defineOverview({ allowed })`, and a widget with `allowedIn`
|
|
255
330
|
only validates inside those overview ids.
|
|
256
331
|
- `src/components/overview/__tests__/recipe-widgets.test.ts` covers lazy
|
|
@@ -374,6 +449,35 @@ and the person can undo the change.
|
|
|
374
449
|
`createOverviewStore(...).save` as shown there.
|
|
375
450
|
- **Not built:** the activity widget (Track B, #3710) and agenda.
|
|
376
451
|
|
|
452
|
+
## Record overviews (`record.ts`)
|
|
453
|
+
|
|
454
|
+
`recordOverview(definition, relations, { id?, metrics?, maxMetrics?,
|
|
455
|
+
related? })` (both entries) is the default overview of a record page:
|
|
456
|
+
|
|
457
|
+
1. **Summary strip** (`metrics`, default on): `metric` tiles of span 1, a
|
|
458
|
+
count per `children` relation (`field` = the FK) and, where its columns
|
|
459
|
+
have a money column, the sum of it (`measure: 'sum'`, `field` = the
|
|
460
|
+
amount, `parentField` = the FK), at most `maxMetrics`
|
|
461
|
+
(`RECORD_OVERVIEW_MAX_METRICS` = 4). Ordinary widgets: removable.
|
|
462
|
+
2. **`line-items`** (span 4) for the first `items` relation.
|
|
463
|
+
3. **`related`** (span 4, id `related`) over the `children` relations;
|
|
464
|
+
`related: 'panels'` instead declares one `records` panel per relation
|
|
465
|
+
(span `RECORD_OVERVIEW_PANEL_SPAN` = 2, newest five, `columns` from the
|
|
466
|
+
relation) — the previous default.
|
|
467
|
+
|
|
468
|
+
Default widget ids come from the relation (`count-Order-customerId`,
|
|
469
|
+
`sum-...`, `items-OrderLine-orderId`, `records-...`; a `-2` suffix tells apart
|
|
470
|
+
two that fold alike), not their position, so a host that narrows the defaults
|
|
471
|
+
keeps every id, and added widgets (`w<n>`) never collide with a hidden
|
|
472
|
+
default; `models` confines added widgets to the child models and `allowed` is
|
|
473
|
+
`RECORD_OVERVIEW_ALLOWED` (`related`, `line-items`, `records`, `metric`,
|
|
474
|
+
`chart`, `note`). The id defaults to `recordOverviewId(definition.objectRef)`
|
|
475
|
+
— `detail:<model>` with `@`, `/` and `:` folded to dots
|
|
476
|
+
(`detail:acme.shop.Customer`), because a qualified model id is not a valid
|
|
477
|
+
overview id — so the layout persists **per model kind**, not per record.
|
|
478
|
+
`RecordScreen` renders it with `presentation="plain"` and extends the widget
|
|
479
|
+
context with `record`.
|
|
480
|
+
|
|
377
481
|
## Host section presentation
|
|
378
482
|
|
|
379
483
|
`OverviewGrid` defaults to framed cards. Pass `presentation="plain"` for
|
package/agents/screens.md
CHANGED
|
@@ -8,8 +8,9 @@ invariants, and the traps that apply before editing anything live in
|
|
|
8
8
|
|
|
9
9
|
`RecipeScreens` is the default screen set for a package that ships models but no
|
|
10
10
|
consumer UI (tags, facts, secrets, profiles, reports, prompts). It composes
|
|
11
|
-
`ListScreen`, `
|
|
12
|
-
|
|
11
|
+
`ListScreen`, `RecordScreen` (the record view, which itself composes
|
|
12
|
+
`DetailScreen`, `OverviewGrid` and `EditForm`) and `EditForm` (create), each of
|
|
13
|
+
which can also be used on its own. Every screen takes a generated web `definition`
|
|
13
14
|
(`ScreenCollectionDefinition`, structurally a `SmrtWebCollectionDefinition`) and
|
|
14
15
|
an optional resolved `policy` (`ScreenPolicy`, structurally smrt-fields'
|
|
15
16
|
`ResolvedObjectFieldPolicy`). The module imports neither package: smrt-svelte
|
|
@@ -34,14 +35,25 @@ stays below the domain layer, and the app passes both in as props.
|
|
|
34
35
|
policy default (an explicit `null` included) beats the manifest default.
|
|
35
36
|
`locked` governs who may change the POLICY, never the record value, so it is
|
|
36
37
|
not applied here.
|
|
37
|
-
- **Values are `values.ts`**: money (
|
|
38
|
-
|
|
38
|
+
- **Values are `values.ts`**: money (an INTEGER field with the `money` role —
|
|
39
|
+
`ui.format: 'money'`, the legacy `ui.widget: 'currency'`, an explicit role,
|
|
40
|
+
or a money name; see "Field roles") is integer minor units end to end. Editing shows major units but converts
|
|
39
41
|
with exact string math (`majorStringToMinorUnits`), never `* 100`; integers are
|
|
40
42
|
rejected unless JavaScript-safe; datetimes go out as ISO strings (an unchanged datetime keeps the
|
|
41
43
|
loaded record's full precision via `parseDraft`'s `record` context; the control
|
|
42
|
-
only shows minutes); JSON as parsed values.
|
|
44
|
+
only shows minutes); JSON as parsed values. For display an empty JSON
|
|
45
|
+
object/array (or one whose values are all blank) formats as `''`, the
|
|
46
|
+
"Not set" placeholder, and `DetailScreen` lists a non-empty object as
|
|
47
|
+
key/value rows (`jsonScreenEntries`). Empty optional text becomes `null` when the field is nullable and `''`
|
|
43
48
|
otherwise (unset text persists as `''`); every other empty optional field is
|
|
44
49
|
`null`. Errors are codes, mapped to messages by the component via `useI18n`.
|
|
50
|
+
- **Reference fields link (`relations`, `hrefFor`, `labels`).** `DetailScreen`
|
|
51
|
+
renders a `foreignKey` / `crossPackageRef` value as `<a href={hrefFor(field,
|
|
52
|
+
id)}>{labels[model](id)}</a>`; without an href the label alone, without a
|
|
53
|
+
label a shortened id (`shortScreenId`: first eight characters and `…`) in
|
|
54
|
+
`<code>` with the full id as its tooltip, inside the link when there is one. `labels` is keyed by the **target model id**,
|
|
55
|
+
which the screen finds through the `reference` relations (below), so pass
|
|
56
|
+
`relations` whenever you pass `labels`.
|
|
45
57
|
- **Transport-neutral.** `RecipeScreens` drives a `RecipeScreensSource`
|
|
46
58
|
(`list` / `get` / `create` / `update` / `delete`); an operation the source lacks
|
|
47
59
|
(or `can` turns off) is simply not offered, so a read-only source is a
|
|
@@ -49,6 +61,13 @@ stays below the domain layer, and the app passes both in as props.
|
|
|
49
61
|
fires on every user navigation, so an app can mirror them into its router.
|
|
50
62
|
`EditForm.onsubmit` throws to report a failed save or returns `{ fieldErrors }`.
|
|
51
63
|
Remount `EditForm` with `{#key}` when switching records (`RecipeScreens` does).
|
|
64
|
+
- **`view` and `edit` are `RecordScreen`** (below); `create` stays the bare
|
|
65
|
+
`EditForm`. `onnavigate` is unchanged (`edit` is still a view of its own, so
|
|
66
|
+
a router maps it to `.../<id>/edit`). Pass `definitions` (every exposed
|
|
67
|
+
collection, keyed by name) for the related-records panels and `record`
|
|
68
|
+
(loaders, widget context, overview override and its `onoverviewchange`,
|
|
69
|
+
`hrefFor`, `labels`, `viewAllHref`) for the rest of the record view; without
|
|
70
|
+
`definitions` there are no relations and the view is the detail alone.
|
|
52
71
|
- **Not the policy-editing surface.** The policy gear, field-usage telemetry and
|
|
53
72
|
the per-field renderer registry live in `ObjectForm`
|
|
54
73
|
(`@happyvertical/smrt-fields/svelte`); `EditForm` is the dependency-light
|
|
@@ -60,3 +79,150 @@ stays below the domain layer, and the app passes both in as props.
|
|
|
60
79
|
`collectionDefinitions[<collection>]` from `@smrt/web` and the source is the
|
|
61
80
|
model's `/api/<collection>` route (see [cookbook-shell.md](cookbook-shell.md)).
|
|
62
81
|
A model the API does not expose has neither, so the entry page shows its notice.
|
|
82
|
+
|
|
83
|
+
## Field roles (`roles.ts`)
|
|
84
|
+
|
|
85
|
+
`deriveFieldRoles(definition)` is the pure, Node-tested rule for what a field
|
|
86
|
+
MEANS on a record page: `FieldRole` = `title | identifier | status | money |
|
|
87
|
+
quantity | date | party | subtotal | tax | discount | total`, several per field
|
|
88
|
+
(`totalAmount` -> `['money', 'total']`), one key per declared field. Sources in
|
|
89
|
+
order:
|
|
90
|
+
|
|
91
|
+
1. Explicit metadata on `ScreenFieldDefinition`: `role` (authoritative — name
|
|
92
|
+
heuristics never add to it), `format` (`money | date | datetime | percent`,
|
|
93
|
+
wins over `ui.format`), `display: true` (the `title`), `enum`.
|
|
94
|
+
2. Manifest hints: `ui.format`, and `ui.widget: 'currency'` on an INTEGER (on
|
|
95
|
+
a text field it is the currency-code picker, never money;
|
|
96
|
+
`currencyCodeField` finds it, and `RecordScreen` formats amounts in the
|
|
97
|
+
record's own currency).
|
|
98
|
+
3. Name heuristics: `*Amount|*Total|price|cost` -> money on integers only;
|
|
99
|
+
`subtotal|tax|discount|total` (not `*Rate`); `status|state` WITH an enum;
|
|
100
|
+
`number|reference|code` but not `phoneNumber` / `postalCode` /
|
|
101
|
+
`currencyCode`; `*At|*Date|*On|*Until` datetimes; `quantity|qty`; an FK
|
|
102
|
+
whose name or target collection is party-like (customer, vendor, profile,
|
|
103
|
+
...). Without a `display` field the first text `name|title|label|
|
|
104
|
+
displayName` is the title.
|
|
105
|
+
|
|
106
|
+
`deriveScreenFields` uses them: a text field with an `enum` is kind `select`
|
|
107
|
+
(`options`), money comes from the roles, and every `ScreenField` carries
|
|
108
|
+
`roles`. `formatScreenValue` shows `format: 'date'` without a time and
|
|
109
|
+
`format: 'percent'` as a percentage. Helpers: `fieldsWithRole`,
|
|
110
|
+
`fieldWithRole`, `isDocumentLike` (identifier plus party or total),
|
|
111
|
+
`hasLineItemRoles` (quantity plus money). Columns by role are
|
|
112
|
+
`screens/columns.ts`: `relatedColumns` (identifier or title, status, lead
|
|
113
|
+
date, party, amount) and `lineItemColumns` (item, quantity, unit price —
|
|
114
|
+
`summarize: false` —, amount).
|
|
115
|
+
|
|
116
|
+
## Relations (`relations.ts`)
|
|
117
|
+
|
|
118
|
+
`deriveScreenRelations(definitions, model)` is the pure, Node-tested rule for
|
|
119
|
+
what a record view shows around a record. `definitions` is every exposed
|
|
120
|
+
collection definition keyed by collection name (`collectionDefinitions` from
|
|
121
|
+
`@smrt/web`); `model` is a qualified `objectRef` (or a key of the map). It
|
|
122
|
+
reads the generated `relationships` edges (`ScreenRelationshipDefinition`:
|
|
123
|
+
`field`, `kind`, `relatedCollection` — a collection **name**, resolved by map
|
|
124
|
+
key, then by `name`), so a definition without `relationships` has no
|
|
125
|
+
relations. A `ScreenRelation` is `{ model, field, label, kind, columns?, sort? }`
|
|
126
|
+
(`relationKey(relation)` = `Order-customerId`):
|
|
127
|
+
|
|
128
|
+
| `kind` | Meaning | `model` | `field` | `label` |
|
|
129
|
+
|---|---|---|---|---|
|
|
130
|
+
| `children` | another collection with a `foreignKey` / `crossPackageRef` edge targeting this model | the child's `objectRef` | the FK on the child | the child's plural title; two FKs to the same parent disambiguate as `Orders (Approver)` |
|
|
131
|
+
| `items` | a `children` edge marked `relationships[].role: 'items'` (core `@foreignKey(T, { role: 'items' })`), or a child with line-item roles and one FK here | as `children` | as `children` | as `children` |
|
|
132
|
+
| `reference` | one of this model's own FK edges | the target's `objectRef` | the FK on this model | the field label (`ownerId` -> `Owner`) |
|
|
133
|
+
|
|
134
|
+
`items` come first, then `children`, each sorted by label, then `reference`
|
|
135
|
+
in declaration order. `children` carry `relatedColumns`, `items`
|
|
136
|
+
`lineItemColumns` and a line `sort` (`sortOrder`, `position`, `lineNumber`,
|
|
137
|
+
`sequence`, else `createdAt`).
|
|
138
|
+
Edges whose target or source is not in `definitions` are skipped (an unexposed
|
|
139
|
+
model has no route to link to), as are `oneToMany` / `manyToMany` edges and
|
|
140
|
+
edges whose field the definition does not carry.
|
|
141
|
+
|
|
142
|
+
## RecordScreen (`RecordScreen.svelte`, `./screens`)
|
|
143
|
+
|
|
144
|
+
The record page: a header, a details card, a customizable `OverviewGrid`
|
|
145
|
+
below, and the edit form as a **mode** of the same screen. Props are
|
|
146
|
+
`RecordScreenProps` in `types.ts`.
|
|
147
|
+
|
|
148
|
+
- **Header anatomy (`RecordHeader.svelte`, model `deriveRecordHeader` in
|
|
149
|
+
`record-header.ts`).** A small back link above the title; the heading is
|
|
150
|
+
`title`, else a document's kind and identifier ("Order GRA-3159",
|
|
151
|
+
identifier monospace — never the party), else the title-role field, else
|
|
152
|
+
the identifier, else the class name; a non-document's identifier shows as
|
|
153
|
+
a monospace chip; the status is a `Badge` toned by value (`statusTones`,
|
|
154
|
+
else `DEFAULT_STATUS_TONES`, else neutral); two to four key facts by role
|
|
155
|
+
(party link, lead date shown date-only, total money, then email / phone).
|
|
156
|
+
It reads only the view fields, so a field the policy omits never reaches
|
|
157
|
+
the header. Actions: Edit is the one primary button (hidden while
|
|
158
|
+
editing); a "More actions" popover holds `extraActions` and Delete, which
|
|
159
|
+
still confirms.
|
|
160
|
+
- **Details card.** `DetailScreen` with `variant="card"`, `hideEmpty` (empty
|
|
161
|
+
fields behind "Show empty fields (n)") and `exclude`: what the header
|
|
162
|
+
shows, the currency-code field, and — when the model has an `items`
|
|
163
|
+
relation — the subtotal / discount / tax / total role fields, which the
|
|
164
|
+
line-items totals block shows instead. `children` render inside the card.
|
|
165
|
+
- **Body = `recordOverview(definition, relations)`** unless an `overview` is
|
|
166
|
+
passed: the summary strip, `line-items`, then `related` (see
|
|
167
|
+
[overview-surfaces.md](overview-surfaces.md#record-overviews-recordts)),
|
|
168
|
+
persisted **per model kind** under `recordOverviewId(objectRef)`
|
|
169
|
+
(`detail:acme.shop.Customer`). The grid renders `presentation="plain"`,
|
|
170
|
+
follows the shell's layout editor unless `layoutEditing` is passed, and
|
|
171
|
+
offers the child models in its add dialog. `override` / `onoverviewchange`
|
|
172
|
+
are the host-owned persistence pair of `createOverview`
|
|
173
|
+
(`@happyvertical/smrt-preferences`, kind `overview`, in production); omit
|
|
174
|
+
`override` to keep edits in memory. With `loaders.records` the screen also
|
|
175
|
+
registers `related` and `line-items` (`registerRecordWidgets`) with the
|
|
176
|
+
record's totals (`recordTotals`) and currency.
|
|
177
|
+
- **Loaders run in the browser with the record context.** `loaders`
|
|
178
|
+
(`CoreWidgetLoaders`) are registered on a registry of the screen's own
|
|
179
|
+
(or pass `registry` with recipe widgets on it); each `load` receives
|
|
180
|
+
`widgetContext` extended with `overviewId`, the `signal`, `locale` and
|
|
181
|
+
`record: { model: definition.objectRef, id }`, and honours `filter:
|
|
182
|
+
'parent'` + `field` as overview-surfaces.md describes. A widget without a
|
|
183
|
+
loader is not registered, so a default needing it is dropped (reported,
|
|
184
|
+
never an error); without `loaders` the grid is empty. A record change
|
|
185
|
+
reloads every panel; the registry and overview are fixed at mount, so
|
|
186
|
+
remount (`{#key}`) to change the model kind — `RecipeScreens` keys on
|
|
187
|
+
`definition.objectRef`.
|
|
188
|
+
- **One heading per related panel.** A `records` widget whose `model` +
|
|
189
|
+
`field` + `filter: 'parent'` match a `children` relation (user-added ones
|
|
190
|
+
included) is headed `Orders · 3` (the loader's `total`, else its row count)
|
|
191
|
+
with the panel's only "View all": `viewAllHref(relation)`, else the loaded
|
|
192
|
+
`href`. The screen strips `total` / `href` from that widget's data, so the
|
|
193
|
+
body never repeats them. A `metric` widget keeps the plain title and no
|
|
194
|
+
link (its number links when its data has an `href`).
|
|
195
|
+
- **Edit form.** `EditForm` edits a `select` field with a smrt-ui `Select`
|
|
196
|
+
(humanized choices, "Not set" unless required, an out-of-list stored value
|
|
197
|
+
kept). `derivedFields` render read-only and formatted with "Worked out
|
|
198
|
+
from the line items." and are never in the payload; `RecordScreen` passes
|
|
199
|
+
its `derivedFields` prop, else the totals role fields when an `items`
|
|
200
|
+
relation exists. `items?: Snippet` (the host's line-items editor) renders
|
|
201
|
+
under the form, in the edit column on desktop and inside the edit sheet on
|
|
202
|
+
phones.
|
|
203
|
+
- **`mode: 'edit'`** keeps the detail rendered and adds `EditForm`
|
|
204
|
+
(`showHeader={false}`, keyed by record id, `fieldErrors` / `error` /
|
|
205
|
+
`submitting` / `onsave` as `EditFormProps`): on desktop (`min-width: 48rem`,
|
|
206
|
+
a `matchMedia` the screen watches; the server renders desktop) a sticky
|
|
207
|
+
`<aside>` in a `minmax(0, 1fr) minmax(20rem, 28rem)` grid beside the header,
|
|
208
|
+
sliding in with `--smrt-duration-medium1` / `--smrt-easing-standard` and
|
|
209
|
+
still under `prefers-reduced-motion`; on phones a `PhoneSheet
|
|
210
|
+
variant="page"` in a fixed full-screen `<section>` the screen owns (an
|
|
211
|
+
`AdminShell`'s `overlays` snippet is a shell prop a screen cannot reach, so
|
|
212
|
+
the screen stacks its own at `--smrt-z-index-modal`). The sheet stays
|
|
213
|
+
mounted while closed so it animates open; the form inside mounts only in
|
|
214
|
+
edit mode, so Cancel never keeps a stale draft. Cancel, the sheet's close
|
|
215
|
+
button and Escape all call `oncancel`; the detail's Edit action hides while
|
|
216
|
+
editing. `RecipeScreens` maps `onedit` to `navigate('edit', id)` and
|
|
217
|
+
`oncancel` / a saved `onsave` back to `view`.
|
|
218
|
+
- Strings: `ui.screens.view_all`, `ui.screens.related`, `more_actions`,
|
|
219
|
+
`details`, `show_empty`, `derived_hint`, `select_none`, `items`, and the
|
|
220
|
+
existing `ui.screens.edit_title` for the aside and sheet heading.
|
|
221
|
+
- Tests: `__tests__/roles.test.ts`, `__tests__/record-header.test.ts`,
|
|
222
|
+
`__tests__/relations.test.ts`, `__tests__/RecordScreen.test.ts` (header
|
|
223
|
+
anatomy, overflow Delete, details exclusions, line items and the mismatch
|
|
224
|
+
flag, derived fields and the items slot on both layouts, axe
|
|
225
|
+
in view and both edit layouts, the record context reaching every loader,
|
|
226
|
+
"View all" hrefs, host-owned override edits, record change reload) and the
|
|
227
|
+
link cases in `__tests__/DetailScreen.test.ts`; `overview/__tests__/record.test.ts`
|
|
228
|
+
and the parent-context case in `overview/__tests__/load.test.ts`.
|
|
@@ -18,9 +18,12 @@ export * from './server.js';
|
|
|
18
18
|
export { default as WidgetOptionsForm } from './WidgetOptionsForm.svelte';
|
|
19
19
|
export { default as ChartWidget } from './widgets/ChartWidget.svelte';
|
|
20
20
|
export { type CoreWidgetLoaders, createChartWidget, createMetricWidget, createNoteWidget, createRecordListWidget, createShortcutsWidget, registerCoreWidgets, } from './widgets/core.js';
|
|
21
|
-
export { type ChartWidgetData, type MetricWidgetData, type RecordListWidgetData, type ShortcutEntry, type ShortcutNavSection, type ShortcutsWidgetData, shortcutsFromNav, } from './widgets/data.js';
|
|
21
|
+
export { type ChartWidgetData, type LineItemsWidgetData, type MetricWidgetData, type RecordListColumn, type RecordListRow, type RecordListWidgetData, type RecordStatusTone, type RelatedWidgetData, type RelatedWidgetTab, type ShortcutEntry, type ShortcutNavSection, type ShortcutsWidgetData, shortcutsFromNav, } from './widgets/data.js';
|
|
22
|
+
export { default as LineItemsWidget } from './widgets/LineItemsWidget.svelte';
|
|
22
23
|
export { default as MetricWidget } from './widgets/MetricWidget.svelte';
|
|
23
24
|
export { default as NoteWidget } from './widgets/NoteWidget.svelte';
|
|
24
25
|
export { default as RecordListWidget } from './widgets/RecordListWidget.svelte';
|
|
26
|
+
export { default as RelatedWidget } from './widgets/RelatedWidget.svelte';
|
|
27
|
+
export { createLineItemsWidget, createRelatedWidget, registerRecordWidgets, } from './widgets/record-widgets.js';
|
|
25
28
|
export { default as ShortcutsWidget } from './widgets/ShortcutsWidget.svelte';
|
|
26
29
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/overview/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,OAAO,EACL,uBAAuB,EACvB,iBAAiB,EACjB,KAAK,4BAA4B,EACjC,KAAK,sBAAsB,EAC3B,KAAK,wBAAwB,EAC7B,KAAK,2BAA2B,EAChC,yBAAyB,GAC1B,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EACL,cAAc,EACd,kBAAkB,EAClB,KAAK,yBAAyB,EAC9B,KAAK,gBAAgB,EACrB,KAAK,mBAAmB,GACzB,MAAM,wBAAwB,CAAC;AAChC,OAAO,EACL,KAAK,wBAAwB,EAC7B,iBAAiB,EACjB,KAAK,iBAAiB,GACvB,MAAM,aAAa,CAAC;AACrB,YAAY,EACV,iBAAiB,EACjB,iBAAiB,EACjB,mBAAmB,EACnB,sBAAsB,GACvB,MAAM,iBAAiB,CAAC;AACzB,OAAO,EACL,KAAK,SAAS,EACd,KAAK,UAAU,EACf,aAAa,EACb,QAAQ,GACT,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,OAAO,IAAI,qBAAqB,EAAE,MAAM,gCAAgC,CAAC;AAClF,OAAO,EAAE,OAAO,IAAI,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAChE,OAAO,EAAE,WAAW,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAC3D,cAAc,aAAa,CAAC;AAC5B,OAAO,EAAE,OAAO,IAAI,iBAAiB,EAAE,MAAM,4BAA4B,CAAC;AAC1E,OAAO,EAAE,OAAO,IAAI,WAAW,EAAE,MAAM,8BAA8B,CAAC;AACtE,OAAO,EACL,KAAK,iBAAiB,EACtB,iBAAiB,EACjB,kBAAkB,EAClB,gBAAgB,EAChB,sBAAsB,EACtB,qBAAqB,EACrB,mBAAmB,GACpB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EACL,KAAK,eAAe,EACpB,KAAK,gBAAgB,EACrB,KAAK,oBAAoB,EACzB,KAAK,aAAa,EAClB,KAAK,kBAAkB,EACvB,KAAK,mBAAmB,EACxB,gBAAgB,GACjB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAAE,OAAO,IAAI,YAAY,EAAE,MAAM,+BAA+B,CAAC;AACxE,OAAO,EAAE,OAAO,IAAI,UAAU,EAAE,MAAM,6BAA6B,CAAC;AACpE,OAAO,EAAE,OAAO,IAAI,gBAAgB,EAAE,MAAM,mCAAmC,CAAC;AAChF,OAAO,EAAE,OAAO,IAAI,eAAe,EAAE,MAAM,kCAAkC,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/overview/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,OAAO,EACL,uBAAuB,EACvB,iBAAiB,EACjB,KAAK,4BAA4B,EACjC,KAAK,sBAAsB,EAC3B,KAAK,wBAAwB,EAC7B,KAAK,2BAA2B,EAChC,yBAAyB,GAC1B,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EACL,cAAc,EACd,kBAAkB,EAClB,KAAK,yBAAyB,EAC9B,KAAK,gBAAgB,EACrB,KAAK,mBAAmB,GACzB,MAAM,wBAAwB,CAAC;AAChC,OAAO,EACL,KAAK,wBAAwB,EAC7B,iBAAiB,EACjB,KAAK,iBAAiB,GACvB,MAAM,aAAa,CAAC;AACrB,YAAY,EACV,iBAAiB,EACjB,iBAAiB,EACjB,mBAAmB,EACnB,sBAAsB,GACvB,MAAM,iBAAiB,CAAC;AACzB,OAAO,EACL,KAAK,SAAS,EACd,KAAK,UAAU,EACf,aAAa,EACb,QAAQ,GACT,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,OAAO,IAAI,qBAAqB,EAAE,MAAM,gCAAgC,CAAC;AAClF,OAAO,EAAE,OAAO,IAAI,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAChE,OAAO,EAAE,WAAW,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAC3D,cAAc,aAAa,CAAC;AAC5B,OAAO,EAAE,OAAO,IAAI,iBAAiB,EAAE,MAAM,4BAA4B,CAAC;AAC1E,OAAO,EAAE,OAAO,IAAI,WAAW,EAAE,MAAM,8BAA8B,CAAC;AACtE,OAAO,EACL,KAAK,iBAAiB,EACtB,iBAAiB,EACjB,kBAAkB,EAClB,gBAAgB,EAChB,sBAAsB,EACtB,qBAAqB,EACrB,mBAAmB,GACpB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EACL,KAAK,eAAe,EACpB,KAAK,mBAAmB,EACxB,KAAK,gBAAgB,EACrB,KAAK,gBAAgB,EACrB,KAAK,aAAa,EAClB,KAAK,oBAAoB,EACzB,KAAK,gBAAgB,EACrB,KAAK,iBAAiB,EACtB,KAAK,gBAAgB,EACrB,KAAK,aAAa,EAClB,KAAK,kBAAkB,EACvB,KAAK,mBAAmB,EACxB,gBAAgB,GACjB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAAE,OAAO,IAAI,eAAe,EAAE,MAAM,kCAAkC,CAAC;AAC9E,OAAO,EAAE,OAAO,IAAI,YAAY,EAAE,MAAM,+BAA+B,CAAC;AACxE,OAAO,EAAE,OAAO,IAAI,UAAU,EAAE,MAAM,6BAA6B,CAAC;AACpE,OAAO,EAAE,OAAO,IAAI,gBAAgB,EAAE,MAAM,mCAAmC,CAAC;AAChF,OAAO,EAAE,OAAO,IAAI,aAAa,EAAE,MAAM,gCAAgC,CAAC;AAC1E,OAAO,EACL,qBAAqB,EACrB,mBAAmB,EACnB,qBAAqB,GACtB,MAAM,6BAA6B,CAAC;AACrC,OAAO,EAAE,OAAO,IAAI,eAAe,EAAE,MAAM,kCAAkC,CAAC"}
|
|
@@ -18,7 +18,10 @@ export { default as WidgetOptionsForm } from './WidgetOptionsForm.svelte';
|
|
|
18
18
|
export { default as ChartWidget } from './widgets/ChartWidget.svelte';
|
|
19
19
|
export { createChartWidget, createMetricWidget, createNoteWidget, createRecordListWidget, createShortcutsWidget, registerCoreWidgets, } from './widgets/core.js';
|
|
20
20
|
export { shortcutsFromNav, } from './widgets/data.js';
|
|
21
|
+
export { default as LineItemsWidget } from './widgets/LineItemsWidget.svelte';
|
|
21
22
|
export { default as MetricWidget } from './widgets/MetricWidget.svelte';
|
|
22
23
|
export { default as NoteWidget } from './widgets/NoteWidget.svelte';
|
|
23
24
|
export { default as RecordListWidget } from './widgets/RecordListWidget.svelte';
|
|
25
|
+
export { default as RelatedWidget } from './widgets/RelatedWidget.svelte';
|
|
26
|
+
export { createLineItemsWidget, createRelatedWidget, registerRecordWidgets, } from './widgets/record-widgets.js';
|
|
24
27
|
export { default as ShortcutsWidget } from './widgets/ShortcutsWidget.svelte';
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The default overview of a record view (#3718 record page), persisted per
|
|
3
|
+
* model kind under `detail:<model>`: a summary strip of `metric` tiles
|
|
4
|
+
* (a count per related relation, and the sum of its money column where it
|
|
5
|
+
* has one), then the `line-items` table and totals when the model has an
|
|
6
|
+
* `items` relation, then one tabbed `related` widget over the `children`
|
|
7
|
+
* relations. Every piece is an ordinary widget, so a person can remove,
|
|
8
|
+
* move or replace it from the layout editor; `related: 'panels'` keeps the
|
|
9
|
+
* earlier one `records` panel per relation.
|
|
10
|
+
*
|
|
11
|
+
* Svelte-free. The widgets use the parent-filter vocabulary: `filter:
|
|
12
|
+
* 'parent'` plus the FK on the child (`field` for a count or a records
|
|
13
|
+
* panel; `parentField` when `field` is the measured one) confine the
|
|
14
|
+
* host's query to rows that point at `ctx.record.id`. `related` and
|
|
15
|
+
* `line-items` load through the host's `records` loader
|
|
16
|
+
* (`registerRecordWidgets`), so the shell's own loaders need no data access.
|
|
17
|
+
*/
|
|
18
|
+
import type { ScreenRelation } from '../screens/relations.js';
|
|
19
|
+
import type { ScreenCollectionDefinition } from '../screens/types.js';
|
|
20
|
+
import type { OverviewDefinition } from './types.js';
|
|
21
|
+
export interface RecordOverviewOptions {
|
|
22
|
+
/** Overview id; defaults to `recordOverviewId(definition.objectRef)`. */
|
|
23
|
+
id?: string;
|
|
24
|
+
/** The summary strip of `metric` tiles (default on). */
|
|
25
|
+
metrics?: boolean;
|
|
26
|
+
/** Most tiles in the strip (default {@link RECORD_OVERVIEW_MAX_METRICS}). */
|
|
27
|
+
maxMetrics?: number;
|
|
28
|
+
/**
|
|
29
|
+
* `tabs` (default): one `related` widget with a tab per relation.
|
|
30
|
+
* `panels`: one `records` panel per relation, with role-chosen columns.
|
|
31
|
+
*/
|
|
32
|
+
related?: 'tabs' | 'panels';
|
|
33
|
+
}
|
|
34
|
+
/** Widget types a record overview offers by default. */
|
|
35
|
+
export declare const RECORD_OVERVIEW_ALLOWED: readonly string[];
|
|
36
|
+
/** Tiles in the default summary strip. */
|
|
37
|
+
export declare const RECORD_OVERVIEW_MAX_METRICS = 4;
|
|
38
|
+
/** Rows a default `records` panel shows. */
|
|
39
|
+
export declare const RECORD_OVERVIEW_LIMIT = 5;
|
|
40
|
+
/**
|
|
41
|
+
* `detail:<model>` as an overview id. A qualified model id
|
|
42
|
+
* (`@acme/shop:Customer`) carries characters an overview id cannot
|
|
43
|
+
* (`OVERVIEW_PAGE_ID_PATTERN`), so `@`, `/` and `:` fold to dots:
|
|
44
|
+
* `detail:acme.shop.Customer`. Stable per model kind.
|
|
45
|
+
*/
|
|
46
|
+
export declare function recordOverviewId(model: string): string;
|
|
47
|
+
/** Span of a default `records` panel: two side by side on a wide page. */
|
|
48
|
+
export declare const RECORD_OVERVIEW_PANEL_SPAN = 2;
|
|
49
|
+
/** The default record overview of `definition` for its relations. */
|
|
50
|
+
export declare function recordOverview(definition: ScreenCollectionDefinition, relations: readonly ScreenRelation[], options?: RecordOverviewOptions): OverviewDefinition;
|
|
51
|
+
//# sourceMappingURL=record.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"record.d.ts","sourceRoot":"","sources":["../../../src/components/overview/record.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AACH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAC;AAE9D,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,qBAAqB,CAAC;AAEtE,OAAO,KAAK,EAAE,kBAAkB,EAAkB,MAAM,YAAY,CAAC;AAGrE,MAAM,WAAW,qBAAqB;IACpC,yEAAyE;IACzE,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,wDAAwD;IACxD,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,6EAA6E;IAC7E,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB;;;OAGG;IACH,OAAO,CAAC,EAAE,MAAM,GAAG,QAAQ,CAAC;CAC7B;AAED,wDAAwD;AACxD,eAAO,MAAM,uBAAuB,EAAE,SAAS,MAAM,EAOpD,CAAC;AAEF,0CAA0C;AAC1C,eAAO,MAAM,2BAA2B,IAAI,CAAC;AAE7C,4CAA4C;AAC5C,eAAO,MAAM,qBAAqB,IAAI,CAAC;AAEvC;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAOtD;AAwBD,0EAA0E;AAC1E,eAAO,MAAM,0BAA0B,IAAI,CAAC;AAE5C,qEAAqE;AACrE,wBAAgB,cAAc,CAC5B,UAAU,EAAE,0BAA0B,EACtC,SAAS,EAAE,SAAS,cAAc,EAAE,EACpC,OAAO,GAAE,qBAA0B,GAClC,kBAAkB,CAgGpB"}
|