@antelopejs/dms 0.8.3 → 0.9.1

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 (424) hide show
  1. package/CHANGELOG.md +36 -0
  2. package/data/module-store/catalog.json +71 -0
  3. package/dist/config.d.ts +7 -0
  4. package/dist/config.js +8 -0
  5. package/dist/config.js.map +1 -1
  6. package/dist/implementations/dms/frontend-backend-proxies.d.ts +3 -0
  7. package/dist/implementations/dms/frontend-backend-proxies.js +39 -0
  8. package/dist/implementations/dms/frontend-backend-proxies.js.map +1 -0
  9. package/dist/implementations/dms/frontend-bootstrap.d.ts +1 -0
  10. package/dist/implementations/dms/frontend-bootstrap.js +13 -0
  11. package/dist/implementations/dms/frontend-bootstrap.js.map +1 -1
  12. package/dist/implementations/dms/frontend-modules.d.ts +6 -2
  13. package/dist/implementations/dms/frontend-modules.js +37 -8
  14. package/dist/implementations/dms/frontend-modules.js.map +1 -1
  15. package/dist/implementations/dms/frontend-ready.d.ts +8 -0
  16. package/dist/implementations/dms/frontend-ready.js +34 -0
  17. package/dist/implementations/dms/frontend-ready.js.map +1 -0
  18. package/dist/implementations/dms/manifest.d.ts +7 -0
  19. package/dist/implementations/dms/manifest.js +13 -0
  20. package/dist/implementations/dms/manifest.js.map +1 -1
  21. package/dist/implementations/dms/menu-categories.d.ts +16 -0
  22. package/dist/implementations/dms/menu-categories.js +30 -0
  23. package/dist/implementations/dms/menu-categories.js.map +1 -0
  24. package/dist/implementations/dms/nav-badges.d.ts +0 -8
  25. package/dist/implementations/dms/nav-badges.js +0 -16
  26. package/dist/implementations/dms/nav-badges.js.map +1 -1
  27. package/dist/implementations/dms/page.d.ts +13 -5
  28. package/dist/implementations/dms/page.js +72 -41
  29. package/dist/implementations/dms/page.js.map +1 -1
  30. package/dist/implementations/dms-html-render/index.js +5 -2
  31. package/dist/implementations/dms-html-render/index.js.map +1 -1
  32. package/dist/implementations/dms-notifications/index.d.ts +4 -3
  33. package/dist/implementations/dms-notifications/index.js +14 -6
  34. package/dist/implementations/dms-notifications/index.js.map +1 -1
  35. package/dist/pages/settings/settings-index.js +3 -2
  36. package/dist/pages/settings/settings-index.js.map +1 -1
  37. package/dist/pages/settings/users/invites.js +2 -2
  38. package/dist/pages/settings/users/invites.js.map +1 -1
  39. package/dist/pages/settings/users/member-change-notifications.js +17 -6
  40. package/dist/pages/settings/users/member-change-notifications.js.map +1 -1
  41. package/dist/pages/settings/users/member-invite-form.d.ts +3 -2
  42. package/dist/pages/settings/users/member-invite-form.js +7 -4
  43. package/dist/pages/settings/users/member-invite-form.js.map +1 -1
  44. package/dist/pages/settings/users/member-roles-field.js +2 -1
  45. package/dist/pages/settings/users/member-roles-field.js.map +1 -1
  46. package/dist/pages/settings/users/members.js +4 -1
  47. package/dist/pages/settings/users/members.js.map +1 -1
  48. package/dist/pages/settings/users/notifications.d.ts +6 -0
  49. package/dist/pages/settings/users/notifications.js +23 -15
  50. package/dist/pages/settings/users/notifications.js.map +1 -1
  51. package/dist/pages/settings/users/profile.js +1 -1
  52. package/dist/pages/settings/users/profile.js.map +1 -1
  53. package/dist/pages/settings/users/region-form.d.ts +1 -1
  54. package/dist/pages/settings/users/region-form.js +2 -1
  55. package/dist/pages/settings/users/region-form.js.map +1 -1
  56. package/dist/pages/settings/users/role-editor-store.d.ts +3 -1
  57. package/dist/pages/settings/users/role-editor-store.js +17 -4
  58. package/dist/pages/settings/users/role-editor-store.js.map +1 -1
  59. package/dist/pages/settings/users/roles.js +1 -0
  60. package/dist/pages/settings/users/roles.js.map +1 -1
  61. package/dist/realtime/registry.d.ts +1 -0
  62. package/dist/realtime/registry.js +5 -0
  63. package/dist/realtime/registry.js.map +1 -1
  64. package/dist/routes/index.d.ts +1 -0
  65. package/dist/routes/index.js +1 -0
  66. package/dist/routes/index.js.map +1 -1
  67. package/dist/routes/realtime.d.ts +5 -1
  68. package/dist/routes/realtime.js +16 -9
  69. package/dist/routes/realtime.js.map +1 -1
  70. package/dist/routes/store.d.ts +21 -0
  71. package/dist/routes/store.js +130 -0
  72. package/dist/routes/store.js.map +1 -0
  73. package/dist/store/activity.d.ts +2 -0
  74. package/dist/store/activity.js +12 -0
  75. package/dist/store/activity.js.map +1 -0
  76. package/dist/store/cache.d.ts +8 -0
  77. package/dist/store/cache.js +29 -0
  78. package/dist/store/cache.js.map +1 -0
  79. package/dist/store/catalog.d.ts +4 -0
  80. package/dist/store/catalog.js +69 -0
  81. package/dist/store/catalog.js.map +1 -0
  82. package/dist/store/compatibility.d.ts +3 -0
  83. package/dist/store/compatibility.js +45 -0
  84. package/dist/store/compatibility.js.map +1 -0
  85. package/dist/store/declarations.d.ts +18 -0
  86. package/dist/store/declarations.js +116 -0
  87. package/dist/store/declarations.js.map +1 -0
  88. package/dist/store/frontend-compatibility.d.ts +18 -0
  89. package/dist/store/frontend-compatibility.js +93 -0
  90. package/dist/store/frontend-compatibility.js.map +1 -0
  91. package/dist/store/interfaces.d.ts +6 -0
  92. package/dist/store/interfaces.js +126 -0
  93. package/dist/store/interfaces.js.map +1 -0
  94. package/dist/store/listing.d.ts +2 -0
  95. package/dist/store/listing.js +180 -0
  96. package/dist/store/listing.js.map +1 -0
  97. package/dist/store/operations.d.ts +8 -0
  98. package/dist/store/operations.js +254 -0
  99. package/dist/store/operations.js.map +1 -0
  100. package/dist/store/registry.d.ts +4 -0
  101. package/dist/store/registry.js +61 -0
  102. package/dist/store/registry.js.map +1 -0
  103. package/dist/store/requirements.d.ts +14 -0
  104. package/dist/store/requirements.js +81 -0
  105. package/dist/store/requirements.js.map +1 -0
  106. package/dist/store/runtime.d.ts +11 -0
  107. package/dist/store/runtime.js +78 -0
  108. package/dist/store/runtime.js.map +1 -0
  109. package/dist/store/tarball.d.ts +2 -0
  110. package/dist/store/tarball.js +80 -0
  111. package/dist/store/tarball.js.map +1 -0
  112. package/dist/store/types.d.ts +98 -0
  113. package/dist/store/types.js +3 -0
  114. package/dist/store/types.js.map +1 -0
  115. package/dist/test/integration/account-deletion.test.js +2 -2
  116. package/dist/test/integration/account-deletion.test.js.map +1 -1
  117. package/dist/test/integration/auth/auth-key-rotation.test.js +2 -1
  118. package/dist/test/integration/auth/auth-key-rotation.test.js.map +1 -1
  119. package/dist/test/integration/auth/current-password.test.js +2 -1
  120. package/dist/test/integration/auth/current-password.test.js.map +1 -1
  121. package/dist/test/integration/auth/session-revocation.test.js +2 -1
  122. package/dist/test/integration/auth/session-revocation.test.js.map +1 -1
  123. package/dist/test/integration/auth/sign-in-country.test.js +2 -1
  124. package/dist/test/integration/auth/sign-in-country.test.js.map +1 -1
  125. package/dist/test/integration/auth/two-factor-codes.test.js +2 -1
  126. package/dist/test/integration/auth/two-factor-codes.test.js.map +1 -1
  127. package/dist/test/integration/auth/two-factor-password.test.js +3 -2
  128. package/dist/test/integration/auth/two-factor-password.test.js.map +1 -1
  129. package/dist/test/integration/email-change.test.js +2 -1
  130. package/dist/test/integration/email-change.test.js.map +1 -1
  131. package/dist/test/integration/files/component-files.test.js +2 -2
  132. package/dist/test/integration/files/component-files.test.js.map +1 -1
  133. package/dist/test/integration/member-settings-access.test.js +8 -7
  134. package/dist/test/integration/member-settings-access.test.js.map +1 -1
  135. package/dist/test/integration/menu-access-events.test.d.ts +1 -0
  136. package/dist/test/integration/menu-access-events.test.js +148 -0
  137. package/dist/test/integration/menu-access-events.test.js.map +1 -0
  138. package/dist/test/integration/notification-inbox.test.js +4 -1
  139. package/dist/test/integration/notification-inbox.test.js.map +1 -1
  140. package/dist/test/integration/notification-locked-subjects.test.js +3 -2
  141. package/dist/test/integration/notification-locked-subjects.test.js.map +1 -1
  142. package/dist/test/integration/notification-unread-badge.test.js +51 -5
  143. package/dist/test/integration/notification-unread-badge.test.js.map +1 -1
  144. package/dist/test/integration/page-layout-route-guard.test.d.ts +1 -0
  145. package/dist/test/integration/page-layout-route-guard.test.js +56 -0
  146. package/dist/test/integration/page-layout-route-guard.test.js.map +1 -0
  147. package/dist/test/integration/permission-warnings.test.js +3 -2
  148. package/dist/test/integration/permission-warnings.test.js.map +1 -1
  149. package/dist/test/integration/removed-member-notifications.test.js +3 -2
  150. package/dist/test/integration/removed-member-notifications.test.js.map +1 -1
  151. package/dist/test/integration/role-delete-reassign.test.js +2 -1
  152. package/dist/test/integration/role-delete-reassign.test.js.map +1 -1
  153. package/dist/test/integration/role-permission-ancestors.test.js +2 -1
  154. package/dist/test/integration/role-permission-ancestors.test.js.map +1 -1
  155. package/dist/test/unit/frontend-bootstrap.test.js +13 -0
  156. package/dist/test/unit/frontend-bootstrap.test.js.map +1 -1
  157. package/dist/test/unit/implementations/dms/category-slug-registry.test.js +14 -5
  158. package/dist/test/unit/implementations/dms/category-slug-registry.test.js.map +1 -1
  159. package/dist/test/unit/implementations/dms/frontend-backend-proxies.test.d.ts +1 -0
  160. package/dist/test/unit/implementations/dms/frontend-backend-proxies.test.js +66 -0
  161. package/dist/test/unit/implementations/dms/frontend-backend-proxies.test.js.map +1 -0
  162. package/dist/test/unit/implementations/dms/manifest-strip.test.js +26 -0
  163. package/dist/test/unit/implementations/dms/manifest-strip.test.js.map +1 -1
  164. package/dist/test/unit/implementations/dms/nav-badges.test.js +23 -9
  165. package/dist/test/unit/implementations/dms/nav-badges.test.js.map +1 -1
  166. package/dist/test/unit/implementations/dms-html-render/generate-html.test.js +22 -4
  167. package/dist/test/unit/implementations/dms-html-render/generate-html.test.js.map +1 -1
  168. package/dist/test/unit/interfaces/dms/page-layout-query.test.js +12 -0
  169. package/dist/test/unit/interfaces/dms/page-layout-query.test.js.map +1 -1
  170. package/dist/test/unit/interfaces/dms/page-teardown.test.js +1 -1
  171. package/dist/test/unit/interfaces/dms/page-teardown.test.js.map +1 -1
  172. package/dist/test/unit/pages/settings/member-roles-field.test.js +1 -1
  173. package/dist/test/unit/pages/settings/member-roles-field.test.js.map +1 -1
  174. package/dist/test/unit/pages/settings/role-delete-confirm.test.js.map +1 -1
  175. package/dist/test/unit/realtime/menu-topics.test.d.ts +1 -0
  176. package/dist/test/unit/realtime/menu-topics.test.js +26 -0
  177. package/dist/test/unit/realtime/menu-topics.test.js.map +1 -0
  178. package/dist/test/unit/store/store.test.d.ts +1 -0
  179. package/dist/test/unit/store/store.test.js +127 -0
  180. package/dist/test/unit/store/store.test.js.map +1 -0
  181. package/dist/validation/store.schema.d.ts +39 -0
  182. package/dist/validation/store.schema.js +27 -0
  183. package/dist/validation/store.schema.js.map +1 -0
  184. package/frontend-vue/deferred-plugins.ts +3 -4
  185. package/frontend-vue/dms.email.ts +5 -1
  186. package/frontend-vue/dms.frontend.ts +15 -5
  187. package/frontend-vue/dms.server.ts +74 -0
  188. package/frontend-vue/layers/dms-auth/app/composables/useLogout.ts +1 -1
  189. package/frontend-vue/layers/dms-auth/app/composables/usePostLoginRedirect.ts +16 -3
  190. package/frontend-vue/layers/dms-auth/app/custom-pages/auth/2fa.vue +3 -1
  191. package/frontend-vue/layers/dms-auth/app/custom-pages/auth/backup.vue +3 -1
  192. package/frontend-vue/layers/dms-auth/app/custom-pages/auth/forgot-validation.vue +1 -1
  193. package/frontend-vue/layers/dms-auth/app/custom-pages/auth/oauth-complete.vue +26 -3
  194. package/frontend-vue/layers/dms-auth/app/custom-pages/auth/recover.vue +1 -1
  195. package/frontend-vue/layers/dms-auth/app/custom-pages/auth/signup.vue +22 -25
  196. package/frontend-vue/layers/dms-auth/app/custom-pages/auth/validate.vue +1 -1
  197. package/frontend-vue/layers/dms-auth/app/middleware/auth.ts +5 -7
  198. package/frontend-vue/layers/dms-auth/app/plugins/permissions-preload.ts +17 -0
  199. package/frontend-vue/layers/dms-auth/server/accounts.ts +135 -0
  200. package/frontend-vue/layers/dms-auth/server/actions.ts +251 -0
  201. package/frontend-vue/layers/dms-auth/server/oauth.ts +260 -0
  202. package/frontend-vue/layers/dms-auth/server/session.ts +158 -0
  203. package/frontend-vue/layers/dms-core/app/build/utils/asyncDataScope.ts +47 -0
  204. package/frontend-vue/layers/dms-core/app/build/utils/permission-preview.ts +6 -2
  205. package/frontend-vue/layers/dms-core/app/composables/auth/useApiData.ts +148 -0
  206. package/frontend-vue/layers/dms-core/app/composables/auth/useAuthFetch.ts +7 -20
  207. package/frontend-vue/layers/dms-core/app/composables/auth/useCurrentUser.ts +2 -2
  208. package/frontend-vue/layers/dms-core/app/composables/auth/useMultiAccount.ts +18 -5
  209. package/frontend-vue/layers/dms-core/app/composables/auth/usePermissions.ts +35 -6
  210. package/frontend-vue/layers/dms-core/app/composables/auth/useSessionRecovery.ts +1 -1
  211. package/frontend-vue/layers/dms-core/app/composables/period/compareResolvers.ts +20 -14
  212. package/frontend-vue/layers/dms-core/app/composables/period/periodClock.ts +121 -0
  213. package/frontend-vue/layers/dms-core/app/composables/period/periodRenderNow.ts +42 -0
  214. package/frontend-vue/layers/dms-core/app/composables/period/periodTimeZone.ts +31 -0
  215. package/frontend-vue/layers/dms-core/app/composables/period/presetResolvers.ts +48 -19
  216. package/frontend-vue/layers/dms-core/app/composables/period/usePeriod.ts +33 -4
  217. package/frontend-vue/layers/dms-core/app/composables/period/usePeriodScope.ts +78 -25
  218. package/frontend-vue/layers/dms-core/app/composables/realtime/usePageRealtime.ts +3 -0
  219. package/frontend-vue/layers/dms-core/app/composables/realtime/useUserRealtime.ts +36 -6
  220. package/frontend-vue/layers/dms-core/app/composables/user/useUserRegionalPreferences.ts +1 -1
  221. package/frontend-vue/layers/dms-core/app/plugins/async-data-scope.ts +26 -0
  222. package/frontend-vue/layers/dms-core/app/utils/pageRoutes.ts +22 -0
  223. package/frontend-vue/layers/dms-core/app/utils/regional.ts +36 -3
  224. package/frontend-vue/layers/dms-core/app/utils/trailingDeduper.ts +10 -1
  225. package/frontend-vue/layers/dms-core/shared/types/app-config.ts +48 -4
  226. package/frontend-vue/layers/dms-layout/app/app.config.ts +42 -23
  227. package/frontend-vue/layers/dms-layout/app/assets/css/main.css +72 -20
  228. package/frontend-vue/layers/dms-layout/app/build/components/layout/DashboardFrame.vue +9 -0
  229. package/frontend-vue/layers/dms-layout/app/build/components/layout/DashboardSidebar.vue +0 -3
  230. package/frontend-vue/layers/dms-layout/app/build/components/notification/NotificationPopover.vue +9 -3
  231. package/frontend-vue/layers/dms-layout/app/build/components/pages/modules/ModuleStoreDependencyPicker.vue +136 -0
  232. package/frontend-vue/layers/dms-layout/app/build/components/pages/modules/ModuleStoreRequirements.vue +98 -0
  233. package/frontend-vue/layers/dms-layout/app/build/components/pages/modules/ModuleStoreTile.vue +247 -29
  234. package/frontend-vue/layers/dms-layout/app/build/components/pages/modules/ModuleTile.vue +19 -2
  235. package/frontend-vue/layers/dms-layout/app/build/components/pages/settings/members/MemberRolePicker.vue +13 -12
  236. package/frontend-vue/layers/dms-layout/app/build/components/pages/settings/notification/NotificationInboxDisplay.vue +17 -7
  237. package/frontend-vue/layers/dms-layout/app/build/components/pages/settings/notification/NotificationPreferencesForm.vue +0 -1
  238. package/frontend-vue/layers/dms-layout/app/build/components/pages/settings/profile/ProfilePersonalInfo.vue +36 -33
  239. package/frontend-vue/layers/dms-layout/app/build/components/pages/settings/profile/ProfileSecuritySummary.vue +1 -2
  240. package/frontend-vue/layers/dms-layout/app/build/components/pages/settings/roles/role-types.ts +5 -4
  241. package/frontend-vue/layers/dms-layout/app/build/components/pages/settings/security/SecuritySessions.vue +35 -28
  242. package/frontend-vue/layers/dms-layout/app/build/components/pages/settings/security/SecurityStatus.vue +0 -1
  243. package/frontend-vue/layers/dms-layout/app/build/components/pages/settings/security/SecurityTwoFactor.vue +1 -1
  244. package/frontend-vue/layers/dms-layout/app/build/composables/dev-reload/useDevReloadHolder.ts +7 -6
  245. package/frontend-vue/layers/dms-layout/app/build/composables/layout/sidePanelState.ts +1 -1
  246. package/frontend-vue/layers/dms-layout/app/build/composables/navigation/useVisitNavBadges.ts +26 -0
  247. package/frontend-vue/layers/dms-layout/app/build/composables/notification/useNotificationCatalog.ts +25 -23
  248. package/frontend-vue/layers/dms-layout/app/build/composables/notification/useNotificationPreferences.ts +44 -23
  249. package/frontend-vue/layers/dms-layout/app/build/composables/security/useSessionHandoff.ts +1 -1
  250. package/frontend-vue/layers/dms-layout/app/build/composables/settings/profile/preferencesSummary.ts +1 -1
  251. package/frontend-vue/layers/dms-layout/app/build/composables/settings/profile/useAccountData.ts +3 -2
  252. package/frontend-vue/layers/dms-layout/app/build/composables/settings/profile/useProfileAvatar.ts +1 -18
  253. package/frontend-vue/layers/dms-layout/app/build/composables/settings/profile/useProfilePreferences.ts +19 -23
  254. package/frontend-vue/layers/dms-layout/app/build/composables/settings/security/useSecurityFormat.ts +6 -3
  255. package/frontend-vue/layers/dms-layout/app/build/composables/settings/security/useSecurityOverview.ts +13 -18
  256. package/frontend-vue/layers/dms-layout/app/build/utils/module-store-catalog.ts +186 -120
  257. package/frontend-vue/layers/dms-layout/app/build/utils/module-store-install.ts +146 -0
  258. package/frontend-vue/layers/dms-layout/app/build/utils/modules-catalog.ts +8 -6
  259. package/frontend-vue/layers/dms-layout/app/build/utils/publicErrorMessage.ts +19 -0
  260. package/frontend-vue/layers/dms-layout/app/components/navigation/CollapsedMenuItem.vue +0 -11
  261. package/frontend-vue/layers/dms-layout/app/components/navigation/NavigationMenu.vue +3 -13
  262. package/frontend-vue/layers/dms-layout/app/composables/general/useSystemState.ts +7 -11
  263. package/frontend-vue/layers/dms-layout/app/composables/notification/useNotifications.ts +103 -22
  264. package/frontend-vue/layers/dms-layout/app/composables/page/useModuleStore.ts +109 -0
  265. package/frontend-vue/layers/dms-layout/app/composables/page/useModulesListing.ts +25 -102
  266. package/frontend-vue/layers/dms-layout/app/composables/page/usePageComponentPreload.ts +0 -10
  267. package/frontend-vue/layers/dms-layout/app/composables/page/useSiteLayout.ts +177 -96
  268. package/frontend-vue/layers/dms-layout/app/composables/profile/useUserLanguage.ts +3 -2
  269. package/frontend-vue/layers/dms-layout/app/custom-pages/modules.vue +341 -62
  270. package/frontend-vue/layers/dms-layout/app/emails/components/EmailLayout.vue +31 -11
  271. package/frontend-vue/layers/dms-layout/app/error.vue +5 -2
  272. package/frontend-vue/layers/dms-layout/app/middleware/module-routing.global.ts +1 -1
  273. package/frontend-vue/layers/dms-layout/app/middleware/page-leave-guard.global.ts +2 -2
  274. package/frontend-vue/layers/dms-layout/app/pages/[...slug].vue +12 -9
  275. package/frontend-vue/layers/dms-layout/app/plugins/dms-menu-sync.client.ts +31 -3
  276. package/frontend-vue/layers/dms-layout/app/plugins/favicon.ts +58 -0
  277. package/frontend-vue/layers/dms-layout/app/plugins/notification-stream.client.ts +15 -7
  278. package/frontend-vue/layers/dms-layout/app/plugins/profile-sync.client.ts +5 -1
  279. package/frontend-vue/layers/dms-layout/app/plugins/regional-preferences.ts +10 -4
  280. package/frontend-vue/layers/dms-layout/app/plugins/time-zone-cookie.client.ts +12 -0
  281. package/frontend-vue/layers/dms-layout/app/types/module-store.ts +134 -0
  282. package/frontend-vue/layers/dms-layout/app/types/page.ts +13 -0
  283. package/frontend-vue/layers/dms-layout/i18n/locales/layout-en-GB.json +107 -9
  284. package/frontend-vue/layers/dms-layout/i18n/locales/layout-fr-FR.json +107 -9
  285. package/frontend-vue/layers/dms-layout/server/html-render.ts +58 -0
  286. package/frontend-vue/layers/dms-layout/server/render-token.ts +95 -0
  287. package/frontend-vue/layers/dms-onboarding/app/composables/onboarding/useOnboarding.ts +25 -21
  288. package/frontend-vue/layers/dms-onboarding/app/middleware/onboarding.global.ts +1 -1
  289. package/frontend-vue/layers/dms-onboarding/app/plugins/onboarding-preload.ts +9 -0
  290. package/frontend-vue/layers/dms-ui/app/build/composables/data-types/registerDefaults.ts +4 -1
  291. package/frontend-vue/layers/dms-ui/app/build/composables/files/useFileMetadata.ts +162 -0
  292. package/frontend-vue/layers/dms-ui/app/build/composables/form/formRecordLoad.ts +23 -4
  293. package/frontend-vue/layers/dms-ui/app/build/composables/live/usePageDataRefresh.ts +101 -0
  294. package/frontend-vue/layers/dms-ui/app/build/composables/navigation/useNavBadges.ts +33 -6
  295. package/frontend-vue/layers/dms-ui/app/build/composables/period/periodDisplay.ts +19 -16
  296. package/frontend-vue/layers/dms-ui/app/build/composables/period/periodQuery.ts +40 -20
  297. package/frontend-vue/layers/dms-ui/app/build/composables/table-view/useTableFooter.ts +6 -8
  298. package/frontend-vue/layers/dms-ui/app/build/composables/table-view/useTableListData.ts +42 -14
  299. package/frontend-vue/layers/dms-ui/app/build/composables/table-view/useTableRows.ts +19 -8
  300. package/frontend-vue/layers/dms-ui/app/build/composables/table-view/useTableViews.ts +1 -1
  301. package/frontend-vue/layers/dms-ui/app/components/chart/ChartCard.vue +5 -2
  302. package/frontend-vue/layers/dms-ui/app/components/flow-canvas/FlowCanvas.vue +9 -9
  303. package/frontend-vue/layers/dms-ui/app/components/form/Form.vue +20 -18
  304. package/frontend-vue/layers/dms-ui/app/components/form/components/Cascader.vue +2 -1
  305. package/frontend-vue/layers/dms-ui/app/components/form/components/File.vue +26 -132
  306. package/frontend-vue/layers/dms-ui/app/components/form/components/Image.vue +40 -105
  307. package/frontend-vue/layers/dms-ui/app/components/form/components/InputAddress.vue +2 -0
  308. package/frontend-vue/layers/dms-ui/app/components/form/components/Relation.vue +4 -4
  309. package/frontend-vue/layers/dms-ui/app/components/period/PeriodSelector.vue +9 -13
  310. package/frontend-vue/layers/dms-ui/app/components/table-view/CascaderPath.vue +2 -1
  311. package/frontend-vue/layers/dms-ui/app/components/table-view/FilePreview.vue +12 -24
  312. package/frontend-vue/layers/dms-ui/app/components/table-view/ImagePreview.vue +17 -29
  313. package/frontend-vue/layers/dms-ui/app/components/table-view/KanbanBoard.vue +7 -3
  314. package/frontend-vue/layers/dms-ui/app/components/table-view/TableView.vue +20 -8
  315. package/frontend-vue/layers/dms-ui/app/components/top-list/TopListCard.vue +8 -11
  316. package/frontend-vue/layers/dms-ui/app/composables/chart/useChartFetch.ts +146 -182
  317. package/frontend-vue/layers/dms-ui/app/composables/live/usePageLiveRefresh.ts +8 -2
  318. package/frontend-vue/layers/dms-ui/app/composables/useFileReadUrls.ts +11 -99
  319. package/frontend-vue/layers/dms-ui/app/utils/blockRefresh.ts +32 -3
  320. package/frontend-vue/package.json +3 -3
  321. package/frontend-vue/pnpm-lock.yaml +16 -22
  322. package/frontend-vue/server/private-options.ts +27 -0
  323. package/frontend-vue/tests/async-data-scope.test.ts +121 -0
  324. package/frontend-vue/tests/auth-middleware-error.test.ts +3 -3
  325. package/frontend-vue/tests/banner-block-fetch.test.ts +3 -0
  326. package/frontend-vue/tests/block-fetch-options-forwarding.test.ts +3 -0
  327. package/frontend-vue/tests/block-items-period-realtime.test.ts +3 -0
  328. package/frontend-vue/tests/block-not-found.test.ts +16 -2
  329. package/frontend-vue/tests/block-page-refresh.test.ts +3 -0
  330. package/frontend-vue/tests/block-route-params.test.ts +3 -0
  331. package/frontend-vue/tests/branding-defaults.test.ts +34 -0
  332. package/frontend-vue/tests/builtin-emails.test.ts +23 -2
  333. package/frontend-vue/tests/chart-live-pause.test.ts +4 -1
  334. package/frontend-vue/tests/chart-value-propagation.test.ts +4 -1
  335. package/frontend-vue/tests/composed-text-blocks.test.ts +3 -0
  336. package/frontend-vue/tests/email-layout.test.ts +66 -4
  337. package/frontend-vue/tests/error-page-message.test.ts +25 -2
  338. package/frontend-vue/tests/favicon.test.ts +131 -0
  339. package/frontend-vue/tests/file-fields-ssr.test.ts +145 -0
  340. package/frontend-vue/tests/file-read-urls.test.ts +145 -34
  341. package/frontend-vue/tests/file-unavailable.test.ts +5 -1
  342. package/frontend-vue/tests/fixtures/dataEngine.ts +44 -0
  343. package/frontend-vue/tests/form-load-error.test.ts +55 -1
  344. package/frontend-vue/tests/helpers/api-data-runtime.ts +77 -0
  345. package/frontend-vue/tests/image-hydration-ids.test.ts +21 -16
  346. package/frontend-vue/tests/image-reference-preservation.test.ts +59 -53
  347. package/frontend-vue/tests/input-number-adjust.test.ts +14 -0
  348. package/frontend-vue/tests/key-value-list-copy.test.ts +3 -0
  349. package/frontend-vue/tests/member-role-picker.test.ts +4 -2
  350. package/frontend-vue/tests/menu-sync-reconnect.test.ts +47 -0
  351. package/frontend-vue/tests/metadata-retry.test.ts +5 -1
  352. package/frontend-vue/tests/module-routing.test.ts +2 -5
  353. package/frontend-vue/tests/module-store-catalog.test.ts +270 -51
  354. package/frontend-vue/tests/modules-catalog.test.ts +17 -4
  355. package/frontend-vue/tests/modules-listing-transfer.test.ts +95 -0
  356. package/frontend-vue/tests/multi-account-validate.test.ts +23 -1
  357. package/frontend-vue/tests/nav-badge-tones.test.ts +66 -3
  358. package/frontend-vue/tests/notification-counts-from-writes.test.ts +223 -0
  359. package/frontend-vue/tests/notification-counts-transfer.test.ts +88 -0
  360. package/frontend-vue/tests/notification-inbox-display.test.ts +57 -5
  361. package/frontend-vue/tests/notification-popover-errors.test.ts +21 -1
  362. package/frontend-vue/tests/oauth-complete-handoff.test.ts +209 -0
  363. package/frontend-vue/tests/onboarding-middleware.test.ts +1 -1
  364. package/frontend-vue/tests/onboarding-transfer.test.ts +106 -0
  365. package/frontend-vue/tests/page-data-refresh.test.ts +141 -0
  366. package/frontend-vue/tests/page-fill-height.test.ts +16 -3
  367. package/frontend-vue/tests/page-no-visible-blocks.test.ts +12 -2
  368. package/frontend-vue/tests/page-realtime-remount.test.ts +1 -1
  369. package/frontend-vue/tests/page-record-label.test.ts +0 -7
  370. package/frontend-vue/tests/page-validation-redirect.test.ts +12 -2
  371. package/frontend-vue/tests/period-hydration-now.test.ts +185 -0
  372. package/frontend-vue/tests/period-live-pause.test.ts +3 -0
  373. package/frontend-vue/tests/period-reader-zone.test.ts +137 -0
  374. package/frontend-vue/tests/period-scope-first-fetch.test.ts +17 -1
  375. package/frontend-vue/tests/period-ssr.test.ts +195 -0
  376. package/frontend-vue/tests/permission-preview-partial.test.ts +0 -2
  377. package/frontend-vue/tests/permissions-transfer.test.ts +194 -0
  378. package/frontend-vue/tests/post-login-redirect.test.ts +10 -5
  379. package/frontend-vue/tests/profile-personal-info-ssr.test.ts +150 -0
  380. package/frontend-vue/tests/profile-preferences-summary.test.ts +15 -11
  381. package/frontend-vue/tests/realtime-reconnect.test.ts +22 -3
  382. package/frontend-vue/tests/roles-name-errors.test.ts +1 -1
  383. package/frontend-vue/tests/row-side-panel.test.ts +1 -1
  384. package/frontend-vue/tests/security-sessions-load-error.test.ts +3 -1
  385. package/frontend-vue/tests/server-routes-vs-pages.test.ts +26 -0
  386. package/frontend-vue/tests/server-routes.test.ts +582 -0
  387. package/frontend-vue/tests/session-handoff.test.ts +1 -1
  388. package/frontend-vue/tests/settings-reads-ssr.test.ts +232 -0
  389. package/frontend-vue/tests/side-panels.test.ts +8 -1
  390. package/frontend-vue/tests/sign-in-exit-history.test.ts +219 -0
  391. package/frontend-vue/tests/signup-invitation-link.test.ts +56 -8
  392. package/frontend-vue/tests/site-layout-categories.test.ts +42 -0
  393. package/frontend-vue/tests/site-layout-hydration.test.ts +3 -3
  394. package/frontend-vue/tests/site-layout-rendered.test.ts +103 -0
  395. package/frontend-vue/tests/site-layout-resync.test.ts +87 -0
  396. package/frontend-vue/tests/ssr-guard-preload.test.ts +188 -0
  397. package/frontend-vue/tests/table-cell-tones.test.ts +36 -1
  398. package/frontend-vue/tests/table-data-ssr.test.ts +195 -0
  399. package/frontend-vue/tests/table-list-data-requests.test.ts +154 -0
  400. package/frontend-vue/tests/table-retry-loading.test.ts +37 -0
  401. package/frontend-vue/tests/table-source-navigation.test.ts +0 -1
  402. package/frontend-vue/tests/table-source-period-scope.test.ts +0 -1
  403. package/frontend-vue/tests/table-view-views.test.ts +1 -1
  404. package/frontend-vue/tests/top-list-card-actions.test.ts +3 -0
  405. package/frontend-vue/tests/top-list-card-period-badge-ssr.test.ts +212 -0
  406. package/frontend-vue/tests/top-list-card-period-badge.test.ts +79 -0
  407. package/frontend-vue/tests/top-list-card-value-suffix.test.ts +3 -0
  408. package/frontend-vue/tests/trailing-deduper.test.ts +22 -0
  409. package/frontend-vue/tests/use-api-data-update.test.ts +119 -0
  410. package/frontend-vue/tests/use-api-data.test.ts +410 -0
  411. package/frontend-vue/tests/user-language.test.ts +8 -5
  412. package/frontend-vue/tests/widget-label-i18n.test.ts +4 -1
  413. package/frontend-vue/vitest.config.ts +6 -0
  414. package/package.json +2 -2
  415. package/skills/dms/SKILL.md +2 -1
  416. package/skills/dms-module/SKILL.md +1 -1
  417. package/skills/dms-pages/SKILL.md +4 -1
  418. package/frontend-vue/layers/dms-core/app/build/composables/page/usePageRecordLabel.ts +0 -9
  419. package/frontend-vue/layers/dms-layout/app/composables/page/usePrefetch.ts +0 -21
  420. package/frontend-vue/layers/dms-ui/app/build/composables/form/useControlError.ts +0 -10
  421. package/frontend-vue/layers/dms-ui/app/build/composables/table-view/useServerRenderedAsyncData.ts +0 -23
  422. package/frontend-vue/tests/control-error-path.test.ts +0 -11
  423. package/frontend-vue/tests/modules-listing-per-request.test.ts +0 -104
  424. package/frontend-vue/tests/page-layout-background-refresh.test.ts +0 -321
