@nest-my-admin/core 0.3.2 → 0.5.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.
Files changed (118) hide show
  1. package/README.md +56 -0
  2. package/dist/admin.module.js +6 -0
  3. package/dist/admin.module.js.map +1 -1
  4. package/dist/api/action.service.js +3 -0
  5. package/dist/api/action.service.js.map +1 -1
  6. package/dist/api/admin-api.service.d.ts +54 -2
  7. package/dist/api/admin-api.service.js +320 -11
  8. package/dist/api/admin-api.service.js.map +1 -1
  9. package/dist/api/menu-routes.d.ts +16 -0
  10. package/dist/api/menu-routes.js +10 -0
  11. package/dist/api/menu-routes.js.map +1 -0
  12. package/dist/api/menu.d.ts +15 -0
  13. package/dist/api/menu.js +85 -0
  14. package/dist/api/menu.js.map +1 -0
  15. package/dist/appearance/appearance.service.d.ts +28 -0
  16. package/dist/appearance/appearance.service.js +88 -0
  17. package/dist/appearance/appearance.service.js.map +1 -0
  18. package/dist/appearance/entities.d.ts +8 -0
  19. package/dist/appearance/entities.js +35 -0
  20. package/dist/appearance/entities.js.map +1 -0
  21. package/dist/audit/entities.d.ts +4 -0
  22. package/dist/audit/entities.js.map +1 -1
  23. package/dist/constants.d.ts +2 -0
  24. package/dist/constants.js +2 -0
  25. package/dist/constants.js.map +1 -1
  26. package/dist/contract.d.ts +256 -7
  27. package/dist/crud/computed-columns.d.ts +65 -0
  28. package/dist/crud/computed-columns.js +264 -0
  29. package/dist/crud/computed-columns.js.map +1 -0
  30. package/dist/crud/list-query-builder.d.ts +3 -1
  31. package/dist/crud/list-query-builder.js +5 -2
  32. package/dist/crud/list-query-builder.js.map +1 -1
  33. package/dist/crud/list-query.js +6 -1
  34. package/dist/crud/list-query.js.map +1 -1
  35. package/dist/crud/list-tabs.d.ts +7 -0
  36. package/dist/crud/list-tabs.js +44 -0
  37. package/dist/crud/list-tabs.js.map +1 -0
  38. package/dist/dashboard/dashboard-routes.d.ts +18 -0
  39. package/dist/dashboard/dashboard-routes.js +13 -0
  40. package/dist/dashboard/dashboard-routes.js.map +1 -0
  41. package/dist/dashboard/dashboard.service.d.ts +20 -0
  42. package/dist/dashboard/dashboard.service.js +80 -0
  43. package/dist/dashboard/dashboard.service.js.map +1 -0
  44. package/dist/dashboard/widget-registry.d.ts +22 -0
  45. package/dist/dashboard/widget-registry.js +77 -0
  46. package/dist/dashboard/widget-registry.js.map +1 -0
  47. package/dist/decorators/admin-action.d.ts +15 -2
  48. package/dist/decorators/admin-action.js +21 -2
  49. package/dist/decorators/admin-action.js.map +1 -1
  50. package/dist/decorators/admin-field.d.ts +23 -3
  51. package/dist/decorators/admin-field.js +1 -1
  52. package/dist/decorators/admin-field.js.map +1 -1
  53. package/dist/decorators/admin-print.d.ts +35 -0
  54. package/dist/decorators/admin-print.js +53 -0
  55. package/dist/decorators/admin-print.js.map +1 -0
  56. package/dist/decorators/admin-resource.d.ts +7 -0
  57. package/dist/decorators/admin-resource.js.map +1 -1
  58. package/dist/decorators/admin-widget.d.ts +27 -0
  59. package/dist/decorators/admin-widget.js +14 -0
  60. package/dist/decorators/admin-widget.js.map +1 -0
  61. package/dist/export/export-cells.d.ts +8 -0
  62. package/dist/export/export-cells.js +45 -0
  63. package/dist/export/export-cells.js.map +1 -0
  64. package/dist/export/xlsx.d.ts +23 -0
  65. package/dist/export/xlsx.js +115 -0
  66. package/dist/export/xlsx.js.map +1 -0
  67. package/dist/http/admin-http.server.d.ts +5 -1
  68. package/dist/http/admin-http.server.js +41 -2
  69. package/dist/http/admin-http.server.js.map +1 -1
  70. package/dist/index.d.ts +6 -2
  71. package/dist/index.js +4 -0
  72. package/dist/index.js.map +1 -1
  73. package/dist/inlines/inline-config.d.ts +3 -0
  74. package/dist/inlines/inline-config.js +11 -3
  75. package/dist/inlines/inline-config.js.map +1 -1
  76. package/dist/inlines/inline-reader.d.ts +5 -0
  77. package/dist/inlines/inline-reader.js +9 -2
  78. package/dist/inlines/inline-reader.js.map +1 -1
  79. package/dist/inlines/inline-writer.js +4 -0
  80. package/dist/inlines/inline-writer.js.map +1 -1
  81. package/dist/internal.d.ts +3 -0
  82. package/dist/internal.js +2 -0
  83. package/dist/internal.js.map +1 -1
  84. package/dist/options.d.ts +49 -0
  85. package/dist/options.js +31 -0
  86. package/dist/options.js.map +1 -1
  87. package/dist/policy/admin-policy.service.d.ts +14 -1
  88. package/dist/policy/admin-policy.service.js +127 -9
  89. package/dist/policy/admin-policy.service.js.map +1 -1
  90. package/dist/policy/catalog.d.ts +2 -2
  91. package/dist/policy/catalog.js +5 -4
  92. package/dist/policy/catalog.js.map +1 -1
  93. package/dist/policy/explain.js +3 -1
  94. package/dist/policy/explain.js.map +1 -1
  95. package/dist/print/html.d.ts +16 -0
  96. package/dist/print/html.js +37 -0
  97. package/dist/print/html.js.map +1 -0
  98. package/dist/print/print-page.d.ts +10 -0
  99. package/dist/print/print-page.js +47 -0
  100. package/dist/print/print-page.js.map +1 -0
  101. package/dist/rbac/rbac.service.d.ts +3 -1
  102. package/dist/rbac/rbac.service.js +8 -4
  103. package/dist/rbac/rbac.service.js.map +1 -1
  104. package/dist/registry/resource-registry.d.ts +25 -0
  105. package/dist/registry/resource-registry.js +109 -0
  106. package/dist/registry/resource-registry.js.map +1 -1
  107. package/dist/resource/admin-resource-base.d.ts +120 -9
  108. package/dist/resource/admin-resource-base.js +16 -2
  109. package/dist/resource/admin-resource-base.js.map +1 -1
  110. package/dist/schema/build-resource-schema.js +104 -6
  111. package/dist/schema/build-resource-schema.js.map +1 -1
  112. package/dist/schema/currency.d.ts +9 -0
  113. package/dist/schema/currency.js +11 -0
  114. package/dist/schema/currency.js.map +1 -0
  115. package/dist/schema/field-config.d.ts +33 -4
  116. package/dist/schema/field-config.js +68 -3
  117. package/dist/schema/field-config.js.map +1 -1
  118. package/package.json +2 -2
