@antelopejs/dms 0.9.8 → 0.11.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 (451) hide show
  1. package/CHANGELOG.md +171 -0
  2. package/README.md +1 -1
  3. package/data/module-store/catalog.json +2 -2
  4. package/dist/attachments/table-view.js +2 -2
  5. package/dist/attachments/table-view.js.map +1 -1
  6. package/dist/automation/actions.d.ts +2 -0
  7. package/dist/automation/actions.js +116 -71
  8. package/dist/automation/actions.js.map +1 -1
  9. package/dist/automation/i18n.d.ts +4 -0
  10. package/dist/automation/i18n.js +19 -0
  11. package/dist/automation/i18n.js.map +1 -0
  12. package/dist/automation/send-notification.d.ts +21 -0
  13. package/dist/automation/send-notification.js +163 -0
  14. package/dist/automation/send-notification.js.map +1 -0
  15. package/dist/automation/triggers.js +19 -25
  16. package/dist/automation/triggers.js.map +1 -1
  17. package/dist/client-origin-cors.d.ts +1 -0
  18. package/dist/client-origin-cors.js +19 -0
  19. package/dist/client-origin-cors.js.map +1 -0
  20. package/dist/config.d.ts +3 -2
  21. package/dist/config.js +5 -7
  22. package/dist/config.js.map +1 -1
  23. package/dist/frontend-module.d.ts +4 -0
  24. package/dist/frontend-module.js +37 -0
  25. package/dist/frontend-module.js.map +1 -0
  26. package/dist/implementations/dms/client-ip.js +1 -1
  27. package/dist/implementations/dms/client-ip.js.map +1 -1
  28. package/dist/implementations/dms/dev-reload.d.ts +5 -0
  29. package/dist/implementations/dms/dev-reload.js +23 -3
  30. package/dist/implementations/dms/dev-reload.js.map +1 -1
  31. package/dist/implementations/dms/frontend-modules.d.ts +2 -4
  32. package/dist/implementations/dms/frontend-modules.js +38 -94
  33. package/dist/implementations/dms/frontend-modules.js.map +1 -1
  34. package/dist/implementations/dms/frontend-ready.d.ts +12 -2
  35. package/dist/implementations/dms/frontend-ready.js +34 -4
  36. package/dist/implementations/dms/frontend-ready.js.map +1 -1
  37. package/dist/implementations/dms/layout-banners.d.ts +2 -1
  38. package/dist/implementations/dms/layout-banners.js +9 -0
  39. package/dist/implementations/dms/layout-banners.js.map +1 -1
  40. package/dist/implementations/dms/manifest.d.ts +7 -2
  41. package/dist/implementations/dms/manifest.js +12 -7
  42. package/dist/implementations/dms/manifest.js.map +1 -1
  43. package/dist/implementations/dms/page.d.ts +4 -3
  44. package/dist/implementations/dms/page.js +49 -18
  45. package/dist/implementations/dms/page.js.map +1 -1
  46. package/dist/implementations/dms/permissions-resolver.d.ts +2 -2
  47. package/dist/implementations/dms/permissions-resolver.js +2 -2
  48. package/dist/implementations/dms/permissions-resolver.js.map +1 -1
  49. package/dist/implementations/dms/realtime.js +1 -0
  50. package/dist/implementations/dms/realtime.js.map +1 -1
  51. package/dist/implementations/dms-base/bulk-selection.d.ts +1 -1
  52. package/dist/implementations/dms-base/bulk-selection.js +23 -1
  53. package/dist/implementations/dms-base/bulk-selection.js.map +1 -1
  54. package/dist/implementations/dms-base/filter-tokens.js +5 -3
  55. package/dist/implementations/dms-base/filter-tokens.js.map +1 -1
  56. package/dist/implementations/dms-base/search-route.d.ts +1 -0
  57. package/dist/implementations/dms-base/search-route.js +35 -13
  58. package/dist/implementations/dms-base/search-route.js.map +1 -1
  59. package/dist/implementations/dms-base/table-view.js +11 -6
  60. package/dist/implementations/dms-base/table-view.js.map +1 -1
  61. package/dist/implementations/dms-notifications/index.d.ts +2 -2
  62. package/dist/implementations/dms-notifications/index.js +5 -5
  63. package/dist/implementations/dms-notifications/index.js.map +1 -1
  64. package/dist/index.js +32 -55
  65. package/dist/index.js.map +1 -1
  66. package/dist/pages/modules/index.d.ts +1 -0
  67. package/dist/pages/modules/index.js +1 -0
  68. package/dist/pages/modules/index.js.map +1 -1
  69. package/dist/pages/modules/modules-store.d.ts +9 -0
  70. package/dist/pages/modules/modules-store.js +30 -0
  71. package/dist/pages/modules/modules-store.js.map +1 -0
  72. package/dist/pages/settings/users/account-credentials.js +2 -2
  73. package/dist/pages/settings/users/account-credentials.js.map +1 -1
  74. package/dist/pages/settings/users/account-data-store.js +25 -8
  75. package/dist/pages/settings/users/account-data-store.js.map +1 -1
  76. package/dist/pages/settings/users/invite-extension-routes.js +9 -3
  77. package/dist/pages/settings/users/invite-extension-routes.js.map +1 -1
  78. package/dist/pages/settings/users/member-management.js +13 -14
  79. package/dist/pages/settings/users/member-management.js.map +1 -1
  80. package/dist/pages/settings/users/profile.d.ts +1 -4
  81. package/dist/pages/settings/users/profile.js +0 -35
  82. package/dist/pages/settings/users/profile.js.map +1 -1
  83. package/dist/pages/settings/users/role-editor-store.js +26 -18
  84. package/dist/pages/settings/users/role-editor-store.js.map +1 -1
  85. package/dist/pages/settings/users/role-editor.d.ts +0 -1
  86. package/dist/pages/settings/users/role-editor.js +1 -2
  87. package/dist/pages/settings/users/role-editor.js.map +1 -1
  88. package/dist/pages/settings/users/role-preview.js +1 -2
  89. package/dist/pages/settings/users/role-preview.js.map +1 -1
  90. package/dist/pages/settings/users/roles.js +2 -2
  91. package/dist/pages/settings/users/roles.js.map +1 -1
  92. package/dist/pages/settings/users/two-factor-operations.js.map +1 -1
  93. package/dist/realtime/broker.d.ts +6 -0
  94. package/dist/realtime/broker.js +8 -1
  95. package/dist/realtime/broker.js.map +1 -1
  96. package/dist/realtime/presence.d.ts +8 -3
  97. package/dist/realtime/presence.js +8 -4
  98. package/dist/realtime/presence.js.map +1 -1
  99. package/dist/realtime/sessions.d.ts +11 -1
  100. package/dist/realtime/sessions.js +21 -3
  101. package/dist/realtime/sessions.js.map +1 -1
  102. package/dist/realtime/table-view.d.ts +2 -2
  103. package/dist/realtime/table-view.js +4 -3
  104. package/dist/realtime/table-view.js.map +1 -1
  105. package/dist/routes/auth/client-ip.d.ts +1 -0
  106. package/dist/routes/auth/client-ip.js +18 -0
  107. package/dist/routes/auth/client-ip.js.map +1 -1
  108. package/dist/routes/auth/oauth/config.d.ts +2 -1
  109. package/dist/routes/auth/oauth/config.js +5 -1
  110. package/dist/routes/auth/oauth/config.js.map +1 -1
  111. package/dist/routes/auth/session-handoff.d.ts +0 -1
  112. package/dist/routes/auth/session-handoff.js +0 -2
  113. package/dist/routes/auth/session-handoff.js.map +1 -1
  114. package/dist/routes/auth.js +3 -2
  115. package/dist/routes/auth.js.map +1 -1
  116. package/dist/routes/index.d.ts +0 -1
  117. package/dist/routes/index.js +0 -1
  118. package/dist/routes/index.js.map +1 -1
  119. package/dist/routes/realtime.d.ts +13 -1
  120. package/dist/routes/realtime.js +114 -29
  121. package/dist/routes/realtime.js.map +1 -1
  122. package/dist/startup-config.d.ts +2 -0
  123. package/dist/startup-config.js +62 -0
  124. package/dist/startup-config.js.map +1 -0
  125. package/dist/store/interfaces.d.ts +3 -2
  126. package/dist/store/interfaces.js +16 -6
  127. package/dist/store/interfaces.js.map +1 -1
  128. package/dist/store/listing.js +25 -15
  129. package/dist/store/listing.js.map +1 -1
  130. package/dist/store/operations.js +5 -2
  131. package/dist/store/operations.js.map +1 -1
  132. package/dist/store/requirements.js +3 -2
  133. package/dist/store/requirements.js.map +1 -1
  134. package/dist/store/runtime.d.ts +10 -1
  135. package/dist/store/runtime.js +33 -6
  136. package/dist/store/runtime.js.map +1 -1
  137. package/dist/store/types.d.ts +10 -0
  138. package/dist/utils/ensure-default-tenant.d.ts +2 -1
  139. package/dist/utils/ensure-default-tenant.js +13 -1
  140. package/dist/utils/ensure-default-tenant.js.map +1 -1
  141. package/dist/utils/export-jobs.js +2 -1
  142. package/dist/utils/export-jobs.js.map +1 -1
  143. package/dist/validation/auth.schema.d.ts +2 -2
  144. package/dist/validation/member-invite.schema.d.ts +2 -10
  145. package/dist/validation/member-invite.schema.js +2 -15
  146. package/dist/validation/member-invite.schema.js.map +1 -1
  147. package/frontend-vue/dms.frontend.ts +24 -5
  148. package/frontend-vue/dms.server.ts +17 -0
  149. package/frontend-vue/layers/dms-auth/server/accounts.ts +3 -4
  150. package/frontend-vue/layers/dms-core/app/build/composables/renderNow.ts +33 -0
  151. package/frontend-vue/layers/dms-core/app/build/composables/user/tablePreferences.ts +5 -1
  152. package/frontend-vue/layers/dms-core/app/build/utils/crossTab.ts +199 -0
  153. package/frontend-vue/layers/dms-core/app/build/utils/sharedRealtimeConnection.ts +410 -0
  154. package/frontend-vue/layers/dms-core/app/composables/auth/useApiData.ts +77 -12
  155. package/frontend-vue/layers/dms-core/app/composables/data-types/useDataType.ts +26 -0
  156. package/frontend-vue/layers/dms-core/app/composables/live/livePauseSource.ts +29 -0
  157. package/frontend-vue/layers/dms-core/app/composables/period/compareResolvers.ts +150 -9
  158. package/frontend-vue/layers/dms-core/app/composables/period/usePeriod.ts +6 -4
  159. package/frontend-vue/layers/dms-core/app/composables/period/usePeriodScope.ts +27 -1
  160. package/frontend-vue/layers/dms-core/app/composables/realtime/useUserRealtime.ts +256 -119
  161. package/frontend-vue/layers/dms-core/app/composables/translation/useComposedText.ts +21 -8
  162. package/frontend-vue/layers/dms-core/app/composables/translation/useTranslation.ts +25 -5
  163. package/frontend-vue/layers/dms-core/app/composables/useApiError.ts +3 -5
  164. package/frontend-vue/layers/dms-core/app/composables/useFieldErrors.ts +61 -26
  165. package/frontend-vue/layers/dms-core/app/plugins/dev-error-log.ts +16 -0
  166. package/frontend-vue/layers/dms-core/app/types/user.ts +6 -0
  167. package/frontend-vue/layers/dms-core/app/utils/composedText.ts +7 -2
  168. package/frontend-vue/layers/dms-core/app/utils/formatter.ts +134 -35
  169. package/frontend-vue/layers/dms-core/app/utils/url-interpolation.ts +18 -1
  170. package/frontend-vue/layers/dms-core/i18n/locales/core-en-GB.json +136 -2
  171. package/frontend-vue/layers/dms-core/i18n/locales/core-fr-FR.json +136 -2
  172. package/frontend-vue/layers/dms-core/shared/types/app-config.ts +0 -2
  173. package/frontend-vue/layers/dms-layout/app/app.config.ts +0 -1
  174. package/frontend-vue/layers/dms-layout/app/assets/css/main.css +11 -1
  175. package/frontend-vue/layers/dms-layout/app/assets/fonts/Geist-Italic-Variable.woff2 +0 -0
  176. package/frontend-vue/layers/dms-layout/app/assets/fonts/Geist-Variable.woff2 +0 -0
  177. package/frontend-vue/layers/dms-layout/app/assets/fonts/GeistMono-Italic-Variable.woff2 +0 -0
  178. package/frontend-vue/layers/dms-layout/app/assets/fonts/GeistMono-Variable.woff2 +0 -0
  179. package/frontend-vue/layers/dms-layout/app/build/components/layout/DashboardBanners.vue +3 -2
  180. package/frontend-vue/layers/dms-layout/app/build/components/layout/DashboardHeader.vue +41 -21
  181. package/frontend-vue/layers/dms-layout/app/build/components/layout/DashboardPageBody.vue +6 -2
  182. package/frontend-vue/layers/dms-layout/app/build/components/layout/DashboardSidebar.vue +4 -19
  183. package/frontend-vue/layers/dms-layout/app/build/components/layout/Footer.vue +11 -107
  184. package/frontend-vue/layers/dms-layout/app/build/components/layout/GithubStarPrompt.vue +18 -7
  185. package/frontend-vue/layers/dms-layout/app/build/components/layout/PageHeaderActionsOutlet.vue +4 -0
  186. package/frontend-vue/layers/dms-layout/app/build/components/layout/RowSidePanel.vue +43 -82
  187. package/frontend-vue/layers/dms-layout/app/build/components/layout/SidebarUserMenu.vue +44 -3
  188. package/frontend-vue/layers/dms-layout/app/build/components/layout/UserIdentity.vue +11 -3
  189. package/frontend-vue/layers/dms-layout/app/build/components/pages/modules/ModuleCatalogTile.vue +132 -35
  190. package/frontend-vue/layers/dms-layout/app/build/components/pages/modules/ModuleManageMenu.vue +59 -0
  191. package/frontend-vue/layers/dms-layout/app/build/components/pages/modules/ModuleSourceLabel.vue +25 -0
  192. package/frontend-vue/layers/dms-layout/app/build/components/pages/modules/ModuleStoreBanners.vue +73 -0
  193. package/frontend-vue/layers/dms-layout/app/build/components/pages/modules/ModuleStoreOperation.vue +116 -0
  194. package/frontend-vue/layers/dms-layout/app/build/components/pages/modules/ModuleStoreRequirements.vue +8 -3
  195. package/frontend-vue/layers/dms-layout/app/build/components/pages/modules/ModuleStoreTile.vue +85 -207
  196. package/frontend-vue/layers/dms-layout/app/build/components/pages/modules/ModuleTile.vue +10 -3
  197. package/frontend-vue/layers/dms-layout/app/build/components/pages/modules/ModuleTileSkeleton.vue +68 -0
  198. package/frontend-vue/layers/dms-layout/app/build/components/pages/settings/notification/NotificationInboxDisplay.vue +24 -8
  199. package/frontend-vue/layers/dms-layout/app/build/components/pages/settings/notification/NotificationInboxItem.vue +8 -5
  200. package/frontend-vue/layers/dms-layout/app/build/components/pages/settings/region/RegionTimeZoneInput.vue +1 -0
  201. package/frontend-vue/layers/dms-layout/app/build/components/pages/settings/roles/role-permissions.ts +19 -0
  202. package/frontend-vue/layers/dms-layout/app/build/components/pages/settings/roles/useRoleEditor.ts +2 -1
  203. package/frontend-vue/layers/dms-layout/app/build/composables/layout/useSidePanelWidth.ts +31 -70
  204. package/frontend-vue/layers/dms-layout/app/build/composables/notification/useNotificationGroupsOpen.ts +11 -1
  205. package/frontend-vue/layers/dms-layout/app/build/utils/dev-reload-stream.ts +81 -0
  206. package/frontend-vue/layers/dms-layout/app/build/utils/github-repository.ts +2 -2
  207. package/frontend-vue/layers/dms-layout/app/build/utils/module-store-catalog.ts +232 -36
  208. package/frontend-vue/layers/dms-layout/app/build/utils/modules-catalog.ts +122 -14
  209. package/frontend-vue/layers/dms-layout/app/composables/layout/useLayoutBanners.ts +32 -3
  210. package/frontend-vue/layers/dms-layout/app/composables/layout/useServedHeaderActions.ts +49 -11
  211. package/frontend-vue/layers/dms-layout/app/composables/page/useModuleHistory.ts +3 -2
  212. package/frontend-vue/layers/dms-layout/app/composables/page/useModuleStore.ts +59 -4
  213. package/frontend-vue/layers/dms-layout/app/composables/page/useModuleStoreActions.ts +194 -0
  214. package/frontend-vue/layers/dms-layout/app/composables/page/usePageComponentPreload.ts +23 -3
  215. package/frontend-vue/layers/dms-layout/app/composables/page/usePageLayout.ts +4 -2
  216. package/frontend-vue/layers/dms-layout/app/composables/page/usePageRecordDeletion.ts +162 -0
  217. package/frontend-vue/layers/dms-layout/app/composables/page/useSiteLayout.ts +6 -1
  218. package/frontend-vue/layers/dms-layout/app/custom-layouts/DefaultLayout.vue +6 -2
  219. package/frontend-vue/layers/dms-layout/app/custom-layouts/SettingsLayout.vue +6 -2
  220. package/frontend-vue/layers/dms-layout/app/custom-pages/modules-store.vue +291 -0
  221. package/frontend-vue/layers/dms-layout/app/custom-pages/modules.vue +87 -474
  222. package/frontend-vue/layers/dms-layout/app/middleware/module-routing.global.ts +3 -0
  223. package/frontend-vue/layers/dms-layout/app/pages/[...slug].vue +13 -22
  224. package/frontend-vue/layers/dms-layout/app/plugins/command-palette-navigation.client.ts +11 -10
  225. package/frontend-vue/layers/dms-layout/app/plugins/command-palette-personal-pages.client.ts +22 -52
  226. package/frontend-vue/layers/dms-layout/app/plugins/command-palette-quick-actions.client.ts +7 -7
  227. package/frontend-vue/layers/dms-layout/app/plugins/command-palette-session.client.ts +11 -10
  228. package/frontend-vue/layers/dms-layout/app/plugins/dms-dev-reload.client.ts +14 -9
  229. package/frontend-vue/layers/dms-layout/app/theme/actions.ts +5 -4
  230. package/frontend-vue/layers/dms-layout/app/theme/form-controls.ts +9 -4
  231. package/frontend-vue/layers/dms-layout/app/theme/surfaces.ts +22 -6
  232. package/frontend-vue/layers/dms-layout/app/types/module-store.ts +9 -0
  233. package/frontend-vue/layers/dms-layout/app/types/page.ts +15 -1
  234. package/frontend-vue/layers/dms-layout/app/utils/account-menu.ts +11 -0
  235. package/frontend-vue/layers/dms-layout/app/utils/breadcrumb.ts +57 -0
  236. package/frontend-vue/layers/dms-layout/app/utils/pageQuery.ts +26 -0
  237. package/frontend-vue/layers/dms-layout/i18n/locales/layout-en-GB.json +45 -18
  238. package/frontend-vue/layers/dms-layout/i18n/locales/layout-fr-FR.json +44 -17
  239. package/frontend-vue/layers/dms-ui/app/build/components/containers/TargetComponentTree.vue +31 -0
  240. package/frontend-vue/layers/dms-ui/app/build/components/containers/constants.ts +25 -0
  241. package/frontend-vue/layers/dms-ui/app/build/components/containers/drawer/DynamicDrawer.vue +244 -15
  242. package/frontend-vue/layers/dms-ui/app/build/components/containers/modal/DynamicModal.vue +42 -25
  243. package/frontend-vue/layers/dms-ui/app/build/components/containers/row/RowHeader.vue +153 -0
  244. package/frontend-vue/layers/dms-ui/app/build/components/containers/row/RowNotFound.vue +44 -0
  245. package/frontend-vue/layers/dms-ui/app/build/components/containers/row/drawerRowHeader.ts +35 -0
  246. package/frontend-vue/layers/dms-ui/app/build/components/form/FormEntries.vue +44 -9
  247. package/frontend-vue/layers/dms-ui/app/build/components/form/FormErrorSummary.vue +11 -4
  248. package/frontend-vue/layers/dms-ui/app/build/components/form/FormFieldControl.vue +38 -5
  249. package/frontend-vue/layers/dms-ui/app/build/components/form/FormFieldNotes.vue +29 -5
  250. package/frontend-vue/layers/dms-ui/app/build/components/form/FormLoadError.vue +5 -1
  251. package/frontend-vue/layers/dms-ui/app/build/components/form/FormSectionNav.vue +3 -1
  252. package/frontend-vue/layers/dms-ui/app/build/components/form/FormSections.vue +106 -27
  253. package/frontend-vue/layers/dms-ui/app/build/components/table/Actions.vue +12 -4
  254. package/frontend-vue/layers/dms-ui/app/build/components/table/Empty.vue +4 -2
  255. package/frontend-vue/layers/dms-ui/app/build/components/table/FiltersRow.vue +48 -1
  256. package/frontend-vue/layers/dms-ui/app/build/components/table/Pagination.vue +55 -54
  257. package/frontend-vue/layers/dms-ui/app/build/components/table/RowSelection.vue +2 -1
  258. package/frontend-vue/layers/dms-ui/app/build/components/table/Table.vue +396 -288
  259. package/frontend-vue/layers/dms-ui/app/build/components/table/Tabs.vue +2 -1
  260. package/frontend-vue/layers/dms-ui/app/build/components/table/Views.vue +2 -1
  261. package/frontend-vue/layers/dms-ui/app/build/components/table-view/CardAvatar.vue +59 -0
  262. package/frontend-vue/layers/dms-ui/app/build/components/table-view/CardGridSkeleton.vue +19 -2
  263. package/frontend-vue/layers/dms-ui/app/build/components/table-view/CardRowActions.vue +38 -0
  264. package/frontend-vue/layers/dms-ui/app/build/components/table-view/CardsDisplay.vue +148 -104
  265. package/frontend-vue/layers/dms-ui/app/build/components/table-view/LiveHoldBanner.vue +17 -2
  266. package/frontend-vue/layers/dms-ui/app/build/composables/actions/bulkSelection.ts +43 -9
  267. package/frontend-vue/layers/dms-ui/app/build/composables/actions/rowComponentOptions.ts +76 -0
  268. package/frontend-vue/layers/dms-ui/app/build/composables/actions/rowNavigation.ts +172 -27
  269. package/frontend-vue/layers/dms-ui/app/build/composables/actions/useActionTargets.ts +270 -46
  270. package/frontend-vue/layers/dms-ui/app/build/composables/confirm/actionError.ts +6 -1
  271. package/frontend-vue/layers/dms-ui/app/build/composables/confirm/confirmDialogTexts.ts +2 -0
  272. package/frontend-vue/layers/dms-ui/app/build/composables/containers/closingLayers.ts +186 -0
  273. package/frontend-vue/layers/dms-ui/app/build/composables/containers/context.ts +14 -0
  274. package/frontend-vue/layers/dms-ui/app/build/composables/containers/drawerSize.ts +229 -0
  275. package/frontend-vue/layers/dms-ui/app/build/composables/containers/useResizableSize.ts +175 -0
  276. package/frontend-vue/layers/dms-ui/app/build/composables/data-types/metricCells.ts +18 -35
  277. package/frontend-vue/layers/dms-ui/app/build/composables/data-types/numberSuffix.ts +44 -0
  278. package/frontend-vue/layers/dms-ui/app/build/composables/data-types/registerDefaults.ts +123 -27
  279. package/frontend-vue/layers/dms-ui/app/build/composables/data-types/registerFieldTypes.ts +2 -1
  280. package/frontend-vue/layers/dms-ui/app/build/composables/data-types/relationFilter.ts +75 -0
  281. package/frontend-vue/layers/dms-ui/app/build/composables/data-types/relationRows.ts +92 -0
  282. package/frontend-vue/layers/dms-ui/app/build/composables/data-types/relationValue.ts +39 -0
  283. package/frontend-vue/layers/dms-ui/app/build/composables/data-types/twoLineCell.ts +3 -3
  284. package/frontend-vue/layers/dms-ui/app/build/composables/data-types/useColumnValueRenderer.ts +6 -2
  285. package/frontend-vue/layers/dms-ui/app/build/composables/form/createFormFields.ts +15 -0
  286. package/frontend-vue/layers/dms-ui/app/build/composables/form/fieldSaved.ts +40 -0
  287. package/frontend-vue/layers/dms-ui/app/build/composables/form/fieldValueRule.ts +62 -0
  288. package/frontend-vue/layers/dms-ui/app/build/composables/form/formEntryContext.ts +5 -0
  289. package/frontend-vue/layers/dms-ui/app/build/composables/form/formFooter.ts +42 -7
  290. package/frontend-vue/layers/dms-ui/app/build/composables/form/formLayout.ts +106 -4
  291. package/frontend-vue/layers/dms-ui/app/build/composables/form/formRecordLoad.ts +11 -5
  292. package/frontend-vue/layers/dms-ui/app/build/composables/form/formSections.ts +32 -0
  293. package/frontend-vue/layers/dms-ui/app/build/composables/form/formValidation.ts +36 -4
  294. package/frontend-vue/layers/dms-ui/app/build/composables/form/readonlyValue.ts +19 -0
  295. package/frontend-vue/layers/dms-ui/app/build/composables/form/registerFormFunctions.ts +27 -0
  296. package/frontend-vue/layers/dms-ui/app/build/composables/form/repeaterTable.ts +78 -0
  297. package/frontend-vue/layers/dms-ui/app/build/composables/form/serverFieldErrors.ts +49 -0
  298. package/frontend-vue/layers/dms-ui/app/build/composables/form/toasterClearance.ts +118 -0
  299. package/frontend-vue/layers/dms-ui/app/build/composables/form/useInstantForm.ts +12 -1
  300. package/frontend-vue/layers/dms-ui/app/build/composables/live/currentPageLive.ts +41 -3
  301. package/frontend-vue/layers/dms-ui/app/build/composables/live/livePoller.ts +10 -2
  302. package/frontend-vue/layers/dms-ui/app/build/composables/live/pageReadClock.ts +28 -0
  303. package/frontend-vue/layers/dms-ui/app/build/composables/live/shortcuts.ts +1 -1
  304. package/frontend-vue/layers/dms-ui/app/build/composables/live/usePageLiveHost.ts +17 -3
  305. package/frontend-vue/layers/dms-ui/app/build/composables/live/useUpdatedLabel.ts +38 -0
  306. package/frontend-vue/layers/dms-ui/app/build/composables/page-toolbar/pageToolbarContext.ts +75 -0
  307. package/frontend-vue/layers/dms-ui/app/build/composables/page-toolbar/toolbarControlHeight.ts +29 -0
  308. package/frontend-vue/layers/dms-ui/app/build/composables/period/periodComparison.ts +52 -0
  309. package/frontend-vue/layers/dms-ui/app/build/composables/period/periodDisplay.ts +21 -0
  310. package/frontend-vue/layers/dms-ui/app/build/composables/period/periodShortLabels.ts +28 -0
  311. package/frontend-vue/layers/dms-ui/app/build/composables/period/usePeriodDraft.ts +1 -0
  312. package/frontend-vue/layers/dms-ui/app/build/composables/table/useRelationFilterLabels.ts +97 -0
  313. package/frontend-vue/layers/dms-ui/app/build/composables/table/useRowScrollAnchor.ts +106 -0
  314. package/frontend-vue/layers/dms-ui/app/build/composables/table/useTable.ts +9 -0
  315. package/frontend-vue/layers/dms-ui/app/build/composables/table/useTableColumns.ts +1 -2
  316. package/frontend-vue/layers/dms-ui/app/build/composables/table/utils/archivedCount.ts +31 -0
  317. package/frontend-vue/layers/dms-ui/app/build/composables/table/utils/filterEditorValue.ts +38 -0
  318. package/frontend-vue/layers/dms-ui/app/build/composables/table/utils/formatFilterValue.ts +33 -2
  319. package/frontend-vue/layers/dms-ui/app/build/composables/table/utils/scrollEdges.ts +31 -0
  320. package/frontend-vue/layers/dms-ui/app/build/composables/table-view/useCardFields.ts +33 -0
  321. package/frontend-vue/layers/dms-ui/app/build/composables/table-view/useMobileDisplay.ts +48 -0
  322. package/frontend-vue/layers/dms-ui/app/build/composables/table-view/useScrolledPastTop.ts +41 -18
  323. package/frontend-vue/layers/dms-ui/app/build/composables/table-view/useTableFooter.ts +3 -2
  324. package/frontend-vue/layers/dms-ui/app/build/composables/table-view/useTableLinkedVisit.ts +78 -0
  325. package/frontend-vue/layers/dms-ui/app/build/composables/table-view/useTableLiveHold.ts +135 -22
  326. package/frontend-vue/layers/dms-ui/app/build/composables/table-view/useTableRows.ts +56 -25
  327. package/frontend-vue/layers/dms-ui/app/build/composables/table-view/useTableViewRowActions.ts +90 -35
  328. package/frontend-vue/layers/dms-ui/app/build/composables/table-view/useTableViews.ts +86 -10
  329. package/frontend-vue/layers/dms-ui/app/build/composables/table-view/utils/bulkActions.ts +14 -4
  330. package/frontend-vue/layers/dms-ui/app/build/composables/table-view/utils/card.ts +127 -2
  331. package/frontend-vue/layers/dms-ui/app/build/composables/table-view/utils/compareValues.ts +13 -0
  332. package/frontend-vue/layers/dms-ui/app/build/composables/table-view/utils/expandedRows.ts +28 -0
  333. package/frontend-vue/layers/dms-ui/app/build/composables/table-view/utils/groupedRows.ts +114 -1
  334. package/frontend-vue/layers/dms-ui/app/build/composables/table-view/utils/linkedArrival.ts +308 -0
  335. package/frontend-vue/layers/dms-ui/app/build/composables/table-view/utils/locateRow.ts +106 -0
  336. package/frontend-vue/layers/dms-ui/app/build/composables/table-view/utils/pageArrival.ts +34 -0
  337. package/frontend-vue/layers/dms-ui/app/build/composables/table-view/utils/pinnedRows.ts +17 -0
  338. package/frontend-vue/layers/dms-ui/app/build/composables/table-view/utils/quickFilters.ts +41 -33
  339. package/frontend-vue/layers/dms-ui/app/build/composables/table-view/utils/recordLink.ts +24 -8
  340. package/frontend-vue/layers/dms-ui/app/build/composables/table-view/utils/tableCounts.ts +113 -0
  341. package/frontend-vue/layers/dms-ui/app/build/composables/table-view/utils/tableQuery.ts +27 -4
  342. package/frontend-vue/layers/dms-ui/app/build/composables/table-view/utils/views.ts +22 -6
  343. package/frontend-vue/layers/dms-ui/app/build/composables/table-view/utils/writeError.ts +21 -0
  344. package/frontend-vue/layers/dms-ui/app/build/utils/addressSuggestions.ts +49 -0
  345. package/frontend-vue/layers/dms-ui/app/build/utils/codeHighlight.ts +67 -29
  346. package/frontend-vue/layers/dms-ui/app/build/utils/eyebrow.ts +12 -0
  347. package/frontend-vue/layers/dms-ui/app/build/utils/fieldOptionsI18n.ts +51 -11
  348. package/frontend-vue/layers/dms-ui/app/build/utils/htmlGrammar.ts +79 -0
  349. package/frontend-vue/layers/dms-ui/app/build/utils/inputWidth.ts +53 -0
  350. package/frontend-vue/layers/dms-ui/app/build/utils/numberAdjustment.ts +6 -3
  351. package/frontend-vue/layers/dms-ui/app/build/utils/relativeDate.ts +19 -5
  352. package/frontend-vue/layers/dms-ui/app/build/utils/scrollWithin.ts +99 -0
  353. package/frontend-vue/layers/dms-ui/app/build/utils/shellParser.ts +1 -1
  354. package/frontend-vue/layers/dms-ui/app/build/utils/streamHighlight.ts +90 -0
  355. package/frontend-vue/layers/dms-ui/app/build/utils/urlVariables.ts +36 -14
  356. package/frontend-vue/layers/dms-ui/app/components/PasswordStrength.vue +1 -1
  357. package/frontend-vue/layers/dms-ui/app/components/RecursiveComponent.vue +9 -1
  358. package/frontend-vue/layers/dms-ui/app/components/blocks/LiveToggleBlock.vue +80 -32
  359. package/frontend-vue/layers/dms-ui/app/components/blocks/PageToolbarBlock.vue +137 -0
  360. package/frontend-vue/layers/dms-ui/app/components/blocks/StatGroupBlock.vue +5 -0
  361. package/frontend-vue/layers/dms-ui/app/components/chart/ApexChartHost.vue +16 -2
  362. package/frontend-vue/layers/dms-ui/app/components/chart/Chart.vue +24 -5
  363. package/frontend-vue/layers/dms-ui/app/components/chart/ChartCard.vue +41 -23
  364. package/frontend-vue/layers/dms-ui/app/components/code-snippet/CodeSnippet.vue +23 -12
  365. package/frontend-vue/layers/dms-ui/app/components/confirm/ConfirmModal.vue +1 -1
  366. package/frontend-vue/layers/dms-ui/app/components/container-footer/ContainerFooter.vue +34 -0
  367. package/frontend-vue/layers/dms-ui/app/components/field-row/FieldRow.vue +25 -2
  368. package/frontend-vue/layers/dms-ui/app/components/flow-canvas/FlowCanvas.vue +2 -2
  369. package/frontend-vue/layers/dms-ui/app/components/form/Form.vue +119 -36
  370. package/frontend-vue/layers/dms-ui/app/components/form/components/Cascader.vue +53 -22
  371. package/frontend-vue/layers/dms-ui/app/components/form/components/DatePicker.vue +20 -1
  372. package/frontend-vue/layers/dms-ui/app/components/form/components/Display.vue +13 -1
  373. package/frontend-vue/layers/dms-ui/app/components/form/components/Image.vue +8 -3
  374. package/frontend-vue/layers/dms-ui/app/components/form/components/InputAddress.vue +53 -5
  375. package/frontend-vue/layers/dms-ui/app/components/form/components/InputCode.vue +29 -5
  376. package/frontend-vue/layers/dms-ui/app/components/form/components/InputNumber.vue +45 -8
  377. package/frontend-vue/layers/dms-ui/app/components/form/components/InputPercentage.vue +28 -5
  378. package/frontend-vue/layers/dms-ui/app/components/form/components/InputSecret.vue +5 -0
  379. package/frontend-vue/layers/dms-ui/app/components/form/components/InputText.vue +19 -2
  380. package/frontend-vue/layers/dms-ui/app/components/form/components/InputTime.vue +2 -1
  381. package/frontend-vue/layers/dms-ui/app/components/form/components/Relation.vue +226 -65
  382. package/frontend-vue/layers/dms-ui/app/components/form/components/Repeater.vue +80 -30
  383. package/frontend-vue/layers/dms-ui/app/components/form/components/RepeaterTable.vue +210 -0
  384. package/frontend-vue/layers/dms-ui/app/components/form/components/Select.vue +4 -2
  385. package/frontend-vue/layers/dms-ui/app/components/grid/GridRow.vue +11 -2
  386. package/frontend-vue/layers/dms-ui/app/components/key-value-list/KeyValueList.vue +79 -70
  387. package/frontend-vue/layers/dms-ui/app/components/kpi/KpiCard.vue +117 -21
  388. package/frontend-vue/layers/dms-ui/app/components/meter/Meter.vue +2 -1
  389. package/frontend-vue/layers/dms-ui/app/components/period/PeriodSelector.vue +113 -34
  390. package/frontend-vue/layers/dms-ui/app/components/save-bar/SaveBar.vue +14 -2
  391. package/frontend-vue/layers/dms-ui/app/components/section-header/Eyebrow.vue +6 -1
  392. package/frontend-vue/layers/dms-ui/app/components/segmented/Segmented.vue +13 -0
  393. package/frontend-vue/layers/dms-ui/app/components/stat-group/StatGroup.vue +52 -3
  394. package/frontend-vue/layers/dms-ui/app/components/tab/Tab.vue +2 -1
  395. package/frontend-vue/layers/dms-ui/app/components/table-view/CascaderPath.vue +74 -25
  396. package/frontend-vue/layers/dms-ui/app/components/table-view/KanbanBoard.vue +48 -44
  397. package/frontend-vue/layers/dms-ui/app/components/table-view/KanbanDisplay.vue +4 -1
  398. package/frontend-vue/layers/dms-ui/app/components/table-view/TableView.vue +426 -97
  399. package/frontend-vue/layers/dms-ui/app/components/top-list/TopListCard.vue +33 -5
  400. package/frontend-vue/layers/dms-ui/app/composables/chart/apexCategoryLabels.ts +68 -0
  401. package/frontend-vue/layers/dms-ui/app/composables/chart/apexDatetimeBuckets.ts +306 -0
  402. package/frontend-vue/layers/dms-ui/app/composables/chart/formatValue.ts +4 -3
  403. package/frontend-vue/layers/dms-ui/app/composables/chart/heatmapColors.ts +93 -0
  404. package/frontend-vue/layers/dms-ui/app/composables/chart/localizeSeries.ts +62 -0
  405. package/frontend-vue/layers/dms-ui/app/composables/chart/useApexChart.ts +116 -8
  406. package/frontend-vue/layers/dms-ui/app/composables/chart/useApexChart.types.ts +7 -0
  407. package/frontend-vue/layers/dms-ui/app/composables/containers/types.ts +84 -1
  408. package/frontend-vue/layers/dms-ui/app/composables/containers/useDrawer.ts +69 -8
  409. package/frontend-vue/layers/dms-ui/app/composables/form/types/field-saved.ts +11 -0
  410. package/frontend-vue/layers/dms-ui/app/composables/form/types/field.ts +16 -0
  411. package/frontend-vue/layers/dms-ui/app/composables/form/types/functions.ts +1 -0
  412. package/frontend-vue/layers/dms-ui/app/composables/form/useForm.ts +189 -28
  413. package/frontend-vue/layers/dms-ui/app/composables/live/usePageLive.ts +29 -12
  414. package/frontend-vue/layers/dms-ui/app/composables/page-toolbar/usePageToolbarSize.ts +30 -0
  415. package/frontend-vue/layers/dms-ui/app/composables/table-view/kanban.ts +4 -2
  416. package/frontend-vue/layers/dms-ui/app/composables/table-view/types/action-target.ts +22 -3
  417. package/frontend-vue/layers/dms-ui/app/composables/table-view/types/config.ts +4 -0
  418. package/frontend-vue/layers/dms-ui/app/composables/table-view/types/display.ts +24 -1
  419. package/frontend-vue/layers/dms-ui/app/plugins/closing-layers.client.ts +10 -0
  420. package/frontend-vue/layers/dms-ui/app/plugins/live-pause-source.ts +15 -0
  421. package/frontend-vue/layers/dms-ui/app/plugins/register.ts +2 -0
  422. package/frontend-vue/layers/dms-ui/app/types/input-number.ts +3 -2
  423. package/frontend-vue/layers/dms-ui/app/types/page-toolbar.ts +7 -0
  424. package/frontend-vue/layers/dms-ui/app/types/row-action.ts +0 -2
  425. package/frontend-vue/layers/dms-ui/app/types/row-navigation.ts +17 -0
  426. package/frontend-vue/layers/dms-ui/app/types/table/query.ts +2 -1
  427. package/frontend-vue/layers/dms-ui/app/utils/blockRefresh.ts +3 -1
  428. package/frontend-vue/layers/dms-ui/app/utils/cascader.ts +94 -3
  429. package/frontend-vue/layers/dms-ui/app/utils/componentTree.ts +24 -0
  430. package/frontend-vue/layers/dms-ui/i18n/locales/ui-en-GB.json +20 -5
  431. package/frontend-vue/layers/dms-ui/i18n/locales/ui-fr-FR.json +20 -5
  432. package/frontend-vue/package.json +6 -2
  433. package/package.json +11 -10
  434. package/skills/dms/SKILL.md +1 -1
  435. package/skills/dms-auth/SKILL.md +5 -3
  436. package/skills/dms-best-practices/REFERENCE.md +2 -0
  437. package/skills/dms-best-practices/SKILL.md +4 -0
  438. package/skills/dms-module/SKILL.md +3 -2
  439. package/skills/dms-pages/REFERENCE.md +129 -16
  440. package/skills/dms-pages/SKILL.md +1 -1
  441. package/skills/dms-project/DEV-SERVERS.md +23 -1
  442. package/skills/dms-project/REFERENCE.md +1 -1
  443. package/skills/dms-project/SKILL.md +4 -1
  444. package/skills/dms-project/scripts/dms-dev.sh +205 -17
  445. package/dist/hooks/tenant-instances.d.ts +0 -1
  446. package/dist/hooks/tenant-instances.js +0 -13
  447. package/dist/hooks/tenant-instances.js.map +0 -1
  448. package/dist/routes/startup-gate.d.ts +0 -7
  449. package/dist/routes/startup-gate.js +0 -39
  450. package/dist/routes/startup-gate.js.map +0 -1
  451. package/frontend-vue/layers/dms-core/app/composables/period/periodRenderNow.ts +0 -42
