@antelopejs/dms 0.9.7 → 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 (414) hide show
  1. package/CHANGELOG.md +114 -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 -45
  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/realtime.d.ts +13 -1
  117. package/dist/routes/realtime.js +114 -29
  118. package/dist/routes/realtime.js.map +1 -1
  119. package/dist/startup-config.d.ts +2 -0
  120. package/dist/startup-config.js +62 -0
  121. package/dist/startup-config.js.map +1 -0
  122. package/dist/store/interfaces.d.ts +3 -2
  123. package/dist/store/interfaces.js +16 -6
  124. package/dist/store/interfaces.js.map +1 -1
  125. package/dist/store/listing.js +24 -13
  126. package/dist/store/listing.js.map +1 -1
  127. package/dist/store/operations.js +4 -0
  128. package/dist/store/operations.js.map +1 -1
  129. package/dist/store/requirements.js +3 -2
  130. package/dist/store/requirements.js.map +1 -1
  131. package/dist/store/runtime.d.ts +10 -1
  132. package/dist/store/runtime.js +33 -6
  133. package/dist/store/runtime.js.map +1 -1
  134. package/dist/store/types.d.ts +10 -0
  135. package/dist/validation/auth.schema.d.ts +2 -2
  136. package/dist/validation/member-invite.schema.d.ts +2 -10
  137. package/dist/validation/member-invite.schema.js +2 -15
  138. package/dist/validation/member-invite.schema.js.map +1 -1
  139. package/frontend-vue/dms.frontend.ts +24 -5
  140. package/frontend-vue/dms.server.ts +17 -0
  141. package/frontend-vue/layers/dms-auth/server/accounts.ts +3 -4
  142. package/frontend-vue/layers/dms-core/app/build/composables/renderNow.ts +34 -0
  143. package/frontend-vue/layers/dms-core/app/build/composables/user/tablePreferences.ts +5 -1
  144. package/frontend-vue/layers/dms-core/app/build/utils/crossTab.ts +199 -0
  145. package/frontend-vue/layers/dms-core/app/build/utils/sharedRealtimeConnection.ts +410 -0
  146. package/frontend-vue/layers/dms-core/app/composables/auth/useApiData.ts +77 -12
  147. package/frontend-vue/layers/dms-core/app/composables/data-types/useDataType.ts +26 -0
  148. package/frontend-vue/layers/dms-core/app/composables/hydration/isHydratingComponent.ts +29 -0
  149. package/frontend-vue/layers/dms-core/app/composables/live/livePauseSource.ts +29 -0
  150. package/frontend-vue/layers/dms-core/app/composables/period/compareResolvers.ts +150 -9
  151. package/frontend-vue/layers/dms-core/app/composables/period/usePeriod.ts +6 -4
  152. package/frontend-vue/layers/dms-core/app/composables/period/usePeriodScope.ts +27 -1
  153. package/frontend-vue/layers/dms-core/app/composables/realtime/useUserRealtime.ts +256 -119
  154. package/frontend-vue/layers/dms-core/app/composables/translation/useComposedText.ts +21 -8
  155. package/frontend-vue/layers/dms-core/app/composables/translation/useTranslation.ts +22 -5
  156. package/frontend-vue/layers/dms-core/app/plugins/dev-error-log.ts +16 -0
  157. package/frontend-vue/layers/dms-core/app/types/user.ts +6 -0
  158. package/frontend-vue/layers/dms-core/app/utils/composedText.ts +7 -2
  159. package/frontend-vue/layers/dms-core/app/utils/formatter.ts +166 -35
  160. package/frontend-vue/layers/dms-core/app/utils/url-interpolation.ts +18 -1
  161. package/frontend-vue/layers/dms-core/i18n/locales/core-en-GB.json +134 -2
  162. package/frontend-vue/layers/dms-core/i18n/locales/core-fr-FR.json +134 -2
  163. package/frontend-vue/layers/dms-layout/app/build/components/layout/DashboardBanners.vue +3 -2
  164. package/frontend-vue/layers/dms-layout/app/build/components/layout/DashboardHeader.vue +41 -21
  165. package/frontend-vue/layers/dms-layout/app/build/components/layout/DashboardPageBody.vue +9 -0
  166. package/frontend-vue/layers/dms-layout/app/build/components/layout/DashboardSidebar.vue +4 -19
  167. package/frontend-vue/layers/dms-layout/app/build/components/layout/Footer.vue +11 -3
  168. package/frontend-vue/layers/dms-layout/app/build/components/layout/GithubStarPrompt.vue +18 -7
  169. package/frontend-vue/layers/dms-layout/app/build/components/layout/PageHeaderActionBar.vue +8 -0
  170. package/frontend-vue/layers/dms-layout/app/build/components/layout/PageHeaderActionsOutlet.vue +14 -0
  171. package/frontend-vue/layers/dms-layout/app/build/components/layout/RowSidePanel.vue +43 -82
  172. package/frontend-vue/layers/dms-layout/app/build/components/layout/SidebarUserMenu.vue +44 -3
  173. package/frontend-vue/layers/dms-layout/app/build/components/layout/UserIdentity.vue +11 -3
  174. package/frontend-vue/layers/dms-layout/app/build/components/pages/modules/ModuleCatalogTile.vue +132 -35
  175. package/frontend-vue/layers/dms-layout/app/build/components/pages/modules/ModuleManageMenu.vue +59 -0
  176. package/frontend-vue/layers/dms-layout/app/build/components/pages/modules/ModuleSourceLabel.vue +25 -0
  177. package/frontend-vue/layers/dms-layout/app/build/components/pages/modules/ModuleStoreBanners.vue +73 -0
  178. package/frontend-vue/layers/dms-layout/app/build/components/pages/modules/ModuleStoreOperation.vue +116 -0
  179. package/frontend-vue/layers/dms-layout/app/build/components/pages/modules/ModuleStoreRequirements.vue +8 -3
  180. package/frontend-vue/layers/dms-layout/app/build/components/pages/modules/ModuleStoreTile.vue +85 -207
  181. package/frontend-vue/layers/dms-layout/app/build/components/pages/modules/ModuleTile.vue +10 -3
  182. package/frontend-vue/layers/dms-layout/app/build/components/pages/modules/ModuleTileSkeleton.vue +68 -0
  183. package/frontend-vue/layers/dms-layout/app/build/components/pages/settings/notification/NotificationInboxDisplay.vue +24 -8
  184. package/frontend-vue/layers/dms-layout/app/build/components/pages/settings/notification/NotificationInboxItem.vue +8 -5
  185. package/frontend-vue/layers/dms-layout/app/build/components/pages/settings/region/RegionTimeZoneInput.vue +1 -0
  186. package/frontend-vue/layers/dms-layout/app/build/components/pages/settings/roles/role-permissions.ts +19 -0
  187. package/frontend-vue/layers/dms-layout/app/build/components/pages/settings/roles/useRoleEditor.ts +2 -1
  188. package/frontend-vue/layers/dms-layout/app/build/composables/layout/useSidePanelWidth.ts +31 -70
  189. package/frontend-vue/layers/dms-layout/app/build/composables/notification/useNotificationGroupsOpen.ts +11 -1
  190. package/frontend-vue/layers/dms-layout/app/build/utils/dev-reload-stream.ts +81 -0
  191. package/frontend-vue/layers/dms-layout/app/build/utils/module-store-catalog.ts +232 -36
  192. package/frontend-vue/layers/dms-layout/app/build/utils/modules-catalog.ts +122 -14
  193. package/frontend-vue/layers/dms-layout/app/composables/layout/useLayoutBanners.ts +32 -3
  194. package/frontend-vue/layers/dms-layout/app/composables/layout/usePageRecord.ts +50 -0
  195. package/frontend-vue/layers/dms-layout/app/composables/layout/useServedHeaderActions.ts +25 -7
  196. package/frontend-vue/layers/dms-layout/app/composables/page/useModuleHistory.ts +3 -2
  197. package/frontend-vue/layers/dms-layout/app/composables/page/useModuleStore.ts +51 -4
  198. package/frontend-vue/layers/dms-layout/app/composables/page/useModuleStoreActions.ts +194 -0
  199. package/frontend-vue/layers/dms-layout/app/composables/page/usePageComponentPreload.ts +23 -3
  200. package/frontend-vue/layers/dms-layout/app/composables/page/usePageLayout.ts +4 -2
  201. package/frontend-vue/layers/dms-layout/app/composables/page/useSiteLayout.ts +6 -1
  202. package/frontend-vue/layers/dms-layout/app/custom-layouts/DefaultLayout.vue +9 -0
  203. package/frontend-vue/layers/dms-layout/app/custom-layouts/SettingsLayout.vue +9 -0
  204. package/frontend-vue/layers/dms-layout/app/custom-pages/modules-store.vue +291 -0
  205. package/frontend-vue/layers/dms-layout/app/custom-pages/modules.vue +87 -474
  206. package/frontend-vue/layers/dms-layout/app/middleware/module-routing.global.ts +3 -0
  207. package/frontend-vue/layers/dms-layout/app/pages/[...slug].vue +6 -22
  208. package/frontend-vue/layers/dms-layout/app/plugins/command-palette-navigation.client.ts +2 -1
  209. package/frontend-vue/layers/dms-layout/app/plugins/command-palette-personal-pages.client.ts +14 -44
  210. package/frontend-vue/layers/dms-layout/app/plugins/dms-dev-reload.client.ts +14 -9
  211. package/frontend-vue/layers/dms-layout/app/theme/form-controls.ts +9 -4
  212. package/frontend-vue/layers/dms-layout/app/theme/surfaces.ts +22 -6
  213. package/frontend-vue/layers/dms-layout/app/types/module-store.ts +9 -0
  214. package/frontend-vue/layers/dms-layout/app/types/page.ts +15 -1
  215. package/frontend-vue/layers/dms-layout/app/utils/account-menu.ts +11 -0
  216. package/frontend-vue/layers/dms-layout/app/utils/breadcrumb.ts +57 -0
  217. package/frontend-vue/layers/dms-layout/app/utils/pageQuery.ts +26 -0
  218. package/frontend-vue/layers/dms-layout/app/utils/pageRecord.ts +71 -0
  219. package/frontend-vue/layers/dms-layout/i18n/locales/layout-en-GB.json +39 -14
  220. package/frontend-vue/layers/dms-layout/i18n/locales/layout-fr-FR.json +38 -13
  221. package/frontend-vue/layers/dms-ui/app/build/components/containers/TargetComponentTree.vue +31 -0
  222. package/frontend-vue/layers/dms-ui/app/build/components/containers/constants.ts +25 -0
  223. package/frontend-vue/layers/dms-ui/app/build/components/containers/drawer/DynamicDrawer.vue +244 -15
  224. package/frontend-vue/layers/dms-ui/app/build/components/containers/modal/DynamicModal.vue +42 -25
  225. package/frontend-vue/layers/dms-ui/app/build/components/containers/row/RowHeader.vue +153 -0
  226. package/frontend-vue/layers/dms-ui/app/build/components/containers/row/RowNotFound.vue +44 -0
  227. package/frontend-vue/layers/dms-ui/app/build/components/containers/row/drawerRowHeader.ts +35 -0
  228. package/frontend-vue/layers/dms-ui/app/build/components/form/FormEntries.vue +44 -9
  229. package/frontend-vue/layers/dms-ui/app/build/components/form/FormErrorSummary.vue +11 -4
  230. package/frontend-vue/layers/dms-ui/app/build/components/form/FormFieldControl.vue +38 -5
  231. package/frontend-vue/layers/dms-ui/app/build/components/form/FormFieldNotes.vue +29 -5
  232. package/frontend-vue/layers/dms-ui/app/build/components/form/FormSectionNav.vue +3 -1
  233. package/frontend-vue/layers/dms-ui/app/build/components/form/FormSections.vue +106 -27
  234. package/frontend-vue/layers/dms-ui/app/build/components/table/Actions.vue +12 -4
  235. package/frontend-vue/layers/dms-ui/app/build/components/table/Empty.vue +4 -2
  236. package/frontend-vue/layers/dms-ui/app/build/components/table/FiltersRow.vue +38 -1
  237. package/frontend-vue/layers/dms-ui/app/build/components/table/Pagination.vue +55 -54
  238. package/frontend-vue/layers/dms-ui/app/build/components/table/RowSelection.vue +2 -1
  239. package/frontend-vue/layers/dms-ui/app/build/components/table/Table.vue +396 -288
  240. package/frontend-vue/layers/dms-ui/app/build/components/table/Tabs.vue +2 -1
  241. package/frontend-vue/layers/dms-ui/app/build/components/table/Views.vue +2 -1
  242. package/frontend-vue/layers/dms-ui/app/build/components/table-view/CardAvatar.vue +59 -0
  243. package/frontend-vue/layers/dms-ui/app/build/components/table-view/CardGridSkeleton.vue +19 -2
  244. package/frontend-vue/layers/dms-ui/app/build/components/table-view/CardRowActions.vue +38 -0
  245. package/frontend-vue/layers/dms-ui/app/build/components/table-view/CardsDisplay.vue +148 -104
  246. package/frontend-vue/layers/dms-ui/app/build/components/table-view/LiveHoldBanner.vue +17 -2
  247. package/frontend-vue/layers/dms-ui/app/build/composables/actions/bulkSelection.ts +43 -9
  248. package/frontend-vue/layers/dms-ui/app/build/composables/actions/rowComponentOptions.ts +76 -0
  249. package/frontend-vue/layers/dms-ui/app/build/composables/actions/rowNavigation.ts +172 -27
  250. package/frontend-vue/layers/dms-ui/app/build/composables/actions/useActionTargets.ts +270 -46
  251. package/frontend-vue/layers/dms-ui/app/build/composables/confirm/confirmDialogTexts.ts +2 -0
  252. package/frontend-vue/layers/dms-ui/app/build/composables/containers/closingLayers.ts +186 -0
  253. package/frontend-vue/layers/dms-ui/app/build/composables/containers/context.ts +14 -0
  254. package/frontend-vue/layers/dms-ui/app/build/composables/containers/drawerSize.ts +229 -0
  255. package/frontend-vue/layers/dms-ui/app/build/composables/containers/useResizableSize.ts +175 -0
  256. package/frontend-vue/layers/dms-ui/app/build/composables/data-types/metricCells.ts +18 -35
  257. package/frontend-vue/layers/dms-ui/app/build/composables/data-types/numberSuffix.ts +47 -0
  258. package/frontend-vue/layers/dms-ui/app/build/composables/data-types/registerDefaults.ts +99 -24
  259. package/frontend-vue/layers/dms-ui/app/build/composables/data-types/registerFieldTypes.ts +2 -1
  260. package/frontend-vue/layers/dms-ui/app/build/composables/data-types/relationFilter.ts +75 -0
  261. package/frontend-vue/layers/dms-ui/app/build/composables/data-types/relationRows.ts +71 -0
  262. package/frontend-vue/layers/dms-ui/app/build/composables/data-types/relationValue.ts +39 -0
  263. package/frontend-vue/layers/dms-ui/app/build/composables/data-types/twoLineCell.ts +3 -3
  264. package/frontend-vue/layers/dms-ui/app/build/composables/data-types/useColumnValueRenderer.ts +6 -2
  265. package/frontend-vue/layers/dms-ui/app/build/composables/form/createFormFields.ts +15 -0
  266. package/frontend-vue/layers/dms-ui/app/build/composables/form/fieldSaved.ts +40 -0
  267. package/frontend-vue/layers/dms-ui/app/build/composables/form/fieldValueRule.ts +62 -0
  268. package/frontend-vue/layers/dms-ui/app/build/composables/form/formEntryContext.ts +5 -0
  269. package/frontend-vue/layers/dms-ui/app/build/composables/form/formFooter.ts +42 -7
  270. package/frontend-vue/layers/dms-ui/app/build/composables/form/formLayout.ts +106 -4
  271. package/frontend-vue/layers/dms-ui/app/build/composables/form/formSections.ts +32 -0
  272. package/frontend-vue/layers/dms-ui/app/build/composables/form/readonlyValue.ts +19 -0
  273. package/frontend-vue/layers/dms-ui/app/build/composables/form/registerFormFunctions.ts +27 -0
  274. package/frontend-vue/layers/dms-ui/app/build/composables/form/repeaterTable.ts +65 -0
  275. package/frontend-vue/layers/dms-ui/app/build/composables/form/serverFieldErrors.ts +49 -0
  276. package/frontend-vue/layers/dms-ui/app/build/composables/form/toasterClearance.ts +118 -0
  277. package/frontend-vue/layers/dms-ui/app/build/composables/form/useInstantForm.ts +12 -1
  278. package/frontend-vue/layers/dms-ui/app/build/composables/live/currentPageLive.ts +41 -3
  279. package/frontend-vue/layers/dms-ui/app/build/composables/live/livePoller.ts +10 -2
  280. package/frontend-vue/layers/dms-ui/app/build/composables/live/pageReadClock.ts +28 -0
  281. package/frontend-vue/layers/dms-ui/app/build/composables/live/shortcuts.ts +1 -1
  282. package/frontend-vue/layers/dms-ui/app/build/composables/live/usePageLiveHost.ts +17 -3
  283. package/frontend-vue/layers/dms-ui/app/build/composables/live/useUpdatedLabel.ts +38 -0
  284. package/frontend-vue/layers/dms-ui/app/build/composables/page-toolbar/pageToolbarContext.ts +75 -0
  285. package/frontend-vue/layers/dms-ui/app/build/composables/page-toolbar/toolbarControlHeight.ts +29 -0
  286. package/frontend-vue/layers/dms-ui/app/build/composables/period/periodComparison.ts +52 -0
  287. package/frontend-vue/layers/dms-ui/app/build/composables/period/periodDisplay.ts +21 -0
  288. package/frontend-vue/layers/dms-ui/app/build/composables/period/periodShortLabels.ts +28 -0
  289. package/frontend-vue/layers/dms-ui/app/build/composables/period/usePeriodDraft.ts +1 -0
  290. package/frontend-vue/layers/dms-ui/app/build/composables/table/useRelationFilterLabels.ts +73 -0
  291. package/frontend-vue/layers/dms-ui/app/build/composables/table/useRowScrollAnchor.ts +106 -0
  292. package/frontend-vue/layers/dms-ui/app/build/composables/table/useTable.ts +9 -0
  293. package/frontend-vue/layers/dms-ui/app/build/composables/table/useTableColumns.ts +1 -2
  294. package/frontend-vue/layers/dms-ui/app/build/composables/table/utils/archivedCount.ts +31 -0
  295. package/frontend-vue/layers/dms-ui/app/build/composables/table/utils/filterEditorValue.ts +38 -0
  296. package/frontend-vue/layers/dms-ui/app/build/composables/table/utils/formatFilterValue.ts +33 -2
  297. package/frontend-vue/layers/dms-ui/app/build/composables/table/utils/scrollEdges.ts +31 -0
  298. package/frontend-vue/layers/dms-ui/app/build/composables/table-view/useCardFields.ts +33 -0
  299. package/frontend-vue/layers/dms-ui/app/build/composables/table-view/useMobileDisplay.ts +48 -0
  300. package/frontend-vue/layers/dms-ui/app/build/composables/table-view/useScrolledPastTop.ts +41 -18
  301. package/frontend-vue/layers/dms-ui/app/build/composables/table-view/useTableFooter.ts +3 -2
  302. package/frontend-vue/layers/dms-ui/app/build/composables/table-view/useTableLinkedVisit.ts +78 -0
  303. package/frontend-vue/layers/dms-ui/app/build/composables/table-view/useTableLiveHold.ts +135 -22
  304. package/frontend-vue/layers/dms-ui/app/build/composables/table-view/useTableRows.ts +56 -25
  305. package/frontend-vue/layers/dms-ui/app/build/composables/table-view/useTableViewRowActions.ts +77 -32
  306. package/frontend-vue/layers/dms-ui/app/build/composables/table-view/useTableViews.ts +86 -10
  307. package/frontend-vue/layers/dms-ui/app/build/composables/table-view/utils/bulkActions.ts +14 -4
  308. package/frontend-vue/layers/dms-ui/app/build/composables/table-view/utils/card.ts +127 -2
  309. package/frontend-vue/layers/dms-ui/app/build/composables/table-view/utils/compareValues.ts +13 -0
  310. package/frontend-vue/layers/dms-ui/app/build/composables/table-view/utils/expandedRows.ts +28 -0
  311. package/frontend-vue/layers/dms-ui/app/build/composables/table-view/utils/groupedRows.ts +114 -1
  312. package/frontend-vue/layers/dms-ui/app/build/composables/table-view/utils/linkedArrival.ts +308 -0
  313. package/frontend-vue/layers/dms-ui/app/build/composables/table-view/utils/locateRow.ts +106 -0
  314. package/frontend-vue/layers/dms-ui/app/build/composables/table-view/utils/pageArrival.ts +34 -0
  315. package/frontend-vue/layers/dms-ui/app/build/composables/table-view/utils/pinnedRows.ts +17 -0
  316. package/frontend-vue/layers/dms-ui/app/build/composables/table-view/utils/quickFilters.ts +41 -33
  317. package/frontend-vue/layers/dms-ui/app/build/composables/table-view/utils/recordLink.ts +24 -8
  318. package/frontend-vue/layers/dms-ui/app/build/composables/table-view/utils/tableCounts.ts +113 -0
  319. package/frontend-vue/layers/dms-ui/app/build/composables/table-view/utils/tableQuery.ts +27 -4
  320. package/frontend-vue/layers/dms-ui/app/build/composables/table-view/utils/views.ts +22 -6
  321. package/frontend-vue/layers/dms-ui/app/build/utils/addressSuggestions.ts +49 -0
  322. package/frontend-vue/layers/dms-ui/app/build/utils/eyebrow.ts +12 -0
  323. package/frontend-vue/layers/dms-ui/app/build/utils/fieldOptionsI18n.ts +51 -11
  324. package/frontend-vue/layers/dms-ui/app/build/utils/inputWidth.ts +53 -0
  325. package/frontend-vue/layers/dms-ui/app/build/utils/numberAdjustment.ts +6 -3
  326. package/frontend-vue/layers/dms-ui/app/build/utils/relativeDate.ts +19 -5
  327. package/frontend-vue/layers/dms-ui/app/build/utils/scrollWithin.ts +99 -0
  328. package/frontend-vue/layers/dms-ui/app/build/utils/urlVariables.ts +36 -14
  329. package/frontend-vue/layers/dms-ui/app/components/PasswordStrength.vue +1 -1
  330. package/frontend-vue/layers/dms-ui/app/components/RecursiveComponent.vue +9 -1
  331. package/frontend-vue/layers/dms-ui/app/components/blocks/LiveToggleBlock.vue +80 -32
  332. package/frontend-vue/layers/dms-ui/app/components/blocks/PageToolbarBlock.vue +137 -0
  333. package/frontend-vue/layers/dms-ui/app/components/blocks/StatGroupBlock.vue +5 -0
  334. package/frontend-vue/layers/dms-ui/app/components/chart/ApexChartHost.vue +16 -2
  335. package/frontend-vue/layers/dms-ui/app/components/chart/Chart.vue +24 -5
  336. package/frontend-vue/layers/dms-ui/app/components/chart/ChartCard.vue +41 -23
  337. package/frontend-vue/layers/dms-ui/app/components/confirm/ConfirmModal.vue +1 -1
  338. package/frontend-vue/layers/dms-ui/app/components/container-footer/ContainerFooter.vue +34 -0
  339. package/frontend-vue/layers/dms-ui/app/components/field-row/FieldRow.vue +25 -2
  340. package/frontend-vue/layers/dms-ui/app/components/flow-canvas/FlowCanvas.vue +2 -2
  341. package/frontend-vue/layers/dms-ui/app/components/form/Form.vue +118 -36
  342. package/frontend-vue/layers/dms-ui/app/components/form/components/DatePicker.vue +20 -1
  343. package/frontend-vue/layers/dms-ui/app/components/form/components/Display.vue +13 -1
  344. package/frontend-vue/layers/dms-ui/app/components/form/components/Image.vue +8 -3
  345. package/frontend-vue/layers/dms-ui/app/components/form/components/InputAddress.vue +53 -5
  346. package/frontend-vue/layers/dms-ui/app/components/form/components/InputCode.vue +29 -5
  347. package/frontend-vue/layers/dms-ui/app/components/form/components/InputNumber.vue +45 -8
  348. package/frontend-vue/layers/dms-ui/app/components/form/components/InputPercentage.vue +28 -5
  349. package/frontend-vue/layers/dms-ui/app/components/form/components/InputSecret.vue +5 -0
  350. package/frontend-vue/layers/dms-ui/app/components/form/components/InputText.vue +19 -2
  351. package/frontend-vue/layers/dms-ui/app/components/form/components/InputTime.vue +2 -1
  352. package/frontend-vue/layers/dms-ui/app/components/form/components/Relation.vue +205 -65
  353. package/frontend-vue/layers/dms-ui/app/components/form/components/Repeater.vue +80 -30
  354. package/frontend-vue/layers/dms-ui/app/components/form/components/RepeaterTable.vue +203 -0
  355. package/frontend-vue/layers/dms-ui/app/components/form/components/Select.vue +4 -2
  356. package/frontend-vue/layers/dms-ui/app/components/grid/GridRow.vue +11 -2
  357. package/frontend-vue/layers/dms-ui/app/components/key-value-list/KeyValueList.vue +79 -70
  358. package/frontend-vue/layers/dms-ui/app/components/kpi/KpiCard.vue +117 -21
  359. package/frontend-vue/layers/dms-ui/app/components/meter/Meter.vue +2 -1
  360. package/frontend-vue/layers/dms-ui/app/components/period/PeriodSelector.vue +113 -34
  361. package/frontend-vue/layers/dms-ui/app/components/save-bar/SaveBar.vue +14 -2
  362. package/frontend-vue/layers/dms-ui/app/components/section-header/Eyebrow.vue +6 -1
  363. package/frontend-vue/layers/dms-ui/app/components/segmented/Segmented.vue +13 -0
  364. package/frontend-vue/layers/dms-ui/app/components/stat-group/StatGroup.vue +52 -3
  365. package/frontend-vue/layers/dms-ui/app/components/tab/Tab.vue +2 -1
  366. package/frontend-vue/layers/dms-ui/app/components/table-view/KanbanBoard.vue +45 -35
  367. package/frontend-vue/layers/dms-ui/app/components/table-view/KanbanDisplay.vue +4 -1
  368. package/frontend-vue/layers/dms-ui/app/components/table-view/TableView.vue +410 -96
  369. package/frontend-vue/layers/dms-ui/app/components/top-list/TopListCard.vue +33 -5
  370. package/frontend-vue/layers/dms-ui/app/composables/chart/apexCategoryLabels.ts +68 -0
  371. package/frontend-vue/layers/dms-ui/app/composables/chart/apexDatetimeBuckets.ts +306 -0
  372. package/frontend-vue/layers/dms-ui/app/composables/chart/formatValue.ts +4 -3
  373. package/frontend-vue/layers/dms-ui/app/composables/chart/heatmapColors.ts +93 -0
  374. package/frontend-vue/layers/dms-ui/app/composables/chart/localizeSeries.ts +62 -0
  375. package/frontend-vue/layers/dms-ui/app/composables/chart/useApexChart.ts +116 -8
  376. package/frontend-vue/layers/dms-ui/app/composables/chart/useApexChart.types.ts +7 -0
  377. package/frontend-vue/layers/dms-ui/app/composables/containers/types.ts +84 -1
  378. package/frontend-vue/layers/dms-ui/app/composables/containers/useDrawer.ts +69 -8
  379. package/frontend-vue/layers/dms-ui/app/composables/form/types/field-saved.ts +11 -0
  380. package/frontend-vue/layers/dms-ui/app/composables/form/types/field.ts +4 -0
  381. package/frontend-vue/layers/dms-ui/app/composables/form/types/functions.ts +1 -0
  382. package/frontend-vue/layers/dms-ui/app/composables/form/useForm.ts +142 -21
  383. package/frontend-vue/layers/dms-ui/app/composables/live/usePageLive.ts +11 -4
  384. package/frontend-vue/layers/dms-ui/app/composables/page-toolbar/usePageToolbarSize.ts +30 -0
  385. package/frontend-vue/layers/dms-ui/app/composables/table-view/kanban.ts +4 -2
  386. package/frontend-vue/layers/dms-ui/app/composables/table-view/types/action-target.ts +22 -3
  387. package/frontend-vue/layers/dms-ui/app/composables/table-view/types/config.ts +4 -0
  388. package/frontend-vue/layers/dms-ui/app/composables/table-view/types/display.ts +24 -1
  389. package/frontend-vue/layers/dms-ui/app/plugins/closing-layers.client.ts +10 -0
  390. package/frontend-vue/layers/dms-ui/app/plugins/live-pause-source.ts +15 -0
  391. package/frontend-vue/layers/dms-ui/app/plugins/register.ts +2 -0
  392. package/frontend-vue/layers/dms-ui/app/types/input-number.ts +3 -2
  393. package/frontend-vue/layers/dms-ui/app/types/page-toolbar.ts +7 -0
  394. package/frontend-vue/layers/dms-ui/app/types/row-action.ts +0 -2
  395. package/frontend-vue/layers/dms-ui/app/types/row-navigation.ts +17 -0
  396. package/frontend-vue/layers/dms-ui/app/types/table/query.ts +2 -1
  397. package/frontend-vue/layers/dms-ui/app/utils/blockRefresh.ts +3 -1
  398. package/frontend-vue/layers/dms-ui/app/utils/componentTree.ts +24 -0
  399. package/frontend-vue/layers/dms-ui/i18n/locales/ui-en-GB.json +16 -4
  400. package/frontend-vue/layers/dms-ui/i18n/locales/ui-fr-FR.json +16 -4
  401. package/frontend-vue/package.json +2 -2
  402. package/package.json +7 -6
  403. package/skills/dms/SKILL.md +1 -1
  404. package/skills/dms-auth/SKILL.md +5 -3
  405. package/skills/dms-best-practices/REFERENCE.md +2 -0
  406. package/skills/dms-best-practices/SKILL.md +4 -0
  407. package/skills/dms-module/SKILL.md +3 -2
  408. package/skills/dms-pages/REFERENCE.md +125 -16
  409. package/skills/dms-pages/SKILL.md +1 -1
  410. package/skills/dms-project/DEV-SERVERS.md +23 -1
  411. package/skills/dms-project/REFERENCE.md +1 -1
  412. package/skills/dms-project/SKILL.md +4 -1
  413. package/skills/dms-project/scripts/dms-dev.sh +205 -17
  414. package/frontend-vue/layers/dms-core/app/composables/period/periodRenderNow.ts +0 -42
