@antelopejs/dms 0.9.8 → 0.11.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (451) hide show
  1. package/CHANGELOG.md +171 -0
  2. package/README.md +1 -1
  3. package/data/module-store/catalog.json +2 -2
  4. package/dist/attachments/table-view.js +2 -2
  5. package/dist/attachments/table-view.js.map +1 -1
  6. package/dist/automation/actions.d.ts +2 -0
  7. package/dist/automation/actions.js +116 -71
  8. package/dist/automation/actions.js.map +1 -1
  9. package/dist/automation/i18n.d.ts +4 -0
  10. package/dist/automation/i18n.js +19 -0
  11. package/dist/automation/i18n.js.map +1 -0
  12. package/dist/automation/send-notification.d.ts +21 -0
  13. package/dist/automation/send-notification.js +163 -0
  14. package/dist/automation/send-notification.js.map +1 -0
  15. package/dist/automation/triggers.js +19 -25
  16. package/dist/automation/triggers.js.map +1 -1
  17. package/dist/client-origin-cors.d.ts +1 -0
  18. package/dist/client-origin-cors.js +19 -0
  19. package/dist/client-origin-cors.js.map +1 -0
  20. package/dist/config.d.ts +3 -2
  21. package/dist/config.js +5 -7
  22. package/dist/config.js.map +1 -1
  23. package/dist/frontend-module.d.ts +4 -0
  24. package/dist/frontend-module.js +37 -0
  25. package/dist/frontend-module.js.map +1 -0
  26. package/dist/implementations/dms/client-ip.js +1 -1
  27. package/dist/implementations/dms/client-ip.js.map +1 -1
  28. package/dist/implementations/dms/dev-reload.d.ts +5 -0
  29. package/dist/implementations/dms/dev-reload.js +23 -3
  30. package/dist/implementations/dms/dev-reload.js.map +1 -1
  31. package/dist/implementations/dms/frontend-modules.d.ts +2 -4
  32. package/dist/implementations/dms/frontend-modules.js +38 -94
  33. package/dist/implementations/dms/frontend-modules.js.map +1 -1
  34. package/dist/implementations/dms/frontend-ready.d.ts +12 -2
  35. package/dist/implementations/dms/frontend-ready.js +34 -4
  36. package/dist/implementations/dms/frontend-ready.js.map +1 -1
  37. package/dist/implementations/dms/layout-banners.d.ts +2 -1
  38. package/dist/implementations/dms/layout-banners.js +9 -0
  39. package/dist/implementations/dms/layout-banners.js.map +1 -1
  40. package/dist/implementations/dms/manifest.d.ts +7 -2
  41. package/dist/implementations/dms/manifest.js +12 -7
  42. package/dist/implementations/dms/manifest.js.map +1 -1
  43. package/dist/implementations/dms/page.d.ts +4 -3
  44. package/dist/implementations/dms/page.js +49 -18
  45. package/dist/implementations/dms/page.js.map +1 -1
  46. package/dist/implementations/dms/permissions-resolver.d.ts +2 -2
  47. package/dist/implementations/dms/permissions-resolver.js +2 -2
  48. package/dist/implementations/dms/permissions-resolver.js.map +1 -1
  49. package/dist/implementations/dms/realtime.js +1 -0
  50. package/dist/implementations/dms/realtime.js.map +1 -1
  51. package/dist/implementations/dms-base/bulk-selection.d.ts +1 -1
  52. package/dist/implementations/dms-base/bulk-selection.js +23 -1
  53. package/dist/implementations/dms-base/bulk-selection.js.map +1 -1
  54. package/dist/implementations/dms-base/filter-tokens.js +5 -3
  55. package/dist/implementations/dms-base/filter-tokens.js.map +1 -1
  56. package/dist/implementations/dms-base/search-route.d.ts +1 -0
  57. package/dist/implementations/dms-base/search-route.js +35 -13
  58. package/dist/implementations/dms-base/search-route.js.map +1 -1
  59. package/dist/implementations/dms-base/table-view.js +11 -6
  60. package/dist/implementations/dms-base/table-view.js.map +1 -1
  61. package/dist/implementations/dms-notifications/index.d.ts +2 -2
  62. package/dist/implementations/dms-notifications/index.js +5 -5
  63. package/dist/implementations/dms-notifications/index.js.map +1 -1
  64. package/dist/index.js +32 -55
  65. package/dist/index.js.map +1 -1
  66. package/dist/pages/modules/index.d.ts +1 -0
  67. package/dist/pages/modules/index.js +1 -0
  68. package/dist/pages/modules/index.js.map +1 -1
  69. package/dist/pages/modules/modules-store.d.ts +9 -0
  70. package/dist/pages/modules/modules-store.js +30 -0
  71. package/dist/pages/modules/modules-store.js.map +1 -0
  72. package/dist/pages/settings/users/account-credentials.js +2 -2
  73. package/dist/pages/settings/users/account-credentials.js.map +1 -1
  74. package/dist/pages/settings/users/account-data-store.js +25 -8
  75. package/dist/pages/settings/users/account-data-store.js.map +1 -1
  76. package/dist/pages/settings/users/invite-extension-routes.js +9 -3
  77. package/dist/pages/settings/users/invite-extension-routes.js.map +1 -1
  78. package/dist/pages/settings/users/member-management.js +13 -14
  79. package/dist/pages/settings/users/member-management.js.map +1 -1
  80. package/dist/pages/settings/users/profile.d.ts +1 -4
  81. package/dist/pages/settings/users/profile.js +0 -35
  82. package/dist/pages/settings/users/profile.js.map +1 -1
  83. package/dist/pages/settings/users/role-editor-store.js +26 -18
  84. package/dist/pages/settings/users/role-editor-store.js.map +1 -1
  85. package/dist/pages/settings/users/role-editor.d.ts +0 -1
  86. package/dist/pages/settings/users/role-editor.js +1 -2
  87. package/dist/pages/settings/users/role-editor.js.map +1 -1
  88. package/dist/pages/settings/users/role-preview.js +1 -2
  89. package/dist/pages/settings/users/role-preview.js.map +1 -1
  90. package/dist/pages/settings/users/roles.js +2 -2
  91. package/dist/pages/settings/users/roles.js.map +1 -1
  92. package/dist/pages/settings/users/two-factor-operations.js.map +1 -1
  93. package/dist/realtime/broker.d.ts +6 -0
  94. package/dist/realtime/broker.js +8 -1
  95. package/dist/realtime/broker.js.map +1 -1
  96. package/dist/realtime/presence.d.ts +8 -3
  97. package/dist/realtime/presence.js +8 -4
  98. package/dist/realtime/presence.js.map +1 -1
  99. package/dist/realtime/sessions.d.ts +11 -1
  100. package/dist/realtime/sessions.js +21 -3
  101. package/dist/realtime/sessions.js.map +1 -1
  102. package/dist/realtime/table-view.d.ts +2 -2
  103. package/dist/realtime/table-view.js +4 -3
  104. package/dist/realtime/table-view.js.map +1 -1
  105. package/dist/routes/auth/client-ip.d.ts +1 -0
  106. package/dist/routes/auth/client-ip.js +18 -0
  107. package/dist/routes/auth/client-ip.js.map +1 -1
  108. package/dist/routes/auth/oauth/config.d.ts +2 -1
  109. package/dist/routes/auth/oauth/config.js +5 -1
  110. package/dist/routes/auth/oauth/config.js.map +1 -1
  111. package/dist/routes/auth/session-handoff.d.ts +0 -1
  112. package/dist/routes/auth/session-handoff.js +0 -2
  113. package/dist/routes/auth/session-handoff.js.map +1 -1
  114. package/dist/routes/auth.js +3 -2
  115. package/dist/routes/auth.js.map +1 -1
  116. package/dist/routes/index.d.ts +0 -1
  117. package/dist/routes/index.js +0 -1
  118. package/dist/routes/index.js.map +1 -1
  119. package/dist/routes/realtime.d.ts +13 -1
  120. package/dist/routes/realtime.js +114 -29
  121. package/dist/routes/realtime.js.map +1 -1
  122. package/dist/startup-config.d.ts +2 -0
  123. package/dist/startup-config.js +62 -0
  124. package/dist/startup-config.js.map +1 -0
  125. package/dist/store/interfaces.d.ts +3 -2
  126. package/dist/store/interfaces.js +16 -6
  127. package/dist/store/interfaces.js.map +1 -1
  128. package/dist/store/listing.js +25 -15
  129. package/dist/store/listing.js.map +1 -1
  130. package/dist/store/operations.js +5 -2
  131. package/dist/store/operations.js.map +1 -1
  132. package/dist/store/requirements.js +3 -2
  133. package/dist/store/requirements.js.map +1 -1
  134. package/dist/store/runtime.d.ts +10 -1
  135. package/dist/store/runtime.js +33 -6
  136. package/dist/store/runtime.js.map +1 -1
  137. package/dist/store/types.d.ts +10 -0
  138. package/dist/utils/ensure-default-tenant.d.ts +2 -1
  139. package/dist/utils/ensure-default-tenant.js +13 -1
  140. package/dist/utils/ensure-default-tenant.js.map +1 -1
  141. package/dist/utils/export-jobs.js +2 -1
  142. package/dist/utils/export-jobs.js.map +1 -1
  143. package/dist/validation/auth.schema.d.ts +2 -2
  144. package/dist/validation/member-invite.schema.d.ts +2 -10
  145. package/dist/validation/member-invite.schema.js +2 -15
  146. package/dist/validation/member-invite.schema.js.map +1 -1
  147. package/frontend-vue/dms.frontend.ts +24 -5
  148. package/frontend-vue/dms.server.ts +17 -0
  149. package/frontend-vue/layers/dms-auth/server/accounts.ts +3 -4
  150. package/frontend-vue/layers/dms-core/app/build/composables/renderNow.ts +33 -0
  151. package/frontend-vue/layers/dms-core/app/build/composables/user/tablePreferences.ts +5 -1
  152. package/frontend-vue/layers/dms-core/app/build/utils/crossTab.ts +199 -0
  153. package/frontend-vue/layers/dms-core/app/build/utils/sharedRealtimeConnection.ts +410 -0
  154. package/frontend-vue/layers/dms-core/app/composables/auth/useApiData.ts +77 -12
  155. package/frontend-vue/layers/dms-core/app/composables/data-types/useDataType.ts +26 -0
  156. package/frontend-vue/layers/dms-core/app/composables/live/livePauseSource.ts +29 -0
  157. package/frontend-vue/layers/dms-core/app/composables/period/compareResolvers.ts +150 -9
  158. package/frontend-vue/layers/dms-core/app/composables/period/usePeriod.ts +6 -4
  159. package/frontend-vue/layers/dms-core/app/composables/period/usePeriodScope.ts +27 -1
  160. package/frontend-vue/layers/dms-core/app/composables/realtime/useUserRealtime.ts +256 -119
  161. package/frontend-vue/layers/dms-core/app/composables/translation/useComposedText.ts +21 -8
  162. package/frontend-vue/layers/dms-core/app/composables/translation/useTranslation.ts +25 -5
  163. package/frontend-vue/layers/dms-core/app/composables/useApiError.ts +3 -5
  164. package/frontend-vue/layers/dms-core/app/composables/useFieldErrors.ts +61 -26
  165. package/frontend-vue/layers/dms-core/app/plugins/dev-error-log.ts +16 -0
  166. package/frontend-vue/layers/dms-core/app/types/user.ts +6 -0
  167. package/frontend-vue/layers/dms-core/app/utils/composedText.ts +7 -2
  168. package/frontend-vue/layers/dms-core/app/utils/formatter.ts +134 -35
  169. package/frontend-vue/layers/dms-core/app/utils/url-interpolation.ts +18 -1
  170. package/frontend-vue/layers/dms-core/i18n/locales/core-en-GB.json +136 -2
  171. package/frontend-vue/layers/dms-core/i18n/locales/core-fr-FR.json +136 -2
  172. package/frontend-vue/layers/dms-core/shared/types/app-config.ts +0 -2
  173. package/frontend-vue/layers/dms-layout/app/app.config.ts +0 -1
  174. package/frontend-vue/layers/dms-layout/app/assets/css/main.css +11 -1
  175. package/frontend-vue/layers/dms-layout/app/assets/fonts/Geist-Italic-Variable.woff2 +0 -0
  176. package/frontend-vue/layers/dms-layout/app/assets/fonts/Geist-Variable.woff2 +0 -0
  177. package/frontend-vue/layers/dms-layout/app/assets/fonts/GeistMono-Italic-Variable.woff2 +0 -0
  178. package/frontend-vue/layers/dms-layout/app/assets/fonts/GeistMono-Variable.woff2 +0 -0
  179. package/frontend-vue/layers/dms-layout/app/build/components/layout/DashboardBanners.vue +3 -2
  180. package/frontend-vue/layers/dms-layout/app/build/components/layout/DashboardHeader.vue +41 -21
  181. package/frontend-vue/layers/dms-layout/app/build/components/layout/DashboardPageBody.vue +6 -2
  182. package/frontend-vue/layers/dms-layout/app/build/components/layout/DashboardSidebar.vue +4 -19
  183. package/frontend-vue/layers/dms-layout/app/build/components/layout/Footer.vue +11 -107
  184. package/frontend-vue/layers/dms-layout/app/build/components/layout/GithubStarPrompt.vue +18 -7
  185. package/frontend-vue/layers/dms-layout/app/build/components/layout/PageHeaderActionsOutlet.vue +4 -0
  186. package/frontend-vue/layers/dms-layout/app/build/components/layout/RowSidePanel.vue +43 -82
  187. package/frontend-vue/layers/dms-layout/app/build/components/layout/SidebarUserMenu.vue +44 -3
  188. package/frontend-vue/layers/dms-layout/app/build/components/layout/UserIdentity.vue +11 -3
  189. package/frontend-vue/layers/dms-layout/app/build/components/pages/modules/ModuleCatalogTile.vue +132 -35
  190. package/frontend-vue/layers/dms-layout/app/build/components/pages/modules/ModuleManageMenu.vue +59 -0
  191. package/frontend-vue/layers/dms-layout/app/build/components/pages/modules/ModuleSourceLabel.vue +25 -0
  192. package/frontend-vue/layers/dms-layout/app/build/components/pages/modules/ModuleStoreBanners.vue +73 -0
  193. package/frontend-vue/layers/dms-layout/app/build/components/pages/modules/ModuleStoreOperation.vue +116 -0
  194. package/frontend-vue/layers/dms-layout/app/build/components/pages/modules/ModuleStoreRequirements.vue +8 -3
  195. package/frontend-vue/layers/dms-layout/app/build/components/pages/modules/ModuleStoreTile.vue +85 -207
  196. package/frontend-vue/layers/dms-layout/app/build/components/pages/modules/ModuleTile.vue +10 -3
  197. package/frontend-vue/layers/dms-layout/app/build/components/pages/modules/ModuleTileSkeleton.vue +68 -0
  198. package/frontend-vue/layers/dms-layout/app/build/components/pages/settings/notification/NotificationInboxDisplay.vue +24 -8
  199. package/frontend-vue/layers/dms-layout/app/build/components/pages/settings/notification/NotificationInboxItem.vue +8 -5
  200. package/frontend-vue/layers/dms-layout/app/build/components/pages/settings/region/RegionTimeZoneInput.vue +1 -0
  201. package/frontend-vue/layers/dms-layout/app/build/components/pages/settings/roles/role-permissions.ts +19 -0
  202. package/frontend-vue/layers/dms-layout/app/build/components/pages/settings/roles/useRoleEditor.ts +2 -1
  203. package/frontend-vue/layers/dms-layout/app/build/composables/layout/useSidePanelWidth.ts +31 -70
  204. package/frontend-vue/layers/dms-layout/app/build/composables/notification/useNotificationGroupsOpen.ts +11 -1
  205. package/frontend-vue/layers/dms-layout/app/build/utils/dev-reload-stream.ts +81 -0
  206. package/frontend-vue/layers/dms-layout/app/build/utils/github-repository.ts +2 -2
  207. package/frontend-vue/layers/dms-layout/app/build/utils/module-store-catalog.ts +232 -36
  208. package/frontend-vue/layers/dms-layout/app/build/utils/modules-catalog.ts +122 -14
  209. package/frontend-vue/layers/dms-layout/app/composables/layout/useLayoutBanners.ts +32 -3
  210. package/frontend-vue/layers/dms-layout/app/composables/layout/useServedHeaderActions.ts +49 -11
  211. package/frontend-vue/layers/dms-layout/app/composables/page/useModuleHistory.ts +3 -2
  212. package/frontend-vue/layers/dms-layout/app/composables/page/useModuleStore.ts +59 -4
  213. package/frontend-vue/layers/dms-layout/app/composables/page/useModuleStoreActions.ts +194 -0
  214. package/frontend-vue/layers/dms-layout/app/composables/page/usePageComponentPreload.ts +23 -3
  215. package/frontend-vue/layers/dms-layout/app/composables/page/usePageLayout.ts +4 -2
  216. package/frontend-vue/layers/dms-layout/app/composables/page/usePageRecordDeletion.ts +162 -0
  217. package/frontend-vue/layers/dms-layout/app/composables/page/useSiteLayout.ts +6 -1
  218. package/frontend-vue/layers/dms-layout/app/custom-layouts/DefaultLayout.vue +6 -2
  219. package/frontend-vue/layers/dms-layout/app/custom-layouts/SettingsLayout.vue +6 -2
  220. package/frontend-vue/layers/dms-layout/app/custom-pages/modules-store.vue +291 -0
  221. package/frontend-vue/layers/dms-layout/app/custom-pages/modules.vue +87 -474
  222. package/frontend-vue/layers/dms-layout/app/middleware/module-routing.global.ts +3 -0
  223. package/frontend-vue/layers/dms-layout/app/pages/[...slug].vue +13 -22
  224. package/frontend-vue/layers/dms-layout/app/plugins/command-palette-navigation.client.ts +11 -10
  225. package/frontend-vue/layers/dms-layout/app/plugins/command-palette-personal-pages.client.ts +22 -52
  226. package/frontend-vue/layers/dms-layout/app/plugins/command-palette-quick-actions.client.ts +7 -7
  227. package/frontend-vue/layers/dms-layout/app/plugins/command-palette-session.client.ts +11 -10
  228. package/frontend-vue/layers/dms-layout/app/plugins/dms-dev-reload.client.ts +14 -9
  229. package/frontend-vue/layers/dms-layout/app/theme/actions.ts +5 -4
  230. package/frontend-vue/layers/dms-layout/app/theme/form-controls.ts +9 -4
  231. package/frontend-vue/layers/dms-layout/app/theme/surfaces.ts +22 -6
  232. package/frontend-vue/layers/dms-layout/app/types/module-store.ts +9 -0
  233. package/frontend-vue/layers/dms-layout/app/types/page.ts +15 -1
  234. package/frontend-vue/layers/dms-layout/app/utils/account-menu.ts +11 -0
  235. package/frontend-vue/layers/dms-layout/app/utils/breadcrumb.ts +57 -0
  236. package/frontend-vue/layers/dms-layout/app/utils/pageQuery.ts +26 -0
  237. package/frontend-vue/layers/dms-layout/i18n/locales/layout-en-GB.json +45 -18
  238. package/frontend-vue/layers/dms-layout/i18n/locales/layout-fr-FR.json +44 -17
  239. package/frontend-vue/layers/dms-ui/app/build/components/containers/TargetComponentTree.vue +31 -0
  240. package/frontend-vue/layers/dms-ui/app/build/components/containers/constants.ts +25 -0
  241. package/frontend-vue/layers/dms-ui/app/build/components/containers/drawer/DynamicDrawer.vue +244 -15
  242. package/frontend-vue/layers/dms-ui/app/build/components/containers/modal/DynamicModal.vue +42 -25
  243. package/frontend-vue/layers/dms-ui/app/build/components/containers/row/RowHeader.vue +153 -0
  244. package/frontend-vue/layers/dms-ui/app/build/components/containers/row/RowNotFound.vue +44 -0
  245. package/frontend-vue/layers/dms-ui/app/build/components/containers/row/drawerRowHeader.ts +35 -0
  246. package/frontend-vue/layers/dms-ui/app/build/components/form/FormEntries.vue +44 -9
  247. package/frontend-vue/layers/dms-ui/app/build/components/form/FormErrorSummary.vue +11 -4
  248. package/frontend-vue/layers/dms-ui/app/build/components/form/FormFieldControl.vue +38 -5
  249. package/frontend-vue/layers/dms-ui/app/build/components/form/FormFieldNotes.vue +29 -5
  250. package/frontend-vue/layers/dms-ui/app/build/components/form/FormLoadError.vue +5 -1
  251. package/frontend-vue/layers/dms-ui/app/build/components/form/FormSectionNav.vue +3 -1
  252. package/frontend-vue/layers/dms-ui/app/build/components/form/FormSections.vue +106 -27
  253. package/frontend-vue/layers/dms-ui/app/build/components/table/Actions.vue +12 -4
  254. package/frontend-vue/layers/dms-ui/app/build/components/table/Empty.vue +4 -2
  255. package/frontend-vue/layers/dms-ui/app/build/components/table/FiltersRow.vue +48 -1
  256. package/frontend-vue/layers/dms-ui/app/build/components/table/Pagination.vue +55 -54
  257. package/frontend-vue/layers/dms-ui/app/build/components/table/RowSelection.vue +2 -1
  258. package/frontend-vue/layers/dms-ui/app/build/components/table/Table.vue +396 -288
  259. package/frontend-vue/layers/dms-ui/app/build/components/table/Tabs.vue +2 -1
  260. package/frontend-vue/layers/dms-ui/app/build/components/table/Views.vue +2 -1
  261. package/frontend-vue/layers/dms-ui/app/build/components/table-view/CardAvatar.vue +59 -0
  262. package/frontend-vue/layers/dms-ui/app/build/components/table-view/CardGridSkeleton.vue +19 -2
  263. package/frontend-vue/layers/dms-ui/app/build/components/table-view/CardRowActions.vue +38 -0
  264. package/frontend-vue/layers/dms-ui/app/build/components/table-view/CardsDisplay.vue +148 -104
  265. package/frontend-vue/layers/dms-ui/app/build/components/table-view/LiveHoldBanner.vue +17 -2
  266. package/frontend-vue/layers/dms-ui/app/build/composables/actions/bulkSelection.ts +43 -9
  267. package/frontend-vue/layers/dms-ui/app/build/composables/actions/rowComponentOptions.ts +76 -0
  268. package/frontend-vue/layers/dms-ui/app/build/composables/actions/rowNavigation.ts +172 -27
  269. package/frontend-vue/layers/dms-ui/app/build/composables/actions/useActionTargets.ts +270 -46
  270. package/frontend-vue/layers/dms-ui/app/build/composables/confirm/actionError.ts +6 -1
  271. package/frontend-vue/layers/dms-ui/app/build/composables/confirm/confirmDialogTexts.ts +2 -0
  272. package/frontend-vue/layers/dms-ui/app/build/composables/containers/closingLayers.ts +186 -0
  273. package/frontend-vue/layers/dms-ui/app/build/composables/containers/context.ts +14 -0
  274. package/frontend-vue/layers/dms-ui/app/build/composables/containers/drawerSize.ts +229 -0
  275. package/frontend-vue/layers/dms-ui/app/build/composables/containers/useResizableSize.ts +175 -0
  276. package/frontend-vue/layers/dms-ui/app/build/composables/data-types/metricCells.ts +18 -35
  277. package/frontend-vue/layers/dms-ui/app/build/composables/data-types/numberSuffix.ts +44 -0
  278. package/frontend-vue/layers/dms-ui/app/build/composables/data-types/registerDefaults.ts +123 -27
  279. package/frontend-vue/layers/dms-ui/app/build/composables/data-types/registerFieldTypes.ts +2 -1
  280. package/frontend-vue/layers/dms-ui/app/build/composables/data-types/relationFilter.ts +75 -0
  281. package/frontend-vue/layers/dms-ui/app/build/composables/data-types/relationRows.ts +92 -0
  282. package/frontend-vue/layers/dms-ui/app/build/composables/data-types/relationValue.ts +39 -0
  283. package/frontend-vue/layers/dms-ui/app/build/composables/data-types/twoLineCell.ts +3 -3
  284. package/frontend-vue/layers/dms-ui/app/build/composables/data-types/useColumnValueRenderer.ts +6 -2
  285. package/frontend-vue/layers/dms-ui/app/build/composables/form/createFormFields.ts +15 -0
  286. package/frontend-vue/layers/dms-ui/app/build/composables/form/fieldSaved.ts +40 -0
  287. package/frontend-vue/layers/dms-ui/app/build/composables/form/fieldValueRule.ts +62 -0
  288. package/frontend-vue/layers/dms-ui/app/build/composables/form/formEntryContext.ts +5 -0
  289. package/frontend-vue/layers/dms-ui/app/build/composables/form/formFooter.ts +42 -7
  290. package/frontend-vue/layers/dms-ui/app/build/composables/form/formLayout.ts +106 -4
  291. package/frontend-vue/layers/dms-ui/app/build/composables/form/formRecordLoad.ts +11 -5
  292. package/frontend-vue/layers/dms-ui/app/build/composables/form/formSections.ts +32 -0
  293. package/frontend-vue/layers/dms-ui/app/build/composables/form/formValidation.ts +36 -4
  294. package/frontend-vue/layers/dms-ui/app/build/composables/form/readonlyValue.ts +19 -0
  295. package/frontend-vue/layers/dms-ui/app/build/composables/form/registerFormFunctions.ts +27 -0
  296. package/frontend-vue/layers/dms-ui/app/build/composables/form/repeaterTable.ts +78 -0
  297. package/frontend-vue/layers/dms-ui/app/build/composables/form/serverFieldErrors.ts +49 -0
  298. package/frontend-vue/layers/dms-ui/app/build/composables/form/toasterClearance.ts +118 -0
  299. package/frontend-vue/layers/dms-ui/app/build/composables/form/useInstantForm.ts +12 -1
  300. package/frontend-vue/layers/dms-ui/app/build/composables/live/currentPageLive.ts +41 -3
  301. package/frontend-vue/layers/dms-ui/app/build/composables/live/livePoller.ts +10 -2
  302. package/frontend-vue/layers/dms-ui/app/build/composables/live/pageReadClock.ts +28 -0
  303. package/frontend-vue/layers/dms-ui/app/build/composables/live/shortcuts.ts +1 -1
  304. package/frontend-vue/layers/dms-ui/app/build/composables/live/usePageLiveHost.ts +17 -3
  305. package/frontend-vue/layers/dms-ui/app/build/composables/live/useUpdatedLabel.ts +38 -0
  306. package/frontend-vue/layers/dms-ui/app/build/composables/page-toolbar/pageToolbarContext.ts +75 -0
  307. package/frontend-vue/layers/dms-ui/app/build/composables/page-toolbar/toolbarControlHeight.ts +29 -0
  308. package/frontend-vue/layers/dms-ui/app/build/composables/period/periodComparison.ts +52 -0
  309. package/frontend-vue/layers/dms-ui/app/build/composables/period/periodDisplay.ts +21 -0
  310. package/frontend-vue/layers/dms-ui/app/build/composables/period/periodShortLabels.ts +28 -0
  311. package/frontend-vue/layers/dms-ui/app/build/composables/period/usePeriodDraft.ts +1 -0
  312. package/frontend-vue/layers/dms-ui/app/build/composables/table/useRelationFilterLabels.ts +97 -0
  313. package/frontend-vue/layers/dms-ui/app/build/composables/table/useRowScrollAnchor.ts +106 -0
  314. package/frontend-vue/layers/dms-ui/app/build/composables/table/useTable.ts +9 -0
  315. package/frontend-vue/layers/dms-ui/app/build/composables/table/useTableColumns.ts +1 -2
  316. package/frontend-vue/layers/dms-ui/app/build/composables/table/utils/archivedCount.ts +31 -0
  317. package/frontend-vue/layers/dms-ui/app/build/composables/table/utils/filterEditorValue.ts +38 -0
  318. package/frontend-vue/layers/dms-ui/app/build/composables/table/utils/formatFilterValue.ts +33 -2
  319. package/frontend-vue/layers/dms-ui/app/build/composables/table/utils/scrollEdges.ts +31 -0
  320. package/frontend-vue/layers/dms-ui/app/build/composables/table-view/useCardFields.ts +33 -0
  321. package/frontend-vue/layers/dms-ui/app/build/composables/table-view/useMobileDisplay.ts +48 -0
  322. package/frontend-vue/layers/dms-ui/app/build/composables/table-view/useScrolledPastTop.ts +41 -18
  323. package/frontend-vue/layers/dms-ui/app/build/composables/table-view/useTableFooter.ts +3 -2
  324. package/frontend-vue/layers/dms-ui/app/build/composables/table-view/useTableLinkedVisit.ts +78 -0
  325. package/frontend-vue/layers/dms-ui/app/build/composables/table-view/useTableLiveHold.ts +135 -22
  326. package/frontend-vue/layers/dms-ui/app/build/composables/table-view/useTableRows.ts +56 -25
  327. package/frontend-vue/layers/dms-ui/app/build/composables/table-view/useTableViewRowActions.ts +90 -35
  328. package/frontend-vue/layers/dms-ui/app/build/composables/table-view/useTableViews.ts +86 -10
  329. package/frontend-vue/layers/dms-ui/app/build/composables/table-view/utils/bulkActions.ts +14 -4
  330. package/frontend-vue/layers/dms-ui/app/build/composables/table-view/utils/card.ts +127 -2
  331. package/frontend-vue/layers/dms-ui/app/build/composables/table-view/utils/compareValues.ts +13 -0
  332. package/frontend-vue/layers/dms-ui/app/build/composables/table-view/utils/expandedRows.ts +28 -0
  333. package/frontend-vue/layers/dms-ui/app/build/composables/table-view/utils/groupedRows.ts +114 -1
  334. package/frontend-vue/layers/dms-ui/app/build/composables/table-view/utils/linkedArrival.ts +308 -0
  335. package/frontend-vue/layers/dms-ui/app/build/composables/table-view/utils/locateRow.ts +106 -0
  336. package/frontend-vue/layers/dms-ui/app/build/composables/table-view/utils/pageArrival.ts +34 -0
  337. package/frontend-vue/layers/dms-ui/app/build/composables/table-view/utils/pinnedRows.ts +17 -0
  338. package/frontend-vue/layers/dms-ui/app/build/composables/table-view/utils/quickFilters.ts +41 -33
  339. package/frontend-vue/layers/dms-ui/app/build/composables/table-view/utils/recordLink.ts +24 -8
  340. package/frontend-vue/layers/dms-ui/app/build/composables/table-view/utils/tableCounts.ts +113 -0
  341. package/frontend-vue/layers/dms-ui/app/build/composables/table-view/utils/tableQuery.ts +27 -4
  342. package/frontend-vue/layers/dms-ui/app/build/composables/table-view/utils/views.ts +22 -6
  343. package/frontend-vue/layers/dms-ui/app/build/composables/table-view/utils/writeError.ts +21 -0
  344. package/frontend-vue/layers/dms-ui/app/build/utils/addressSuggestions.ts +49 -0
  345. package/frontend-vue/layers/dms-ui/app/build/utils/codeHighlight.ts +67 -29
  346. package/frontend-vue/layers/dms-ui/app/build/utils/eyebrow.ts +12 -0
  347. package/frontend-vue/layers/dms-ui/app/build/utils/fieldOptionsI18n.ts +51 -11
  348. package/frontend-vue/layers/dms-ui/app/build/utils/htmlGrammar.ts +79 -0
  349. package/frontend-vue/layers/dms-ui/app/build/utils/inputWidth.ts +53 -0
  350. package/frontend-vue/layers/dms-ui/app/build/utils/numberAdjustment.ts +6 -3
  351. package/frontend-vue/layers/dms-ui/app/build/utils/relativeDate.ts +19 -5
  352. package/frontend-vue/layers/dms-ui/app/build/utils/scrollWithin.ts +99 -0
  353. package/frontend-vue/layers/dms-ui/app/build/utils/shellParser.ts +1 -1
  354. package/frontend-vue/layers/dms-ui/app/build/utils/streamHighlight.ts +90 -0
  355. package/frontend-vue/layers/dms-ui/app/build/utils/urlVariables.ts +36 -14
  356. package/frontend-vue/layers/dms-ui/app/components/PasswordStrength.vue +1 -1
  357. package/frontend-vue/layers/dms-ui/app/components/RecursiveComponent.vue +9 -1
  358. package/frontend-vue/layers/dms-ui/app/components/blocks/LiveToggleBlock.vue +80 -32
  359. package/frontend-vue/layers/dms-ui/app/components/blocks/PageToolbarBlock.vue +137 -0
  360. package/frontend-vue/layers/dms-ui/app/components/blocks/StatGroupBlock.vue +5 -0
  361. package/frontend-vue/layers/dms-ui/app/components/chart/ApexChartHost.vue +16 -2
  362. package/frontend-vue/layers/dms-ui/app/components/chart/Chart.vue +24 -5
  363. package/frontend-vue/layers/dms-ui/app/components/chart/ChartCard.vue +41 -23
  364. package/frontend-vue/layers/dms-ui/app/components/code-snippet/CodeSnippet.vue +23 -12
  365. package/frontend-vue/layers/dms-ui/app/components/confirm/ConfirmModal.vue +1 -1
  366. package/frontend-vue/layers/dms-ui/app/components/container-footer/ContainerFooter.vue +34 -0
  367. package/frontend-vue/layers/dms-ui/app/components/field-row/FieldRow.vue +25 -2
  368. package/frontend-vue/layers/dms-ui/app/components/flow-canvas/FlowCanvas.vue +2 -2
  369. package/frontend-vue/layers/dms-ui/app/components/form/Form.vue +119 -36
  370. package/frontend-vue/layers/dms-ui/app/components/form/components/Cascader.vue +53 -22
  371. package/frontend-vue/layers/dms-ui/app/components/form/components/DatePicker.vue +20 -1
  372. package/frontend-vue/layers/dms-ui/app/components/form/components/Display.vue +13 -1
  373. package/frontend-vue/layers/dms-ui/app/components/form/components/Image.vue +8 -3
  374. package/frontend-vue/layers/dms-ui/app/components/form/components/InputAddress.vue +53 -5
  375. package/frontend-vue/layers/dms-ui/app/components/form/components/InputCode.vue +29 -5
  376. package/frontend-vue/layers/dms-ui/app/components/form/components/InputNumber.vue +45 -8
  377. package/frontend-vue/layers/dms-ui/app/components/form/components/InputPercentage.vue +28 -5
  378. package/frontend-vue/layers/dms-ui/app/components/form/components/InputSecret.vue +5 -0
  379. package/frontend-vue/layers/dms-ui/app/components/form/components/InputText.vue +19 -2
  380. package/frontend-vue/layers/dms-ui/app/components/form/components/InputTime.vue +2 -1
  381. package/frontend-vue/layers/dms-ui/app/components/form/components/Relation.vue +226 -65
  382. package/frontend-vue/layers/dms-ui/app/components/form/components/Repeater.vue +80 -30
  383. package/frontend-vue/layers/dms-ui/app/components/form/components/RepeaterTable.vue +210 -0
  384. package/frontend-vue/layers/dms-ui/app/components/form/components/Select.vue +4 -2
  385. package/frontend-vue/layers/dms-ui/app/components/grid/GridRow.vue +11 -2
  386. package/frontend-vue/layers/dms-ui/app/components/key-value-list/KeyValueList.vue +79 -70
  387. package/frontend-vue/layers/dms-ui/app/components/kpi/KpiCard.vue +117 -21
  388. package/frontend-vue/layers/dms-ui/app/components/meter/Meter.vue +2 -1
  389. package/frontend-vue/layers/dms-ui/app/components/period/PeriodSelector.vue +113 -34
  390. package/frontend-vue/layers/dms-ui/app/components/save-bar/SaveBar.vue +14 -2
  391. package/frontend-vue/layers/dms-ui/app/components/section-header/Eyebrow.vue +6 -1
  392. package/frontend-vue/layers/dms-ui/app/components/segmented/Segmented.vue +13 -0
  393. package/frontend-vue/layers/dms-ui/app/components/stat-group/StatGroup.vue +52 -3
  394. package/frontend-vue/layers/dms-ui/app/components/tab/Tab.vue +2 -1
  395. package/frontend-vue/layers/dms-ui/app/components/table-view/CascaderPath.vue +74 -25
  396. package/frontend-vue/layers/dms-ui/app/components/table-view/KanbanBoard.vue +48 -44
  397. package/frontend-vue/layers/dms-ui/app/components/table-view/KanbanDisplay.vue +4 -1
  398. package/frontend-vue/layers/dms-ui/app/components/table-view/TableView.vue +426 -97
  399. package/frontend-vue/layers/dms-ui/app/components/top-list/TopListCard.vue +33 -5
  400. package/frontend-vue/layers/dms-ui/app/composables/chart/apexCategoryLabels.ts +68 -0
  401. package/frontend-vue/layers/dms-ui/app/composables/chart/apexDatetimeBuckets.ts +306 -0
  402. package/frontend-vue/layers/dms-ui/app/composables/chart/formatValue.ts +4 -3
  403. package/frontend-vue/layers/dms-ui/app/composables/chart/heatmapColors.ts +93 -0
  404. package/frontend-vue/layers/dms-ui/app/composables/chart/localizeSeries.ts +62 -0
  405. package/frontend-vue/layers/dms-ui/app/composables/chart/useApexChart.ts +116 -8
  406. package/frontend-vue/layers/dms-ui/app/composables/chart/useApexChart.types.ts +7 -0
  407. package/frontend-vue/layers/dms-ui/app/composables/containers/types.ts +84 -1
  408. package/frontend-vue/layers/dms-ui/app/composables/containers/useDrawer.ts +69 -8
  409. package/frontend-vue/layers/dms-ui/app/composables/form/types/field-saved.ts +11 -0
  410. package/frontend-vue/layers/dms-ui/app/composables/form/types/field.ts +16 -0
  411. package/frontend-vue/layers/dms-ui/app/composables/form/types/functions.ts +1 -0
  412. package/frontend-vue/layers/dms-ui/app/composables/form/useForm.ts +189 -28
  413. package/frontend-vue/layers/dms-ui/app/composables/live/usePageLive.ts +29 -12
  414. package/frontend-vue/layers/dms-ui/app/composables/page-toolbar/usePageToolbarSize.ts +30 -0
  415. package/frontend-vue/layers/dms-ui/app/composables/table-view/kanban.ts +4 -2
  416. package/frontend-vue/layers/dms-ui/app/composables/table-view/types/action-target.ts +22 -3
  417. package/frontend-vue/layers/dms-ui/app/composables/table-view/types/config.ts +4 -0
  418. package/frontend-vue/layers/dms-ui/app/composables/table-view/types/display.ts +24 -1
  419. package/frontend-vue/layers/dms-ui/app/plugins/closing-layers.client.ts +10 -0
  420. package/frontend-vue/layers/dms-ui/app/plugins/live-pause-source.ts +15 -0
  421. package/frontend-vue/layers/dms-ui/app/plugins/register.ts +2 -0
  422. package/frontend-vue/layers/dms-ui/app/types/input-number.ts +3 -2
  423. package/frontend-vue/layers/dms-ui/app/types/page-toolbar.ts +7 -0
  424. package/frontend-vue/layers/dms-ui/app/types/row-action.ts +0 -2
  425. package/frontend-vue/layers/dms-ui/app/types/row-navigation.ts +17 -0
  426. package/frontend-vue/layers/dms-ui/app/types/table/query.ts +2 -1
  427. package/frontend-vue/layers/dms-ui/app/utils/blockRefresh.ts +3 -1
  428. package/frontend-vue/layers/dms-ui/app/utils/cascader.ts +94 -3
  429. package/frontend-vue/layers/dms-ui/app/utils/componentTree.ts +24 -0
  430. package/frontend-vue/layers/dms-ui/i18n/locales/ui-en-GB.json +20 -5
  431. package/frontend-vue/layers/dms-ui/i18n/locales/ui-fr-FR.json +20 -5
  432. package/frontend-vue/package.json +6 -2
  433. package/package.json +11 -10
  434. package/skills/dms/SKILL.md +1 -1
  435. package/skills/dms-auth/SKILL.md +5 -3
  436. package/skills/dms-best-practices/REFERENCE.md +2 -0
  437. package/skills/dms-best-practices/SKILL.md +4 -0
  438. package/skills/dms-module/SKILL.md +3 -2
  439. package/skills/dms-pages/REFERENCE.md +129 -16
  440. package/skills/dms-pages/SKILL.md +1 -1
  441. package/skills/dms-project/DEV-SERVERS.md +23 -1
  442. package/skills/dms-project/REFERENCE.md +1 -1
  443. package/skills/dms-project/SKILL.md +4 -1
  444. package/skills/dms-project/scripts/dms-dev.sh +205 -17
  445. package/dist/hooks/tenant-instances.d.ts +0 -1
  446. package/dist/hooks/tenant-instances.js +0 -13
  447. package/dist/hooks/tenant-instances.js.map +0 -1
  448. package/dist/routes/startup-gate.d.ts +0 -7
  449. package/dist/routes/startup-gate.js +0 -39
  450. package/dist/routes/startup-gate.js.map +0 -1
  451. package/frontend-vue/layers/dms-core/app/composables/period/periodRenderNow.ts +0 -42
