@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,137 @@
1
+ <script setup lang="ts">
2
+ import { computed, onMounted, ref } from "vue";
3
+ import { usePageLive } from "../../composables/live/usePageLive";
4
+ import { pageReadAt } from "../../build/composables/live/pageReadClock";
5
+ import { useUpdatedLabel } from "../../build/composables/live/useUpdatedLabel";
6
+ import {
7
+ type PageToolbarSize,
8
+ providePageToolbar,
9
+ } from "../../build/composables/page-toolbar/pageToolbarContext";
10
+ import { PAGE_TOOLBAR_CONTROL_HEIGHT_CLASSES } from "../../build/composables/page-toolbar/toolbarControlHeight";
11
+ import { refreshPageBlocks } from "../../utils/blockRefresh";
12
+ import type { DefaultComponentProps } from "../../../../dms-core/app/types/component";
13
+
14
+ // Its ids are optional: a component may draw it by hand around controls of
15
+ // its own, outside the page's block tree.
16
+ interface PageToolbarBlockProps extends Partial<DefaultComponentProps> {
17
+ /** The size of its controls, unless a child sets its own. */
18
+ size?: PageToolbarSize;
19
+ /** Without a live toggle on screen: "updated N s ago". */
20
+ showUpdatedAt?: boolean;
21
+ /** Without a live toggle on screen: the button reading the page again. */
22
+ refresh?: boolean;
23
+ }
24
+
25
+ const props = withDefaults(defineProps<PageToolbarBlockProps>(), {
26
+ size: "sm",
27
+ showUpdatedAt: true,
28
+ refresh: true,
29
+ });
30
+
31
+ // The updated label at the live toggle's steps, so it reads alike with or
32
+ // without `live`; the refresh button stands as tall as the toggle's pill.
33
+ const STATUS_TEXT_CLASSES: Record<PageToolbarSize, string> = {
34
+ xs: "text-[11.5px]",
35
+ sm: "text-[12.5px]",
36
+ md: "text-[13px]",
37
+ };
38
+ const REFRESH_ICON = "i-ph-arrow-clockwise";
39
+
40
+ useComponentEvent(props.componentId);
41
+ useWatch(props.watchActions || [], props.componentId);
42
+
43
+ const { t } = useI18n();
44
+ const toolbar = providePageToolbar(computed(() => props.size));
45
+ const live = usePageLive();
46
+ const statusTextClass = computed(() => STATUS_TEXT_CLASSES[props.size]);
47
+ const heightClass = computed(
48
+ () => PAGE_TOOLBAR_CONTROL_HEIGHT_CLASSES[props.size],
49
+ );
50
+
51
+ // The browser's clock: the server and the hydrating render draw no status.
52
+ const isMounted = ref(false);
53
+ onMounted(() => (isMounted.value = true));
54
+
55
+ // A live page's own clock, else the page's last read.
56
+ const updatedLabel = useUpdatedLabel(
57
+ () => live.lastUpdatedAt.value ?? pageReadAt.value,
58
+ props.showUpdatedAt,
59
+ );
60
+
61
+ // The live toggle says when the page was updated, and more: the toolbar
62
+ // only does where there is none to see.
63
+ const showsStatus = computed(
64
+ () =>
65
+ isMounted.value &&
66
+ (props.showUpdatedAt || props.refresh) &&
67
+ !(live.isEnabled.value && toolbar.hasLiveToggle.value),
68
+ );
69
+
70
+ const isRefreshing = ref(false);
71
+ async function refreshPage() {
72
+ if (isRefreshing.value) return;
73
+ isRefreshing.value = true;
74
+ try {
75
+ await refreshPageBlocks();
76
+ } finally {
77
+ isRefreshing.value = false;
78
+ }
79
+ }
80
+ </script>
81
+
82
+ <template>
83
+ <div
84
+ class="dms-page-toolbar flex w-full flex-wrap items-center justify-end gap-x-3 gap-y-2"
85
+ >
86
+ <slot />
87
+ <span class="dms-page-toolbar__spacer" aria-hidden="true" />
88
+ <div
89
+ v-if="showsStatus"
90
+ class="dms-page-toolbar__status flex items-center gap-1"
91
+ >
92
+ <span
93
+ v-if="props.showUpdatedAt && updatedLabel"
94
+ class="text-muted tabular-nums"
95
+ :class="statusTextClass"
96
+ aria-live="off"
97
+ >
98
+ {{ updatedLabel }}
99
+ </span>
100
+ <UButton
101
+ v-if="props.refresh"
102
+ data-action="refresh"
103
+ color="neutral"
104
+ variant="ghost"
105
+ square
106
+ :size="props.size"
107
+ :class="heightClass"
108
+ :icon="REFRESH_ICON"
109
+ :loading="isRefreshing"
110
+ :aria-label="t('dms.live.refresh')"
111
+ :title="t('dms.live.refresh')"
112
+ @click="refreshPage"
113
+ />
114
+ </div>
115
+ </div>
116
+ </template>
117
+
118
+ <style>
119
+ /* One order whatever the children's: the leading blocks, the spacer, the
120
+ updated label or the live toggle, then the period. A child is matched by
121
+ the block it draws, through the wrappers a role preview may add. Wrapped
122
+ onto more lines, the trailing controls stay on the right. */
123
+ .dms-page-toolbar > * {
124
+ order: 0;
125
+ }
126
+ .dms-page-toolbar > .dms-page-toolbar__spacer {
127
+ order: 1;
128
+ flex: 1 1 0%;
129
+ }
130
+ .dms-page-toolbar > .dms-page-toolbar__status,
131
+ .dms-page-toolbar > :is(.dms-live-toggle, :has(.dms-live-toggle)) {
132
+ order: 2;
133
+ }
134
+ .dms-page-toolbar > :is(.dms-period-selector, :has(.dms-period-selector)) {
135
+ order: 3;
136
+ }
137
+ </style>
@@ -1,6 +1,7 @@
1
1
  <script setup lang="ts">