@@ -1,5 +1,5 @@
1
1
  import { readerClock } from "./periodClock";
2
- import type { PeriodComparison, PeriodRange } from "./types";
2
+ import type { PeriodComparison, PeriodPreset, PeriodRange } from "./types";
3
3
 
4
4
  const NON_OVERLAP_GAP_MS = 1;
5
5
 
@@ -30,7 +30,132 @@ function isWholeDayRange(range: PeriodRange): boolean {
30
30
  );
31
31
  }
32
32
 
33
- function shiftPreviousPeriod(range: PeriodRange): PeriodRange {
33
+ const MONTHS_PER_YEAR = 12;
34
+ const MONTHS_PER_QUARTER = 3;
35
+
36
+ // The calendar unit a preset counts in, in months: its previous period is
37
+ // the previous month, quarter or year, not the same number of days before.
38
+ const PRESET_MONTH_SPANS: Partial<Record<PeriodPreset, number>> = {
39
+ "this-month": 1,
40
+ "last-month": 1,
41
+ "this-quarter": MONTHS_PER_QUARTER,
42
+ "last-quarter": MONTHS_PER_QUARTER,
43
+ ytd: MONTHS_PER_YEAR,
44
+ "last-year": MONTHS_PER_YEAR,
45
+ };
46
+
47
+ /** What a comparison is resolved against beyond the range itself. */
48
+ export interface ComparisonContext {
49
+ /** The preset the range comes from: a calendar one compares by calendar. */
50
+ preset?: PeriodPreset;
51
+ /**
52
+ * The instant the range was resolved at: a range running past today
53
+ * (`this-month` on the 18th) compares what has elapsed of it.
54
+ */
55
+ now?: Date;
56
+ }
57
+
58
+ /** `date` moved by whole months, its day kept within the month reached. */
59
+ function shiftMonths(date: Date, months: number): Date {
60
+ const clock = readerClock();
61
+ const wall = clock.wall(date);
62
+ const month = wall.month + months;
63
+ // Day 0 of the next month is the last day of this one.
64
+ const lastDay = clock.wall(
65
+ clock.instant({ ...wall, month: month + 1, day: 0 }),
66
+ ).day;
67
+ return clock.instant({ ...wall, month, day: Math.min(wall.day, lastDay) });
68
+ }
69
+
70
+ /** Whether `date` is the midnight opening a calendar month. */
71
+ function isMonthStart(date: Date): boolean {
72
+ return isLocalMidnight(date) && readerClock().wall(date).day === 1;
73
+ }
74
+
75
+ /** Months from one month start to another. */
76
+ function monthsBetween(from: Date, to: Date): number {
77
+ const clock = readerClock();
78
+ const start = clock.wall(from);
79
+ const end = clock.wall(to);
80
+ return (end.year - start.year) * MONTHS_PER_YEAR + end.month - start.month;
81
+ }
82
+
83
+ /** The instant right after a range: the start of what follows it. */
84
+ const afterRange = (range: PeriodRange): Date =>
85
+ new Date(range.to.getTime() + NON_OVERLAP_GAP_MS);
86
+
87
+ /**
88
+ * The calendar months a range's previous period steps back by: the unit of a
89
+ * calendar preset, else the months of a range made of whole months (a custom
90
+ * September compares to August). Any other range has none.
91
+ */
92
+ function calendarMonthSpan(
93
+ range: PeriodRange,
94
+ preset: PeriodPreset | undefined,
95
+ ): number | undefined {
96
+ if (!isMonthStart(range.from)) return undefined;
97
+ const presetSpan = preset ? PRESET_MONTH_SPANS[preset] : undefined;
98
+ if (presetSpan) return presetSpan;
99
+ const end = afterRange(range);
100
+ return isMonthStart(end) ? monthsBetween(range.from, end) : undefined;
101
+ }
102
+
103
+ /** The last millisecond of `date`'s day. */
104
+ function endOfDay(date: Date): Date {
105
+ const clock = readerClock();
106
+ const nextDay = clock.instant({
107
+ ...clock.wall(date),
108
+ day: clock.wall(date).day + 1,
109
+ hours: 0,
110
+ minutes: 0,
111
+ seconds: 0,
112
+ milliseconds: 0,
113
+ });
114
+ return new Date(nextDay.getTime() - NON_OVERLAP_GAP_MS);
115
+ }
116
+
117
+ /**
118
+ * What a comparison measures of a range: all of it, or what has elapsed of
119
+ * it when it runs past today — the rest holds no data yet, and comparing it
120
+ * with a whole period reads as a fall.
121
+ */
122
+ function elapsedEnd(range: PeriodRange, now: Date | undefined): Date {
123
+ if (!now) return range.to;
124
+ const today = endOfDay(now);
125
+ return range.to.getTime() > today.getTime() ? today : range.to;
126
+ }
127
+
128
+ /**
129
+ * The same span of the calendar `months` earlier: the whole month, quarter
130
+ * or year before when the range is complete and ends with a month, else its
131
+ * elapsed days (the 1st to the 18th of the month before).
132
+ */
133
+ function shiftCalendarPeriod(
134
+ range: PeriodRange,
135
+ months: number,
136
+ end: Date,
137
+ ): PeriodRange {
138
+ const from = shiftMonths(range.from, -months);
139
+ const isComplete = end.getTime() === range.to.getTime();
140
+ if (isComplete && isMonthStart(afterRange(range))) {
141
+ // The span before ends where the range starts: August, then September.
142
+ return { from, to: new Date(range.from.getTime() - NON_OVERLAP_GAP_MS) };
143
+ }
144
+ return { from, to: endOfDay(shiftMonths(end, -months)) };
145
+ }
146
+
147
+ function shiftPreviousPeriod(
148
+ range: PeriodRange,
149
+ context: ComparisonContext,
150
+ ): PeriodRange {
151
+ const months = calendarMonthSpan(range, context.preset);
152
+ if (months) {
153
+ return shiftCalendarPeriod(range, months, elapsedEnd(range, context.now));
154
+ }
155
+ return shiftEqualLength(range);
156
+ }
157
+
158
+ function shiftEqualLength(range: PeriodRange): PeriodRange {
34
159
  // Whole-day ranges move by calendar days, so a span crossing a daylight
35
160
  // saving change still starts at midnight (a fixed-ms shift lands an hour off).
36
161
  if (isWholeDayRange(range)) {
@@ -50,7 +175,14 @@ function shiftPreviousPeriod(range: PeriodRange): PeriodRange {
50
175
  };
51
176
  }
52
177
 
53
- function shiftPreviousYear(range: PeriodRange): PeriodRange {
178
+ function shiftPreviousYear(
179
+ range: PeriodRange,
180
+ context: ComparisonContext,
181
+ ): PeriodRange {
182
+ const end = elapsedEnd(range, context.now);
183
+ if (end.getTime() !== range.to.getTime()) {
184
+ return shiftCalendarPeriod(range, MONTHS_PER_YEAR, end);
185
+ }
54
186
  return {
55
187
  from: shiftCalendar(range.from, 0, -1),
56
188
  to: shiftCalendar(range.to, 0, -1),
@@ -59,7 +191,7 @@ function shiftPreviousYear(range: PeriodRange): PeriodRange {
59
191
 
60
192
  const COMPARISON_RESOLVERS: Record<
61
193
  Exclude<PeriodComparison, "none" | "custom">,
62
- (range: PeriodRange) => PeriodRange
194
+ (range: PeriodRange, context: ComparisonContext) => PeriodRange
63
195
  > = {
64
196
  "previous-period": shiftPreviousPeriod,
65
197
  "previous-year": shiftPreviousYear,
@@ -68,18 +200,27 @@ const COMPARISON_RESOLVERS: Record<
68
200
  /**
69
201
  * Resolves the range a period is compared against.
70
202
  *
71
- * `previous-period` returns the equal-length span immediately before the
72
- * range, offset by a single millisecond so the two never overlap. Ranges of
203
+ * `previous-period` follows the calendar for a calendar range: a month, a
204
+ * quarter or a year (`this-month`, `last-quarter`, `ytd`…, or a custom range
205
+ * of whole months) compares to the one before — September to August, Q3 to
206
+ * Q2. Any other range compares to the equal-length span immediately before
207
+ * it, offset by a single millisecond so the two never overlap; ranges of
73
208
  * whole days are measured in calendar days, so daylight saving changes don't
74
- * move their midnight boundaries. A range with no bounds (`all`) has nothing
75
- * to compare against: `null`.
209
+ * move their midnight boundaries.
210
+ *
211
+ * A range running past today (`this-month` on the 18th) compares what has
212
+ * elapsed of it — the 1st to the 18th of the month before, or of the year
213
+ * before with `previous-year` — not a whole period against days that hold no
214
+ * data yet. A range with no bounds (`all`) has nothing to compare against:
215
+ * `null`.
76
216
  */
77
217
  export function resolveComparisonRange(
78
218
  comparison: PeriodComparison,
79
219
  range: PeriodRange | null,
80
220
  customRange: PeriodRange | null,
221
+ context: ComparisonContext = {},
81
222
  ): PeriodRange | null {
82
223
  if (comparison === "none" || !range) return null;
83
224
  if (comparison === "custom") return customRange;
84
- return COMPARISON_RESOLVERS[comparison](range);
225
+ return COMPARISON_RESOLVERS[comparison](range, context);
85
226
  }
@@ -25,7 +25,7 @@ import {
25
25
  resolvePresetRange,
26
26
  } from "./presetResolvers";
27
27
  import { resolveComparisonRange } from "./compareResolvers";
28
- import { periodRenderNow } from "./periodRenderNow";
28
+ import { serverRenderNow } from "../../build/composables/renderNow";
29
29
 
30
30
  export interface UsePeriodOptions {
31
31
  defaultPreset?: PeriodPreset;
@@ -52,7 +52,7 @@ export interface UsePeriodReturn {
52
52
  state: ComputedRef<PeriodState>;
53
53
  /**
54
54
  * The instant `state` was resolved from: what a label relative to now
55
- * reads, so it holds still with the period (see `periodRenderNow`).
55
+ * reads, so it holds still with the period (see `serverRenderNow`).
56
56
  */
57
57
  resolvedAt: ComputedRef<Date>;
58
58
  setPreset: (preset: PeriodPreset) => void;
@@ -150,6 +150,7 @@ function buildState(refs: PeriodRefs, now: Date): PeriodState {
150
150
  refs.comparison.value,
151
151
  range,
152
152
  refs.customCompareRange.value,
153
+ { preset: refs.preset.value, now },
153
154
  );
154
155
  const partial = {
155
156
  preset: refs.preset.value,
@@ -184,7 +185,7 @@ function makeSetters(refs: PeriodRefs) {
184
185
  * comparisons and custom ranges resolved into a publishable `state`.
185
186
  *
186
187
  * A server render and the browser hydrating it resolve from the same instant
187
- * (`periodRenderNow`), so both render the same bounds.
188
+ * (`serverRenderNow`), so both render the same bounds.
188
189
  *
189
190
  * Relative presets (`last-hour`, `last-24h`) re-resolve every minute, and
190
191
  * calendar presets (`today`, `last-7-days`, `this-month`...) at each local
@@ -214,7 +215,8 @@ export function usePeriod(options: UsePeriodOptions = {}): UsePeriodReturn {
214
215
  // The server render's instant, until the clock ticks or the period changes
215
216
  // once on screen: what the setup applies (the URL's period) the server
216
217
  // applied as well.
217
- const renderNow = shallowRef(periodRenderNow());
218
+ const serverNow = serverRenderNow();
219
+ const renderNow = shallowRef(serverNow === null ? null : new Date(serverNow));
218
220
  if (renderNow.value) {
219
221
  onMounted(() => {
220
222
  watch(
@@ -88,7 +88,7 @@ function readPeriodScope(
88
88
  * first render must match the HTML. It also answers `null` for a period the
89
89
  * browser could resolve to other bounds: before the browser's cookie names
90
90
  * its time zone. A relative preset resolves from the instant the server
91
- * hands the browser (`periodRenderNow`), so both read the same bounds.
91
+ * hands the browser (`serverRenderNow`), so both read the same bounds.
92
92
  */
93
93
  export function usePeriodScope(
94
94
  id: string | undefined,
@@ -144,3 +144,29 @@ export function appendPeriodToUrl(
144
144
  const separator = url.includes("?") ? "&" : "?";
145
145
  return `${url}${separator}${params.toString()}`;
146
146
  }
147
+
148
+ /**
149
+ * The comparison a period scope applies, `null` while no selector registers
150
+ * it: `none` too when the selected comparison resolves to no window (every
151
+ * period, `all`, has nothing to compare against), so a consumer hides its
152
+ * comparison exactly when the request carries no `compareFrom` /
153
+ * `compareTo`. A server render reads it once, as the caller sets up, like
154
+ * `usePeriodScopePreset`: the mode is a name, the same on both sides.
155
+ */
156
+ export function usePeriodScopeComparison(
157
+ id: string | undefined,
158
+ ): ComputedRef<PeriodState["comparison"] | null> {
159
+ if (!id) return computed(() => null);
160
+ const registry = usePeriodScopeRegistry();
161
+ if (typeof window !== "undefined")
162
+ return computed(() => effectiveComparison(readPeriodScope(registry, id)));
163
+ const comparison = effectiveComparison(readPeriodScope(registry, id));
164
+ return computed(() => comparison);
165
+ }
166
+
167
+ function effectiveComparison(
168
+ state: PeriodState | null,
169
+ ): PeriodState["comparison"] | null {
170
+ if (!state) return null;
171
+ return state.compareRange ? state.comparison : "none";
172
+ }