@@ -0,0 +1,68 @@
1
+ <script setup lang="ts">
2
+ // The placeholder of a ModuleTile while the grid loads, block for block the
3
+ // tile's size: the 36px icon well and the 20px pill, the title's 28px line,
4
+ // two description lines, and the footer band with its xs button. Nothing
5
+ // moves once the tiles replace it.
6
+
7
+ interface ModuleTileSkeletonProps {
8
+ /**
9
+ * A store tile still to install: no status pill, and the 30px npm package
10
+ * line under the description.
11
+ */
12
+ isStore?: boolean;
13
+ }
14
+
15
+ const props = withDefaults(defineProps<ModuleTileSkeletonProps>(), {
16
+ isStore: false,
17
+ });
18
+
19
+ const { t } = useI18n();
20
+ </script>
21
+
22
+ <template>
23
+ <div
24
+ class="dms-card flex min-h-[228px] flex-col gap-3 overflow-hidden px-4 pt-4"
25
+ aria-hidden="true"
26
+ >
27
+ <div class="flex items-start justify-between gap-2.5">
28
+ <USkeleton
29
+ :aria-label="t('dms.a11y.loading')"
30
+ class="size-9 rounded-[10px]"
31
+ />
32
+ <USkeleton
33
+ v-if="!props.isStore"
34
+ :aria-label="t('dms.a11y.loading')"
35
+ class="h-5 w-16 rounded-full"
36
+ />
37
+ </div>
38
+
39
+ <div class="flex h-7 items-center">
40
+ <USkeleton :aria-label="t('dms.a11y.loading')" class="h-4 w-2/5" />
41
+ </div>
42
+ <!-- The description's two lines, each its line height tall. -->
43
+ <div class="-mt-1.5 text-sm leading-[1.45]">
44
+ <div class="flex h-[1.45em] items-center">
45
+ <USkeleton :aria-label="t('dms.a11y.loading')" class="h-3 w-full" />
46
+ </div>
47
+ <div class="flex h-[1.45em] items-center">
48
+ <USkeleton :aria-label="t('dms.a11y.loading')" class="h-3 w-3/5" />
49
+ </div>
50
+ </div>
51
+
52
+ <USkeleton
53
+ v-if="props.isStore"
54
+ :aria-label="t('dms.a11y.loading')"
55
+ class="h-[30px] rounded-[8px]"
56
+ />
57
+
58
+ <div
59
+ class="-mx-4 mt-auto flex items-center justify-between gap-2 border-t border-(--ui-border-muted) bg-(--dms-bg-muted) py-[7px] ps-4 pe-3"
60
+ >
61
+ <USkeleton :aria-label="t('dms.a11y.loading')" class="h-3 w-24" />
62
+ <USkeleton
63
+ :aria-label="t('dms.a11y.loading')"
64
+ class="h-6 w-16 rounded-md"
65
+ />
66
+ </div>
67
+ </div>
68
+ </template>
@@ -4,6 +4,7 @@ import { formatRelativeTime } from "#dms-core/app/utils/formatter";
4
4
  import TableEmpty from "#dms-ui/app/build/components/table/Empty.vue";