@@ -1,7 +1,11 @@
1
+ import { router as inertiaRouter } from "@inertiajs/vue3";
1
2
  import { layoutUrlWithQuery } from "../../utils/pageQuery";
3
+ import { onBeforeMount, toRaw } from "vue";
2
4
  import { withoutTrailingSlash } from "ufo";
3
5
 
4
6
  const STALE_THRESHOLD_MS = 300_000;
7
+ const SITE_LAYOUT_ENDPOINT = "/dms/sitelayout";
8
+ const RENDERED_SITE_LAYOUT_KEY = "dms-rendered-site-layout";
5
9
  const IN_FLIGHT_SITE_LAYOUT_KEY = "__dmsInFlightSiteLayout";
6
10
  const IN_FLIGHT_PAGE_LAYOUTS_KEY = "__dmsInFlightPageLayouts";
7
11
 
@@ -10,28 +14,35 @@ interface PageLayoutRequest {
10
14
  promise: Promise<PageLayout>;
11
15
  }
12
16
 
13
- function getCachedLayoutUrls(
14
- previousSite: SiteLayout | undefined,
15
- previousCache: Record<string, PageLayout>,
16
- nextSite: SiteLayout,
17
- ): string[] {
18
- const urls = Object.entries(previousSite?.pages ?? {}).flatMap(
19
- ([path, page]) => {
20
- const nextPage = nextSite.pages[path];
21
- return previousCache[page.layoutUrl] &&
22
- nextPage?.layoutUrl &&
23
- nextPage.hasAccess !== false
24
- ? [nextPage.layoutUrl]
25
- : [];
26
- },
27
- );
28
- return [...new Set(urls)];
29
- }
30
-
31
17
  interface MatchRouteOptions {
32
18
  includeCategories: boolean;
33
19
  }
