@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
@@ -2,6 +2,10 @@
2
2
  import { pageRequestUrl } from "../../../build/composables/page/pageUrlValues";
3
3
  import type { SelectMenuItem } from "@nuxt/ui";
4
4
  import { refDebounced } from "@vueuse/core";
5
+ import {
6
+ rankAddressSuggestions,
7
+ suggestionPoolSize,
8
+ } from "../../../build/utils/addressSuggestions";
5
9
  import {
6
10
  formErrorsInjectionKey,
7
11
  formInputsInjectionKey,
@@ -48,6 +52,12 @@ interface AddressProps {
48
52
  label?: string;
49
53
  value?: string;
50
54
  };
55
+ /**
56
+ * ISO 3166-1 alpha-2 code ("BE") the country shows while the address has
57
+ * none, written with the first part typed, and the country whose places
58
+ * the street suggestions list first.
59
+ */
60
+ defaultCountry?: string;
51
61
  }
52
62
 
53
63
  const props = defineProps<AddressProps>();
@@ -68,7 +78,18 @@ const defaultAddress: AddressValue = {
68
78
  countryCode: "",
69
79
  };
70
80
 
71
- const safeModelValue = computed(() => modelValue.value ?? defaultAddress);
81
+ const defaultCountryCode = computed(
82
+ () => props.defaultCountry?.trim().toUpperCase() ?? "",
83
+ );
84
+
85
+ // An address with no country shows the default one; it is written with the
86
+ // first part typed, so an address left empty stays empty.
87
+ const safeModelValue = computed<AddressValue>(() => {
88
+ const value = modelValue.value ?? defaultAddress;
89
+ return value.countryCode || !defaultCountryCode.value
90
+ ? value
91
+ : { ...value, countryCode: defaultCountryCode.value };
92
+ });
72
93
 
73
94
  /* -------------------------------------------------------------------------- */
74
95
  /* Field state: which parts show the field's error */