@@ -1 +1 @@
1
- {"version":3,"file":"constants.js","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"AAAA,+GAA+G;AAC/G,MAAM,CAAC,MAAM,uBAAuB,GAAG,wBAAwB,CAAC;AAEhE,+EAA+E;AAC/E,MAAM,CAAC,MAAM,oBAAoB,GAAG,qBAAqB,CAAC;AAE1D,wFAAwF;AACxF,MAAM,CAAC,MAAM,oBAAoB,GAAG,qBAAqB,CAAC;AAE1D,4DAA4D;AAC5D,MAAM,CAAC,MAAM,aAAa,GAAG,uBAAuB,CAAC;AAErD,+FAA+F;AAC/F,MAAM,CAAC,MAAM,oBAAoB,GAAG,sBAAsB,CAAC;AAC3D,MAAM,CAAC,MAAM,qBAAqB,GAAG,sBAAsB,CAAC;AAC5D,MAAM,CAAC,MAAM,kBAAkB,GAAG,mBAAmB,CAAC;AAEtD,oFAAoF;AACpF,MAAM,CAAC,MAAM,QAAQ,GAAG,GAAG,CAAC;AAE5B,qEAAqE;AACrE,MAAM,CAAC,MAAM,mBAAmB,GAAG,oBAAoB,CAAC;AAExD,qGAAqG;AACrG,MAAM,CAAC,MAAM,sBAAsB,GAAG,uBAAuB,CAAC"}
1
+ {"version":3,"file":"constants.js","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"AAAA,+GAA+G;AAC/G,MAAM,CAAC,MAAM,uBAAuB,GAAG,wBAAwB,CAAC;AAEhE,+EAA+E;AAC/E,MAAM,CAAC,MAAM,oBAAoB,GAAG,qBAAqB,CAAC;AAE1D,wFAAwF;AACxF,MAAM,CAAC,MAAM,oBAAoB,GAAG,qBAAqB,CAAC;AAE1D,4DAA4D;AAC5D,MAAM,CAAC,MAAM,aAAa,GAAG,uBAAuB,CAAC;AAErD,+FAA+F;AAC/F,MAAM,CAAC,MAAM,oBAAoB,GAAG,sBAAsB,CAAC;AAC3D,MAAM,CAAC,MAAM,qBAAqB,GAAG,sBAAsB,CAAC;AAC5D,MAAM,CAAC,MAAM,kBAAkB,GAAG,mBAAmB,CAAC;AAEtD,oFAAoF;AACpF,MAAM,CAAC,MAAM,QAAQ,GAAG,GAAG,CAAC;AAE5B,qEAAqE;AACrE,MAAM,CAAC,MAAM,mBAAmB,GAAG,oBAAoB,CAAC;AACxD,MAAM,CAAC,MAAM,qBAAqB,GAAG,sBAAsB,CAAC;AAE5D,qGAAqG;AACrG,MAAM,CAAC,MAAM,sBAAsB,GAAG,uBAAuB,CAAC;AAC9D,MAAM,CAAC,MAAM,qBAAqB,GAAG,sBAAsB,CAAC"}
@@ -38,7 +38,7 @@ export interface FieldSchema {
38
38
  help?: string;
39
39
  placeholder?: string;
40
40
  /** The widget chosen in the field config; the UI infers one from the type when absent. */
41
- widget?: 'text' | 'textarea' | 'number' | 'money' | 'switch' | 'checkbox' | 'select' | 'radio' | 'date' | 'datetime' | 'json' | 'color' | 'badge' | 'slug' | 'password' | 'email' | 'url' | 'file' | 'image' | 'richtext';
41
+ widget?: 'text' | 'textarea' | 'number' | 'money' | 'switch' | 'checkbox' | 'select' | 'radio' | 'date' | 'datetime' | 'json' | 'color' | 'badge' | 'slug' | 'password' | 'email' | 'url' | 'file' | 'image' | 'richtext' | 'stepper';
42
42
  /** Display labels of enum values (values sent stay the raw ones). */
43
43
  enumLabels?: Record<string, string>;
44
44
  /** Badge colour per value. */
@@ -47,8 +47,22 @@ export interface FieldSchema {
47
47
  showIf?: Record<string, string | number | boolean | null | Array<string | number | boolean | null>>;
48
48
  /** The slug widget fills itself from this field until edited. */
49
49
  slugFrom?: string;
50
- /** Currency code for the money widget (display only). */
51
- currency?: string;
50
+ /**
51
+ * `stepper` widget: the steps in order, the values that are not steps (shown as a badge), and whether records carry
52
+ * `_steps` (when each step was reached, from the history child).
53
+ */
54
+ steps?: {
55
+ values: string[];
56
+ exclude: string[];
57
+ history: boolean;
58
+ };
59
+ /** A soft warning shown under the input while it is empty; the save still goes through. */
60
+ warnIf?: {
61
+ empty: true;
62
+ message: string;
63
+ };
64
+ /** The money widget's unit in the request's language, and where it goes (display only). */
65
+ currency?: CurrencyDisplay;
52
66
  /** Set for `file` and `image` widgets: what may be uploaded to the field. */
53
67
  file?: {
54
68
  accept: string[];
@@ -125,12 +139,30 @@ export interface FormLayoutInline {
125
139
  max: number;
126
140
  /** The child's field that points at the parent (set by the server). */
127
141
  link: string;
142
+ /** Shown, never edited in this form (writes are refused). */
143
+ readonly?: true;
144
+ /** The child's computed columns shown in the table (`_computed` on each row), cut to what this user may see. */
145
+ computed?: string[];
146
+ /** A marker on the first card by `order` («Main picture»). */
147
+ markFirst?: string;
148
+ }
149
+ /** Label and value rows in a card (an order's totals): a field of the record, or one of its computed columns (`_computed`). */
150
+ export interface FormLayoutSummary {
151
+ title?: string;
152
+ summary: Array<{
153
+ label: string;
154
+ value: {
155
+ field: string;
156
+ } | {
157
+ computed: string;
158
+ };
159
+ }>;
128
160
  }
129
161
  export interface FormLayoutTab {
130
162
  tab: string;
131
- sections: Array<FormLayoutSection | FormLayoutInline>;
163
+ sections: Array<FormLayoutSection | FormLayoutInline | FormLayoutSummary>;
132
164
  }
133
- export type FormLayoutNode = FormLayoutSection | FormLayoutTab | FormLayoutInline;
165
+ export type FormLayoutNode = FormLayoutSection | FormLayoutTab | FormLayoutInline | FormLayoutSummary;
134
166
  /** One inline of a record (`_inlines[child]` on `GET /resources/:parent/:id`). */
135
167
  export interface InlineRows {
136
168
  /** The children of this record, as the child's own endpoints answer them (`_id`, `_perm`, `_readonly`, `_files`…), by `order` then key. */
@@ -246,10 +278,19 @@ export interface ActionSchema {
246
278
  /** Ask before running: `true` for the default question, or the question itself. */
247
279
  confirm?: string | true;
248
280
  variant: 'default' | 'destructive';
281
+ /** The record's next step: a filled button, last in the record's header (record actions without input, one per resource). */
282
+ primary?: true;
249
283
  icon?: string;
250
284
  /** The form to fill in before running; its values are sent as `input`. */
251
285
  input?: DtoFormSchema;
252
286
  }
287
+ /** A print template of a resource (`@AdminPrint`): a page the browser prints, for one record or (`bulk`) a selection. */
288
+ export interface PrintSchema {
289
+ name: string;
290
+ label: string;
291
+ bulk: boolean;
292
+ icon?: string;
293
+ }
253
294
  /** Body of `POST /resources/:resource/actions/:name`. Record actions need `ids` (encoded record ids); resource actions refuse them. */
254
295
  export interface ActionRequest {
255
296
  ids?: string[];
@@ -336,7 +377,47 @@ export interface MetaResponse {
336
377
  /** Languages people can switch between. */
337
378
  locales: string[];
338
379
  groups: MetaGroup[];
380
+ /** This user may see at least one dashboard widget: the dashboard replaces the home page. */
381
+ dashboard?: boolean;
382
+ /** The host's curated menu (`menu` option), cut to what this user reaches; absent without one (groups are the menu). */
383
+ menu?: MetaMenu;
384
+ }
385
+ /** One entry of a menu section. */
386
+ export type MetaMenuItem = {
387
+ kind: 'resource';
388
+ resource: string;
389
+ label: string;
390
+ icon?: string;
391
+ creatable: boolean;
392
+ searchable: boolean;
393
+ /** A count is served for it by `GET /api/menu/badges` (key `<section>.<resource>`). */
394
+ badge?: true;
395
+ } | {
396
+ kind: 'page';
397
+ page: string;
398
+ label: string;
399
+ icon?: string;
400
+ } | {
401
+ kind: 'link';
402
+ href: string;
403
+ label: string;
404
+ };
405
+ export interface MetaMenuSection {
406
+ key: string;
407
+ label: string;
408
+ icon?: string;
409
+ items: MetaMenuItem[];
339
410
  }
411
+ export interface MetaMenu {
412
+ sections: MetaMenuSection[];
413
+ /** Everything visible that no section places (key `advanced`), collapsed by default. May be empty. */
414
+ advanced: MetaMenuSection;
415
+ }
416
+ /** `GET /api/menu/badges`: counts by `<section>.<resource>`, scoped to the viewer; a badge the viewer may not count is absent. */
417
+ export type MenuBadges = Record<string, {
418
+ count: number;
419
+ estimate: boolean;
420
+ }>;
340
421
  export type SortDirection = 'asc' | 'desc';
341
422
  export type FilterOperator = 'eq' | 'ne' | 'in' | 'nin' | 'lt' | 'lte' | 'gt' | 'gte' | 'between' | 'contains' | 'startsWith' | 'isNull';
342
423
  /** A filterable field and the operators its column type supports (spec §11). */
@@ -375,6 +456,14 @@ export interface ResourceSchema {
375
456
  badge?: string;
376
457
  meta: string[];
377
458
  };
459
+ /** Tabs over the list (`list.tabs`) this viewer may use: a tab writes `filter` to the URL, plus `tab=<key>` when `where`. */
460
+ tabs?: ListTabSchema[];
461
+ /** Computed columns (`list.computed`) this viewer may see, by key; their values are each record's `_computed`. */
462
+ computed?: Record<string, ComputedColumnSchema>;
463
+ /** `list.export`, for a viewer holding `<resource>.export`: `GET /resources/:resource/export` with the list's query. */
464
+ export?: {
465
+ max: number;
466
+ };
378
467
  };
379
468
  /** False for the root of a single-table inheritance, or when the user may not create. */
380
469
  creatable: boolean;
@@ -392,6 +481,8 @@ export interface ResourceSchema {
392
481
  * per record by `_perm.actions`.
393
482
  */
394
483
  actions: ActionSchema[];
484
+ /** The print templates (`@AdminPrint`) the signed-in user may print: `GET /resources/:resource/print/:name?id=…`. */
485
+ prints: PrintSchema[];
395
486
  /**
396
487
  * Other resources whose relation fields point at this one (spec §9.4 Related): a record's related records are
397
488
  * `/<resource>?filter[<field>][<operator>]=<id>`.
@@ -413,8 +504,22 @@ export interface ResourceSchema {
413
504
  requiredOnCreate: string[];
414
505
  /** Shown on the update form but not writable (`readonly: true`); records add their own in `_readonly`. */
415
506
  readonly: string[];
416
- /** Sections, inlines and tabs (`form.layout`); absent = one section in form order. */
507
+ /** Sections, inlines and tabs (`form.layout`, or its main column); absent = one section in form order. */
417
508
  layout?: FormLayoutNode[];
509
+ /** Read-only cards beside the main column (`form.layout.aside`), cut to what this user may see. */
510
+ aside?: AsideCardSchema[];
511
+ /** `view`: an existing record opens as text until «Edit». */
512
+ mode?: 'view';
513
+ /** The record's header: badge fields, and a subtitle of field values and computed columns (`_computed`). */
514
+ header?: {
515
+ badges?: string[];
516
+ subtitle?: Array<{
517
+ field: string;
518
+ } | {
519
+ computed: string;
520
+ }>;
521
+ stepper?: string;
522
+ };
418
523
  constraints: {
419
524
  create: Record<string, FieldConstraints>;
420
525
  update: Record<string, FieldConstraints>;
@@ -435,6 +540,8 @@ export interface ResourceSchema {
435
540
  * resources with such fields add `_files`: field name → `AdminFileRef` (`AdminFileRef[]` with `file.many`) for every
436
541
  * field that holds a file. `GET /resources/:resource/:id` of a resource with inlines adds `_inlines`: child resource
437
542
  * name → `InlineRows`, for each inline the user may see; so do the answers of its POST and PATCH, read after the save.
543
+ * List pages of a resource with `list.computed` add `_computed`: column key → `ComputedValue`, for the computed columns
544
+ * the user may see and the page shows.
438
545
  */
439
546
  export type AdminRecord = Record<string, unknown>;
440
547
  /**
@@ -445,7 +552,8 @@ export type AdminRecord = Record<string, unknown>;
445
552
  export interface RecordPermissions {
446
553
  update: boolean;
447
554
  delete: boolean;
448
- actions?: string[];
555
+ /** Record actions by name: the label to show on this record (`label.for`, else the action's label), or `false` when it may not run here. */
556
+ actions?: Record<string, string | false>;
449
557
  }
450
558
  /** `POST /resources/:resource/bulk-delete` with `{ ids }` (encoded record ids): each id succeeds or fails on its own. */
451
559
  export interface BulkResult {
@@ -530,6 +638,11 @@ export interface SessionResponse {
530
638
  enabled: boolean;
531
639
  view: boolean;
532
640
  };
641
+ /** With `appearance`: the admin-wide accent colour (null: the host's branding), and whether this user may change it. */
642
+ appearance?: {
643
+ accent: string | null;
644
+ manage: boolean;
645
+ };
533
646
  /** Changes when roles or memberships change: refetch meta and schemas. */
534
647
  permissionsVersion: number;
535
648
  /** A superuser looking through another user's eyes (`X-View-As`): `user` is the target, `by` the superuser. Read-only. */
@@ -827,6 +940,137 @@ export interface AuditResponse {
827
940
  }
828
941
  /** A label in one language, or per language (`{ en: 'Orders', fa: 'سفارش‌ها' }`). */
829
942
  export type LocalizedLabel = string | Record<string, string>;
943
+ /** A status colour of the design (badges, computed cells, stat changes). */
944
+ export type Tone = 'ok' | 'warn' | 'bad' | 'info' | 'neutral' | 'primary';
945
+ /**
946
+ * An aside card (spec §5.6). Own fields come from the record; a relation card's from `_aside[index]` (the related
947
+ * record's fields this user may see, with its `_id`, absent when they may not see it), linking to it when `link`.
948
+ */
949
+ export interface AsideCardSchema {
950
+ title: string;
951
+ icon?: string;
952
+ fields: string[];
953
+ relation?: {
954
+ field: string;
955
+ resource: string;
956
+ link: boolean;
957
+ };
958
+ }
959
+ /** Dashboard widgets (spec §5.8). */
960
+ export type WidgetType = 'stat' | 'chart' | 'table' | 'progress' | 'list';
961
+ /**
962
+ * The period a widget is asked for, computed by the UI in the browser's time zone (Jalali-aware): ISO instants, `to`
963
+ * excluded, and the window before it for comparisons. The server checks `from < to` and a span of at most 366 days.
964
+ */
965
+ export interface WidgetParams {
966
+ period: 'day' | 'week' | 'month' | 'year' | 'range';
967
+ from: string;
968
+ to: string;
969
+ previousFrom: string;
970
+ previousTo: string;
971
+ }
972
+ /** `GET /api/dashboard`: the widgets this user may see, in order. */
973
+ export interface DashboardResponse {
974
+ widgets: Array<{
975
+ name: string;
976
+ type: WidgetType;
977
+ title: string;
978
+ size: 1 | 2 | 3 | 4;
979
+ }>;
980
+ }
981
+ export interface StatWidgetData {
982
+ /** Already formatted by the host or a plain number as text (the UI formats digits). */
983
+ value: string;
984
+ unit?: string;
985
+ /** Percent against the previous period. */
986
+ change?: number;
987
+ previousLabel?: string;
988
+ }
989
+ export interface ChartWidgetData {
990
+ kind: 'bar' | 'line';
991
+ labels: string[];
992
+ series: Array<{
993
+ label: string;
994
+ values: number[];
995
+ dashed?: boolean;
996
+ }>;
997
+ total?: string;
998
+ subtitle?: string;
999
+ }
1000
+ export interface TableWidgetData {
1001
+ columns: Array<{
1002
+ key: string;
1003
+ label: string;
1004
+ }>;
1005
+ /** Cell values by column key; a `{ label, tone }` cell is a status badge. */
1006
+ rows: Array<Record<string, string | number | {
1007
+ label: string;
1008
+ tone: Tone;
1009
+ }>>;
1010
+ /** «View all»: the list with this filter. */
1011
+ link?: {
1012
+ resource: string;
1013
+ filter?: Record<string, string>;
1014
+ };
1015
+ }
1016
+ export interface ProgressWidgetData {
1017
+ percent: number;
1018
+ value: string;
1019
+ caption: string;
1020
+ }
1021
+ export interface ListWidgetData {
1022
+ items: Array<{
1023
+ icon?: string;
1024
+ text: string;
1025
+ status?: Tone;
1026
+ link?: string;
1027
+ }>;
1028
+ }
1029
+ /** `GET /api/dashboard/:widget`: the data of the widget's type. */
1030
+ export type WidgetData = StatWidgetData | ChartWidgetData | TableWidgetData | ProgressWidgetData | ListWidgetData;
1031
+ /** A list tab (spec §5.5). */
1032
+ export interface ListTabSchema {
1033
+ key: string;
1034
+ label: string;
1035
+ /** `filter[...]` list parameters the tab sets (none: «all»). */
1036
+ filter: Record<string, string>;
1037
+ /** The tab restricts the list beyond its filters: send `tab=<key>`. */
1038
+ where: boolean;
1039
+ count: 'exact' | 'estimate' | 'none';
1040
+ }
1041
+ /** `GET /api/resources/:resource/tab-counts`: each tab's count for the viewer, `null` for `count: 'none'`. */
1042
+ export type TabCounts = Record<string, {
1043
+ count: number;
1044
+ estimate: boolean;
1045
+ } | null>;
1046
+ /** A computed list column (spec §5.4). */
1047
+ export interface ComputedColumnSchema {
1048
+ label: string;
1049
+ kind: 'image' | 'title' | 'money' | 'badge' | 'count' | 'toggle';
1050
+ sortable: boolean;
1051
+ /** `toggle`: the enum field a click writes (PATCH `{ [field]: on | off }`), when the viewer may edit it. */
1052
+ toggle?: {
1053
+ field: string;
1054
+ on: string;
1055
+ off: string;
1056
+ };
1057
+ }
1058
+ /**
1059
+ * A computed cell's value (`AdminRecord._computed[key]`): `value` is the main one (an image is its URL, a toggle
1060
+ * a boolean), `subline` and `previous` go with `title` and `money`, `label` and `tone` with `badge`.
1061
+ */
1062
+ export interface ComputedValue {
1063
+ value: unknown;
1064
+ subline?: unknown;
1065
+ previous?: unknown;
1066
+ label?: string;
1067
+ tone?: Tone;
1068
+ }
1069
+ /** A money unit as shown: `۳٬۲۵۰٬۰۰۰ تومان` (after) or `$12.50` (before). */
1070
+ export interface CurrencyDisplay {
1071
+ unit: string;
1072
+ position: 'after' | 'before';
1073
+ }
830
1074
  /** Host branding (spec §9.5). Colours and lengths are validated by core before they reach the page. */
831
1075
  export interface BrandingConfig {
832
1076
  name?: LocalizedLabel;
@@ -845,4 +1089,9 @@ export interface AdminRuntimeConfig {
845
1089
  locale: string;
846
1090
  locales: string[];
847
1091
  branding: BrandingConfig;
1092
+ /** The global money unit, in every configured language (the UI picks its own). */
1093
+ currency?: {
1094
+ unit: LocalizedLabel;
1095
+ position: 'after' | 'before';
1096
+ };
848
1097
  }
@@ -0,0 +1,65 @@
1
+ import type { EntityMetadata, ObjectLiteral, SelectQueryBuilder } from 'typeorm';
2
+ import type { ComputedValue, FieldSchema } from '../contract.js';
3
+ import type { LocalizedText } from '../i18n/localized-text.js';
4
+ import type { AdminContext } from '../resource/admin-context.js';
5
+ import type { ComputedColumn } from '../resource/admin-resource-base.js';
6
+ type RelationMeta = EntityMetadata['relations'][number];
7
+ /** A source once checked against the entity: what to read and how. */
8
+ export type CompiledSource = {
9
+ type: 'field';
10
+ path: string;
11
+ } | {
12
+ type: 'aggregate';
13
+ fn: 'min' | 'max' | 'sum' | 'count';
14
+ relation: RelationMeta;
15
+ field?: string;
16
+ } | {
17
+ type: 'first';
18
+ relation: RelationMeta;
19
+ field: string;
20
+ by: string;
21
+ } | {
22
+ type: 'toggle';
23
+ field: string;
24
+ on: string;
25
+ off: string;
26
+ } | {
27
+ type: 'compute';
28
+ fn: (rows: any[], ctx: AdminContext) => Promise<Record<string, unknown>>;
29
+ fields: string[];
30
+ };
31
+ export interface CompiledComputed {
32
+ key: string;
33
+ column: ComputedColumn;
34
+ source: CompiledSource;
35
+ subline?: CompiledSource;
36
+ previous?: CompiledSource;
37
+ /** What it reads, for the policy: own fields and paths, and the child entities (and their fields) it aggregates. */
38
+ deps: {
39
+ own: string[];
40
+ children: Array<{
41
+ entity: Function;
42
+ fields: string[];
43
+ }>;
44
+ };
45
+ }
46
+ /**
47
+ * Checks `list.computed` at boot (spec §5.4) and compiles each column: sources exist, relations are one-to-many of a
48
+ * single-key entity, `sortable` only on aggregates and first rows, a toggle's values are its enum's, `map` only on badges.
49
+ */
50
+ export declare function checkComputed(computed: Record<string, ComputedColumn> | undefined, metadata: EntityMetadata, enumValues: (field: string) => string[] | undefined, fail: (message: string) => never): Map<string, CompiledComputed>;
51
+ /** A query of a child entity as the viewer may read it (the child resource's `query()` and scopes), or a plain one. */
52
+ export type ChildQuery = (entity: Function, alias: string, ctx: AdminContext | undefined) => SelectQueryBuilder<ObjectLiteral>;
53
+ /**
54
+ * The page's computed values, by record id: one query per relation or path source and one `compute` call, whatever the
55
+ * page size (no N+1). Badge labels are localized with `text`.
56
+ */
57
+ export declare function loadComputed(columns: CompiledComputed[], rows: ObjectLiteral[], metadata: EntityMetadata, ctx: AdminContext, childQuery: ChildQuery, pathQuery: (alias: string) => SelectQueryBuilder<ObjectLiteral>, text: (label: LocalizedText) => string,
58
+ /** A field's schema (to serialize decimals as strings, dates as ISO…): the entity's resource field, if any. */
59
+ fieldFor: (entity: Function, name: string) => FieldSchema | undefined): Promise<Map<string, Record<string, ComputedValue>>>;
60
+ /**
61
+ * Sorting by an aggregate or first-row column: a correlated subquery over the rows the viewer may read, selected as
62
+ * `nma_sort` so paging with joins can order by it. Returns the expression to order by.
63
+ */
64
+ export declare function addComputedSort(qb: SelectQueryBuilder<ObjectLiteral>, compiled: CompiledComputed, metadata: EntityMetadata, ctx: AdminContext | undefined, childQuery: ChildQuery): string;
65
+ export {};