5
5
  import TablePagination from "#dms-ui/app/build/components/table/Pagination.vue";
6
6
  import type { TableViewDisplayContext } from "#dms-ui/app/composables/table-view/types/display";
7
+ import { useConfirm } from "#dms-ui/app/composables/confirm";
7
8
  import { useNotificationCatalog } from "../../../../composables/notification/useNotificationCatalog";
8
9
  import {
9
10
  type UserNotification,
@@ -31,6 +32,7 @@ const SKELETON_ROWS = 3;
31
32
 
32
33
  const { t, locale } = useI18n();
33
34
  const toast = useToast();
35
+ const { confirm } = useConfirm();
34
36
  const catalog = useNotificationCatalog();
35
37
  const {
36
38
  unreadCount,
@@ -97,16 +99,30 @@ const toggleRead = (notification: UserNotification) =>
97
99
  : markAsRead(notification._id),
98
100
  );
99
101
 
102
+ // A deletion cannot be undone, and its button sits next to Mark read: it is
103
+ // asked first, as "Delete all" is, with the safe answer focused.
104
+ const removeNotification = async (notification: UserNotification) => {
105
+ const isConfirmed = await confirm({
106
+ title: t("page.settings.notifications.delete_one_title"),
107
+ description: t("page.settings.notifications.delete_one_description"),
108
+ icon: "i-ph-trash",
109
+ color: "error",
110
+ confirmIcon: "i-ph-trash",
111
+ confirmLabel: t("page.settings.notifications.delete"),
112
+ cancelLabel: t("page.settings.notifications.cancel"),
113
+ initialFocus: "cancel",
114
+ });
115
+ if (isConfirmed) {
116
+ await runThenRefresh(() => deleteNotification(notification._id));
117
+ }
118
+ };
119
+
100
120
  // What the stream changes elsewhere (a notification arriving, read in
101
121
  // another tab) is listed again here: once per change of the count or of the
102
122
  // newest notification, not each time the bell's lists are rebuilt.
103
- watch(
104
- [unreadCount, () => notifications.value[0]?._id],
105
- () => {
106
- if (ownChanges === 0) void props.context.refresh();
107
- },
108
- );
109
-
123
+ watch([unreadCount, () => notifications.value[0]?._id], () => {
124
+ if (ownChanges === 0) void props.context.refresh();
125
+ });
110
126
  </script>
111
127
 
112
128
  <template>
@@ -136,7 +152,7 @@ watch(
136
152
  :source="sourceOf(notification)"
137
153
  @open="openNotification(notification)"
138
154
  @toggle-read="toggleRead(notification)"
139
- @delete="runThenRefresh(() => deleteNotification(notification._id))"
155
+ @delete="removeNotification(notification)"
140
156
  />
141
157
  </section>
142
158
  </template>
@@ -32,12 +32,15 @@ const readToggleLabel = computed(() =>
32
32
  ? t("page.settings.notifications.mark_read")
33
33
  : t("page.settings.notifications.mark_unread"),
34
34
  );
35
- // Row actions stay compact until the row is hovered or holds focus, then
36
- // show their labels (v2 C07).
37
- // Hover or focus spells the actions out, except on phones: a tap focuses
38
- // the row, and the labels would squeeze the text there.
35
+ // Row actions stay quiet until the row is hovered or holds focus, then
36
+ // show their labels (v2 C07). The labels only fade in: they keep their room
37
+ // laid out, so the buttons never move under the pointer on the way to one
38
+ // (a label appearing used to slide Delete under a Mark read click). Phones
39
+ // show the icons alone: a tap focuses the row, and the labels would squeeze
40
+ // the text there.
39
41
  const actionLabelUi = {
40
- label: "hidden sm:group-hover:inline sm:group-focus-within:inline",
42
+ label:
43
+ "hidden sm:inline sm:opacity-0 sm:transition-opacity sm:duration-150 sm:group-hover:opacity-100 sm:group-focus-within:opacity-100",
41
44
  };
42
45
  </script>
43
46
 
@@ -54,6 +54,7 @@ const options = computed(() => [
54
54
  :filter-fields="['label', 'value', 'offset']"
55
55
  :search-input="{ placeholder: t('page.settings.region.time_zone_search') }"
56
56
  :virtualize="{ estimateSize: ITEM_HEIGHT }"
57
+ :aria-label="t('dms.a11y.show_options')"
57
58
  >
58
59
  <template #item-trailing="{ item }">
59
60
  <span class="text-dimmed font-mono text-[11px]">{{ item.offset }}</span>
@@ -393,6 +393,25 @@ export function revokePermission(
393
393
  return remaining;
394
394
  }
395
395
 
396
+ /**
397
+ * The "added automatically" hints still true of a selection: a node no
398
+ * longer granted loses its hint, and a hint stops naming what is no longer
399
+ * granted, so a revoke that cascades (unticking a list takes the edit that
400
+ * had added it) leaves no hint on an unticked row.
401
+ */
402
+ export function keepGrantedAutoAdded(
403
+ autoAdded: Map<string, string[]>,
404
+ selection: Set<string>,
405
+ ): Map<string, string[]> {
406
+ const kept = new Map<string, string[]>();
407
+ for (const [id, added] of autoAdded) {
408
+ if (!selection.has(id)) continue;
409
+ const granted = added.filter((addedId) => selection.has(addedId));
410
+ if (granted.length > 0) kept.set(id, granted);
411
+ }
412
+ return kept;
413
+ }
414
+
396
415
  function matchesQuery(
397
416
  node: RolePermissionNode,
398
417
  query: string,
@@ -5,6 +5,7 @@ import {
5
5
  buildPermissionIndex,
6
6
  diffPermissions,
7
7
  grantPermission,
8
+ keepGrantedAutoAdded,
8
9
  revokePermission,
9
10
  } from "./role-permissions";
10
11
  import {
@@ -173,7 +174,7 @@ export function useRoleEditor(data: Ref<RolesPageData | null>) {
173
174
  } else {
174
175
  selection.value = revokePermission(index.value, selection.value, id);
175
176
  }
176
- autoAdded.value = nextAutoAdded;
177
+ autoAdded.value = keepGrantedAutoAdded(nextAutoAdded, selection.value);
177
178
  }
178
179
 
179
180
  const payload = computed<RoleDraft>(() => ({
@@ -1,35 +1,22 @@
1
1
  import type { Ref } from "vue";
2
+ import {
3
+ RESIZE_KEYBOARD_STEP_PX,
4
+ useResizableSize,
5
+ } from "#dms-ui/app/build/composables/containers/useResizableSize";
2
6
  import {
3
7
  resolveSidePanelWidthBounds,
4
8
  type SidePanel,
5
9
  type SidePanelWidthBounds,
6
10
  } from "../../../composables/useAppSidePanels";
7
11
  import {
8
- clampSidePanelWidth,
9
12
  readSidePanelPreferences,
10
- storedSidePanelWidth,
11
13
  storeSidePanelWidth,
12
14
  useSidePanelDragWidth,
13
15
  useSidePanelPreferences,
14
16
  } from "./sidePanelState";
15
17
 
16
18
  /** @internal */
17
- export const SIDE_PANEL_KEYBOARD_STEP_PX = 16;
18
-
19
- type WidthStep = (width: number, bounds: SidePanelWidthBounds) => number;
20
-
21
- // The panel sits on the right: the arrow pointing away from it widens it.
22
- const KEYBOARD_STEPS: Record<string, WidthStep> = {
23
- ArrowLeft: (width) => width + SIDE_PANEL_KEYBOARD_STEP_PX,
24
- ArrowRight: (width) => width - SIDE_PANEL_KEYBOARD_STEP_PX,
25
- Home: (_, bounds) => bounds.minWidth,
26
- End: (_, bounds) => bounds.maxWidth,
27
- };
28
-
29
- interface DragStart {
30
- x: number;
31
- width: number;
32
- }
19
+ export const SIDE_PANEL_KEYBOARD_STEP_PX = RESIZE_KEYBOARD_STEP_PX;
33
20
 
34
21
  /** @internal */
35
22
  export interface SidePanelWidth {
@@ -54,60 +41,34 @@ export interface SidePanelWidth {
54
41
  export function useSidePanelWidth(panel: SidePanel): SidePanelWidth {
55
42
  const bounds = resolveSidePanelWidthBounds(panel);
56
43
  const preferences = useSidePanelPreferences();
57
- const dragWidth = useSidePanelDragWidth();
58
- const width = computed(
59
- () =>
60
- dragWidth.value ??
61
- storedSidePanelWidth(
62
- readSidePanelPreferences(preferences.value),
63
- panel.id,
64
- bounds,
65
- ),
66
- );
67
- let dragStart: DragStart | null = null;
68
-
69
- function commit(next: number): void {
70
- storeSidePanelWidth(
71
- preferences,
72
- panel.id,
73
- clampSidePanelWidth(next, bounds),
74
- );
75
- }
76
-
77
- function startDrag(event: PointerEvent, renderedWidth: number): void {
78
- event.preventDefault();
79
- dragStart = { x: event.clientX, width: renderedWidth };
80
- dragWidth.value = clampSidePanelWidth(renderedWidth, bounds);
81
- }
82
-
83
- function drag(event: PointerEvent): void {
84
- if (dragStart === null) return;
85
- const next = dragStart.width + dragStart.x - event.clientX;
86
- dragWidth.value = clampSidePanelWidth(next, bounds);
87
- }
88
-
89
- function endDrag(): void {
90
- if (dragStart === null) return;
91
- dragStart = null;
92
- commit(width.value);
93
- dragWidth.value = null;
94
- }
95
-
96
- function resizeFromKey(event: KeyboardEvent): void {
97
- const step = KEYBOARD_STEPS[event.key];
98
- if (!step) return;
99
- event.preventDefault();
100
- commit(step(width.value, bounds));
101
- }
44
+ const resizable = useResizableSize({
45
+ side: "right",
46
+ bounds: {
47
+ defaultSize: bounds.defaultWidth,
48
+ minSize: bounds.minWidth,
49
+ maxSize: bounds.maxWidth,
50
+ },
51
+ storage: {
52
+ read: () => readSidePanelPreferences(preferences.value).widths[panel.id],
53
+ write: (width) =>
54
+ storeSidePanelWidth(
55
+ preferences,
56
+ panel.id,
57
+ width ?? bounds.defaultWidth,
58
+ ),
59
+ },
60
+ liveSize: useSidePanelDragWidth(),
61
+ });
102
62
 
103
63
  return {
104
- width,
64
+ // The panel always has a default width: its size is never natural.
65
+ width: computed(() => resizable.size.value ?? bounds.defaultWidth),
105
66
  bounds,
106
- isDragging: computed(() => dragWidth.value !== null),
107
- startDrag,
108
- drag,
109
- endDrag,
110
- resizeFromKey,
111
- reset: () => commit(bounds.defaultWidth),
67
+ isDragging: resizable.isDragging,
68
+ startDrag: resizable.startDrag,
69
+ drag: resizable.drag,
70
+ endDrag: resizable.endDrag,
71
+ resizeFromKey: (event) => resizable.resizeFromKey(event),
72
+ reset: resizable.reset,
112
73
  };
113
74
  }
@@ -28,12 +28,22 @@ function writeStorage(key: string, value: string): void {
28
28
  * Which groups of the preferences matrix are open. A group starts folded,
29
29
  * so the page opens short and each group row's count sums it up; the state
30
30
  * the viewer picks is kept per group in this browser.
31
+ *
32
+ * The kept state is read once mounted: the server cannot see it, so the
33
+ * server render and the browser hydrating it both draw every group folded,
34
+ * and a kept group opens right after (reading it in setup left the
35
+ * collapsible open on one side and folded on the other).
31
36
  */
32
37
  export const useNotificationGroupsOpen = () => {
33
38
  const picked = ref<Record<string, boolean>>({});
39
+ const isMounted = ref(false);
40
+ onMounted(() => {
41
+ isMounted.value = true;
42
+ });
34
43
 
35
44
  const isOpen = (categoryId: string): boolean =>
36
- picked.value[categoryId] ?? readStorage(storageKey(categoryId)) === OPEN;
45
+ picked.value[categoryId] ??
46
+ (isMounted.value && readStorage(storageKey(categoryId)) === OPEN);
37
47
 
38
48
  const toggleOpen = (categoryId: string) => {
39
49
  const open = !isOpen(categoryId);
@@ -1,5 +1,13 @@
1
+ import { type Ref, watch } from "vue";
2
+ import {
3
+ type CrossTabEnvironment,
4
+ shareAcrossTabs,
5
+ } from "#dms-core/app/build/utils/crossTab";
6
+
1
7
  const RELOAD_EVENT_NAME = "reload";
2
8
  const REOPEN_DELAY_MS = 2000;
9
+ const SHARED_STREAM_NAME_PREFIX = "dms-dev-reload";
10
+ const RELOAD_MESSAGE = "reload";
3
11
 
4
12
  export interface DevReloadStreamOptions {
5
13
  endpoint: string;
@@ -78,3 +86,76 @@ export function openDevReloadStream(
78
86
  },
79
87
  };
80
88
  }
89
+
90
+ /**
91
+ * The `reload` stream of every tab of the browser, held by one of them: a
92
+ * stream per tab would take one of the browser's six HTTP/1.1 connections to
93
+ * the dev server each. When the holding tab goes, another one opens it.
94
+ */
95
+ export function openSharedDevReloadStream(
96
+ options: DevReloadStreamOptions,
97
+ environment?: CrossTabEnvironment,
98
+ ): DevReloadStream {
99
+ const leave = shareAcrossTabs(
100
+ `${SHARED_STREAM_NAME_PREFIX}:${options.endpoint}`,
101
+ (emit) =>
102
+ openDevReloadStream({
103
+ endpoint: options.endpoint,
104
+ onReload: () => emit(RELOAD_MESSAGE),
105
+ }).close,
106
+ (message) => {
107
+ if (message === RELOAD_MESSAGE) options.onReload();
108
+ },
109
+ environment,
110
+ );
111
+ return { close: leave };
112
+ }
113
+
114
+ /** The user's realtime connection, as far as the reload signal goes. */
115
+ export interface DevReloadCarrier {
116
+ /**
117
+ * The topic the open connection carries the reload signal under, as the
118
+ * backend named it; unset while it carries none.
119
+ */
120
+ devReloadTopic: Ref<string | undefined>;
121
+ subscribe: (topic: string, handler: () => void) => () => void;
122
+ }
123
+
124
+ /**
125
+ * Follows the backend's reloads over the user's realtime connection while it
126
+ * is open and carries them, and over the reload stream the browser's tabs
127
+ * share only while it does not (signed out, reconnecting): a tab adds no
128
+ * long-lived connection of its own to the six HTTP/1.1 allows per host.
129
+ */
130
+ export function followDevReload(
131
+ options: DevReloadStreamOptions,
132
+ carrier: DevReloadCarrier,
133
+ environment?: CrossTabEnvironment,
134
+ ): DevReloadStream {
135
+ let stream: DevReloadStream | undefined;
136
+ let unsubscribe: (() => void) | undefined;
137
+ const stopWatching = watch(
138
+ carrier.devReloadTopic,
139
+ (topic) => {
140
+ unsubscribe?.();
141
+ unsubscribe = undefined;
142
+ if (topic) {
143
+ unsubscribe = carrier.subscribe(topic, () => options.onReload());
144
+ stream?.close();
145
+ stream = undefined;
146
+ return;
147
+ }
148
+ stream ??= openSharedDevReloadStream(options, environment);
149
+ },
150
+ { immediate: true },
151
+ );
152
+ return {
153
+ close: () => {
154
+ stopWatching();
155
+ unsubscribe?.();
156
+ unsubscribe = undefined;
157
+ stream?.close();
158
+ stream = undefined;
159
+ },
160
+ };
161
+ }
@@ -1,5 +1,5 @@
1
1
  /** The DMS repository on GitHub, as `owner/name`. */
2
- export const GITHUB_REPOSITORY = "AntelopeJS/dms";
2
+ const GITHUB_REPOSITORY = "AntelopeJS/dms";
3
3
 
4
- /** Opened by the auth footer's star button and by the dashboard's star prompt. */
4
+ /** Opened by the dashboard's star prompt. */
5
5
  export const GITHUB_REPOSITORY_URL = `https://github.com/${GITHUB_REPOSITORY}`;