@@ -308,6 +329,7 @@ interface PhotonResponse {
308
329
  interface AddressSuggestion {
309
330
  id: string;
310
331
  label: string;
332
+ countryCode?: string;
311
333
  patch: Partial<AddressValue>;
312
334
  }
313
335
 
@@ -329,6 +351,9 @@ const streetQueryDebounced = refDebounced(streetQuery, SEARCH_DEBOUNCE_MS);
329
351
  const suggestions = ref<AddressSuggestion[]>([]);
330
352
  const isSearching = ref(false);
331
353
  const showSuggestions = ref(false);
354
+ // Suggestions only open under the street field while it has the focus: an
355
+ // answer arriving once the user left it must not cover the next fields.
356
+ const isStreetFocused = ref(false);
332
357
 
333
358
  // Photon/OSM exposes a single `housenumber`. We only pull a box/unit out when it
334
359
  // is *explicitly* marked (BE "bte", NL "bus", "box", or a "/" separator). A bare
@@ -403,22 +428,31 @@ watch(streetQueryDebounced, async (query) => {
403
428
  params: {
404
429
  q: query,
405
430
  lang: photonLang.value,
406
- limit: photonLimit.value,
431
+ // A wider pool, so the places of the address's country can come
432
+ // first and the duplicates can go.
433
+ limit: suggestionPoolSize(photonLimit.value),
407
434
  },
408
435
  });
409
436
 
410
437
  if (seq !== searchSeq) return;
411
438
 
412
- suggestions.value = (response.features ?? [])
439
+ const found = (response.features ?? [])
413
440
  .filter(
414
441
  (feature) => feature.properties?.street || feature.properties?.name,
415
442
  )
416
443
  .map((feature, index) => ({
417
444
  id: String(index),
418
445
  label: formatPhotonLabel(feature.properties),
446
+ countryCode: feature.properties.countrycode?.toUpperCase(),
419
447
  patch: mapPhotonFeature(feature.properties),
420
448
  }));
421
- showSuggestions.value = suggestions.value.length > 0;
449
+ suggestions.value = rankAddressSuggestions(
450
+ found,
451
+ safeModelValue.value.countryCode,
452
+ photonLimit.value,
453
+ );
454
+ showSuggestions.value =
455
+ isStreetFocused.value && suggestions.value.length > 0;
422
456
  } catch {
423
457
  if (seq === searchSeq) suggestions.value = [];
424
458
  } finally {
@@ -438,7 +472,9 @@ const streetModel = computed({
438
472
  });
439
473
 
440
474
  const applySuggestion = (suggestion: AddressSuggestion) => {
441
- patchFields(suggestion.patch);
475
+ // A place the geocoder gives no country keeps the one shown.
476
+ const { countryCode, ...located } = suggestion.patch;
477
+ patchFields(countryCode ? suggestion.patch : located);
442
478
  // Bump the sequence so any still-in-flight request is discarded and cannot
443
479
  // repopulate the list / reopen the dropdown after the user picked a result.
444
480
  searchSeq++;
@@ -449,17 +485,27 @@ const applySuggestion = (suggestion: AddressSuggestion) => {
449
485
  let blurTimer: ReturnType<typeof setTimeout> | undefined;
450
486
 
451
487
  const onStreetFocus = () => {
488
+ isStreetFocused.value = true;
452
489
  if (autocompleteEnabled.value && suggestions.value.length > 0) {
453
490
  showSuggestions.value = true;
454
491
  }
455
492
  };
456
493
 
457
494
  const onStreetBlur = () => {
495
+ isStreetFocused.value = false;
458
496
  blurTimer = setTimeout(() => {
459
497
  showSuggestions.value = false;
460
498
  }, BLUR_CLOSE_DELAY_MS);
461
499
  };
462
500
 
501
+ /** Escape closes the suggestions, as it would any list; typing reopens it. */
502
+ const onStreetEscape = (event: KeyboardEvent) => {
503
+ if (!showSuggestions.value) return;
504
+ // Only the list closes, not the drawer or modal around the form.
505
+ event.stopPropagation();
506
+ showSuggestions.value = false;
507
+ };
508
+
463
509
  onBeforeUnmount(() => {
464
510
  if (blurTimer) clearTimeout(blurTimer);
465
511
  });
@@ -532,6 +578,7 @@ const streetPlaceholder = computed(() => {
532
578
  autocomplete="off"
533
579
  @focus="onStreetFocus"
534
580
  @blur="onStreetBlur"
581
+ @keydown.esc="onStreetEscape"
535
582
  />
536
583
  <div
537
584
  v-if="autocompleteEnabled && showSuggestions && suggestions.length"
@@ -635,6 +682,7 @@ const streetPlaceholder = computed(() => {
635
682
  value-key="value"
636
683
  label-key="label"
637
684
  searchable
685
+ :aria-label="t('dms.a11y.show_options')"
638
686
  @update:model-value="updateField('countryCode', $event)"
639
687
  />
640
688
  </div>
@@ -21,6 +21,12 @@ interface InputCodeProps {
21
21
  completions?: CodeEditorCompletion[];
22
22
  placeholder?: string;
23
23
  disabled?: boolean;
24
+ /**
25
+ * Fills the height its flex parent leaves it (a drawer's body, a stacked
26
+ * `DmsFieldRow fill`) and scrolls inside it: `minLines` stays its floor
27
+ * (the parent scrolls below it), `maxLines` is ignored.
28
+ */
29
+ fill?: boolean;
24
30
  }
25
31
 
26
32
  interface CompletionsResponse {
@@ -35,6 +41,7 @@ const props = withDefaults(defineProps<InputCodeProps>(), {
35
41
  completions: undefined,
36
42
  placeholder: undefined,
37
43
  id: undefined,
44
+ fill: false,
38
45
  });
39
46
  const model = defineModel<string | null | undefined>();
40
47
  const { t } = useI18n();
@@ -152,13 +159,18 @@ onBeforeUnmount(() => {
152
159
  </script>
153
160
 
154
161
  <template>
162
+ <!-- Filling, the root clips without scrolling (`overflow-clip`): its
163
+ minimum stays its content's, the editor's floor, and the parent scrolls
164
+ below it. The editor's area holds no size of its own (`contain-size`): a
165
+ long text scrolls in it instead of growing the root. -->
155
166
  <div
156
- class="border-accented overflow-hidden rounded-md border focus-within:ring-2"
157
- :class="
167
+ class="border-accented rounded-md border focus-within:ring-2"
168
+ :class="[
158
169
  isInvalid
159
170
  ? 'border-error focus-within:ring-error/25'
160
- : 'focus-within:border-primary focus-within:ring-primary/25'
161
- "
171
+ : 'focus-within:border-primary focus-within:ring-primary/25',
172
+ fill ? 'flex flex-1 flex-col overflow-clip' : 'overflow-hidden',
173
+ ]"
162
174
  :style="sizeStyle"
163
175
  @focusout="emitFormBlur"
164
176
  >
@@ -167,11 +179,23 @@ onBeforeUnmount(() => {
167
179
  <pre
168
180
  v-if="!isReady"
169
181
  class="text-highlighted min-h-(--dms-code-min-height) overflow-auto px-3 py-2 font-mono text-[12.5px] whitespace-pre-wrap"
182
+ :class="fill && 'flex-1 contain-size'"
170
183
  >{{ model }}</pre
171
184
  >
185
+ <!-- Important: CodeMirror's unlayered `.cm-content { min-height: 100% }`
186
+ outranks a utility, and `min-lines` would never apply. -->
172
187
  <div
173
188
  ref="host"
174
- class="[&_.cm-content]:min-h-(--dms-code-min-height) [&_.cm-scroller]:max-h-(--dms-code-max-height) [&_.cm-scroller]:overflow-auto"
189
+ data-dms-code-host
190
+ class="[&_.cm-content]:min-h-(--dms-code-min-height)! [&_.cm-scroller]:overflow-auto"
191
+ :class="
192
+ fill
193
+ ? [
194
+ 'flex flex-col contain-size [&_.cm-editor]:min-h-0 [&_.cm-editor]:flex-1 [&_.cm-scroller]:min-h-0 [&_.cm-scroller]:flex-1',
195
+ isReady && 'min-h-(--dms-code-min-height) flex-1',
196
+ ]
197
+ : '[&_.cm-scroller]:max-h-(--dms-code-max-height)'
198
+ "
175
199
  />
176
200
  <div
177
201
  class="border-default text-dimmed flex items-center gap-3 border-t bg-(--dms-bg-muted) px-3 py-1 font-mono text-[11px]"
@@ -16,6 +16,10 @@ import {
16
16
  numberAdjustment,
17
17
  parseTypedNumber,
18
18
  } from "../../../build/utils/numberAdjustment";
19
+ import {
20
+ type InputWidth,
21
+ isCompactNumberInput,
22
+ } from "../../../build/utils/inputWidth";
19
23
  import type { InputNumberAdjustment } from "../../../types/input-number";
20
24
 
21
25
  defineOptions({ inheritAttrs: false });
@@ -28,12 +32,23 @@ interface InputNumberFieldProps extends InputNumberProps {
28
32
  * it as the field's error, instead of clamping it into range on blur.
29
33
  */
30
34
  clamp?: boolean;
35
+ /**
36
+ * `"compact"` sizes the field for a short number from `sm` up, `"full"`
37
+ * fills the row; left out, a `max` of a few digits makes it compact.
38
+ */
39
+ width?: InputWidth;
40
+ /**
41
+ * `true` puts a typed value on the nearest `step` when the field is left.
42
+ * Off by default: `step` only drives the steppers and the arrow keys, and
43
+ * a value is never rewritten (9,692 kept as 9,692 with steps of 100).
44
+ */
45
+ stepSnapping?: boolean;
31
46
  }
32
47
 
33
48
  interface InputNumberAdjustEmits {
34
49
  /**
35
50
  * The field kept another value than the one typed, on leaving it or on
36
- * Enter: clamped to `min` / `max`, or put on its `step`.
51
+ * Enter: clamped to `min` / `max`, or put on its `step` (`stepSnapping`).
37
52
  */
38
53
  adjust: [adjustment: InputNumberAdjustment];
39
54
  }
@@ -42,6 +57,7 @@ type InputNumberFieldEmits = InputNumberEmits & InputNumberAdjustEmits;
42
57
 
43
58
  const props = withDefaults(defineProps<InputNumberFieldProps>(), {
44
59
  clamp: true,
60
+ stepSnapping: false,
45
61
  });
46
62
  const emits = defineEmits<InputNumberFieldEmits>();
47
63
  defineSlots<InputNumberSlots>();
@@ -54,6 +70,7 @@ const inputProps = computed(() => {
54
70
  const {
55
71
  suffix: _suffix,
56
72
  clamp: _clamp,
73
+ width: _width,
57
74
  onAdjust: _onAdjust,
58
75
  ...rest
59
76
  } = forwarded.value;
@@ -64,12 +81,32 @@ const inputProps = computed(() => {
64
81
  ...numberStepperState(props.modelValue, bounds.value),
65
82
  };
66
83
  });
84
+ const isCompact = computed(() => isCompactNumberInput(props));
67
85
  const { processI18n } = useTranslation();
68
86
  const { locale } = useI18n();
69
87
 
70
88
  // v2 number fields keep the value left-aligned with a compact caret stepper.
71
89
  const DEFAULT_ORIENTATION = "vertical";
72
90
 
91
+ // The unit sits inside the box, before the stepper, so a field with a unit
92
+ // is as wide as the fields around it: the value's end padding makes room for
93
+ // the stepper (2rem, `end-8` below), a gap and the unit, sized in
94
+ // characters (`ch` slightly overestimates a short unit, never clips it).
95
+ const SUFFIX_BASE_CLASS = "pe-[calc(var(--dms-field-suffix-width)+2.375rem)]";
96
+ const suffixText = computed(() =>
97
+ props.suffix ? processI18n(props.suffix) : "",
98
+ );
99
+ const suffixStyle = computed(() =>
100
+ suffixText.value
101
+ ? { "--dms-field-suffix-width": `${suffixText.value.length}ch` }
102
+ : undefined,
103
+ );
104
+ const fieldUi = computed(() =>
105
+ suffixText.value
106
+ ? { ...props.ui, base: [props.ui?.base, SUFFIX_BASE_CLASS] }
107
+ : props.ui,
108
+ );
109
+
73
110
  // A minus typed or pasted where no negative number is allowed is refused
74
111
  // by the field before it shows: it says why, rather than leaving an emptied
75
112
  // field to read as never filled.
@@ -134,10 +171,9 @@ async function settle(event: Event): Promise<void> {
134
171
  </script>
135
172
 
136
173
  <template>
137
- <!-- The unit sits after the field rather than inside it, where the
138
- stepper already takes the end of the box. -->
139
174
  <div
140
- :class="props.suffix ? 'flex items-center gap-2' : 'contents'"
175
+ :class="suffixText ? 'relative flex items-center' : 'contents'"
176
+ :style="suffixStyle"
141
177
  @beforeinput.capture="onIncomingText"
142
178
  @input="onTyped"
143
179
  @keydown.enter="settle"
@@ -146,17 +182,18 @@ async function settle(event: Event): Promise<void> {
146
182
  v-bind="{ ...inputProps, ...$attrs }"
147
183
  @blur="settle"
148
184
  @update:model-value="onSettledValue"
149
- :class="props.suffix && 'min-w-0 flex-1'"
185
+ :class="[suffixText && 'min-w-0 flex-1', isCompact && 'sm:max-w-44']"
186
+ :ui="fieldUi"
150
187
  :orientation="props.orientation ?? DEFAULT_ORIENTATION"
151
188
  :increment="{ color: 'neutral' }"
152
189
  :decrement="{ color: 'neutral' }"
153
190
  />
154
191
  <span
155
- v-if="props.suffix"
156
- class="text-muted shrink-0 text-[13px]"
192
+ v-if="suffixText"
193
+ class="text-muted pointer-events-none absolute inset-y-0 end-8 flex items-center text-[13px] whitespace-nowrap"
157
194
  data-field-suffix
158
195
  >
159
- {{ processI18n(props.suffix) }}
196
+ {{ suffixText }}
160
197
  </span>
161
198
  </div>
162
199
  </template>
@@ -4,10 +4,20 @@ import type {
4
4
  InputNumberEmits,
5
5
  InputNumberSlots,
6
6
  } from "@nuxt/ui";
7
+ import { computed } from "vue";
8
+ import {
9
+ type InputWidth,
10
+ isCompactNumberInput,
11
+ } from "../../../build/utils/inputWidth";
12
+
13
+ interface InputPercentageProps extends InputNumberProps {
14
+ /** As on `InputNumber`; left out, the 0-100 bounds make it compact. */
15
+ width?: InputWidth;
16
+ }
7
17
 
8
18
  const PERCENTAGE_MULTIPLIER = 100;
9
19
 
10
- const props = defineProps<InputNumberProps>();
20
+ const props = defineProps<InputPercentageProps>();
11
21
  const emits = defineEmits<InputNumberEmits>();
12
22
  defineSlots<InputNumberSlots>();
13
23
 
@@ -25,13 +35,23 @@ const displayValue = computed({
25
35
  },
26
36
  });
27
37
 
38
+ const bounds = computed(() => ({
39
+ min: props.min ?? 0,
40
+ max: props.max ?? PERCENTAGE_MULTIPLIER,
41
+ }));
42
+ const isCompact = computed(() =>
43
+ isCompactNumberInput({ width: props.width, ...bounds.value }),
44
+ );
45
+
28
46
  const forwardedProps = computed(() => {
47
+ const { width: _width, ...rest } = props;
29
48
  return {
30
- ...props,
49
+ ...rest,
50
+ ...bounds.value,
31
51
  modelValue: displayValue.value,
32
- min: props.min ?? 0,
33
- max: props.max ?? PERCENTAGE_MULTIPLIER,
34
52
  step: props.step ?? 0.01,
53
+ // The step drives the steppers only: a stored 12.345 % stays as it is.
54
+ stepSnapping: props.stepSnapping ?? false,
35
55
  // The wrapper takes the caller's class, so the field fills it.
36
56
  class: "w-full",
37
57
  ui: { ...props.ui, base: ["pe-7", props.ui?.base] },
@@ -40,7 +60,10 @@ const forwardedProps = computed(() => {
40
60
  </script>
41
61
 
42
62
  <template>
43
- <div class="relative inline-flex" :class="props.class">
63
+ <div
64
+ class="relative inline-flex"
65
+ :class="[props.class, isCompact && 'sm:max-w-44']"
66
+ >
44
67
  <UInputNumber
45
68
  v-bind="forwardedProps"
46
69
  @update:model-value="displayValue = $event"
@@ -1,6 +1,7 @@
1
1
  <script setup lang="ts">
2
2
  import { pageRequestUrl } from "../../../build/composables/page/pageUrlValues";
3
3
  import { useConfirm } from "../../../composables/confirm/useConfirm";
4
+ import { FORM_FIELD_SAVED_KEY } from "../../../composables/form/types/field-saved";
4
5
  import DmsCopyButton from "../../copy/CopyButton.vue";
5
6
 
6
7
  interface InputSecretProps {
@@ -23,6 +24,7 @@ const { t } = useI18n();
23
24
  const toast = useToast();
24
25
  const { confirm } = useConfirm();
25
26
  const { $authFetch } = useAuthFetch();
27
+ const markFieldSaved = inject(FORM_FIELD_SAVED_KEY, null);
26
28
 
27
29
  // v2 .secret: the end of the value stays visible, so a reader can tell two
28
30
  // secrets apart without revealing either.
@@ -56,6 +58,9 @@ async function rotate(): Promise<void> {
56
58
  method: "POST",
57
59
  });
58
60
  model.value = response.value;
61
+ // The server stored the new secret already: it is not a change to
62
+ // save, and "Discard" must not bring the old one back.
63
+ if (props.id) markFieldSaved?.(props.id, response.value);
59
64
  },
60
65
  });
61
66
  if (confirmed) {
@@ -7,12 +7,23 @@ import type {
7
7
  import { computed } from "vue";
8
8
  import { useForwardPropsEmits } from "reka-ui";
9
9
  import { characterCountText } from "../../../build/utils/characterCount";
10
+ import {
11
+ type InputWidth,
12
+ isCompactTextInput,
13
+ } from "../../../build/utils/inputWidth";
10
14
 
11
15
  interface InputTextProps extends InputProps {
12
16
  /** Longest value accepted; the counter reads against it. */
13
17
  maxLength?: number;
14
18
  /** Shows the characters typed at the end of the field ("4 / 60"). */
15
19
  showCount?: boolean;
20
+ /**
21
+ * `"compact"` sizes the field for a short text from `sm` up, `"full"`
22
+ * fills the row; left out, a `maxLength` of 16 or less makes it compact.
23
+ */
24
+ width?: InputWidth;
25
+ /** How the value reads shown, not edited (a URL's image): not the input's. */
26
+ preview?: "avatar" | "image";
16
27
  }
17
28
 
18
29
  const props = defineProps<InputTextProps>();
@@ -21,16 +32,22 @@ defineSlots<InputSlots>();
21
32
 
22
33
  const forwarded = useForwardPropsEmits(props, emits);
23
34
  const inputProps = computed(() => {
24
- const { showCount: _showCount, ...rest } = forwarded.value;
35
+ const {
36
+ showCount: _showCount,
37
+ width: _width,
38
+ preview: _preview,
39
+ ...rest
40
+ } = forwarded.value;
25
41
  return rest;
26
42
  });
43
+ const isCompact = computed(() => isCompactTextInput(props));
27
44
  const countText = computed(() =>
28
45
  characterCountText(props.modelValue, props.maxLength),
29
46
  );
30
47
  </script>
31
48
 
32
49
  <template>
33
- <UInput v-bind="inputProps">
50
+ <UInput v-bind="inputProps" :class="isCompact && 'sm:max-w-44'">
34
51
  <template v-if="props.showCount" #trailing>
35
52
  <span class="text-dimmed text-xs tabular-nums" data-character-count>
36
53
  {{ countText }}
@@ -10,6 +10,7 @@ interface InputTimeProps extends Omit<InputProps, "modelValue" | "type"> {
10
10
 
11
11
  const props = defineProps<InputTimeProps>();
12
12
  const { report } = useControlError();
13
+ const { locale } = useI18n();
13
14
  const UNREADABLE_DURATION = "$dms.field_errors.invalid_duration";
14
15
  const emits = defineEmits<{
15
16
  "update:modelValue": [value: number | null];
@@ -21,7 +22,7 @@ const isUserTyping = ref(false);
21
22
  const updateDisplayValue = () => {
22
23
  if (isUserTyping.value) return;
23
24
  if (props.modelValue !== undefined && props.modelValue !== null) {
24
- displayValue.value = formatTimeSpan(props.modelValue);
25
+ displayValue.value = formatDuration(props.modelValue, locale.value);
25
26
  } else {
26
27
  displayValue.value = "";
27
28
  }