34
20
 
21
+ // The categories a URL resolves against, by slug, per served layout: the
22
+ // layout lists them by full id, and a `urlTransparent` one answers at its
23
+ // parent's slug, so it is never a URL's target.
24
+ const navigableCategoriesByLayout = new WeakMap<
25
+ SiteLayout,
26
+ Map<string, CategoryInfo>
27
+ >();
28
+
29
+ /** The category of the layout a URL resolves to, by its slug. */
30
+ export function findNavigableCategory(
31
+ layout: SiteLayout,
32
+ slug: string,
33
+ ): CategoryInfo | undefined {
34
+ let bySlug = navigableCategoriesByLayout.get(layout);
35
+ if (!bySlug) {
36
+ bySlug = new Map(
37
+ Object.values(layout.categories)
38
+ .filter((category) => !category.urlTransparent)
39
+ .map((category) => [category.fullSlug, category]),
40
+ );
41
+ navigableCategoriesByLayout.set(layout, bySlug);
42
+ }
43
+ return bySlug.get(slug);
44
+ }
45
+
35
46
  interface MatchRouteResult {
36
47
  pattern: string;
37
48
  metadata: PageInfo | CategoryInfo;
@@ -99,24 +110,84 @@ export function extractRouteParams(
99
110
  return buildParamBag(paramNames, match.slice(1));
100
111
  }
101
112
 
113
+ /**
114
+ * A partial reload of the page on screen: the server sends the site layout
115
+ * and the page fresh, and they replace the browser's copies, the layout
116
+ * Inertia carries from page to page included. A failure rejects and leaves
117
+ * the page as it is: Inertia would otherwise show the error in its place.
118
+ */
119
+ function reloadSiteLayoutAndPage(): Promise<void> {
120
+ return new Promise((resolve, reject) => {
121
+ let failure: unknown;
122
+ inertiaRouter.reload({
123
+ only: ["shared", "page"],
124
+ onHttpException: (response) => {
125
+ failure = new Error(`Site layout reload failed (${response.status})`);
126
+ return false;
127
+ },
128
+ onNetworkError: (error) => {
129
+ failure = error;
130
+ return false;
131
+ },
132
+ onFinish: () => (failure ? reject(failure) : resolve()),
133
+ });
134
+ });
135
+ }
136
+
137
+ interface SiteLayoutResponse {
138
+ siteLayout: SiteLayout;
139
+ siteLayoutTree: SiteLayoutTree;
140
+ quickActions: QuickActionsPayload;
141
+ modules: Record<string, ModuleWithAccess>;
142
+ isOwner: boolean;
143
+ }
144
+
145
+ /** The shared site layout, as a page's props or `/dms/sitelayout` set it. */
146
+ function useSiteLayoutState() {
147
+ return {
148
+ siteLayout: useDmsState<SiteLayout | undefined>(
149
+ "dms-siteLayout",
150
+ () => undefined,
151
+ ),
152
+ siteLayoutTree: useDmsState<SiteLayoutTree | undefined>(
153
+ "dms-pageTree",
154
+ () => undefined,
155
+ ),
156
+ quickActions: useDmsState<QuickActionsPayload | undefined>(
157
+ "dms-quickActions",
158
+ () => undefined,
159
+ ),
160
+ modules: useDmsState<Record<string, ModuleWithAccess> | undefined>(
161
+ "dms-modules",
162
+ () => undefined,
163
+ ),
164
+ isOwner: useDmsState<boolean>("dms-isOwner", () => false),
165
+ lastRefreshTime: useDmsState<number>("dms-lastRefreshTime", () => 0),
166
+ };
167
+ }
168
+
169
+ function applySiteLayoutResponse(
170
+ state: ReturnType<typeof useSiteLayoutState>,
171
+ result: SiteLayoutResponse,
172
+ ): void {
173
+ state.siteLayout.value = result.siteLayout;
174
+ state.siteLayoutTree.value = result.siteLayoutTree;
175
+ state.quickActions.value = result.quickActions;
176
+ state.modules.value = result.modules;
177
+ state.isOwner.value = result.isOwner;
178
+ state.lastRefreshTime.value = Date.now();
179
+ }
180
+
102
181
  export const useSiteLayout = () => {
103
- const siteLayout = useDmsState<SiteLayout | undefined>(
104
- "dms-siteLayout",
105
- () => undefined,
106
- );
107
- const siteLayoutTree = useDmsState<SiteLayoutTree | undefined>(
108
- "dms-pageTree",
109
- () => undefined,
110
- );
111
- const quickActions = useDmsState<QuickActionsPayload | undefined>(
112
- "dms-quickActions",
113
- () => undefined,
114
- );
115
- const modules = useDmsState<Record<string, ModuleWithAccess> | undefined>(
116
- "dms-modules",
117
- () => undefined,
118
- );
119
- const isOwner = useDmsState<boolean>("dms-isOwner", () => false);
182
+ const state = useSiteLayoutState();
183
+ const {
184
+ siteLayout,
185
+ siteLayoutTree,
186
+ quickActions,
187
+ modules,
188
+ isOwner,
189
+ lastRefreshTime,
190
+ } = state;
120
191
 
121
192
  const isLoading = useDmsState<boolean>("dms-loading", () => false);
122
193
  const loadingError = useDmsState<string | null>("dms-error", () => null);
@@ -125,7 +196,6 @@ export const useSiteLayout = () => {
125
196
  "dms-pageLayouts",
126
197
  () => ({}),
127
198
  );
128
- const lastRefreshTime = useDmsState<number>("dms-lastRefreshTime", () => 0);
129
199
 
130
200
  // Held on the DMS app rather than in a per-call ref: every caller of
131
201
  // useSiteLayout writes the same shared layout state, so they have to see the
@@ -148,79 +218,40 @@ export const useSiteLayout = () => {
148
218
  },
149
219
  };
150
220
 
151
- interface SiteLayoutResponse {
152
- siteLayout: SiteLayout;
153
- siteLayoutTree: SiteLayoutTree;
154
- quickActions: QuickActionsPayload;
155
- modules: Record<string, ModuleWithAccess>;
156
- isOwner: boolean;
157
- }
158
-
159
- const SITE_LAYOUT_ENDPOINT = "/dms/sitelayout";
160
221
  const SITE_LAYOUT_ERROR_MESSAGE = "Error loading siteLayout";
161
222
  const UNKNOWN_SITE_LAYOUT_ERROR = "Unknown error loading siteLayout";
162
223
  const HTTP_INTERNAL_ERROR = 500;
163
224
 
164
- const applySiteLayoutResponse = (result: SiteLayoutResponse) => {
165
- siteLayout.value = result.siteLayout;
166
- siteLayoutTree.value = result.siteLayoutTree;
167
- quickActions.value = result.quickActions;
168
- modules.value = result.modules;
169
- isOwner.value = result.isOwner;
170
- lastRefreshTime.value = Date.now();
171
- };
172
-
173
225
  const handleSiteLayoutError = (error: unknown) => {
174
226
  const errorMessage =
175
227
  error instanceof Error ? error.message : UNKNOWN_SITE_LAYOUT_ERROR;
176
228
  loadingError.value = errorMessage;
177
- showError({
229
+ showDmsError({
178
230
  statusCode: HTTP_INTERNAL_ERROR,
179
231
  statusMessage: SITE_LAYOUT_ERROR_MESSAGE,
180
232
  message: errorMessage,
181
233
  });
182
234
  };
183
235
 
184
- const requestSiteLayout = async (fatal: boolean): Promise<boolean> => {
236
+ const requestSiteLayout = async (): Promise<boolean> => {
185
237
  const initialLayout = siteLayout.value;
186
238
  const initialCache = pageLayouts.value;
239
+ // A layout another request committed meanwhile is newer than this one.
187
240
  const isCurrent = () =>
188
241
  siteLayout.value === initialLayout && pageLayouts.value === initialCache;
189
242
  const { $authFetch } = useAuthFetch();
190
243
  try {
191
244
  const result = await $authFetch<SiteLayoutResponse>(SITE_LAYOUT_ENDPOINT);
192
- const nextCache: Record<string, PageLayout> = {};
193
- // Initial page loads mutate this cache in place; identity guards cannot detect those additions.
194
- while (isCurrent()) {
195
- const urls = fatal
196
- ? []
197
- : getCachedLayoutUrls(
198
- initialLayout,
199
- initialCache,
200
- result.siteLayout,
201
- ).filter((url) => !nextCache[url]);
202
- if (!urls.length) {
203
- if (!fatal) pageLayouts.value = nextCache;
204
- applySiteLayoutResponse(result);
205
- return true;
206
- }
207
- const layouts = await Promise.all(
208
- urls.map(
209
- async (url) => [url, await $authFetch<PageLayout>(url)] as const,
210
- ),
211
- );
212
- Object.assign(nextCache, Object.fromEntries(layouts));
213
- }
245
+ if (isCurrent()) applySiteLayoutResponse(state, result);
214
246
  return true;
215
247
  } catch (error) {
216
- // Failed background refreshes must not leave a fatal error for the next navigation.
217
- if (fatal && isCurrent()) handleSiteLayoutError(error);
248
+ if (isCurrent()) handleSiteLayoutError(error);
218
249
  throw error;
219
250
  }
220
251
  };
221
252
 
222
- const startSiteLayoutFetch = (fatal = true): Promise<boolean> => {
223
- const started = requestSiteLayout(fatal).finally(() => {
253
+ const startSiteLayoutFetch = (): Promise<boolean> => {
254
+ const started = requestSiteLayout().finally(() => {
224
255
  isLoading.value = false;
225
256
  // A waiting refresh may already have started its replacement request.
226
257
  if (loadingPromise.value === started) loadingPromise.value = null;
@@ -246,12 +277,9 @@ export const useSiteLayout = () => {
246
277
  pageLayouts.value = {};
247
278
  }
248
279
 
249
- // `fatal: false` keeps a failed refetch from swapping the app for the error
250
- // page — for background resyncs (a realtime menu invalidation), where a
251
- // network blip must not destroy a working session.
252
- const refresh = async (options?: { fatal?: boolean }) => {
253
- // Background refreshes stage page layouts before committing; identity refreshes clear immediately.
254
- if (options?.fatal !== false) clearPageLayoutCaches();
280
+ // A background resync (a realtime menu invalidation) goes through `resync`.
281
+ const refresh = async () => {
282
+ clearPageLayoutCaches();
255
283
 
256
284
  // A fetch already in flight was started before whatever prompted this
257
285
  // call, so its answer cannot contain the change: joining it would report
@@ -270,11 +298,26 @@ export const useSiteLayout = () => {
270
298
  if (!loadingPromise.value) {
271
299
  isLoading.value = true;
272
300
  loadingError.value = null;
273
- loadingPromise.value = startSiteLayoutFetch(options?.fatal ?? true);
301
+ loadingPromise.value = startSiteLayoutFetch();
274
302
  }
275
303
  await loadingPromise.value;
276
304
  };
277
305
 
306
+ /**
307
+ * Re-reads the menu and the page on screen from the server, for a change
308
+ * the backend announced (a realtime menu invalidation) or a switch of
309
+ * session. The pages prefetched on hover are dropped first: each carries
310
+ * the layout and the access of before. A navigation that starts meanwhile
311
+ * drops the reload's answer, and the page it opens still carries the layout
312
+ * the reload meant to replace: that page is reloaded in turn.
313
+ */
314
+ const resync = async (): Promise<void> => {
315
+ inertiaRouter.flushAll();
316
+ const path = window.location.pathname;
317
+ await reloadSiteLayoutAndPage();
318
+ if (window.location.pathname !== path) await reloadSiteLayoutAndPage();
319
+ };
320
+
278
321
  const refreshIfStale = async () => {
279
322
  const elapsed = Date.now() - lastRefreshTime.value;
280
323
  if (elapsed < STALE_THRESHOLD_MS) {
@@ -335,12 +378,11 @@ export const useSiteLayout = () => {
335
378
  };
336
379
  }
337
380
 
338
- if (options.includeCategories && layout.categories[normalizedPath]) {
339
- return {
340
- pattern: normalizedPath,
341
- metadata: layout.categories[normalizedPath],
342
- params: {},
343
- };
381
+ const category = options.includeCategories
382
+ ? findNavigableCategory(layout, normalizedPath)
383
+ : undefined;
384
+ if (category) {
385
+ return { pattern: normalizedPath, metadata: category, params: {} };
344
386
  }
345
387
 
346
388
  for (const [pattern, metadata] of Object.entries(layout.pages)) {
@@ -420,7 +462,7 @@ export const useSiteLayout = () => {
420
462
  return false;
421
463
  }
422
464
  clearPageLayoutCaches();
423
- applySiteLayoutResponse(result);
465
+ applySiteLayoutResponse(state, result);
424
466
  return true;
425
467
  } catch {
426
468
  return false;
@@ -440,9 +482,48 @@ export const useSiteLayout = () => {
440
482
  loadSiteLayout,
441
483
  loadPageLayout,
442
484
  refresh,
485
+ resync,
443
486
  refreshIfStale,
444
487
  findMatchingRoute,
445
488
  findMatchingRouteOrCategory,
446
489
  probeAndCommitRoute,
447
490
  };
448
491
  };
492
+
493
+ /**
494
+ * The site layout for the component rendering it (the sidebar), called in
495
+ * its setup. A page the backend describes brings it with its props; a page
496
+ * only a frontend layer knows (a custom page) does not, and this loads it
497
+ * with the page then: a server render waits for it before rendering the
498
+ * component, and hands it to the browser, which takes it over before the
499
+ * component mounts instead of asking again.
500
+ */
501
+ export function useRenderedSiteLayout(): void {
502
+ const state = useSiteLayoutState();
503
+ if (state.siteLayout.value) return;
504
+ const layout = useSiteLayout();
505
+ // Through `loadSiteLayout`, which sets the state: a middleware loading it
506
+ // at the same time (the auth guard of a custom page) joins this request.
507
+ const { data } = useApiData<SiteLayoutResponse | null>(
508
+ RENDERED_SITE_LAYOUT_KEY,
509
+ async () => {
510
+ await layout.loadSiteLayout();
511
+ const { siteLayout, siteLayoutTree, quickActions, modules, isOwner } =
512
+ state;
513
+ // What the page payload carries: the plain values, not the state.
514
+ return siteLayout.value
515
+ ? {
516
+ siteLayout: toRaw(siteLayout.value),
517
+ siteLayoutTree: toRaw(siteLayoutTree.value!),
518
+ quickActions: toRaw(quickActions.value!),
519
+ modules: toRaw(modules.value!),
520
+ isOwner: isOwner.value,
521
+ }
522
+ : null;
523
+ },
524
+ );
525
+ onBeforeMount(() => {
526
+ if (data.value && !state.siteLayout.value)
527
+ applySiteLayoutResponse(state, data.value);
528
+ });
529
+ }
@@ -1,4 +1,5 @@
1
- const PROFILE_ENDPOINT = "/settings/user/profile";
1
+ import { pageRoutePath } from "#dms-core/app/utils/pageRoutes";
2
+ const PROFILE_ENDPOINT = pageRoutePath("/settings/user/profile");
2
3
 
3
4
  /**
4
5
  * Switches the interface language and stores it on the user's profile, then
@@ -9,7 +10,7 @@ const PROFILE_ENDPOINT = "/settings/user/profile";
9
10
  export function useUserLanguage() {
10
11
  const dmsApp = useDmsApp();
11
12
  const { $authFetch } = useAuthFetch();
12
- const { user, fetch: refreshUser } = useUserSession();
13
+ const { user, fetch: refreshUser } = useDmsUserSession();
13
14
 
14
15
  async function changeLanguage(language: string): Promise<void> {
15
16
  await dmsApp.$i18n.setLocale(language);