@antelopejs/dms 0.9.8 → 0.10.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 (420) hide show
  1. package/CHANGELOG.md +102 -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 -0
  21. package/dist/config.js +5 -3
  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 +22 -89
  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 +1 -2
  41. package/dist/implementations/dms/manifest.js +2 -0
  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 +28 -48
  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 +24 -13
  129. package/dist/store/listing.js.map +1 -1
  130. package/dist/store/operations.js +4 -0
  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/validation/auth.schema.d.ts +2 -2
  139. package/dist/validation/member-invite.schema.d.ts +2 -10
  140. package/dist/validation/member-invite.schema.js +2 -15
  141. package/dist/validation/member-invite.schema.js.map +1 -1
  142. package/frontend-vue/dms.frontend.ts +24 -5
  143. package/frontend-vue/dms.server.ts +17 -0
  144. package/frontend-vue/layers/dms-auth/server/accounts.ts +3 -4
  145. package/frontend-vue/layers/dms-core/app/build/composables/renderNow.ts +34 -0
  146. package/frontend-vue/layers/dms-core/app/build/composables/user/tablePreferences.ts +5 -1
  147. package/frontend-vue/layers/dms-core/app/build/utils/crossTab.ts +199 -0
  148. package/frontend-vue/layers/dms-core/app/build/utils/sharedRealtimeConnection.ts +410 -0
  149. package/frontend-vue/layers/dms-core/app/composables/auth/useApiData.ts +77 -12
  150. package/frontend-vue/layers/dms-core/app/composables/data-types/useDataType.ts +26 -0
  151. package/frontend-vue/layers/dms-core/app/composables/hydration/isHydratingComponent.ts +29 -0
  152. package/frontend-vue/layers/dms-core/app/composables/live/livePauseSource.ts +29 -0
  153. package/frontend-vue/layers/dms-core/app/composables/period/compareResolvers.ts +150 -9
  154. package/frontend-vue/layers/dms-core/app/composables/period/usePeriod.ts +6 -4
  155. package/frontend-vue/layers/dms-core/app/composables/period/usePeriodScope.ts +27 -1
  156. package/frontend-vue/layers/dms-core/app/composables/realtime/useUserRealtime.ts +256 -119
  157. package/frontend-vue/layers/dms-core/app/composables/translation/useComposedText.ts +21 -8
  158. package/frontend-vue/layers/dms-core/app/composables/translation/useTranslation.ts +22 -5
  159. package/frontend-vue/layers/dms-core/app/plugins/dev-error-log.ts +16 -0
  160. package/frontend-vue/layers/dms-core/app/types/user.ts +6 -0
  161. package/frontend-vue/layers/dms-core/app/utils/composedText.ts +7 -2
  162. package/frontend-vue/layers/dms-core/app/utils/formatter.ts +166 -35
  163. package/frontend-vue/layers/dms-core/app/utils/url-interpolation.ts +18 -1
  164. package/frontend-vue/layers/dms-core/i18n/locales/core-en-GB.json +134 -2
  165. package/frontend-vue/layers/dms-core/i18n/locales/core-fr-FR.json +134 -2
  166. package/frontend-vue/layers/dms-layout/app/build/components/layout/DashboardBanners.vue +3 -2
  167. package/frontend-vue/layers/dms-layout/app/build/components/layout/DashboardHeader.vue +41 -21
  168. package/frontend-vue/layers/dms-layout/app/build/components/layout/DashboardPageBody.vue +9 -0
  169. package/frontend-vue/layers/dms-layout/app/build/components/layout/DashboardSidebar.vue +4 -19
  170. package/frontend-vue/layers/dms-layout/app/build/components/layout/Footer.vue +11 -3
  171. package/frontend-vue/layers/dms-layout/app/build/components/layout/GithubStarPrompt.vue +18 -7
  172. package/frontend-vue/layers/dms-layout/app/build/components/layout/PageHeaderActionBar.vue +8 -0
  173. package/frontend-vue/layers/dms-layout/app/build/components/layout/PageHeaderActionsOutlet.vue +14 -0
  174. package/frontend-vue/layers/dms-layout/app/build/components/layout/RowSidePanel.vue +43 -82
  175. package/frontend-vue/layers/dms-layout/app/build/components/layout/SidebarUserMenu.vue +44 -3
  176. package/frontend-vue/layers/dms-layout/app/build/components/layout/UserIdentity.vue +11 -3
  177. package/frontend-vue/layers/dms-layout/app/build/components/pages/modules/ModuleCatalogTile.vue +132 -35
  178. package/frontend-vue/layers/dms-layout/app/build/components/pages/modules/ModuleManageMenu.vue +59 -0
  179. package/frontend-vue/layers/dms-layout/app/build/components/pages/modules/ModuleSourceLabel.vue +25 -0
  180. package/frontend-vue/layers/dms-layout/app/build/components/pages/modules/ModuleStoreBanners.vue +73 -0
  181. package/frontend-vue/layers/dms-layout/app/build/components/pages/modules/ModuleStoreOperation.vue +116 -0
  182. package/frontend-vue/layers/dms-layout/app/build/components/pages/modules/ModuleStoreRequirements.vue +8 -3
  183. package/frontend-vue/layers/dms-layout/app/build/components/pages/modules/ModuleStoreTile.vue +85 -207
  184. package/frontend-vue/layers/dms-layout/app/build/components/pages/modules/ModuleTile.vue +10 -3
  185. package/frontend-vue/layers/dms-layout/app/build/components/pages/modules/ModuleTileSkeleton.vue +68 -0
  186. package/frontend-vue/layers/dms-layout/app/build/components/pages/settings/notification/NotificationInboxDisplay.vue +24 -8
  187. package/frontend-vue/layers/dms-layout/app/build/components/pages/settings/notification/NotificationInboxItem.vue +8 -5
  188. package/frontend-vue/layers/dms-layout/app/build/components/pages/settings/region/RegionTimeZoneInput.vue +1 -0
  189. package/frontend-vue/layers/dms-layout/app/build/components/pages/settings/roles/role-permissions.ts +19 -0
  190. package/frontend-vue/layers/dms-layout/app/build/components/pages/settings/roles/useRoleEditor.ts +2 -1
  191. package/frontend-vue/layers/dms-layout/app/build/composables/layout/useSidePanelWidth.ts +31 -70
  192. package/frontend-vue/layers/dms-layout/app/build/composables/notification/useNotificationGroupsOpen.ts +11 -1
  193. package/frontend-vue/layers/dms-layout/app/build/utils/dev-reload-stream.ts +81 -0
  194. package/frontend-vue/layers/dms-layout/app/build/utils/module-store-catalog.ts +232 -36
  195. package/frontend-vue/layers/dms-layout/app/build/utils/modules-catalog.ts +122 -14
  196. package/frontend-vue/layers/dms-layout/app/composables/layout/useLayoutBanners.ts +32 -3
  197. package/frontend-vue/layers/dms-layout/app/composables/layout/usePageRecord.ts +50 -0
  198. package/frontend-vue/layers/dms-layout/app/composables/layout/useServedHeaderActions.ts +25 -7
  199. package/frontend-vue/layers/dms-layout/app/composables/page/useModuleHistory.ts +3 -2
  200. package/frontend-vue/layers/dms-layout/app/composables/page/useModuleStore.ts +51 -4
  201. package/frontend-vue/layers/dms-layout/app/composables/page/useModuleStoreActions.ts +194 -0
  202. package/frontend-vue/layers/dms-layout/app/composables/page/usePageComponentPreload.ts +23 -3
  203. package/frontend-vue/layers/dms-layout/app/composables/page/usePageLayout.ts +4 -2
  204. package/frontend-vue/layers/dms-layout/app/composables/page/useSiteLayout.ts +6 -1
  205. package/frontend-vue/layers/dms-layout/app/custom-layouts/DefaultLayout.vue +9 -0
  206. package/frontend-vue/layers/dms-layout/app/custom-layouts/SettingsLayout.vue +9 -0
  207. package/frontend-vue/layers/dms-layout/app/custom-pages/modules-store.vue +291 -0
  208. package/frontend-vue/layers/dms-layout/app/custom-pages/modules.vue +87 -474
  209. package/frontend-vue/layers/dms-layout/app/middleware/module-routing.global.ts +3 -0
  210. package/frontend-vue/layers/dms-layout/app/pages/[...slug].vue +6 -22
  211. package/frontend-vue/layers/dms-layout/app/plugins/command-palette-navigation.client.ts +2 -1
  212. package/frontend-vue/layers/dms-layout/app/plugins/command-palette-personal-pages.client.ts +14 -44
  213. package/frontend-vue/layers/dms-layout/app/plugins/dms-dev-reload.client.ts +14 -9
  214. package/frontend-vue/layers/dms-layout/app/theme/form-controls.ts +9 -4
  215. package/frontend-vue/layers/dms-layout/app/theme/surfaces.ts +22 -6
  216. package/frontend-vue/layers/dms-layout/app/types/module-store.ts +9 -0
  217. package/frontend-vue/layers/dms-layout/app/types/page.ts +15 -1
  218. package/frontend-vue/layers/dms-layout/app/utils/account-menu.ts +11 -0
  219. package/frontend-vue/layers/dms-layout/app/utils/breadcrumb.ts +57 -0
  220. package/frontend-vue/layers/dms-layout/app/utils/pageQuery.ts +26 -0
  221. package/frontend-vue/layers/dms-layout/app/utils/pageRecord.ts +71 -0
  222. package/frontend-vue/layers/dms-layout/i18n/locales/layout-en-GB.json +39 -14
  223. package/frontend-vue/layers/dms-layout/i18n/locales/layout-fr-FR.json +38 -13
  224. package/frontend-vue/layers/dms-ui/app/build/components/containers/TargetComponentTree.vue +31 -0
  225. package/frontend-vue/layers/dms-ui/app/build/components/containers/constants.ts +25 -0
  226. package/frontend-vue/layers/dms-ui/app/build/components/containers/drawer/DynamicDrawer.vue +244 -15
  227. package/frontend-vue/layers/dms-ui/app/build/components/containers/modal/DynamicModal.vue +42 -25
  228. package/frontend-vue/layers/dms-ui/app/build/components/containers/row/RowHeader.vue +153 -0
  229. package/frontend-vue/layers/dms-ui/app/build/components/containers/row/RowNotFound.vue +44 -0
  230. package/frontend-vue/layers/dms-ui/app/build/components/containers/row/drawerRowHeader.ts +35 -0
  231. package/frontend-vue/layers/dms-ui/app/build/components/form/FormEntries.vue +44 -9
  232. package/frontend-vue/layers/dms-ui/app/build/components/form/FormErrorSummary.vue +11 -4
  233. package/frontend-vue/layers/dms-ui/app/build/components/form/FormFieldControl.vue +38 -5
  234. package/frontend-vue/layers/dms-ui/app/build/components/form/FormFieldNotes.vue +29 -5
  235. package/frontend-vue/layers/dms-ui/app/build/components/form/FormSectionNav.vue +3 -1
  236. package/frontend-vue/layers/dms-ui/app/build/components/form/FormSections.vue +106 -27
  237. package/frontend-vue/layers/dms-ui/app/build/components/table/Actions.vue +12 -4
  238. package/frontend-vue/layers/dms-ui/app/build/components/table/Empty.vue +4 -2
  239. package/frontend-vue/layers/dms-ui/app/build/components/table/FiltersRow.vue +38 -1
  240. package/frontend-vue/layers/dms-ui/app/build/components/table/Pagination.vue +55 -54
  241. package/frontend-vue/layers/dms-ui/app/build/components/table/RowSelection.vue +2 -1
  242. package/frontend-vue/layers/dms-ui/app/build/components/table/Table.vue +396 -288
  243. package/frontend-vue/layers/dms-ui/app/build/components/table/Tabs.vue +2 -1
  244. package/frontend-vue/layers/dms-ui/app/build/components/table/Views.vue +2 -1
  245. package/frontend-vue/layers/dms-ui/app/build/components/table-view/CardAvatar.vue +59 -0
  246. package/frontend-vue/layers/dms-ui/app/build/components/table-view/CardGridSkeleton.vue +19 -2
  247. package/frontend-vue/layers/dms-ui/app/build/components/table-view/CardRowActions.vue +38 -0
  248. package/frontend-vue/layers/dms-ui/app/build/components/table-view/CardsDisplay.vue +148 -104
  249. package/frontend-vue/layers/dms-ui/app/build/components/table-view/LiveHoldBanner.vue +17 -2
  250. package/frontend-vue/layers/dms-ui/app/build/composables/actions/bulkSelection.ts +43 -9
  251. package/frontend-vue/layers/dms-ui/app/build/composables/actions/rowComponentOptions.ts +76 -0
  252. package/frontend-vue/layers/dms-ui/app/build/composables/actions/rowNavigation.ts +172 -27
  253. package/frontend-vue/layers/dms-ui/app/build/composables/actions/useActionTargets.ts +270 -46
  254. package/frontend-vue/layers/dms-ui/app/build/composables/confirm/confirmDialogTexts.ts +2 -0
  255. package/frontend-vue/layers/dms-ui/app/build/composables/containers/closingLayers.ts +186 -0
  256. package/frontend-vue/layers/dms-ui/app/build/composables/containers/context.ts +14 -0
  257. package/frontend-vue/layers/dms-ui/app/build/composables/containers/drawerSize.ts +229 -0
  258. package/frontend-vue/layers/dms-ui/app/build/composables/containers/useResizableSize.ts +175 -0
  259. package/frontend-vue/layers/dms-ui/app/build/composables/data-types/metricCells.ts +18 -35
  260. package/frontend-vue/layers/dms-ui/app/build/composables/data-types/numberSuffix.ts +47 -0
  261. package/frontend-vue/layers/dms-ui/app/build/composables/data-types/registerDefaults.ts +99 -24
  262. package/frontend-vue/layers/dms-ui/app/build/composables/data-types/registerFieldTypes.ts +2 -1
  263. package/frontend-vue/layers/dms-ui/app/build/composables/data-types/relationFilter.ts +75 -0
  264. package/frontend-vue/layers/dms-ui/app/build/composables/data-types/relationRows.ts +71 -0
  265. package/frontend-vue/layers/dms-ui/app/build/composables/data-types/relationValue.ts +39 -0
  266. package/frontend-vue/layers/dms-ui/app/build/composables/data-types/twoLineCell.ts +3 -3
  267. package/frontend-vue/layers/dms-ui/app/build/composables/data-types/useColumnValueRenderer.ts +6 -2
  268. package/frontend-vue/layers/dms-ui/app/build/composables/form/createFormFields.ts +15 -0
  269. package/frontend-vue/layers/dms-ui/app/build/composables/form/fieldSaved.ts +40 -0
  270. package/frontend-vue/layers/dms-ui/app/build/composables/form/fieldValueRule.ts +62 -0
  271. package/frontend-vue/layers/dms-ui/app/build/composables/form/formEntryContext.ts +5 -0
  272. package/frontend-vue/layers/dms-ui/app/build/composables/form/formFooter.ts +42 -7
  273. package/frontend-vue/layers/dms-ui/app/build/composables/form/formLayout.ts +106 -4
  274. package/frontend-vue/layers/dms-ui/app/build/composables/form/formSections.ts +32 -0
  275. package/frontend-vue/layers/dms-ui/app/build/composables/form/readonlyValue.ts +19 -0
  276. package/frontend-vue/layers/dms-ui/app/build/composables/form/registerFormFunctions.ts +27 -0
  277. package/frontend-vue/layers/dms-ui/app/build/composables/form/repeaterTable.ts +65 -0
  278. package/frontend-vue/layers/dms-ui/app/build/composables/form/serverFieldErrors.ts +49 -0
  279. package/frontend-vue/layers/dms-ui/app/build/composables/form/toasterClearance.ts +118 -0
  280. package/frontend-vue/layers/dms-ui/app/build/composables/form/useInstantForm.ts +12 -1
  281. package/frontend-vue/layers/dms-ui/app/build/composables/live/currentPageLive.ts +41 -3
  282. package/frontend-vue/layers/dms-ui/app/build/composables/live/livePoller.ts +10 -2
  283. package/frontend-vue/layers/dms-ui/app/build/composables/live/pageReadClock.ts +28 -0
  284. package/frontend-vue/layers/dms-ui/app/build/composables/live/shortcuts.ts +1 -1
  285. package/frontend-vue/layers/dms-ui/app/build/composables/live/usePageLiveHost.ts +17 -3
  286. package/frontend-vue/layers/dms-ui/app/build/composables/live/useUpdatedLabel.ts +38 -0
  287. package/frontend-vue/layers/dms-ui/app/build/composables/page-toolbar/pageToolbarContext.ts +75 -0
  288. package/frontend-vue/layers/dms-ui/app/build/composables/page-toolbar/toolbarControlHeight.ts +29 -0
  289. package/frontend-vue/layers/dms-ui/app/build/composables/period/periodComparison.ts +52 -0
  290. package/frontend-vue/layers/dms-ui/app/build/composables/period/periodDisplay.ts +21 -0
  291. package/frontend-vue/layers/dms-ui/app/build/composables/period/periodShortLabels.ts +28 -0
  292. package/frontend-vue/layers/dms-ui/app/build/composables/period/usePeriodDraft.ts +1 -0
  293. package/frontend-vue/layers/dms-ui/app/build/composables/table/useRelationFilterLabels.ts +73 -0
  294. package/frontend-vue/layers/dms-ui/app/build/composables/table/useRowScrollAnchor.ts +106 -0
  295. package/frontend-vue/layers/dms-ui/app/build/composables/table/useTable.ts +9 -0
  296. package/frontend-vue/layers/dms-ui/app/build/composables/table/useTableColumns.ts +1 -2
  297. package/frontend-vue/layers/dms-ui/app/build/composables/table/utils/archivedCount.ts +31 -0
  298. package/frontend-vue/layers/dms-ui/app/build/composables/table/utils/filterEditorValue.ts +38 -0
  299. package/frontend-vue/layers/dms-ui/app/build/composables/table/utils/formatFilterValue.ts +33 -2
  300. package/frontend-vue/layers/dms-ui/app/build/composables/table/utils/scrollEdges.ts +31 -0
  301. package/frontend-vue/layers/dms-ui/app/build/composables/table-view/useCardFields.ts +33 -0
  302. package/frontend-vue/layers/dms-ui/app/build/composables/table-view/useMobileDisplay.ts +48 -0
  303. package/frontend-vue/layers/dms-ui/app/build/composables/table-view/useScrolledPastTop.ts +41 -18
  304. package/frontend-vue/layers/dms-ui/app/build/composables/table-view/useTableFooter.ts +3 -2
  305. package/frontend-vue/layers/dms-ui/app/build/composables/table-view/useTableLinkedVisit.ts +78 -0
  306. package/frontend-vue/layers/dms-ui/app/build/composables/table-view/useTableLiveHold.ts +135 -22
  307. package/frontend-vue/layers/dms-ui/app/build/composables/table-view/useTableRows.ts +56 -25
  308. package/frontend-vue/layers/dms-ui/app/build/composables/table-view/useTableViewRowActions.ts +77 -32
  309. package/frontend-vue/layers/dms-ui/app/build/composables/table-view/useTableViews.ts +86 -10
  310. package/frontend-vue/layers/dms-ui/app/build/composables/table-view/utils/bulkActions.ts +14 -4
  311. package/frontend-vue/layers/dms-ui/app/build/composables/table-view/utils/card.ts +127 -2
  312. package/frontend-vue/layers/dms-ui/app/build/composables/table-view/utils/compareValues.ts +13 -0
  313. package/frontend-vue/layers/dms-ui/app/build/composables/table-view/utils/expandedRows.ts +28 -0
  314. package/frontend-vue/layers/dms-ui/app/build/composables/table-view/utils/groupedRows.ts +114 -1
  315. package/frontend-vue/layers/dms-ui/app/build/composables/table-view/utils/linkedArrival.ts +308 -0
  316. package/frontend-vue/layers/dms-ui/app/build/composables/table-view/utils/locateRow.ts +106 -0
  317. package/frontend-vue/layers/dms-ui/app/build/composables/table-view/utils/pageArrival.ts +34 -0
  318. package/frontend-vue/layers/dms-ui/app/build/composables/table-view/utils/pinnedRows.ts +17 -0
  319. package/frontend-vue/layers/dms-ui/app/build/composables/table-view/utils/quickFilters.ts +41 -33
  320. package/frontend-vue/layers/dms-ui/app/build/composables/table-view/utils/recordLink.ts +24 -8
  321. package/frontend-vue/layers/dms-ui/app/build/composables/table-view/utils/tableCounts.ts +113 -0
  322. package/frontend-vue/layers/dms-ui/app/build/composables/table-view/utils/tableQuery.ts +27 -4
  323. package/frontend-vue/layers/dms-ui/app/build/composables/table-view/utils/views.ts +22 -6
  324. package/frontend-vue/layers/dms-ui/app/build/utils/addressSuggestions.ts +49 -0
  325. package/frontend-vue/layers/dms-ui/app/build/utils/eyebrow.ts +12 -0
  326. package/frontend-vue/layers/dms-ui/app/build/utils/fieldOptionsI18n.ts +51 -11
  327. package/frontend-vue/layers/dms-ui/app/build/utils/inputWidth.ts +53 -0
  328. package/frontend-vue/layers/dms-ui/app/build/utils/numberAdjustment.ts +6 -3
  329. package/frontend-vue/layers/dms-ui/app/build/utils/relativeDate.ts +19 -5
  330. package/frontend-vue/layers/dms-ui/app/build/utils/scrollWithin.ts +99 -0
  331. package/frontend-vue/layers/dms-ui/app/build/utils/urlVariables.ts +36 -14
  332. package/frontend-vue/layers/dms-ui/app/components/PasswordStrength.vue +1 -1
  333. package/frontend-vue/layers/dms-ui/app/components/RecursiveComponent.vue +9 -1
  334. package/frontend-vue/layers/dms-ui/app/components/blocks/LiveToggleBlock.vue +80 -32
  335. package/frontend-vue/layers/dms-ui/app/components/blocks/PageToolbarBlock.vue +137 -0
  336. package/frontend-vue/layers/dms-ui/app/components/blocks/StatGroupBlock.vue +5 -0
  337. package/frontend-vue/layers/dms-ui/app/components/chart/ApexChartHost.vue +16 -2
  338. package/frontend-vue/layers/dms-ui/app/components/chart/Chart.vue +24 -5
  339. package/frontend-vue/layers/dms-ui/app/components/chart/ChartCard.vue +41 -23
  340. package/frontend-vue/layers/dms-ui/app/components/confirm/ConfirmModal.vue +1 -1
  341. package/frontend-vue/layers/dms-ui/app/components/container-footer/ContainerFooter.vue +34 -0
  342. package/frontend-vue/layers/dms-ui/app/components/field-row/FieldRow.vue +25 -2
  343. package/frontend-vue/layers/dms-ui/app/components/flow-canvas/FlowCanvas.vue +2 -2
  344. package/frontend-vue/layers/dms-ui/app/components/form/Form.vue +118 -36
  345. package/frontend-vue/layers/dms-ui/app/components/form/components/DatePicker.vue +20 -1
  346. package/frontend-vue/layers/dms-ui/app/components/form/components/Display.vue +13 -1
  347. package/frontend-vue/layers/dms-ui/app/components/form/components/Image.vue +8 -3
  348. package/frontend-vue/layers/dms-ui/app/components/form/components/InputAddress.vue +53 -5
  349. package/frontend-vue/layers/dms-ui/app/components/form/components/InputCode.vue +29 -5
  350. package/frontend-vue/layers/dms-ui/app/components/form/components/InputNumber.vue +45 -8
  351. package/frontend-vue/layers/dms-ui/app/components/form/components/InputPercentage.vue +28 -5
  352. package/frontend-vue/layers/dms-ui/app/components/form/components/InputSecret.vue +5 -0
  353. package/frontend-vue/layers/dms-ui/app/components/form/components/InputText.vue +19 -2
  354. package/frontend-vue/layers/dms-ui/app/components/form/components/InputTime.vue +2 -1
  355. package/frontend-vue/layers/dms-ui/app/components/form/components/Relation.vue +205 -65
  356. package/frontend-vue/layers/dms-ui/app/components/form/components/Repeater.vue +80 -30
  357. package/frontend-vue/layers/dms-ui/app/components/form/components/RepeaterTable.vue +203 -0
  358. package/frontend-vue/layers/dms-ui/app/components/form/components/Select.vue +4 -2
  359. package/frontend-vue/layers/dms-ui/app/components/grid/GridRow.vue +11 -2
  360. package/frontend-vue/layers/dms-ui/app/components/key-value-list/KeyValueList.vue +79 -70
  361. package/frontend-vue/layers/dms-ui/app/components/kpi/KpiCard.vue +117 -21
  362. package/frontend-vue/layers/dms-ui/app/components/meter/Meter.vue +2 -1
  363. package/frontend-vue/layers/dms-ui/app/components/period/PeriodSelector.vue +113 -34
  364. package/frontend-vue/layers/dms-ui/app/components/save-bar/SaveBar.vue +14 -2
  365. package/frontend-vue/layers/dms-ui/app/components/section-header/Eyebrow.vue +6 -1
  366. package/frontend-vue/layers/dms-ui/app/components/segmented/Segmented.vue +13 -0
  367. package/frontend-vue/layers/dms-ui/app/components/stat-group/StatGroup.vue +52 -3
  368. package/frontend-vue/layers/dms-ui/app/components/tab/Tab.vue +2 -1
  369. package/frontend-vue/layers/dms-ui/app/components/table-view/KanbanBoard.vue +45 -35
  370. package/frontend-vue/layers/dms-ui/app/components/table-view/KanbanDisplay.vue +4 -1
  371. package/frontend-vue/layers/dms-ui/app/components/table-view/TableView.vue +410 -96
  372. package/frontend-vue/layers/dms-ui/app/components/top-list/TopListCard.vue +33 -5
  373. package/frontend-vue/layers/dms-ui/app/composables/chart/apexCategoryLabels.ts +68 -0
  374. package/frontend-vue/layers/dms-ui/app/composables/chart/apexDatetimeBuckets.ts +306 -0
  375. package/frontend-vue/layers/dms-ui/app/composables/chart/formatValue.ts +4 -3
  376. package/frontend-vue/layers/dms-ui/app/composables/chart/heatmapColors.ts +93 -0
  377. package/frontend-vue/layers/dms-ui/app/composables/chart/localizeSeries.ts +62 -0
  378. package/frontend-vue/layers/dms-ui/app/composables/chart/useApexChart.ts +116 -8
  379. package/frontend-vue/layers/dms-ui/app/composables/chart/useApexChart.types.ts +7 -0
  380. package/frontend-vue/layers/dms-ui/app/composables/containers/types.ts +84 -1
  381. package/frontend-vue/layers/dms-ui/app/composables/containers/useDrawer.ts +69 -8
  382. package/frontend-vue/layers/dms-ui/app/composables/form/types/field-saved.ts +11 -0
  383. package/frontend-vue/layers/dms-ui/app/composables/form/types/field.ts +4 -0
  384. package/frontend-vue/layers/dms-ui/app/composables/form/types/functions.ts +1 -0
  385. package/frontend-vue/layers/dms-ui/app/composables/form/useForm.ts +142 -21
  386. package/frontend-vue/layers/dms-ui/app/composables/live/usePageLive.ts +11 -4
  387. package/frontend-vue/layers/dms-ui/app/composables/page-toolbar/usePageToolbarSize.ts +30 -0
  388. package/frontend-vue/layers/dms-ui/app/composables/table-view/kanban.ts +4 -2
  389. package/frontend-vue/layers/dms-ui/app/composables/table-view/types/action-target.ts +22 -3
  390. package/frontend-vue/layers/dms-ui/app/composables/table-view/types/config.ts +4 -0
  391. package/frontend-vue/layers/dms-ui/app/composables/table-view/types/display.ts +24 -1
  392. package/frontend-vue/layers/dms-ui/app/plugins/closing-layers.client.ts +10 -0
  393. package/frontend-vue/layers/dms-ui/app/plugins/live-pause-source.ts +15 -0
  394. package/frontend-vue/layers/dms-ui/app/plugins/register.ts +2 -0
  395. package/frontend-vue/layers/dms-ui/app/types/input-number.ts +3 -2
  396. package/frontend-vue/layers/dms-ui/app/types/page-toolbar.ts +7 -0
  397. package/frontend-vue/layers/dms-ui/app/types/row-action.ts +0 -2
  398. package/frontend-vue/layers/dms-ui/app/types/row-navigation.ts +17 -0
  399. package/frontend-vue/layers/dms-ui/app/types/table/query.ts +2 -1
  400. package/frontend-vue/layers/dms-ui/app/utils/blockRefresh.ts +3 -1
  401. package/frontend-vue/layers/dms-ui/app/utils/componentTree.ts +24 -0
  402. package/frontend-vue/layers/dms-ui/i18n/locales/ui-en-GB.json +16 -4
  403. package/frontend-vue/layers/dms-ui/i18n/locales/ui-fr-FR.json +16 -4
  404. package/frontend-vue/package.json +2 -2
  405. package/package.json +7 -6
  406. package/skills/dms/SKILL.md +1 -1
  407. package/skills/dms-auth/SKILL.md +5 -3
  408. package/skills/dms-best-practices/REFERENCE.md +2 -0
  409. package/skills/dms-best-practices/SKILL.md +4 -0
  410. package/skills/dms-module/SKILL.md +3 -2
  411. package/skills/dms-pages/REFERENCE.md +125 -16
  412. package/skills/dms-pages/SKILL.md +1 -1
  413. package/skills/dms-project/DEV-SERVERS.md +23 -1
  414. package/skills/dms-project/REFERENCE.md +1 -1
  415. package/skills/dms-project/SKILL.md +4 -1
  416. package/skills/dms-project/scripts/dms-dev.sh +205 -17
  417. package/dist/routes/startup-gate.d.ts +0 -7
  418. package/dist/routes/startup-gate.js +0 -39
  419. package/dist/routes/startup-gate.js.map +0 -1
  420. package/frontend-vue/layers/dms-core/app/composables/period/periodRenderNow.ts +0 -42