@@ -0,0 +1,210 @@
1
+ <script setup lang="ts">
2
+ import { useId, type VNodeChild } from "vue";
3
+ import { EYEBROW_CLASS } from "../../../build/utils/eyebrow";
4
+ import {
5
+ relationRowValue,
6
+ useRelationRows,
7
+ } from "../../../build/composables/data-types/relationRows";
8
+ import { unlabeledRelationIds } from "../../../build/composables/data-types/relationValue";
9
+ import {
10
+ NUMERIC_TYPE_IDS,
11
+ useColumnValueRenderer,
12
+ } from "../../../build/composables/data-types/useColumnValueRenderer";
13
+ import {
14
+ type RelationColumnRows,
15
+ type RelationLabelSource,
16
+ type RepeaterTableColumn,
17
+ joinRelationValue,
18
+ relationLabelSource,
19
+ renderableColumn,
20
+ } from "../../../build/composables/form/repeaterTable";
21
+
22
+ /**
23
+ * The rows of a read-only list (an array or key-value field shown, not
24
+ * edited) as a table: each value drawn as a grid cell draws it (amounts
25
+ * right-aligned in the form's tabular figures, a select's label, a
26
+ * relation's name), text wrapping between words. In a narrow container
27
+ * (a phone's drawer) a list of more than two fields reads each row as a
28
+ * block of `label value` lines instead, so no amount is ever cut; a wider
29
+ * table still too narrow for its words scrolls sideways.
30
+ */
31
+ interface RepeaterTableProps {
32
+ columns: RepeaterTableColumn[];
33
+ rows: Record<string, unknown>[];
34
+ }
35
+
36
+ const props = defineProps<RepeaterTableProps>();
37
+ const { renderValue } = useColumnValueRenderer();
38
+ const { getDataType } = useDataTypes();
39
+ const { readRelationRows } = useRelationRows();
40
+ // Each column of each list reads its own ids: a key shared by two columns or
41
+ // two lists naming the same route would hand one of them the other's rows.
42
+ const instanceId = useId();
43
+
44
+ /**
45
+ * The related rows of a relation column, by the value its cells hold: read
46
+ * once for the ids the rows hold, narrowed to them with `?ids=`.
47
+ */
48
+ function useColumnRelationRows(columnId: string, source: RelationLabelSource) {
49
+ const ids = computed(() =>
50
+ unlabeledRelationIds(
51
+ props.rows.flatMap((row) => [row[columnId]].flat()),
52
+ NO_LABELS,
53
+ ),
54
+ );
55
+ const { data } = useDmsAsyncData(
56
+ `repeater-table-relation-${instanceId}-${columnId}`,
57
+ async () => {
58
+ const readIds = ids.value;
59
+ return { readIds, rows: await readRelationRows(source, readIds) };
60
+ },
61
+ // Names for the cells, not the page's data.
62
+ { lazy: true, refreshOnPageRefresh: false, watch: [ids] },
63
+ );
64
+ return computed<RelationColumnRows>(() => ({
65
+ rowsByValue: new Map(
66
+ (data.value?.rows ?? []).map((row) => [
67
+ relationRowValue(source, row),
68
+ row,
69
+ ]),
70
+ ),
71
+ readIds: new Set(data.value?.readIds),
72
+ }));
73
+ }
74
+
75
+ const NO_LABELS: ReadonlySet<string> = new Set();
76
+
77
+ // The columns are the field's own and do not change while it is shown.
78
+ const relationRows = new Map(
79
+ props.columns.flatMap((column) => {
80
+ const source = relationLabelSource(column, getDataType(column.type ?? ""));
81
+ return source
82
+ ? [
83
+ [
84
+ column.id,
85
+ { source, rows: useColumnRelationRows(column.id, source) },
86
+ ],
87
+ ]
88
+ : [];
89
+ }),
90
+ );
91
+
92
+ // Two fields (a key and its value) fit any width as a table; more stack
93
+ // below the container's `@md` width.
94
+ const TABLE_FITS_COLUMNS = 2;
95
+ const stacksWhenNarrow = computed(
96
+ () => props.columns.length > TABLE_FITS_COLUMNS,
97
+ );
98
+
99
+ const renderables = computed(() => props.columns.map(renderableColumn));
100
+
101
+ function isNumeric(column: RepeaterTableColumn): boolean {
102
+ return NUMERIC_TYPE_IDS.has(column.type ?? "");
103
+ }
104
+
105
+ function cellValue(column: RepeaterTableColumn, row: Record<string, unknown>) {
106
+ const value = row[column.id];
107
+ const relation = relationRows.get(column.id);
108
+ if (!relation) return value;
109
+ return joinRelationValue(
110
+ value,
111
+ relation.rows.value,
112
+ relation.source.multiple,
113
+ );
114
+ }
115
+
116
+ // A cell renders a VNode tree; a functional wrapper keeps it in the
117
+ // template's flow.
118
+ interface CellProps {
119
+ index: number;
120
+ rowIndex: number;
121
+ }
122
+ const Cell = ({ index, rowIndex }: CellProps): VNodeChild => {
123
+ const column = props.columns[index]!;
124
+ const row = props.rows[rowIndex]!;
125
+ return renderValue(
126
+ renderables.value[index]!,
127
+ cellValue(column, row),
128
+ row,
129
+ "detail",
130
+ );
131
+ };
132
+ // Declared, so `row-index` reaches it camelized, as a component's props do.
133
+ Cell.props = ["index", "rowIndex"];
134
+ </script>
135
+
136
+ <template>
137
+ <div class="@container min-w-0">
138
+ <div
139
+ class="min-w-0 overflow-x-auto"
140
+ :class="stacksWhenNarrow && 'hidden @md:block'"
141
+ >
142
+ <table class="w-full text-sm">
143
+ <thead>
144
+ <tr :class="[EYEBROW_CLASS, 'text-dimmed']">
145
+ <th
146
+ v-for="column in props.columns"
147
+ :key="column.id"
148
+ scope="col"
149
+ class="pe-4 pb-1.5 text-start align-bottom font-semibold whitespace-nowrap last:pe-0"
150
+ :class="isNumeric(column) && 'text-end'"
151
+ >
152
+ {{ column.label }}
153
+ </th>
154
+ </tr>
155
+ </thead>
156
+ <tbody>
157
+ <tr
158
+ v-for="(row, rowIndex) in props.rows"
159
+ :key="rowIndex"
160
+ class="border-default border-t"
161
+ >
162
+ <!-- A text cell wraps between words: `break-word`, unlike
163
+ `anywhere`, keeps a column at least as wide as its longest
164
+ word, so a narrow table scrolls instead of splitting one. -->
165
+ <td
166
+ v-for="(column, index) in props.columns"
167
+ :key="column.id"
168
+ class="text-default py-2 pe-4 align-top last:pe-0"
169
+ :class="
170
+ isNumeric(column)
171
+ ? 'text-end whitespace-nowrap'
172
+ : 'min-w-24 [overflow-wrap:break-word]'
173
+ "
174
+ >
175
+ <Cell :index :row-index="rowIndex" />
176
+ </td>
177
+ </tr>
178
+ </tbody>
179
+ </table>
180
+ </div>
181
+ <!-- The narrow reading: a row per block, a field per line, its label
182
+ beside its value. A value has the line's remaining width, an amount
183
+ never wraps. -->
184
+ <ul v-if="stacksWhenNarrow" class="text-sm @md:hidden">
185
+ <li
186
+ v-for="(row, rowIndex) in props.rows"
187
+ :key="rowIndex"
188
+ class="border-default border-t py-2 first:border-t-0 first:pt-0"
189
+ >
190
+ <dl class="grid grid-cols-[auto_minmax(0,1fr)] gap-x-4 gap-y-1">
191
+ <template v-for="(column, index) in props.columns" :key="column.id">
192
+ <dt class="text-dimmed pt-0.5 font-semibold" :class="EYEBROW_CLASS">
193
+ {{ column.label }}
194
+ </dt>
195
+ <dd
196
+ class="text-default min-w-0"
197
+ :class="
198
+ isNumeric(column)
199
+ ? 'text-end whitespace-nowrap'
200
+ : '[overflow-wrap:break-word]'
201
+ "
202
+ >
203
+ <Cell :index :row-index="rowIndex" />
204
+ </dd>
205
+ </template>
206
+ </dl>
207
+ </li>
208
+ </ul>
209
+ </div>
210
+ </template>
@@ -89,14 +89,16 @@ function handleUpdateModelValue(value: unknown) {
89
89
  "
90
90
  #default
91
91
  >
92
- <span class="inline-flex items-center gap-1.5">
92
+ <!-- Top-aligned: on the text's baseline, the icon would add the
93
+ line's descent and make the trigger taller than a text field. -->
94
+ <span class="inline-flex max-w-full items-center gap-1.5 align-top">
93
95
  <UIcon
94
96
  v-if="selectedItem.icon"
95
97
  :name="selectedItem.icon"
96
98
  class="size-4 shrink-0"
97
99
  :style="colorVar(selectedItem.iconColor)"
98
100
  />
99
- <span :style="colorVar(selectedItem.textColor)">
101
+ <span class="truncate" :style="colorVar(selectedItem.textColor)">
100
102
  {{ selectedItem.label }}
101
103
  </span>
102
104
  </span>
@@ -17,7 +17,13 @@ const DEFAULT_GAP = "1rem";
17
17
 
18
18
  const props = defineProps<GridRowProps>();
19
19
 
20
- const gridContext = inject<GridContext>(GRID_CONTEXT);
20
+ const gridContext = inject<GridContext | null>(GRID_CONTEXT, null);
21
+
22
+ // The grid's template is for its own rows only. A row nested in one of this
23
+ // row's cells (inside a Section, a stack...) lays out its own children: were it
24
+ // to read the outer grid, it would take that grid's column count and leave
25
+ // empty tracks beside its cells. A Grid inside a cell provides its own context.
26
+ provide<GridContext | null>(GRID_CONTEXT, null);
21
27
 
22
28
  /** The identity this row counts under, so its width dies with it. */
23
29
  const rowId = Symbol("grid-row");
@@ -28,7 +34,10 @@ watchEffect(() => gridContext?.setRowColumnCount(rowId, columnCount.value));
28
34
  onUnmounted(() => gridContext?.dropRow(rowId));
29
35
 
30
36
  const gap = computed(() => gridContext?.gap.value ?? DEFAULT_GAP);
31
- const maxColumns = computed(() => gridContext?.maxColumns.value || 1);
37
+ // Outside a Grid, the row spreads its own children over the width.
38
+ const maxColumns = computed(() =>
39
+ Math.max(1, gridContext ? gridContext.maxColumns.value : columnCount.value),
40
+ );
32
41
  const minColumnWidth = computed(
33
42
  () => gridContext?.minColumnWidth.value ?? GRID_DEFAULT_MIN_COLUMN_WIDTH,
34
43
  );
@@ -1,4 +1,5 @@
1
1
  <script setup lang="ts">
2
+ import { readableNumberFormat } from "#dms-core/app/utils/formatter";
2
3
  import { pageLink } from "../../build/composables/page/pageUrlValues";
3
4
  import { computed } from "vue";
4
5
  import { regionalDateTimeFormat } from "#dms-core/app/utils/regional";
@@ -48,7 +49,7 @@ interface KeyValueListProps {
48
49
  items?: KeyValueItem[];
49
50
  /** Tighter rows (32px instead of 38px) for side panels. */
50
51
  dense?: boolean;
51
- /** Columns on wide screens (1–3); one on phones. */
52
+ /** Columns once the list is wide enough (1–3); one when narrow. */
52
53
  columns?: number;
53
54
  /** Loading: values turn to skeletons, or `skeletonCount` rows are drawn. */
54
55
  loading?: boolean;
@@ -76,11 +77,13 @@ const EMPTY_VALUE = "—";
76
77
  const MAX_COLUMNS = 3;
77
78
 
78
79
  // v2 .c-dl: label left, value right, rows split by a muted hairline. Each
79
- // column's first row drops its line, at every breakpoint.
80
+ // column's first row drops its line, at every breakpoint. The columns follow
81
+ // the list's own width (a drawer, a card), not the window's: each keeps its
82
+ // 120px label and room for a value.
80
83
  const COLUMN_CLASSES: Record<number, string> = {
81
84
  1: "[&>div:first-child]:border-t-0",
82
- 2: "gap-x-8 sm:grid-cols-2 [&>div:first-child]:border-t-0 sm:[&>div:nth-child(2)]:border-t-0",
83
- 3: "gap-x-8 sm:grid-cols-2 lg:grid-cols-3 [&>div:first-child]:border-t-0 sm:[&>div:nth-child(2)]:border-t-0 lg:[&>div:nth-child(3)]:border-t-0",
85
+ 2: "gap-x-8 @min-[560px]:grid-cols-2 [&>div:first-child]:border-t-0 @min-[560px]:[&>div:nth-child(2)]:border-t-0",
86
+ 3: "gap-x-8 @min-[560px]:grid-cols-2 @min-[840px]:grid-cols-3 [&>div:first-child]:border-t-0 @min-[560px]:[&>div:nth-child(2)]:border-t-0 @min-[840px]:[&>div:nth-child(3)]:border-t-0",
84
87
  };
85
88
 
86
89
  const { locale, t } = useI18n();
@@ -105,13 +108,13 @@ type ValueFormatter = (item: KeyValueItem, value: string | number) => string;
105
108
 
106
109
  function formatNumber(_item: KeyValueItem, value: string | number): string {
107
110
  if (typeof value !== "number") return value;
108
- return new Intl.NumberFormat(locale.value).format(value);
111
+ return readableNumberFormat(locale.value).format(value);
109
112
  }
110
113
 
111
114
  function formatMoney(item: KeyValueItem, value: string | number): string {
112
115
  if (typeof value !== "number") return value;
113
116
  try {
114
- return new Intl.NumberFormat(locale.value, {
117
+ return readableNumberFormat(locale.value, {
115
118
  style: "currency",
116
119
  currency: item.currency ?? props.currency,
117
120
  }).format(value);
@@ -178,70 +181,76 @@ function keyOf(item: KeyValueItem, index: number): string {
178
181
  <template>
179
182
  <!-- grid-cols-1: minmax(0, 1fr) tracks, so a long value truncates instead
180
183
  of widening the list past a narrow screen. -->
181
- <dl
182
- class="grid grid-cols-1"
183
- :class="[columnClass, props.dense ? 'text-[12.5px]' : 'text-[13px]']"
184
- :aria-busy="props.loading || undefined"
185
- >
186
- <template v-if="showPlaceholders">
187
- <div v-for="index in props.skeletonCount" :key="index" :class="rowClass">
188
- <dt class="min-w-[120px] flex-none">
189
- <USkeleton :aria-label="t('dms.a11y.loading')" class="h-3 w-20" />
190
- </dt>
191
- <dd class="ms-auto">
192
- <USkeleton :aria-label="t('dms.a11y.loading')" class="h-3 w-24" />
193
- </dd>
194
- </div>
195
- </template>
196
- <template v-else>
197
- <div
198
- v-for="(item, index) in props.items"
199
- :key="keyOf(item, index)"
200
- :class="rowClass"
201
- >
202
- <dt class="text-muted min-w-[120px] flex-none">{{ item.label }}</dt>
203
- <dd
204
- class="ms-auto flex min-w-0 flex-wrap items-center justify-end gap-x-1.5 gap-y-0.5 text-end"
184
+ <div class="@container">
185
+ <dl
186
+ class="grid grid-cols-1"
187
+ :class="[columnClass, props.dense ? 'text-[12.5px]' : 'text-[13px]']"
188
+ :aria-busy="props.loading || undefined"
189
+ >
190
+ <template v-if="showPlaceholders">
191
+ <div
192
+ v-for="index in props.skeletonCount"
193
+ :key="index"
194
+ :class="rowClass"
205
195
  >
206
- <USkeleton
207
- :aria-label="t('dms.a11y.loading')"
208
- v-if="props.loading || item.loading"
209
- class="h-3 w-24"
210
- />
211
- <slot
212
- v-else-if="slots.value"
213
- name="value"
214
- :item="item"
215
- :formatted="format(item)"
216
- />
217
- <template v-else>
218
- <component
219
- :is="item.to ? DmsAutoLink : 'span'"
220
- :to="pageLink(item.to)"
221
- class="min-w-0"
222
- :class="item.to && item.type !== 'status' && 'hover:underline'"
223
- >
224
- <DmsStatusPill
225
- v-if="item.type === 'status'"
226
- :tone="item.tone ?? 'neutral'"
227
- :label="format(item)"
228
- />
229
- <span v-else class="block" :class="valueClass(item)">
230
- {{ format(item) }}
196
+ <dt class="min-w-[120px] flex-none">
197
+ <USkeleton :aria-label="t('dms.a11y.loading')" class="h-3 w-20" />
198
+ </dt>
199
+ <dd class="ms-auto">
200
+ <USkeleton :aria-label="t('dms.a11y.loading')" class="h-3 w-24" />
201
+ </dd>
202
+ </div>
203
+ </template>
204
+ <template v-else>
205
+ <div
206
+ v-for="(item, index) in props.items"
207
+ :key="keyOf(item, index)"
208
+ :class="rowClass"
209
+ >
210
+ <dt class="text-muted min-w-[120px] flex-none">{{ item.label }}</dt>
211
+ <dd
212
+ class="ms-auto flex min-w-0 flex-wrap items-center justify-end gap-x-1.5 gap-y-0.5 text-end"
213
+ >
214
+ <USkeleton
215
+ :aria-label="t('dms.a11y.loading')"
216
+ v-if="props.loading || item.loading"
217
+ class="h-3 w-24"
218
+ />
219
+ <slot
220
+ v-else-if="slots.value"
221
+ name="value"
222
+ :item="item"
223
+ :formatted="format(item)"
224
+ />
225
+ <template v-else>
226
+ <component
227
+ :is="item.to ? DmsAutoLink : 'span'"
228
+ :to="pageLink(item.to)"
229
+ class="min-w-0"
230
+ :class="item.to && item.type !== 'status' && 'hover:underline'"
231
+ >
232
+ <DmsStatusPill
233
+ v-if="item.type === 'status'"
234
+ :tone="item.tone ?? 'neutral'"
235
+ :label="format(item)"
236
+ />
237
+ <span v-else class="block" :class="valueClass(item)">
238
+ {{ format(item) }}
239
+ </span>
240
+ </component>
241
+ <span v-if="item.detail" class="text-dimmed truncate text-xs">
242
+ {{ item.detail }}
231
243
  </span>
232
- </component>
233
- <span v-if="item.detail" class="text-dimmed truncate text-xs">
234
- {{ item.detail }}
235
- </span>
236
- </template>
237
- <!-- -my-1: the button is taller than a dense row's text line. -->
238
- <DmsCopyButton
239
- v-if="!props.loading && !item.loading && copyTextOf(item)"
240
- :value="copyTextOf(item)!"
241
- class="-my-1"
242
- />
243
- </dd>
244
- </div>
245
- </template>
246
- </dl>
244
+ </template>
245
+ <!-- -my-1: the button is taller than a dense row's text line. -->
246
+ <DmsCopyButton
247
+ v-if="!props.loading && !item.loading && copyTextOf(item)"
248
+ :value="copyTextOf(item)!"
249
+ class="-my-1"
250
+ />
251
+ </dd>
252
+ </div>
253
+ </template>
254
+ </dl>
255
+ </div>
247
256
  </template>