2
2
  import { computed } from "vue";
3
3
  import DmsStatGroup, {
4
+ type StatGroupColumnsFrom,
4
5
  type StatGroupItem,
5
6
  type StatGroupLayout,
6
7
  } from "../stat-group/StatGroup.vue";
@@ -27,6 +28,8 @@ interface StatGroupBlockProps extends DefaultComponentProps {
27
28
  items?: StatGroupBlockItem[];
28
29
  layout?: StatGroupLayout;
29
30
  columns?: number;
31
+ /** The group's width from which all `columns` sit side by side. */
32
+ columnsFrom?: StatGroupColumnsFrom;
30
33
  /** Accessible name of the group. */
31
34
  label?: string;
32
35
  fetchUrl?: string;
@@ -48,6 +51,7 @@ const props = withDefaults(defineProps<StatGroupBlockProps>(), {
48
51
  items: () => [],
49
52
  layout: "joined",
50
53
  columns: undefined,
54
+ columnsFrom: undefined,
51
55
  label: undefined,
52
56
  fetchUrl: undefined,
53
57
  fetchUrlMethod: undefined,
@@ -100,6 +104,7 @@ const resolvedItems = computed<StatGroupItem[]>(() =>
100
104
  :items="resolvedItems"
101
105
  :layout="props.layout"
102
106
  :columns="props.columns"
107
+ :columns-from="props.columnsFrom"
103
108
  :loading="isPending"
104
109
  :skeleton-count="
105
110
  props.skeletonCount ?? props.columns ?? DEFAULT_SKELETON_COUNT
@@ -117,11 +117,24 @@ function pushOptionsWithoutGroupBroadcast(
117
117
  .catch(() => undefined);
118
118
  }
119
119
 
120
+ function axisTypeOf(options: Record<string, unknown>): unknown {
121
+ return (options.xaxis as Record<string, unknown> | undefined)?.type;
122
+ }
123
+
124
+ /**
125
+ * Apex merges an update into the options it holds: an option the update no
126
+ * longer sets stays. A category axis drawing calendar buckets carries its own
127
+ * label and tooltip formatters, which a datetime axis would keep writing raw
128
+ * timestamps with (and the reverse leaves Apex's datetime state behind), so a
129
+ * chart whose X axis changes type is drawn anew rather than updated.
130
+ */
131
+ const axisType = computed(() => String(axisTypeOf(props.options) ?? ""));
132
+
120
133
  watch(
121
134
  () => props.options,
122
- (next) => {
135
+ (next, previous) => {
123
136
  const instance = chartRef.value;
124
- if (!instance) {
137
+ if (!instance || axisTypeOf(next) !== axisTypeOf(previous)) {
125
138
  pinnedOptions.value = rawApexInput(next);
126
139
  return;
127
140
  }
@@ -158,6 +171,7 @@ function redrawIfResizedWhileAnimating() {
158
171
  <template>
159
172
  <div ref="hostRef" class="dms-apex">
160
173
  <ApexChart
174
+ :key="axisType"
161
175
  ref="chartRef"
162
176
  :type="apexType"
163
177
  :height="height"
@@ -11,6 +11,10 @@ import { useChartFetch } from "../../composables/chart/useChartFetch";
11
11
  import { useThemeRevision } from "../../composables/chart/useThemeRevision";
12
12
  import { formatValue } from "../../composables/chart/formatValue";
13
13
  import { toDonutRecords } from "../../composables/chart/donutRecords";
14
+ import {
15
+ localizeDonutRecords,
16
+ localizeSeries,
17
+ } from "../../composables/chart/localizeSeries";
14
18
  import {
15
19
  CHART_EVENT_NAMES,
16
20
  isSegmentChart,
@@ -117,16 +121,26 @@ const themeRevision = useThemeRevision();
117
121
 
118
122
  const isCircular = computed(() => CIRCULAR_CHART_TYPES.includes(props.type));
119
123
 
124
+ // A bare chart's own series and slices are translated like a card's: the
125
+ // `$` keys of a name, a category or a label reach Apex in the reader's
126
+ // language. A nested chart receives its card's series already translated.
127
+ function localized(series: ChartSeries[]): ChartSeries[] {
128
+ return series.map((entry) => localizeSeries(entry, processI18n));
129
+ }
130
+
120
131
  const staticSeries = computed<ChartSeries[]>(() => {
121
132
  if (isCircular.value) return [];
122
133
  if (!props.staticDataset) return [];
123
- return props.staticDataset as ChartSeries[];
134
+ return localized(props.staticDataset as ChartSeries[]);
124
135
  });
125
136
 
126
137
  const staticDonut = computed<DonutRecord[]>(() => {
127
138
  if (!isCircular.value) return [];
128
139
  if (!props.staticDataset) return [];
129
- return props.staticDataset as DonutRecord[];
140
+ return localizeDonutRecords(
141
+ props.staticDataset as DonutRecord[],
142
+ processI18n,
143
+ );
130
144
  });
131
145
 
132
146
  const isNested = computed(() => !!nestedContext);
@@ -148,7 +162,7 @@ const seriesFromCtx = computed<ChartSeries[]>(() => {
148
162
 
149
163
  const fetchSeries = computed<ChartSeries[]>(() => {
150
164
  if (!data.value) return [];
151
- return data.value.series ?? [];
165
+ return localized(data.value.series ?? []);
152
166
  });
153
167
 
154
168
  const finalSeries = computed<ChartSeries[]>(() => {
@@ -185,14 +199,18 @@ function buildXyClickPayload(opts: {
185
199
  seriesIndex: number;
186
200
  }): ChartClickPayload {
187
201
  const series = finalSeries.value[opts.seriesIndex];
188
- const point = series?.data[opts.dataPointIndex];
202
+ const dataPointIndex = apex.sourcePointIndex(
203
+ opts.seriesIndex,
204
+ opts.dataPointIndex,
205
+ );
206
+ const point = series?.data[dataPointIndex];
189
207
  const pointValue = readPointValue(point);
190
208
  const label =
191
209
  typeof point === "object" && point !== null && "label" in point
192
210
  ? (point as { label?: string }).label
193
211
  : undefined;
194
212
  return {
195
- dataPointIndex: opts.dataPointIndex,
213
+ dataPointIndex,
196
214
  seriesIndex: opts.seriesIndex,
197
215
  ...pointValue,
198
216
  seriesName: series?.name ?? "",
@@ -276,6 +294,7 @@ const apex = useApexChart(() => ({
276
294
  xAxis: props.xAxis,
277
295
  xAxisFormatter: props.xAxisFormatter,
278
296
  yAxisFormatter: yAxisFormatter.value,
297
+ locale: locale.value,
279
298
  onDataPointClick: emitDataClick,
280
299
  }));
281
300
 
@@ -12,6 +12,8 @@ import {
12
12
  } from "../../composables/chart/formatValue";
13
13
  import { resolveChartColor } from "../../composables/chart/useChartTheme";
14
14
  import { useThemeRevision } from "../../composables/chart/useThemeRevision";
15
+ import { usePeriodComparisonDisplay } from "../../build/composables/period/periodComparison";
16
+ import { localizeSeries } from "../../composables/chart/localizeSeries";
15
17
  import {
16
18
  NESTED_CHART_INJECT_KEY,
17
19
  type ChartCardResponse,
@@ -34,6 +36,8 @@ interface Props extends DefaultComponentProps {
34
36
  currencyCode?: string;
35
37
  valuePrecision?: ValuePrecision;
36
38
  showDelta?: boolean;
39
+ /** A rising value is the bad outcome: the delta's colours swap. */
40
+ invert?: boolean;
37
41
  showLegend?: boolean;
38
42
  /** The wrapped chart draws its own legend, naming each series. */
39
43
  showSeriesLegend?: boolean;
@@ -80,26 +84,35 @@ const { data, isLoading } = useChartFetch<ChartCardResponse>({
80
84
  watchSource: () => watchKey.value,
81
85
  });
82
86
 
87
+ // With no comparison selected on the scope, whatever comparison the data
88
+ // still carries is not drawn: no change, no "vs" figure, no second series.
89
+ const comparison = usePeriodComparisonDisplay(props.periodScope);
83
90
  const value = computed(() => data.value?.value);
84
- const previousValue = computed(() => data.value?.previousValue);
85
- const delta = computed(() => data.value?.delta ?? null);
86
-
87
- // ApexCharts prints `name` verbatim in its legend and tooltip, so backend
88
- // series names carrying the `$` convention are resolved here, before the
89
- // array reaches the nested chart and the default slot.
90
- function withResolvedName(entry: ChartSeries): ChartSeries {
91
- return { ...entry, name: processI18n(entry.name) };
91
+ const previousValue = computed(() =>
92
+ comparison.isOff.value ? undefined : data.value?.previousValue,
93
+ );
94
+ const delta = computed(() =>
95
+ comparison.isOff.value ? null : (data.value?.delta ?? null),
96
+ );
97
+
98
+ // ApexCharts prints names, categories and slice labels verbatim, so a
99
+ // route's `$` keys are resolved here, before the array reaches the nested
100
+ // chart and the default slot.
101
+ function localized(entry: ChartSeries): ChartSeries {
102
+ return localizeSeries(entry, processI18n);
92
103
  }
93
104
 
94
105
  const cardSeries = computed<ChartSeries[]>(() =>
95
- (data.value?.series ?? []).map(withResolvedName),
106
+ (data.value?.series ?? []).map(localized),
96
107
  );
97
108
 
98
109
  const cardComparisonSeries = computed<ChartSeries[]>(() =>
99
- (data.value?.comparisonSeries ?? []).map((entry) => ({
100
- ...withResolvedName(entry),
101
- color: entry.color ?? comparisonColor.value,
102
- })),
110
+ comparison.isOff.value
111
+ ? []
112
+ : (data.value?.comparisonSeries ?? []).map((entry) => ({
113
+ ...localized(entry),
114
+ color: entry.color ?? comparisonColor.value,
115
+ })),
103
116
  );
104
117
 
105
118
  const formatted = computed(() =>
@@ -116,13 +129,15 @@ const formatted = computed(() =>
116
129
 
117
130
  const previousFormatted = computed(() =>
118
131
  previousValue.value !== undefined
119
- ? formatValue(
120
- previousValue.value,
121
- props.valueFormat,
122
- locale.value,
123
- props.currencyCode,
124
- props.valuePrecision,
125
- )
132
+ ? t("dms.chart.versus_value", {
133
+ value: formatValue(
134
+ previousValue.value,
135
+ props.valueFormat,
136
+ locale.value,
137
+ props.currencyCode,
138
+ props.valuePrecision,
139
+ ),
140
+ })
126
141
  : null,
127
142
  );
128
143
 
@@ -155,10 +170,13 @@ const primaryLegendLabel = computed(() =>
155
170
  ? processI18n(props.primaryLabel)
156
171
  : t(DEFAULT_PRIMARY_LABEL_KEY, "Period"),
157
172
  );
173
+ // The comparison the scope selects names its series ("Previous year"),
174
+ // unless the card names it itself.
158
175
  const comparisonLegendLabel = computed(() =>
159
176
  props.comparisonLabel
160
177
  ? processI18n(props.comparisonLabel)
161
- : t(DEFAULT_COMPARISON_LABEL_KEY, "Comparison"),
178
+ : (comparison.legendLabel.value ??
179
+ t(DEFAULT_COMPARISON_LABEL_KEY, "Comparison")),
162
180
  );
163
181
 
164
182
  const isFirstLoad = computed(() => isLoading.value && data.value === null);
@@ -215,9 +233,9 @@ const hasMeta = computed(
215
233
  class="mt-1.5 flex flex-wrap items-center gap-2 transition-opacity"
216
234
  :class="isRefreshing && 'opacity-55'"
217
235
  >
218
- <DmsTrendBadge v-if="showTrend" :delta="delta" />
236
+ <DmsTrendBadge v-if="showTrend" :delta="delta" :invert="invert" />
219
237
  <span v-if="previousFormatted" class="text-dimmed text-xs">
220
- vs {{ previousFormatted }}
238
+ {{ previousFormatted }}
221
239
  </span>
222
240
  <span v-else-if="description" class="text-dimmed text-xs">
223
241
  {{ processI18n(description) }}
@@ -1,18 +1,21 @@
1
1
  <script setup lang="ts">
2
- import { computed, onMounted, shallowRef } from "vue";
2
+ import { computed, onMounted, shallowRef, watch } from "vue";
3
3
  import DmsCopyButton from "../copy/CopyButton.vue";
4
4
  import {
5
5
  codeLanguageLabel,
6
6
  PLAIN_CODE_LANGUAGE,
7
7
  resolveCodeLanguage,
8
8
  } from "../../build/utils/codeLanguages";
9
- import type { CodeToken, highlightCode } from "../../build/utils/codeHighlight";
9
+ import type {
10
+ CodeHighlighter,
11
+ CodeToken,
12
+ } from "../../build/utils/codeHighlight";
10
13
 
11
14
  // Read-only code in the editor's look: a head with the title, the language
12
15
  // and a copy button, then the code highlighted by the editor's languages.
13
16
  // Without a title or a language there is no head: the copy button floats in
14
- // the code's corner. Until the highlighter loads (and on the server) the
15
- // code shows as is.
17
+ // the code's corner. Until its language's grammar loads (and on the server)
18
+ // the code shows as is.
16
19
 
17
20
  /**
18
21
  * How long lines break: `false` scrolls them sideways, `true` wraps them
@@ -63,7 +66,7 @@ const WRAP_CLASSES: Record<"false" | "true" | "anywhere", string> = {
63
66
  anywhere: "whitespace-pre-wrap [overflow-wrap:anywhere]",
64
67
  };
65
68
 
66
- const highlight = shallowRef<typeof highlightCode | null>(null);
69
+ const highlight = shallowRef<CodeHighlighter | null>(null);
67
70
 
68
71
  const language = computed(() => resolveCodeLanguage(props.language));
69
72
  // A language given, even `text`, is named in a head; without a title either,
@@ -79,9 +82,7 @@ const wrapClass = computed(
79
82
  () => WRAP_CLASSES[String(props.wrap) as keyof typeof WRAP_CLASSES],
80
83
  );
81
84
  const tokens = computed<CodeToken[]>(() =>
82
- highlight.value
83
- ? highlight.value(props.code, language.value)
84
- : [{ text: props.code }],
85
+ highlight.value ? highlight.value(props.code) : [{ text: props.code }],
85
86
  );
86
87
  const sizeStyle = computed(() => {
87
88
  if (props.maxLines)
@@ -91,10 +92,20 @@ const sizeStyle = computed(() => {
91
92
  return props.maxHeight ? { maxHeight: props.maxHeight } : undefined;
92
93
  });
93
94
 
94
- onMounted(async () => {
95
- const module = await import("../../build/utils/codeHighlight");
96
- highlight.value = module.highlightCode;
97
- });
95
+ // Only the grammar of the language shown loads. A language changed while
96
+ // one loads drops it: the code stays plain until its own grammar is in.
97
+ async function loadHighlighter(): Promise<void> {
98
+ const requested = language.value;
99
+ highlight.value = null;
100
+ const { loadCodeHighlighter } = await import(
101
+ "../../build/utils/codeHighlight"
102
+ );
103
+ const highlighter = await loadCodeHighlighter(requested);
104
+ if (language.value === requested) highlight.value = highlighter;
105
+ }
106
+
107
+ onMounted(loadHighlighter);
108
+ watch(language, loadHighlighter);
98
109
  </script>
99
110
 
100
111
  <template>
@@ -382,7 +382,7 @@ function handleCancel() {
382
382
  size="sm"
383
383
  square
384
384
  :disabled="isPending"
385
- :aria-label="$t('dms.confirm.cancel')"
385
+ :aria-label="$t('dms.confirm.close')"
386
386
  @click="handleCancel"
387
387
  />
388
388
  </template>
@@ -0,0 +1,34 @@
1
+ <script setup lang="ts">
2
+ /**
3
+ * The footer band of a drawer's or a modal's body component: its buttons
4
+ * under a hairline, flush with the container's edges. It sticks to the
5
+ * bottom of the container while the content runs past it. In a drawer, whose
6
+ * body is a flex column, a body component whose root grows (`flex-1`, and
7
+ * `flex flex-col` to lay its own content out) keeps it at the bottom of the
8
+ * drawer while its content is short.
9
+ */
10
+ interface ContainerFooterProps {
11
+ /** Where the buttons sit along the band; `end` by default. */
12
+ justify?: "start" | "end" | "between";
13
+ }
14
+
15
+ const props = withDefaults(defineProps<ContainerFooterProps>(), {
16
+ justify: "end",
17
+ });
18
+
19
+ // Same band as a form's footer in a container (FORM_SURFACE_CLASSES), but
20
+ // pushed to the bottom (`mt-auto`) rather than set under the fields.
21
+ const FOOTER_CLASS =
22
+ "border-default bg-default sticky bottom-[calc(var(--dms-form-foot-pb,0px)*-1)] z-10 mt-auto -mx-[var(--dms-form-foot-px,0px)] -mb-[var(--dms-form-foot-pb,0px)] flex flex-wrap items-center gap-2 border-t px-[var(--dms-form-foot-px,0px)] pt-3 pb-[var(--dms-form-foot-pb,12px)]";
23
+ const JUSTIFY_CLASSES = {
24
+ start: "justify-start",
25
+ end: "justify-end",
26
+ between: "justify-between",
27
+ } as const;
28
+ </script>
29
+
30
+ <template>
31
+ <footer :class="[FOOTER_CLASS, JUSTIFY_CLASSES[props.justify]]">
32
+ <slot />
33
+ </footer>
34
+ </template>
@@ -8,9 +8,10 @@ export type FieldRowLayout = "inline" | "form" | "stack";
8
8
 
9
9
  /**
10
10
  * `row`: the row pads itself and draws a hairline above the next one (rows
11
- * of a card). `list`: the list around it spaces the rows (a stacked form).
11
+ * of a card). `dense`: the same, tighter, for a form in a drawer or a modal.
12
+ * `list`: the list around it spaces the rows (a stacked form).
12
13
  */
13
- export type FieldRowSpacing = "row" | "list";
14
+ export type FieldRowSpacing = "row" | "dense" | "list";
14
15
 
15
16
  // The renderer's props are optional: DmsFieldRow is both the backend
16
17
  // `FieldRow` block (`dms-field-row-block`) and a template component.
@@ -34,6 +35,12 @@ interface FieldRowProps extends Partial<DefaultComponentProps> {
34
35
  required?: boolean;
35
36
  /** Dims the whole row. */
36
37
  disabled?: boolean;
38
+ /**
39
+ * `stack` only: the row and its control fill the height their flex parent
40
+ * leaves them (a drawer's body), handing it to a control that fills it
41
+ * (`DmsInputCode fill`).
42
+ */
43
+ fill?: boolean;
37
44
  }
38
45
 
39
46
  interface FieldRowSlots {
@@ -56,6 +63,7 @@ const props = withDefaults(defineProps<FieldRowProps>(), {
56
63
  spacing: "row",
57
64
  required: false,
58
65
  disabled: false,
66
+ fill: false,
59
67
  });
60
68
  const slots = defineSlots<FieldRowSlots>();
61
69
 
@@ -102,11 +110,25 @@ const theme = tv({
102
110
  },
103
111
  spacing: {
104
112
  row: { root: "border-t border-muted first:border-t-0", body: "py-4" },
113
+ // 12px above and below a 32px control, 6px from a label set above it.
114
+ dense: {
115
+ root: "border-t border-muted first:border-t-0",
116
+ body: "py-3 gap-y-1.5",
117
+ },
105
118
  list: { body: "gap-y-1.5" },
106
119
  },
107
120
  disabled: {
108
121
  true: { root: "opacity-55" },
109
122
  },
123
+ // Flex columns down to the control, which grows: their minimum stays
124
+ // their content's (the control's floor), the parent scrolling below it.
125
+ fill: {
126
+ true: {
127
+ root: "flex flex-1 flex-col",
128
+ body: "flex flex-1 flex-col",
129
+ control: "flex flex-1 flex-col",
130
+ },
131
+ },
110
132
  // Without a label cell, the control is the grid's only child: it spans
111
133
  // both columns instead of falling into the form's 240px label column.
112
134
  labeled: {
@@ -124,6 +146,7 @@ const ui = computed(() =>
124
146
  inset: props.inset,
125
147
  spacing: props.spacing,
126
148
  disabled: props.disabled,
149
+ fill: props.fill && props.layout === "stack",
127
150
  labeled: hasText.value,
128
151
  }),
129
152
  );
@@ -313,8 +313,8 @@ defineExpose(flow);
313
313
  type="button"
314
314
  class="dms-flow-canvas__delete-button"
315
315
  :style="{ left: `${affordance.x}px`, top: `${affordance.y}px` }"
316
- title="Delete node"
317
- aria-label="Delete node"
316
+ :title="$t('dms.flow_canvas.delete_node')"
317
+ :aria-label="$t('dms.flow_canvas.delete_node')"
318
318
  @click.stop="emitDelete([affordance.id])"
319
319
  >
320
320
  <svg