@@ -1,6 +1,6 @@
1
1
  import type { FormSubmitEvent } from "@nuxt/ui";
2
2
  import { z } from "zod";
3
- import { onMounted, unref } from "vue";
3
+ import { nextTick, onMounted, onScopeDispose, unref } from "vue";
4
4
  import type { FormProps, FormFetchResponse, FormSubmitResponse } from "./types";
5
5
  import { jsonSchemaToZod } from "json-schema-to-zod";
6
6
  import { FormEvents } from "./types/events";
@@ -43,6 +43,7 @@ import {
43
43
  isPlainObject,
44
44
  sameFormValue,
45
45
  } from "../../build/composables/unsaved-changes/formValue";
46
+ import { createStartingValueTracker } from "../../build/composables/form/fieldValueRule";
46
47
 
47
48
  /** A server error shown under its field, translated. */
48
49
  export interface FormServerFieldError {
@@ -361,6 +362,26 @@ export function resolveSubmitDefaults(
361
362
  return Object.keys(resolved).length > 0 ? resolved : undefined;
362
363
  }
363
364
 
365
+ /**
366
+ * The values a form's fields start from among its submit defaults: a field
367
+ * the form submits under anyway (the parent a table is filtered on by a route
368
+ * parameter) shows it from the start, and a mandatory one is filled. A
369
+ * default with no field of the form is only submitted.
370
+ */
371
+ export function fieldValuesOfSubmitDefaults(
372
+ fields: ReadonlyArray<{ id: string }>,
373
+ submitDefaults: Record<string, unknown> | undefined,
374
+ ): FormData {
375
+ const values: FormData = {};
376
+ if (!submitDefaults) return values;
377
+ for (const { id } of fields) {
378
+ if (id in submitDefaults) {
379
+ values[id] = submitDefaults[id] as FormFieldValue;
380
+ }
381
+ }
382
+ return values;
383
+ }
384
+
364
385
  export function makeFieldSchemaRequired(schema: z.ZodTypeAny): z.ZodTypeAny {
365
386
  if (schema instanceof z.ZodOptional || schema instanceof z.ZodNullable) {
366
387
  return makeFieldSchemaRequired(schema.unwrap());
@@ -459,10 +480,14 @@ function watchFieldChanges(
459
480
  componentId: string,
460
481
  payload?: unknown,
461
482
  ) => void,
483
+ isStartingValue: (fieldId: string, value: unknown) => boolean,
462
484
  ): void {
463
485
  if (!componentId) return;
464
486
  const id = componentId;
465
487
  const previousValuesJson: Record<string, string> = {};
488
+ // `initial` on each change: a watch writing values (SetFieldValue) leaves
489
+ // the values the form started from to the record it loaded.
490
+ const isInitial = createStartingValueTracker(isStartingValue);
466
491
 
467
492
  // From mount, once `useWatch` listens: the values the form starts from
468
493
  // (defaults, loaded row) reach the watch rules too, not only later edits.
@@ -485,6 +510,7 @@ function watchFieldChanges(
485
510
  fieldId,
486
511
  value: newState[fieldId],
487
512
  formValues: newState,
513
+ initial: isInitial(fieldId, newState[fieldId]),
488
514
  });
489
515
  previousValuesJson[fieldId] = newJson;
490
516
  }
@@ -544,15 +570,41 @@ export const useForm = (props: FormProps, options: UseFormOptions = {}) => {
544
570
  const initialValues = ref<FormData>({});
545
571
  const submitSucceeded = ref(false);
546
572
 
547
- watchFieldChanges(state, props.componentId, sendComponentEvent);
573
+ const allFields = computed(() => flattenFields(props.fields));
574
+
575
+ // Whether a field holds the value the form started from: its default or
576
+ // the loaded record's, compared as its data type does (a joined row is
577
+ // the same as the id the picker holds).
578
+ const isStartingValue = (fieldId: string, value: unknown): boolean => {
579
+ const field = allFields.value.find((entry) => entry.id === fieldId);
580
+ const initial = initialValues.value[fieldId];
581
+ return field
582
+ ? isSameFieldValue(field, value, initial)
583
+ : sameFormValue(value, initial);
584
+ };
585
+
586
+ watchFieldChanges(
587
+ state,
588
+ props.componentId,
589
+ sendComponentEvent,
590
+ isStartingValue,
591
+ );
548
592
 
549
593
  // A successful submit leaves the form at its saved state; a later edit makes
550
594
  // it dirty again, so clear `submitSucceeded` to re-arm the unsaved-changes
551
595
  // guard (and the realtime release-on-unmount) for the new edits. Without this
552
596
  // the guard would stay permanently disabled after the first save.
597
+ // Set while the record a save stored reaches the state: what the server
598
+ // stored is no edit made since.
599
+ let isApplyingSavedRecord = false;
600
+ let isDisposed = false;
601
+ onScopeDispose(() => {
602
+ isDisposed = true;
603
+ });
553
604
  watch(
554
605
  () => state.value,
555
606
  () => {
607
+ if (isApplyingSavedRecord) return;
556
608
  if (submitSucceeded.value) {
557
609
  submitSucceeded.value = false;
558
610
  }
@@ -560,8 +612,6 @@ export const useForm = (props: FormProps, options: UseFormOptions = {}) => {
560
612
  { deep: true },
561
613
  );
562
614
 
563
- const allFields = computed(() => flattenFields(props.fields));
564
-
565
615
  const disabledFields = computed(
566
616
  () => state.value.disabledFields as Set<string> | undefined,
567
617
  );
@@ -607,27 +657,31 @@ export const useForm = (props: FormProps, options: UseFormOptions = {}) => {
607
657
  const isRecordUpdate = computed(
608
658
  () => !!resolvedFetchUrl.value && props.submitUrlMethod !== HttpMethod.post,
609
659
  );
660
+ // A create form (a table view's add form, the duplicate it opens) makes a
661
+ // new row: what it holds is new as a whole, nothing "changed" in it.
662
+ const createsRecord = props.kind === "create";
610
663
 
611
- const fetchData = async () => {
664
+ /** Reads the record at `fetchUrl`: its values, mapped for the fields. */
665
+ const loadRecord = async () => {
612
666
  if (!props.fetchUrl) return undefined;
667
+ const processedUrl = resolveUrlVariables(props.fetchUrl, buildUrlContext());
668
+ if (processedUrl === undefined) return undefined;
669
+
670
+ const fetchedData = await $authFetch<FormFetchResponse>(processedUrl, {
671
+ method: props.fetchUrlMethod || "GET",
672
+ headers: { [CONTENT_LANGUAGE_HEADER]: "*" },
673
+ });
674
+
675
+ initialValues.value = {
676
+ ...initialValues.value,
677
+ ...JSON.parse(JSON.stringify(fetchedData)),
678
+ };
679
+ return processBeforeStateMappers(fetchedData, props.fields, getDataType);
680
+ };
613
681
 
682
+ const fetchData = async () => {
614
683
  try {
615
- const processedUrl = resolveUrlVariables(
616
- props.fetchUrl,
617
- buildUrlContext(),
618
- );
619
- if (processedUrl === undefined) return undefined;
620
-
621
- const fetchedData = await $authFetch<FormFetchResponse>(processedUrl, {
622
- method: props.fetchUrlMethod || "GET",
623
- headers: { [CONTENT_LANGUAGE_HEADER]: "*" },
624
- });
625
-
626
- initialValues.value = {
627
- ...initialValues.value,
628
- ...JSON.parse(JSON.stringify(fetchedData)),
629
- };
630
- return processBeforeStateMappers(fetchedData, props.fields, getDataType);
684
+ return await loadRecord();
631
685
  } catch (error) {
632
686
  // A server render shows the failure in the form (FormLoadError) and
633
687
  // hands it to the browser; a toast it added would show in its HTML
@@ -767,6 +821,63 @@ export const useForm = (props: FormProps, options: UseFormOptions = {}) => {
767
821
  options.onSaved?.();
768
822
  };
769
823
 
824
+ /** Puts the record a save stored in the state: no edit made since. */
825
+ const applyStoredRecord = async (stored: FormData): Promise<void> => {
826
+ isApplyingSavedRecord = true;
827
+ Object.assign(state.value, stored);
828
+ options.onSaved?.();
829
+ await nextTick();
830
+ isApplyingSavedRecord = false;
831
+ };
832
+
833
+ /**
834
+ * Reads the record back from `fetchUrl` once its update went through, for
835
+ * a route that does not answer it. An edit made meanwhile is kept, and a
836
+ * failed read leaves the values as they were sent.
837
+ */
838
+ const refreshSavedRecord = async (): Promise<void> => {
839
+ let stored: FormData | undefined;
840
+ try {
841
+ stored = (await loadRecord()) as FormData | undefined;
842
+ } catch {
843
+ return;
844
+ }
845
+ if (isDisposed || !submitSucceeded.value) return;
846
+ if (!stored || Object.keys(stored).length === 0) return;
847
+ await applyStoredRecord(stored);
848
+ };
849
+
850
+ /**
851
+ * Shows the record its update stored rather than what was typed: the
852
+ * server may store what it was sent normalized (a VAT number stripped of
853
+ * its spaces, the empty rows of a list dropped). A route that answers the
854
+ * record (a table view's edit route, interface-data-api 0.3) is read
855
+ * without a second request: its answer holds the record when it carries
856
+ * one of the form's fields, and only those are taken. Any other answer
857
+ * (`{ success: true }`, nothing) has the form read `fetchUrl` again. The
858
+ * form stays saved.
859
+ */
860
+ const showSavedRecord = async (
861
+ response: FormSubmitResponse | undefined,
862
+ ): Promise<void> => {
863
+ if (!submitSucceeded.value) return;
864
+ const fieldIds = new Set(allFields.value.map((field) => field.id));
865
+ // The route answers JSON, as `fetchUrl` does: field values.
866
+ const record: FormData = isPlainObject(response)
867
+ ? (Object.fromEntries(
868
+ Object.entries(response).filter(([key]) => fieldIds.has(key)),
869
+ ) as FormData)
870
+ : {};
871
+ if (Object.keys(record).length === 0) return refreshSavedRecord();
872
+ initialValues.value = {
873
+ ...initialValues.value,
874
+ ...JSON.parse(JSON.stringify(record)),
875
+ };
876
+ await applyStoredRecord(
877
+ processBeforeStateMappers(record, props.fields, getDataType) as FormData,
878
+ );
879
+ };
880
+
770
881
  const handleSubmitSuccess = async (
771
882
  response: FormSubmitResponse | undefined,
772
883
  plainData: FormData,
@@ -854,6 +965,14 @@ export const useForm = (props: FormProps, options: UseFormOptions = {}) => {
854
965
  try {
855
966
  const response = await sendSubmit(target.url, plainData, markSubmitSaved);
856
967
  await handleSubmitSuccess(response, plainData);
968
+ // A redirect leaves the form, an action form starts over.
969
+ if (
970
+ isRecordUpdate.value &&
971
+ props.kind !== "action" &&
972
+ !props.redirectOnSuccess
973
+ ) {
974
+ await showSavedRecord(response);
975
+ }
857
976
  } catch (error) {
858
977
  reportSubmitError(error);
859
978
  } finally {
@@ -914,5 +1033,7 @@ export const useForm = (props: FormProps, options: UseFormOptions = {}) => {
914
1033
  isFieldGroup,
915
1034
  submitSucceeded,
916
1035
  resolvedFetchUrl,
1036
+ createsRecord,
1037
+ effectiveSubmitDefaults,
917
1038
  };
918
1039
  };
@@ -4,7 +4,10 @@ import {
4
4
  onScopeDispose,
5
5
  type ComputedRef,
6
6
  } from "vue";
7
- import { currentPageLive } from "../../build/composables/live/currentPageLive";
7
+ import {
8
+ currentPageLive,
9
+ isServerPageLive,
10
+ } from "../../build/composables/live/currentPageLive";
8
11
  import type { PageLiveController } from "../../build/composables/live/pageLiveController";
9
12
  import type { PageLiveNote, PageLiveNoteInput } from "../../types/live";
10
13
 
@@ -68,8 +71,11 @@ export interface PageLiveState {
68
71
  * paused, show what was missed, offer its own switch, hold the page while the
69
72
  * user types.
70
73
  *
71
- * On a page without `live`, or while server-rendering, `isEnabled` is false,
72
- * the page reads as live and never paused, and its actions do nothing.
74
+ * On a page without `live`, `isEnabled` is false, the page reads as live and
75
+ * never paused, and its actions do nothing. A server render reads the page as
76
+ * live and never paused too, but `isEnabled` says whether it declares `live`:
77
+ * the browser hydrates the page's blocks with its controller installed, so
78
+ * the server draws them as it will.
73
79
  *
74
80
  * ```ts
75
81
  * const { isPaused, missedCount, resume, hold, release } = usePageLive();
@@ -82,8 +88,9 @@ export interface PageLiveState {
82
88
  export function usePageLive(): PageLiveState {
83
89
  const isPaused = computed(() => currentPageLive()?.isPaused.value ?? false);
84
90
  const hold = usePageLiveHold();
91
+ const isServerLive = isServerPageLive();
85
92
  return {
86
- isEnabled: computed(() => currentPageLive() !== null),
93
+ isEnabled: computed(() => currentPageLive() !== null || isServerLive),
87
94
  isLive: computed(() => !isPaused.value),
88
95
  isPaused,
89
96
  pauseReason: computed(() => currentPageLive()?.pauseReason.value ?? null),
@@ -0,0 +1,30 @@
1
+ import { computed, type ComputedRef } from "vue";
2
+ import { usePageToolbar } from "../../build/composables/page-toolbar/pageToolbarContext";
3
+ import type { PageToolbarSize } from "../../types/page-toolbar";
4
+ import { PAGE_TOOLBAR_CONTROL_HEIGHT_CLASSES } from "../../build/composables/page-toolbar/toolbarControlHeight";
5
+
6
+ const DEFAULT_SIZE: PageToolbarSize = "sm";
7
+
8
+ /** The size of the `PageToolbar` holding a component (see {@link usePageToolbarSize}). */
9
+ export interface PageToolbarSizeState {
10
+ /** The toolbar's size, `sm` outside one. */
11
+ size: ComputedRef<PageToolbarSize>;
12
+ /** The height class its controls share at that size (`h-7` at `sm`). */
13
+ heightClass: ComputedRef<string>;
14
+ }
15
+
16
+ /**
17
+ * The size of the `PageToolbar` a module's component sits in, for a leading
18
+ * block (a scope chip, a picker) to stand as tall as the toggle and the
19
+ * period beside it.
20
+ */
21
+ export function usePageToolbarSize(): PageToolbarSizeState {
22
+ const toolbar = usePageToolbar();
23
+ const size = computed(() => toolbar?.size.value ?? DEFAULT_SIZE);
24
+ return {
25
+ size,
26
+ heightClass: computed(
27
+ () => PAGE_TOOLBAR_CONTROL_HEIGHT_CLASSES[size.value],
28
+ ),
29
+ };
30
+ }
@@ -4,8 +4,8 @@ import type { TableViewColumn } from "./types";
4
4
  /**
5
5
  * The few inputs the (unchanged) KanbanBoard needs beyond the generic
6
6
  * {@link TableViewDisplayContext}: the two-way group-by field shared with the
7
- * options-menu selector, and the raw edit/delete action configs for per-row rule
8
- * evaluation. Everything else (query, componentId, pageId, labelKey) is read from
7
+ * options-menu selector, the raw edit/delete action configs for per-row rule
8
+ * evaluation, and the callback told of a saved move. Everything else (query, componentId, pageId, labelKey) is read from
9
9
  * the generic context. Provided by TableView and injected by the kanban adapter
10
10
  * — slotted content is a descendant of TableView, so a native inject reaches it.
11
11
  */
@@ -13,6 +13,8 @@ export interface KanbanDisplayBridge {
13
13
  groupByField: Ref<string>;
14
14
  editAction?: boolean | RowActionConfig;
15
15
  deleteAction?: boolean | RowActionConfig;
16
+ /** A card was moved to another column and saved: the counts read again. */
17
+ onCardMoved?: () => void;
16
18
  }
17
19
 
18
20
  export const KANBAN_DISPLAY_BRIDGE_KEY: InjectionKey<KanbanDisplayBridge> =
@@ -19,12 +19,31 @@ export interface SidePanelTargetOptions {
19
19
  * `{ index }` (from 1) and `{ total }`.
20
20
  */
21
21
  positionLabel?: string;
22
- /** The open row is kept in the URL (`?record=`): on unless `false`. */
22
+ /**
23
+ * The open row is kept in the URL (`?record=`): on unless `false` for a
24
+ * side panel, off unless `true` for a drawer.
25
+ */
23
26
  deepLink?: boolean;
24
27
  /** The state drawn on a row that no longer exists (a 404). */
25
28
  notFound?: SidePanelNotFoundTexts;
26
29
  }
27
30
 
31
+ /**
32
+ * What a `drawer` target sets besides its component (backend
33
+ * `DrawerTargetOptions`): the row options of a side panel, for a drawer
34
+ * opened on a row, and its size.
35
+ */
36
+ export interface DrawerTargetOptions
37
+ extends Omit<SidePanelTargetOptions, "title"> {
38
+ /** Width of a `left` / `right` drawer: a modal's at that size; 600px without one. */
39
+ size?: ModalSize;
40
+ /**
41
+ * The DMS draws the row header (title, position, previous / next): on when
42
+ * `rowTitle` or `positionLabel` is set, unless `false`.
43
+ */
44
+ rowHeader?: boolean;
45
+ }
46
+
28
47
  /**
29
48
  * Fetches a file with the user's session and saves it (backend
30
49
  * `DownloadActionTarget`).
@@ -38,14 +57,14 @@ export interface DownloadActionTarget {
38
57
  }
39
58
 
40
59
  export type ActionTarget =
41
- | {
60
+ | ({
42
61
  type: "drawer";
43
62
  component: ComponentInfo;
44
63
  title?: string;
45
64
  description?: string;
46
65
  /** Edge the drawer slides in from (`bottom` by default). */
47
66
  direction?: DrawerDirection;
48
- }
67
+ } & DrawerTargetOptions)
49
68
  | {
50
69
  type: "modal";
51
70
  size?: ModalSize;
@@ -274,6 +274,8 @@ export interface TableViewConfig<T extends Data>
274
274
  location: string;
275
275
  enableTableExport?: boolean;
276
276
  archiveMode?: boolean;
277
+ /** Caption count while the archived rows show; "Archived: {count}" else. */
278
+ archivedCountLabel?: string;
277
279
  defaultFilters?: TableFilter[];
278
280
  columns: TableViewColumn[];
279
281
  labelKey?: string;
@@ -298,6 +300,8 @@ export interface TableViewConfig<T extends Data>
298
300
  displays?: TableViewDisplayConfig[];
299
301
  /** Display shown by default when the user has no saved preference. Defaults to the first display. */
300
302
  defaultDisplay?: string;
303
+ /** Display a phone opens on when the user has no saved choice; one of `displays`. */
304
+ mobileDisplay?: string;
301
305
  /** Expandable rows: caret column + detail band. */
302
306
  expandable?: TableViewExpandableConfig;
303
307
  /** How much the table draws around its rows. */
@@ -87,7 +87,11 @@ export interface TableViewDisplayActions<T> {
87
87
  canDeleteRow: (item: T) => boolean;
88
88
  add: () => void;
89
89
  edit: (item: T) => void;
90
- delete: (ids: string[]) => void;
90
+ /**
91
+ * Deletes the rows once confirmed. A display drawing rows the grid does not
92
+ * list (a kanban card) hands them in `rows`, so a dialog can name them.
93
+ */
94
+ delete: (ids: string[], rows?: T[]) => void;
91
95
  duplicate: (id: string) => void;
92
96
  details: (item: T) => void;
93
97
  /** What a click on the row does in the grid: its default action. */
@@ -150,6 +154,10 @@ export interface TableViewCardReorder {
150
154
  export interface TableViewCardConfig {
151
155
  fields?: string[];
152
156
  component?: ComponentInfo;
157
+ /** `cards` only: the narrowest a card gets, a CSS length (`230px` left out). */
158
+ minWidth?: string;
159
+ /** `cards` only: the height of a placeholder card, a CSS length. */
160
+ skeletonHeight?: string;
153
161
  }
154
162
 
155
163
  /**
@@ -180,6 +188,13 @@ export interface TableViewCardProps<T = Record<string, unknown>> {
180
188
  * caller who may edit: the card's move handle, to draw somewhere on it.
181
189
  */
182
190
  reorder?: TableViewCardReorder;
191
+ /**
192
+ * `cards` only: the row's actions as the grid row offers them (its inline
193
+ * buttons and its … menu, with their rules and confirmations), to draw
194
+ * with `<component :is="rowActions" />`. It draws nothing for a table with
195
+ * no row action, and stops its clicks from reaching the card.
196
+ */
197
+ rowActions?: Component;
183
198
  }
184
199
 
185
200
  /**
@@ -239,6 +254,14 @@ export interface TableViewDisplayContext<T = Record<string, unknown>> {
239
254
  pageId?: string;
240
255
  /** Per-instance options declared for this display in the backend config. */
241
256
  options?: Record<string, unknown>;
257
+ /**
258
+ * A self-managed display hands the rows it shows, in the order the user
259
+ * reads them (a board: column by column), each time they change: a row
260
+ * opened from it steps through them in its drawer or side panel ("3 of
261
+ * 12", previous / next, J and K). Without it, a self-managed display's row
262
+ * opens without steps. The shared list's displays need not call it.
263
+ */
264
+ setShownRows?: (rows: T[]) => void;
242
265
  /** Re-fetch the table view (shared list + tab counts + active display). */
243
266
  refresh: () => Promise<void> | void;
244
267
  /**
@@ -0,0 +1,10 @@
1
+ import { watchClosingLayers } from "../build/composables/containers/closingLayers";
2
+
3
+ /**
4
+ * Every dialog the DMS or a module renders lets the page be clicked as soon
5
+ * as it starts closing: one place for UModal, USlideover, UDrawer, the
6
+ * confirm dialogs and DynamicDrawer / DynamicModal alike.
7
+ */
8
+ export default defineDmsPlugin(() => {
9
+ watchClosingLayers(document);
10
+ });
@@ -0,0 +1,15 @@
1
+ import { LIVE_PAUSE_SOURCE } from "#dms-core/app/composables/live/livePauseSource";
2
+ import { currentPageLive } from "../build/composables/live/currentPageLive";
3
+
4
+ /**
5
+ * Gives the core layer the pause of the page on screen (its live
6
+ * controller), so a component's own polling (`useApiData`'s
7
+ * `refreshInterval`) stops with the page's blocks. The server renders no
8
+ * poll and installs no controller: it reads as never paused.
9
+ */
10
+ export default defineDmsPlugin(({ vueApp }) => {
11
+ vueApp.provide(
12
+ LIVE_PAUSE_SOURCE,
13
+ () => currentPageLive()?.isPaused.value ?? false,
14
+ );
15
+ });
@@ -2,10 +2,12 @@ import { registerDefaultDataTypes } from "../build/composables/data-types/regist
2
2
  import { registerDefaultFunctions } from "../build/composables/table-view/registerDefaultFunctions";
3
3
  import { registerFormFunctions } from "../build/composables/form/registerFormFunctions";
4
4
  import { registerBlockFunctions } from "../build/composables/blocks/registerBlockFunctions";
5
+ import { trackPageArrivals } from "../build/composables/table-view/utils/pageArrival";
5
6
 
6
7
  export default defineDmsPlugin(() => {
7
8
  registerDefaultDataTypes();
8
9
  registerDefaultFunctions();
9
10
  registerFormFunctions();
10
11
  registerBlockFunctions();
12
+ trackPageArrivals();
11
13
  });
@@ -1,13 +1,14 @@
1
1
  /**
2
2
  * Why a number field keeps another value than the one typed: above its `max`,
3
- * below its `min`, or off its `step`.
3
+ * below its `min`, or off its `step` (when it snaps to it: `stepSnapping`).
4
4
  */
5
5
  export type InputNumberAdjustmentReason = "min" | "max" | "step";
6
6
 
7
7
  /**
8
8
  * What `DmsInputNumber` emits as `adjust` when it settles a typed number on
9
9
  * another value (on leaving the field, or on Enter): 1020 typed in a field of
10
- * steps of 50 gives `{ typed: 1020, value: 1000, reason: "step" }`.
10
+ * steps of 50 that snaps to them gives
11
+ * `{ typed: 1020, value: 1000, reason: "step" }`.
11
12
  */
12
13
  export interface InputNumberAdjustment {
13
14
  /** The number as typed. */
@@ -0,0 +1,7 @@
1
+ /**
2
+ * The sizes a `PageToolbar` draws its controls at (`xs` 24px, `sm` 28px,
3
+ * `md` 32px tall), as `usePageToolbarSize()` reports them to a module's
4
+ * leading block. The same values as `PageToolbarSize` of
5
+ * `@antelopejs/interface-dms/base/page-toolbar`.
6
+ */
7
+ export type PageToolbarSize = "xs" | "sm" | "md";
@@ -24,8 +24,6 @@ export interface CustomRowAction {
24
24
  rule?: RowActionRule;
25
25
  /** Inline button instead of a menu entry (the backend serializes `isVisible`). */
26
26
  isVisible?: boolean;
27
- /** Legacy spelling of `isVisible`, still honoured. */
28
- visible?: boolean;
29
27
  /**
30
28
  * Preferred row-click target when its rule accepts the row: a double-click,
31
29
  * or a single click on a table with `rowClick: "single"`.
@@ -0,0 +1,17 @@
1
+ /**
2
+ * What a drawer or modal opened on a row receives to step through the rows
3
+ * of the table (`navigation` prop): J and K do the same. The steps follow the
4
+ * open row's neighbours in the table's current order, past the rows loaded:
5
+ * rows arriving or leaving meanwhile (a live table) never make a step skip
6
+ * or revisit one.
7
+ */
8
+ export interface RowNavigation {
9
+ /** Position of the row among all the rows the table lists, from 0. */
10
+ index: number;
11
+ /** The rows the table lists: its count, beyond the page loaded. */
12
+ total: number;
13
+ hasPrev: boolean;
14
+ hasNext: boolean;
15
+ prev: () => void;
16
+ next: () => void;
17
+ }
@@ -10,5 +10,6 @@ export interface TableQueryParams {
10
10
  sortKey?: string;
11
11
  sortDirection?: SortDirection;
12
12
  showArchived?: boolean;
13
- [key: `filter_${string}`]: string | number | undefined;
13
+ /** A list sends the key once per filter, which a row must all pass. */
14
+ [key: `filter_${string}`]: string | string[] | number | undefined;
14
15
  }
@@ -1,3 +1,5 @@
1
+ import { markPageRead } from "../build/composables/live/pageReadClock";
2
+
1
3
  /**
2
4
  * The window event a data block (StatGroup, KeyValueList, NavCardGrid,
3
5
  * ActivityFeed, KPI, top list, meter, chart, a tab set's badges, table view)
@@ -43,7 +45,7 @@ export function refreshPageBlocks(): Promise<void> {
43
45
  waitUntil: (work) => void pending.push(work),
44
46
  };
45
47
  window.dispatchEvent(new CustomEvent(BLOCK_REFRESH_EVENT, { detail }));
46
- return Promise.allSettled(pending).then(() => undefined);
48
+ return Promise.allSettled(pending).then(() => markPageRead());
47
49
  }
48
50
 
49
51
  /**
@@ -0,0 +1,24 @@
1
+ /**
2
+ * The children of a layout block (a Card, a VStack, a Grid) as
3
+ * `RecursiveComponent` draws them: each child's component resolved by its
4
+ * registered name, a `div` when none matches, its own children likewise.
5
+ */
6
+ export function resolveComponentChildren(
7
+ children: ComponentChild[],
8
+ ): ResolvedComponentInfo[] {
9
+ return children.map((child) => {
10
+ const { id, component, ...additionalProps } = child;
11
+ return {
12
+ id,
13
+ options: component.options,
14
+ component: component.componentName
15
+ ? resolveDmsComponent(component.componentName) || "div"
16
+ : "div",
17
+ componentName: component.componentName,
18
+ children: component.children
19
+ ? resolveComponentChildren(component.children)
20
+ : [],
21
+ ...additionalProps,
22
+ };
23
+ });
24
+ }