@nest-my-admin/core 0.3.1 → 0.4.1

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 (101) hide show
  1. package/README.md +33 -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 +34 -2
  7. package/dist/api/admin-api.service.js +210 -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/constants.d.ts +1 -0
  22. package/dist/constants.js +1 -0
  23. package/dist/constants.js.map +1 -1
  24. package/dist/contract.d.ts +245 -7
  25. package/dist/crud/computed-columns.d.ts +65 -0
  26. package/dist/crud/computed-columns.js +264 -0
  27. package/dist/crud/computed-columns.js.map +1 -0
  28. package/dist/crud/list-query-builder.d.ts +3 -1
  29. package/dist/crud/list-query-builder.js +5 -2
  30. package/dist/crud/list-query-builder.js.map +1 -1
  31. package/dist/crud/list-query.js +6 -1
  32. package/dist/crud/list-query.js.map +1 -1
  33. package/dist/crud/list-tabs.d.ts +7 -0
  34. package/dist/crud/list-tabs.js +44 -0
  35. package/dist/crud/list-tabs.js.map +1 -0
  36. package/dist/dashboard/dashboard-routes.d.ts +18 -0
  37. package/dist/dashboard/dashboard-routes.js +13 -0
  38. package/dist/dashboard/dashboard-routes.js.map +1 -0
  39. package/dist/dashboard/dashboard.service.d.ts +20 -0
  40. package/dist/dashboard/dashboard.service.js +80 -0
  41. package/dist/dashboard/dashboard.service.js.map +1 -0
  42. package/dist/dashboard/widget-registry.d.ts +22 -0
  43. package/dist/dashboard/widget-registry.js +77 -0
  44. package/dist/dashboard/widget-registry.js.map +1 -0
  45. package/dist/decorators/admin-action.d.ts +15 -2
  46. package/dist/decorators/admin-action.js +21 -2
  47. package/dist/decorators/admin-action.js.map +1 -1
  48. package/dist/decorators/admin-field.d.ts +23 -3
  49. package/dist/decorators/admin-field.js +1 -1
  50. package/dist/decorators/admin-field.js.map +1 -1
  51. package/dist/decorators/admin-resource.d.ts +14 -0
  52. package/dist/decorators/admin-resource.js.map +1 -1
  53. package/dist/decorators/admin-widget.d.ts +27 -0
  54. package/dist/decorators/admin-widget.js +14 -0
  55. package/dist/decorators/admin-widget.js.map +1 -0
  56. package/dist/http/admin-http.server.d.ts +5 -1
  57. package/dist/http/admin-http.server.js +17 -2
  58. package/dist/http/admin-http.server.js.map +1 -1
  59. package/dist/index.d.ts +4 -2
  60. package/dist/index.js +2 -0
  61. package/dist/index.js.map +1 -1
  62. package/dist/inlines/inline-config.d.ts +3 -0
  63. package/dist/inlines/inline-config.js +11 -3
  64. package/dist/inlines/inline-config.js.map +1 -1
  65. package/dist/inlines/inline-reader.d.ts +5 -0
  66. package/dist/inlines/inline-reader.js +9 -2
  67. package/dist/inlines/inline-reader.js.map +1 -1
  68. package/dist/inlines/inline-writer.js +4 -0
  69. package/dist/inlines/inline-writer.js.map +1 -1
  70. package/dist/internal.d.ts +3 -0
  71. package/dist/internal.js +2 -0
  72. package/dist/internal.js.map +1 -1
  73. package/dist/options.d.ts +49 -0
  74. package/dist/options.js +31 -0
  75. package/dist/options.js.map +1 -1
  76. package/dist/policy/admin-policy.service.d.ts +10 -1
  77. package/dist/policy/admin-policy.service.js +112 -11
  78. package/dist/policy/admin-policy.service.js.map +1 -1
  79. package/dist/policy/catalog.d.ts +2 -2
  80. package/dist/policy/catalog.js +3 -3
  81. package/dist/policy/catalog.js.map +1 -1
  82. package/dist/policy/explain.js +3 -1
  83. package/dist/policy/explain.js.map +1 -1
  84. package/dist/rbac/rbac.service.d.ts +3 -1
  85. package/dist/rbac/rbac.service.js +8 -4
  86. package/dist/rbac/rbac.service.js.map +1 -1
  87. package/dist/registry/resource-registry.d.ts +17 -0
  88. package/dist/registry/resource-registry.js +75 -0
  89. package/dist/registry/resource-registry.js.map +1 -1
  90. package/dist/resource/admin-resource-base.d.ts +111 -9
  91. package/dist/resource/admin-resource-base.js +16 -2
  92. package/dist/resource/admin-resource-base.js.map +1 -1
  93. package/dist/schema/build-resource-schema.js +105 -7
  94. package/dist/schema/build-resource-schema.js.map +1 -1
  95. package/dist/schema/currency.d.ts +9 -0
  96. package/dist/schema/currency.js +11 -0
  97. package/dist/schema/currency.js.map +1 -0
  98. package/dist/schema/field-config.d.ts +33 -4
  99. package/dist/schema/field-config.js +68 -3
  100. package/dist/schema/field-config.js.map +1 -1
  101. package/package.json +2 -2
package/README.md CHANGED
@@ -817,6 +817,39 @@ export class EmployeeAdmin extends AdminResourceBase<Employee> {
817
817
  - **Read replicas.** Reads outside a transaction (that check after commit; with `transactions: false` the before and after images too) go through `dataSource.manager`, which TypeORM replication may send to a replica. A lagging replica then still shows a deleted row (no stamp), or shows an update as unchanged (a smaller diff, or no entry).
818
818
  - **Scopes that depend on a field.** A record's history is open to whoever may open the record now. A reader whose scope depends on a field (`ownerId`, a status) reads the values the record had before it entered their scope, in the fields they may view.
819
819
 
820
+ ## Upgrading to 0.4
821
+
822
+ 0.4 gives the admin a new look (the owner-admin design) and the features a shop owner's panel needs. All five packages are 0.4.0; upgrade them together. Every new feature is an option: an app that sets none of them gets the new look and today's behaviour, except for the points under "What a 0.3 app will notice".
823
+
824
+ **What a 0.3 app will notice**
825
+
826
+ - **The look.** New design tokens: the Vazirmatn font for every language (bundled), 12px cards, pill badges, a 256px sidebar with sections, a floating save bar with ⌘S, filter chips over lists, cards on phones. The default accent is `#5B5BD6`; to keep the old neutral one, set it back: `branding: { primaryColor: 'oklch(0.205 0 0)' }`.
827
+ - **Persian digits by default in `fa`** (۱۲۳ and ٬ thousands separators). People switch back to Latin digits in their account menu (Display); the choice is kept per browser.
828
+ - **Inline children leave navigation.** A resource another resource edits inline (`{ inline: ChildAdmin }`) is no longer in the sidebar, home, group pages, palette or global search; it keeps its URLs, permissions, history and audit entries. To keep it listed: `@AdminResource(Child, { nav: true })`.
829
+ - **Contract changes** for code that reads the JSON API itself: `FieldSchema.currency` is `{ unit, position }` (a `currency: 'USD'` option still works), and a record's `_perm.actions` maps each record action to its label on that record, or `false` where it may not run (it was a list of names).
830
+ - **The e2e/screenshot baselines of your own app**, if you keep any, change with the look.
831
+
832
+ **New options**
833
+
834
+ - **Currency**: `forRoot({ currency: { unit: { en: 'Toman', fa: 'تومان' } } })` labels every `money` field without a unit of its own; a field's `currency` (a code, or `{ unit, position }`) wins.
835
+ - **A curated menu**: `forRoot({ menu: { sections: [{ key: 'sales', label: { fa: 'فروش' }, icon: 'shopping-cart', items: [{ resource: 'order', badge: { 'filter[status][eq]': 'paid' } }, { page: 'shop' }, { href: 'https://shop.example', label: 'Shop' }] }] } })`. Sections replace module groups in the sidebar, home, group pages, breadcrumbs and the palette; everything not placed goes into «Advanced», collapsed. Badges are counted for each user through the list's scoped count (`GET /api/menu/badges`, refreshed every minute).
836
+ - **`nav: false`** on `@AdminResource` takes any resource out of navigation.
837
+ - **Computed list columns**: `list.computed: { picture: { label, kind: 'image', source: { first: 'media', field: 'image', by: 'sort' } }, stock: { label, kind: 'badge', source: 'stock', map: (value, row) => ({ label, tone }) }, variants: { label, kind: 'count', source: { aggregate: 'count', relation: 'variants' }, sortable: true }, active: { label, kind: 'toggle', source: { toggle: 'status', on: 'active', off: 'archived' } } }`, named in `list.columns`. Kinds: image, title (with `subline`), money (with `previous`), badge, count, toggle; sources: a field or path, an aggregate or first row of a one-to-many relation (only the rows the viewer sees), an enum toggle, or `{ compute: (rows, ctx) => …, fields }` called once per page. A column reading something the viewer cannot see is cut.
838
+ - **List tabs**: `list.tabs: [{ key: 'all', label }, { key: 'active', label, filter: { 'filter[status][eq]': 'active' } }, { key: 'out', label, where: (qb) => qb.andWhere(qb.alias + '.stock = 0') }]` (at most six), counted per user (`GET /api/resources/:r/tab-counts`).
839
+ - **Primary record actions with per-record labels**: `@AdminAction({ primary: true, label: { static: 'Next step', for: (order) => (order.status === 'draft' ? 'Mark paid' : null) } })`: a filled button last in the record's header; `null` hides it on that record (and a run is refused).
840
+ - **The record page**: `form.layout: { main: [...sections], aside: [{ title, fields: ['status', 'total'] }, { title, fields: { relation: 'customerId', fields: ['phone'] }, link: true }] }`, `form.mode: 'view'` (opens as text until «Edit»), `form.header: { badges, subtitle: ['customer', { computed: 'items' }], stepper: 'fulfillment' }`.
841
+ - **Inline presentation**: an inline's `readonly`, `computed` (child computed columns as table columns) and `cards: { markFirst }`; a `{ summary: [{ label, value: 'total' | { computed } }] }` layout node; a field's `warnIf: { empty: true, message }` (a soft warning that never blocks a save).
842
+ - **A stepper**: `fields: { fulfillment: { widget: 'stepper', exclude: ['cancelled'], history: { inline: StatusLogAdmin, value: 'value', at: 'at', where: { field: 'fulfillment' } } } }` shows an ordered enum as steps with the time each was reached.
843
+ - **The accent colour, in the admin**: `forRoot({ appearance: {} })` (add `ADMIN_SETTING_ENTITIES` to the DataSource) lets people with `appearance.manage` set the accent for everyone (account menu → Display → «Use for everyone»); everyone may pick their own, kept in their browser. Order: their own, the admin-wide one, `branding.primaryColor`.
844
+ - **A dashboard**: `@AdminWidget('sales', { type: 'stat' | 'chart' | 'table' | 'progress' | 'list', title, order, size, permission })` providers with `load(params, ctx)`; the period (today, week, month, year, a range; Jalali-aware) is computed by the UI and checked by the server. Codes `dashboard.<name>` (or the widget's `permission`); `dashboard.*` grants every widget. With a widget to show, the dashboard replaces the home page.
845
+ - **`@nest-my-admin/testing`**: `expectNoLeaks` also crawls menu badges, tab counts, computed cells and the dashboard.
846
+
847
+ Still missing (planned): printing a record (an invoice, a shipping label) and exporting a list to Excel.
848
+
849
+ ## Upgrading to 0.3.2
850
+
851
+ Nothing to change in an app on 0.3.1. New: `@AdminResource(Entity, { readonly: true })` for records only your own code writes (logs, orders, snapshots): the admin offers no New, Save, Delete, editable cell or inline add and remove, and its API answers 403 to every write, whatever the roles say; the resource's `@AdminAction`s still run with their usual permissions. The schema says `readonly: true`. Before, the way to get this was to throw from `create`/`update`/`delete`, and a superuser still saw the buttons.
852
+
820
853
  ## Upgrading to 0.3.1
821
854
 
822
855
  A fix, nothing to change in an app on 0.3.0. A property of a create DTO that is not a column (a value your `create()` uses, such as the price of a first variant) is no longer shown on the edit form as an empty read-only field; a create-only column (a number fixed once saved) still is. `form.readonly` in the schema changes accordingly.
@@ -5,6 +5,9 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
5
5
  return c > 3 && r && Object.defineProperty(target, key, r), r;
6
6
  };
7
7
  var AdminModule_1;
8
+ import { AdminAppearance } from './appearance/appearance.service.js';
9
+ import { DashboardService } from './dashboard/dashboard.service.js';
10
+ import { WidgetRegistry } from './dashboard/widget-registry.js';
8
11
  import { Module } from '@nestjs/common';
9
12
  import { DiscoveryModule } from '@nestjs/core';
10
13
  import { AdminApiService } from './api/admin-api.service.js';
@@ -30,6 +33,9 @@ let AdminModule = AdminModule_1 = class AdminModule {
30
33
  { provide: ADMIN_OPTIONS, useValue: resolveAdminOptions(options) },
31
34
  ResourceRegistry,
32
35
  PageRegistry,
36
+ WidgetRegistry,
37
+ AdminAppearance,
38
+ DashboardService,
33
39
  AdminAuthService,
34
40
  AdminAudit,
35
41
  AdminRbac,
@@ -1 +1 @@
1
- {"version":3,"file":"admin.module.js","sourceRoot":"","sources":["../src/admin.module.ts"],"names":[],"mappings":";;;;;;;AAAA,OAAO,EAAE,MAAM,EAAsB,MAAM,gBAAgB,CAAC;AAC5D,OAAO,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAC/C,OAAO,EAAE,eAAe,EAAE,MAAM,4BAA4B,CAAC;AAC7D,OAAO,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAC/C,OAAO,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AACtD,OAAO,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAC;AACtD,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAC1D,OAAO,EAAE,WAAW,EAAE,MAAM,kCAAkC,CAAC;AAC/D,OAAO,EAAE,UAAU,EAAE,MAAM,gCAAgC,CAAC;AAC5D,OAAO,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAC;AACxD,OAAO,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AACnD,OAAO,EAAE,eAAe,EAAE,MAAM,6BAA6B,CAAC;AAC9D,OAAO,EAAE,mBAAmB,EAA2B,MAAM,cAAc,CAAC;AAC5E,OAAO,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAC;AACxD,OAAO,EAAE,gBAAgB,EAAE,MAAM,iCAAiC,CAAC;AAG5D,IAAM,WAAW,mBAAjB,MAAM,WAAW;IACf,AAAP,MAAM,CAAC,OAAO,CAAC,OAAO,GAAuB,EAAE;QAC7C,OAAO;YACL,MAAM,eAAa;YACnB,MAAM,EAAE,IAAI;YACZ,OAAO,EAAE,CAAC,eAAe,CAAC;YAC1B,SAAS,EAAE;gBACT,EAAE,OAAO,EAAE,aAAa,EAAE,QAAQ,EAAE,mBAAmB,CAAC,OAAO,CAAC,EAAE;gBAClE,gBAAgB;gBAChB,YAAY;gBACZ,gBAAgB;gBAChB,UAAU;gBACV,SAAS;gBACT,YAAY;gBACZ,UAAU;gBACV,WAAW;gBACX,eAAe;gBACf,WAAW;gBACX,eAAe;aAChB;YACD,OAAO,EAAE,CAAC,gBAAgB,EAAE,UAAU,CAAC;SACxC,CAAC;IACJ,CAAC;CACF,CAAA;AAvBY,WAAW;IADvB,MAAM,CAAC,EAAE,CAAC;GACE,WAAW,CAuBvB"}
1
+ {"version":3,"file":"admin.module.js","sourceRoot":"","sources":["../src/admin.module.ts"],"names":[],"mappings":";;;;;;;AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,oCAAoC,CAAC;AACrE,OAAO,EAAE,gBAAgB,EAAE,MAAM,kCAAkC,CAAC;AACpE,OAAO,EAAE,cAAc,EAAE,MAAM,gCAAgC,CAAC;AAChE,OAAO,EAAE,MAAM,EAAsB,MAAM,gBAAgB,CAAC;AAC5D,OAAO,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAC/C,OAAO,EAAE,eAAe,EAAE,MAAM,4BAA4B,CAAC;AAC7D,OAAO,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAC/C,OAAO,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AACtD,OAAO,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAC;AACtD,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAC1D,OAAO,EAAE,WAAW,EAAE,MAAM,kCAAkC,CAAC;AAC/D,OAAO,EAAE,UAAU,EAAE,MAAM,gCAAgC,CAAC;AAC5D,OAAO,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAC;AACxD,OAAO,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AACnD,OAAO,EAAE,eAAe,EAAE,MAAM,6BAA6B,CAAC;AAC9D,OAAO,EAAE,mBAAmB,EAA2B,MAAM,cAAc,CAAC;AAC5E,OAAO,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAC;AACxD,OAAO,EAAE,gBAAgB,EAAE,MAAM,iCAAiC,CAAC;AAG5D,IAAM,WAAW,mBAAjB,MAAM,WAAW;IACf,AAAP,MAAM,CAAC,OAAO,CAAC,OAAO,GAAuB,EAAE;QAC7C,OAAO;YACL,MAAM,eAAa;YACnB,MAAM,EAAE,IAAI;YACZ,OAAO,EAAE,CAAC,eAAe,CAAC;YAC1B,SAAS,EAAE;gBACT,EAAE,OAAO,EAAE,aAAa,EAAE,QAAQ,EAAE,mBAAmB,CAAC,OAAO,CAAC,EAAE;gBAClE,gBAAgB;gBAChB,YAAY;gBACZ,cAAc;gBACd,eAAe;gBACf,gBAAgB;gBAChB,gBAAgB;gBAChB,UAAU;gBACV,SAAS;gBACT,YAAY;gBACZ,UAAU;gBACV,WAAW;gBACX,eAAe;gBACf,WAAW;gBACX,eAAe;aAChB;YACD,OAAO,EAAE,CAAC,gBAAgB,EAAE,UAAU,CAAC;SACxC,CAAC;IACJ,CAAC;CACF,CAAA;AA1BY,WAAW;IADvB,MAAM,CAAC,EAAE,CAAC;GACE,WAAW,CA0BvB"}
@@ -95,6 +95,9 @@ export class ActionService {
95
95
  const record = await resource.findOne(id, tx);
96
96
  if (!record)
97
97
  throw new AdminNotFoundError(`${schema.label} "${rawId}" not found`);
98
+ // A per-record label of `null` means the action does not exist on this record (it is not offered there either).
99
+ if (action.labelFor && action.labelFor(record) === null)
100
+ throw new AdminNotFoundError(`"${action.name}" does not apply to ${schema.label} "${rawId}"`);
98
101
  if (!policy.recordRule(entry, action.name, record, tx))
99
102
  throw new AdminForbiddenError(`You may not run "${label}" on ${schema.label} "${rawId}"`);
100
103
  return { id, record };
@@ -1 +1 @@
1
- {"version":3,"file":"action.service.js","sourceRoot":"","sources":["../../src/api/action.service.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"action.service.js","sourceRoot":"","sources":["../../src/api/action.service.ts"],"names":[],"mappings":"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"}
@@ -1,4 +1,6 @@
1
- import type { ActionResult, AdminRecord, BulkResult, ListResponse, MetaPageSummary, MetaResponse, OptionsResponse, PageResponse, ResourceSchema, SearchResponse } from '../contract.js';
1
+ import type { ActionResult, AdminRecord, BulkResult, ListResponse, MenuBadges, TabCounts, MetaPageSummary, MetaResponse, OptionsResponse, PageResponse, ResourceSchema, SearchResponse } from '../contract.js';
2
+ import { DashboardService } from '../dashboard/dashboard.service.js';
3
+ import { WidgetRegistry } from '../dashboard/widget-registry.js';
2
4
  import { AdminAudit } from '../audit/audit.service.js';
3
5
  import { FilesService } from '../files/files.service.js';
4
6
  import { AdminPolicy } from '../policy/admin-policy.service.js';
@@ -11,10 +13,13 @@ export declare class AdminApiService {
11
13
  private readonly options;
12
14
  private readonly policy;
13
15
  private readonly files;
16
+ private readonly pageRegistry;
17
+ private readonly dashboard;
18
+ private readonly widgets;
14
19
  private readonly logger;
15
20
  /** The write transaction and what takes part in every change made inside it: files, then the audit log. */
16
21
  private readonly writes;
17
- constructor(registry: ResourceRegistry, options: ResolvedAdminOptions, policy: AdminPolicy, files: FilesService, pages: PageRegistry, audit: AdminAudit);
22
+ constructor(registry: ResourceRegistry, options: ResolvedAdminOptions, policy: AdminPolicy, files: FilesService, pageRegistry: PageRegistry, audit: AdminAudit, dashboard: DashboardService, widgets: WidgetRegistry);
18
23
  /** `_inlines` of a POST or PATCH: the children's changes, saved inside the parent's write. */
19
24
  private readonly inlineWriter;
20
25
  /** `_inlines` of a record: its children through each child resource's read path. */
@@ -28,6 +33,27 @@ export declare class AdminApiService {
28
33
  private view;
29
34
  /** Sidebar data with labels in `locale` (the default locale when omitted). */
30
35
  meta(locale?: string, ctx?: AdminContext): MetaResponse;
36
+ /**
37
+ * Image cells hold a file key; the page gets its URL (the storage's public one, or the admin's download route, which
38
+ * checks the viewer again). A value that is already an http(s) or relative URL stays; anything else becomes null.
39
+ */
40
+ private imageUrls;
41
+ /**
42
+ * A list's count for this user (menu badges, tab counts): through the resource's findMany, so `query()` and scopes
43
+ * apply; an overridden findMany may ignore scopes, so for a scoped user it goes through the scoped base path.
44
+ */
45
+ private count;
46
+ /** `GET /api/resources/:resource/tab-counts`: each tab this user may use, counted in parallel (`null`: `count: 'none'`). */
47
+ tabCounts(name: string, ctx: AdminContext): Promise<TabCounts>;
48
+ /** Computed columns of some rows of a resource, image cells as URLs. */
49
+ private computedValues;
50
+ /** The menu's references are checked once every resource and settings page is registered. */
51
+ onApplicationBootstrap(): void;
52
+ /**
53
+ * `GET /api/menu/badges`: each menu badge counted for this user through the list's own path (scopes and `query()`
54
+ * apply). A badge whose filters name a field this user cannot see, or on a resource they cannot view, is left out.
55
+ */
56
+ badges(ctx: AdminContext): Promise<MenuBadges>;
31
57
  /** A resource's schema with its labels in `locale`. */
32
58
  schema(name: string, locale?: string, ctx?: AdminContext): ResourceSchema;
33
59
  list(name: string, query: URLSearchParams, ctx: AdminContext): Promise<ListResponse>;
@@ -37,6 +63,12 @@ export declare class AdminApiService {
37
63
  */
38
64
  search(query: URLSearchParams, ctx: AdminContext): Promise<SearchResponse>;
39
65
  get(name: string, rawId: string, ctx: AdminContext): Promise<AdminRecord>;
66
+ /**
67
+ * What the record page shows beside the form (spec §5.6): each relation aside card's record (`_aside`, read through
68
+ * the target's own GET, so its permissions and scopes apply; absent when this user may not see it) and the computed
69
+ * columns its header names (`_computed`).
70
+ */
71
+ private recordPage;
40
72
  /** Serializes entities with their relation values and paths (`fields`) loaded and their titles. */
41
73
  private records;
42
74
  /** One record with every relation field loaded (detail and write responses). */
@@ -11,7 +11,7 @@ var __param = (this && this.__param) || function (paramIndex, decorator) {
11
11
  return function (target, key) { decorator(target, key, paramIndex); }
12
12
  };
13
13
  import { Inject, Injectable, Logger } from '@nestjs/common';
14
- import { applyFieldConfig, localizeLayout } from '../schema/field-config.js';
14
+ import { applyFieldConfig, localizeLayout, mainLayout } from '../schema/field-config.js';
15
15
  import { inlineOf, toLayoutInline } from '../inlines/inline-config.js';
16
16
  import { InlineReader } from '../inlines/inline-reader.js';
17
17
  import { InlineWriter } from '../inlines/inline-writer.js';
@@ -20,6 +20,11 @@ import { toErrorResponse } from '../http/error-response.js';
20
20
  import { toActionSchema } from '../decorators/admin-action.js';
21
21
  import { ADMIN_OPTIONS, MAX_BULK } from '../constants.js';
22
22
  import { parseListQuery } from '../crud/list-query.js';
23
+ import { buildMenu, checkMenu } from './menu.js';
24
+ import { DashboardService } from '../dashboard/dashboard.service.js';
25
+ import { WidgetRegistry } from '../dashboard/widget-registry.js';
26
+ import { loadComputed } from '../crud/computed-columns.js';
27
+ import { resourceFileOwner } from '../files/file-owner.js';
23
28
  import { encodeRecordId, parseRecordId, recordIdOf } from '../crud/record-id.js';
24
29
  import { likePattern } from '../crud/list-query-builder.js';
25
30
  import { parseId } from '../crud/list-query.js';
@@ -46,19 +51,39 @@ let AdminApiService = class AdminApiService {
46
51
  options;
47
52
  policy;
48
53
  files;
54
+ pageRegistry;
55
+ dashboard;
56
+ widgets;
49
57
  logger = new Logger('NestMyAdmin');
50
58
  /** The write transaction and what takes part in every change made inside it: files, then the audit log. */
51
59
  writes;
52
- constructor(registry, options, policy, files, pages, audit) {
60
+ constructor(registry, options, policy, files, pageRegistry, audit, dashboard, widgets) {
53
61
  this.registry = registry;
54
62
  this.options = options;
55
63
  this.policy = policy;
56
64
  this.files = files;
65
+ this.pageRegistry = pageRegistry;
66
+ this.dashboard = dashboard;
67
+ this.widgets = widgets;
68
+ const pages = pageRegistry;
57
69
  // Without `audit` nothing is recorded: the audit log is not even a participant.
58
70
  this.writes = new WriteRunner(options, this.logger, [filesParticipant(files), ...(audit.enabled ? [auditParticipant(audit)] : [])]);
59
71
  this.pages = new PageService({ pages, policy, options, files, writes: this.writes });
60
72
  this.actions = new ActionService({ policy, options, logger: this.logger, writes: this.writes, record: (entry, entity, ctx) => this.record(entry, entity, ctx) });
61
- this.inlines = new InlineReader({ policy, serialize: (entry, entities, ctx) => this.fullRecords(entry, entities, ctx) });
73
+ this.inlines = new InlineReader({
74
+ policy,
75
+ serialize: (entry, entities, ctx) => this.fullRecords(entry, entities, ctx),
76
+ computed: async (inline, entities, records, ctx) => {
77
+ const child = inline.child;
78
+ const visible = policy.computedVisible(child, ctx);
79
+ const columns = inline.computed.filter((key) => visible.has(key)).map((key) => child.computed.get(key));
80
+ if (columns.length === 0)
81
+ return;
82
+ const values = await this.computedValues(child, columns, entities, ctx);
83
+ for (const record of records)
84
+ record._computed = values.get(String(record._id)) ?? {};
85
+ },
86
+ });
62
87
  this.inlineWriter = new InlineWriter({
63
88
  policy,
64
89
  view: (entry, ctx) => this.view(entry, ctx),
@@ -95,7 +120,8 @@ let AdminApiService = class AdminApiService {
95
120
  meta(locale = this.options.locale, ctx) {
96
121
  const text = (label) => resolveText(label, locale, this.options.locale);
97
122
  // Only resources the user may view (spec §6.5: meta is filtered per user).
98
- const resources = this.registry.list().filter((entry) => !ctx || this.policy.permissionsOf(ctx).canOn(entry.schema.name, 'view'));
123
+ // `nav: false` resources have no entry of their own (spec §5): reachable by URL, not listed.
124
+ const resources = this.registry.list().filter((entry) => entry.nav && (!ctx || this.policy.permissionsOf(ctx).canOn(entry.schema.name, 'view')));
99
125
  const pages = this.pages.summaries(locale, ctx);
100
126
  // Inside a group: `order` first (lower first), then the label in the request's language.
101
127
  const byOrder = (a, b) => a.order - b.order || a.summary.label.localeCompare(b.summary.label, locale);
@@ -130,7 +156,99 @@ let AdminApiService = class AdminApiService {
130
156
  resources: items,
131
157
  pages: groupPages,
132
158
  }));
133
- return { schemaVersion: 1, title: text(this.options.title), locale, locales: this.options.locales, groups };
159
+ const menu = this.options.menu && buildMenu(this.options.menu, text, groups.flatMap((group) => group.resources), groups.flatMap((group) => group.pages));
160
+ // With widgets in the app, whether this user has a dashboard (it replaces the home page).
161
+ const dashboard = this.widgets.list().length > 0 ? { dashboard: ctx ? this.dashboard.has(ctx) : true } : {};
162
+ return { schemaVersion: 1, title: text(this.options.title), locale, locales: this.options.locales, groups, ...dashboard, ...(menu ? { menu } : {}) };
163
+ }
164
+ /**
165
+ * Image cells hold a file key; the page gets its URL (the storage's public one, or the admin's download route, which
166
+ * checks the viewer again). A value that is already an http(s) or relative URL stays; anything else becomes null.
167
+ */
168
+ async imageUrls(entry, computed, values, ctx) {
169
+ for (const column of computed) {
170
+ if (column.column.kind !== 'image')
171
+ continue;
172
+ const source = column.source;
173
+ const holder = source.type === 'first' ? this.registry.forEntity(source.relation.inverseEntityMetadata.target, entry.dataSource) : source.type === 'field' && !source.path.includes('.') ? entry : undefined;
174
+ const field = source.type === 'first' ? source.field : source.type === 'field' ? source.path : undefined;
175
+ const isFile = holder && field && ['file', 'image'].includes(holder.fieldConfig.get(field)?.widget ?? '');
176
+ const cells = [...values.values()].map((row) => row[column.key]).filter((cell) => cell !== undefined);
177
+ const keys = cells.map((cell) => cell.value).filter((value) => typeof value === 'string');
178
+ const urls = isFile && keys.length > 0 ? await this.files.refs(resourceFileOwner(holder, this.policy), keys.map((key) => ({ [field]: key })), [field], ctx) : [];
179
+ const byKey = new Map(keys.map((key, index) => [key, urls[index]?.[field]?.url]));
180
+ for (const cell of cells) {
181
+ const value = typeof cell.value === 'string' ? cell.value : undefined;
182
+ cell.value = value === undefined ? null : (byKey.get(value) ?? (/^(https?:\/\/|\/)/i.test(value) ? value : null));
183
+ }
184
+ }
185
+ }
186
+ /**
187
+ * A list's count for this user (menu badges, tab counts): through the resource's findMany, so `query()` and scopes
188
+ * apply; an overridden findMany may ignore scopes, so for a scoped user it goes through the scoped base path.
189
+ */
190
+ async count(entry, params, ctx) {
191
+ const overridden = entry.resource.findMany !== AdminResourceBase.prototype.findMany;
192
+ const found = overridden && this.policy.scoped(entry, 'view', ctx) ? await AdminResourceBase.prototype.findMany.call(entry.resource, params, ctx) : await entry.resource.findMany(params, ctx);
193
+ return found.total === null || found.total === undefined ? undefined : { count: found.total, estimate: found.estimated === true };
194
+ }
195
+ /** `GET /api/resources/:resource/tab-counts`: each tab this user may use, counted in parallel (`null`: `count: 'none'`). */
196
+ async tabCounts(name, ctx) {
197
+ const entry = this.registry.get(name);
198
+ this.policy.require(entry, 'view', ctx);
199
+ const schema = this.view(entry, ctx).schema;
200
+ const counts = await Promise.all((schema.list.tabs ?? []).map(async (tab) => {
201
+ if (tab.count === 'none')
202
+ return [tab.key, null];
203
+ const params = parseListQuery(new URLSearchParams({ ...tab.filter, ...(tab.where ? { tab: tab.key } : {}), pageSize: '1' }), schema);
204
+ params.count = tab.count;
205
+ if (params.pagination === 'keyset')
206
+ params.after = undefined;
207
+ return [tab.key, (await this.count(entry, params, ctx)) ?? null];
208
+ }));
209
+ return Object.fromEntries(counts);
210
+ }
211
+ /** Computed columns of some rows of a resource, image cells as URLs. */
212
+ async computedValues(entry, columns, entities, ctx) {
213
+ const locale = ctx.locale ?? this.options.locale;
214
+ const values = await loadComputed(columns, entities, entry.metadata, ctx, this.registry.childQuery, (alias) => entry.resource.readQuery(alias, ctx), (label) => resolveText(label, locale, this.options.locale), (target, field) => this.registry.forEntity(target, entry.dataSource)?.schema.fields.find((candidate) => candidate.name === field));
215
+ await this.imageUrls(entry, columns, values, ctx);
216
+ return values;
217
+ }
218
+ /** The menu's references are checked once every resource and settings page is registered. */
219
+ onApplicationBootstrap() {
220
+ if (this.options.menu)
221
+ checkMenu(this.options.menu, this.registry, this.pageRegistry);
222
+ }
223
+ /**
224
+ * `GET /api/menu/badges`: each menu badge counted for this user through the list's own path (scopes and `query()`
225
+ * apply). A badge whose filters name a field this user cannot see, or on a resource they cannot view, is left out.
226
+ */
227
+ async badges(ctx) {
228
+ const out = {};
229
+ const perms = this.policy.permissionsOf(ctx);
230
+ for (const section of this.options.menu?.sections ?? []) {
231
+ for (const item of section.items) {
232
+ if (!('resource' in item) || !item.badge)
233
+ continue;
234
+ const entry = this.registry.get(item.resource);
235
+ if (!perms.canOn(entry.schema.name, 'view'))
236
+ continue;
237
+ let params;
238
+ try {
239
+ params = parseListQuery(new URLSearchParams({ ...item.badge, pageSize: '1' }), this.view(entry, ctx).schema);
240
+ }
241
+ catch {
242
+ continue; // a filter on a field this user cannot see: no count, so nothing to compare
243
+ }
244
+ // `none` lists are not counted page by page, but a badge is a count: estimate it instead.
245
+ params.count = params.count === 'none' ? 'estimate' : params.count;
246
+ const counted = await this.count(entry, params, ctx);
247
+ if (counted)
248
+ out[`${section.key}.${item.resource}`] = counted;
249
+ }
250
+ }
251
+ return out;
134
252
  }
135
253
  /** A resource's schema with its labels in `locale`. */
136
254
  schema(name, locale = this.options.locale, ctx) {
@@ -144,11 +262,16 @@ let AdminApiService = class AdminApiService {
144
262
  return { ...item, label: fieldLabel ? `${base} (${fieldLabel})` : base };
145
263
  });
146
264
  const fields = entry.schema.fields.map((field) => applyFieldConfig(field, entry.fieldConfig.get(field.name), locale, this.options.locale, this.options.files?.maxBytes, this.files.enabled));
147
- const layout = entry.resource.form?.layout;
265
+ const layout = mainLayout(entry.resource.form?.layout);
148
266
  const inline = (node, label) => toLayoutInline(inlineOf(entry, node), label, locale, this.options.locale);
149
267
  const form = layout ? { ...entry.schema.form, layout: localizeLayout(layout, locale, this.options.locale, inline) } : entry.schema.form;
150
268
  const actions = [...entry.actions.values()].map((action) => toActionSchema(action, locale, this.options.locale));
151
- const localized = { ...entry.schema, label: text(entry.label), related, fields, form, actions };
269
+ const computed = entry.schema.list.computed && Object.fromEntries(Object.entries(entry.schema.list.computed).map(([key, column]) => [key, { ...column, label: text(entry.computed.get(key).column.label) }]));
270
+ const tabs = entry.schema.list.tabs?.map((tab, index) => ({ ...tab, label: text(entry.resource.list.tabs[index].label) }));
271
+ const list = { ...entry.schema.list, ...(computed ? { computed } : {}), ...(tabs ? { tabs } : {}) };
272
+ const asideConfig = entry.resource.form?.layout && !Array.isArray(entry.resource.form.layout) ? entry.resource.form.layout.aside : undefined;
273
+ const localizedForm = form.aside && asideConfig ? { ...form, aside: form.aside.map((card, index) => ({ ...card, title: text(asideConfig[index].title) })) } : form;
274
+ const localized = { ...entry.schema, label: text(entry.label), related, fields, form: localizedForm, actions, list };
152
275
  const schema = ctx ? this.policy.view(entry, localized, ctx).schema : localized;
153
276
  // The child schema of every inline left in the layout (the policy removed those the user may not view).
154
277
  const children = (schema.form.layout ?? []).flatMap((node) => ('tab' in node ? node.sections : [node])).flatMap((node) => ('inline' in node ? [node.inline] : []));
@@ -176,8 +299,18 @@ let AdminApiService = class AdminApiService {
176
299
  const mobile = schema.list.mobile;
177
300
  const shown = new Set([...schema.list.columns, ...(mobile ? [mobile.title, mobile.subtitle, mobile.badge, ...mobile.meta] : [])]);
178
301
  const loaded = schema.fields.filter((field) => isLoadedField(field) && shown.has(field.name));
302
+ const records = await this.records(entry, items, loaded, ctx);
303
+ // Computed columns the viewer sees (the schema kept only those) and the page shows: one batch for the page.
304
+ const computed = [...entry.computed.values()].filter((column) => schema.list.computed?.[column.key] && shown.has(column.key));
305
+ if (computed.length > 0) {
306
+ const locale = ctx.locale ?? this.options.locale;
307
+ const values = await loadComputed(computed, items, entry.metadata, ctx, this.registry.childQuery, (alias) => entry.resource.readQuery(alias, ctx), (label) => resolveText(label, locale, this.options.locale), (entity, field) => this.registry.forEntity(entity, entry.dataSource)?.schema.fields.find((candidate) => candidate.name === field));
308
+ await this.imageUrls(entry, computed, values, ctx);
309
+ for (const record of records)
310
+ record._computed = values.get(String(record._id)) ?? {};
311
+ }
179
312
  return {
180
- items: await this.records(entry, items, loaded, ctx),
313
+ items: records,
181
314
  total: total ?? null,
182
315
  ...(estimated ? { estimated: true } : {}),
183
316
  ...(hasMore !== undefined ? { hasMore } : {}),
@@ -200,7 +333,7 @@ let AdminApiService = class AdminApiService {
200
333
  throw new AdminValidationError({ limit: ['must be an integer from 1 to 20'] });
201
334
  const locale = ctx.locale ?? this.options.locale;
202
335
  const perms = this.policy.permissionsOf(ctx);
203
- const searchable = this.registry.list().filter((entry) => perms.canOn(entry.schema.name, 'view') && this.view(entry, ctx).schema.list.search.length > 0);
336
+ const searchable = this.registry.list().filter((entry) => entry.nav && perms.canOn(entry.schema.name, 'view') && this.view(entry, ctx).schema.list.search.length > 0);
204
337
  const results = await Promise.all(searchable.map(async (entry) => {
205
338
  const schema = this.view(entry, ctx).schema;
206
339
  const sortPath = entry.sortPaths.get(schema.list.defaultSort.field);
@@ -246,8 +379,57 @@ let AdminApiService = class AdminApiService {
246
379
  const record = await this.record(entry, entity, ctx);
247
380
  if (entry.inlines.length > 0)
248
381
  await this.inlines.readInto(record, entry, entity, ctx);
382
+ await this.recordPage(entry, entity, record, ctx);
249
383
  return record;
250
384
  }
385
+ /**
386
+ * What the record page shows beside the form (spec §5.6): each relation aside card's record (`_aside`, read through
387
+ * the target's own GET, so its permissions and scopes apply; absent when this user may not see it) and the computed
388
+ * columns its header names (`_computed`).
389
+ */
390
+ async recordPage(entry, entity, record, ctx) {
391
+ const form = this.view(entry, ctx).schema.form;
392
+ const aside = {};
393
+ for (const [index, card] of (form.aside ?? []).entries()) {
394
+ if (!card.relation)
395
+ continue;
396
+ const value = record[card.relation.field];
397
+ const id = value && typeof value === 'object' ? value.id : value;
398
+ if (id === null || id === undefined)
399
+ continue;
400
+ try {
401
+ const related = await this.get(card.relation.resource, encodeRecordId([id]), ctx);
402
+ aside[String(index)] = { _id: related._id, _title: related._title, ...Object.fromEntries(card.fields.filter((field) => field in related).map((field) => [field, related[field]])) };
403
+ }
404
+ catch (error) {
405
+ if (!(error instanceof AdminNotFoundError) && !(error instanceof AdminForbiddenError))
406
+ throw error;
407
+ }
408
+ }
409
+ if (Object.keys(aside).length > 0)
410
+ record._aside = aside;
411
+ // Stepper fields: when each step was last reached, from the history child (its read path: query() and scopes),
412
+ // only when this user may see its value and time fields.
413
+ for (const field of this.view(entry, ctx).schema.fields) {
414
+ const history = field.steps?.history ? entry.steppers.get(field.name) : undefined;
415
+ if (!history)
416
+ continue;
417
+ const { child } = history;
418
+ const levels = this.policy.levels(child, ctx);
419
+ if (!this.policy.permissionsOf(ctx).canOn(child.schema.name, 'view') || [history.value, history.at].some((name) => (levels.get(name) ?? 'hidden') === 'hidden'))
420
+ continue;
421
+ const qb = child.resource.readQuery('nma_h', ctx).select(`nma_h.${history.value}`, 'v').addSelect(`MAX(nma_h.${history.at})`, 't');
422
+ qb.andWhere(`nma_h.${history.link} = :nmaParent`, { nmaParent: recordIdValue(entity, entry.schema.primaryKeys[0]) });
423
+ Object.entries(history.where).forEach(([name, value], index) => qb.andWhere(`nma_h.${name} = :nmaWhere${index}`, { [`nmaWhere${index}`]: value }));
424
+ const rows = await qb.groupBy(`nma_h.${history.value}`).getRawMany();
425
+ record._steps = { ...(record._steps ?? {}), ...Object.fromEntries(rows.map((row) => [row.v, isoTime(row.t)])) };
426
+ }
427
+ const summaries = (form.layout ?? []).flatMap((node) => ('tab' in node ? node.sections : [node])).flatMap((node) => ('summary' in node ? node.summary : []));
428
+ const keys = [...(form.header?.subtitle ?? []), ...summaries.map((row) => row.value)].flatMap((item) => ('computed' in item ? [item.computed] : []));
429
+ const computed = keys.flatMap((key) => (entry.computed.has(key) ? [entry.computed.get(key)] : []));
430
+ if (computed.length > 0)
431
+ record._computed = (await this.computedValues(entry, [...new Set(computed)], [entity], ctx)).get(String(record._id)) ?? {};
432
+ }
251
433
  /** Serializes entities with their relation values and paths (`fields`) loaded and their titles. */
252
434
  async records(entry, entities, fields, ctx) {
253
435
  // Only what this user may see is serialized (spec §6.5).
@@ -305,7 +487,8 @@ let AdminApiService = class AdminApiService {
305
487
  async create(name, body, ctx) {
306
488
  const entry = this.registry.get(name);
307
489
  const { resource } = entry;
308
- if (entry.schema.creatable)
490
+ // A read-only resource answers 403 (it refuses writes), not the 400 of a resource that cannot be created.
491
+ if (entry.schema.creatable || entry.schema.readonly)
309
492
  this.policy.require(entry, 'create', ctx);
310
493
  else
311
494
  this.policy.requireReach(entry, ctx);
@@ -707,7 +890,9 @@ AdminApiService = __decorate([
707
890
  __metadata("design:paramtypes", [ResourceRegistry, Object, AdminPolicy,
708
891
  FilesService,
709
892
  PageRegistry,
710
- AdminAudit])
893
+ AdminAudit,
894
+ DashboardService,
895
+ WidgetRegistry])
711
896
  ], AdminApiService);
712
897
  export { AdminApiService };
713
898
  /** A serialized record as relationOptions() values: relation refs become ids. */
@@ -743,4 +928,18 @@ function parseValues(raw) {
743
928
  }
744
929
  return parsed;
745
930
  }
931
+ /** The record's (single) key value. */
932
+ function recordIdValue(entity, key) {
933
+ return entity[key];
934
+ }
935
+ /** A time from MAX() as an ISO string: drivers answer a Date, or (SQLite) text in UTC without a zone. */
936
+ function isoTime(value) {
937
+ if (value === null || value === undefined)
938
+ return null;
939
+ if (value instanceof Date)
940
+ return value.toISOString();
941
+ const text = String(value);
942
+ const date = new Date(/[zZ]|[+-]\d\d:?\d\d$/.test(text) ? text : `${text.replace(' ', 'T')}Z`);
943
+ return Number.isNaN(date.getTime()) ? null : date.toISOString();
944
+ }
746
945
  //# sourceMappingURL=admin-api.service.js.map