@antelopejs/dms 0.6.1 → 0.7.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 (472) hide show
  1. package/CHANGELOG.md +39 -0
  2. package/dist/db/models/notification-feed-filter.d.ts +0 -1
  3. package/dist/db/models/notification-feed-filter.js +0 -4
  4. package/dist/db/models/notification-feed-filter.js.map +1 -1
  5. package/dist/db/models/signInAttempts.model.d.ts +18 -0
  6. package/dist/db/models/signInAttempts.model.js +83 -12
  7. package/dist/db/models/signInAttempts.model.js.map +1 -1
  8. package/dist/db/models/userEmailChanges.model.d.ts +8 -1
  9. package/dist/db/models/userEmailChanges.model.js +27 -2
  10. package/dist/db/models/userEmailChanges.model.js.map +1 -1
  11. package/dist/db/models/userNotificationPreferences.model.d.ts +0 -2
  12. package/dist/db/models/userNotificationPreferences.model.js +0 -13
  13. package/dist/db/models/userNotificationPreferences.model.js.map +1 -1
  14. package/dist/db/models/userNotifications.model.d.ts +5 -2
  15. package/dist/db/models/userNotifications.model.js +19 -2
  16. package/dist/db/models/userNotifications.model.js.map +1 -1
  17. package/dist/db/tables/signInAttempts.table.d.ts +2 -1
  18. package/dist/db/tables/signInAttempts.table.js +4 -0
  19. package/dist/db/tables/signInAttempts.table.js.map +1 -1
  20. package/dist/db/tables/userEmailChanges.table.d.ts +2 -1
  21. package/dist/db/tables/userEmailChanges.table.js +6 -1
  22. package/dist/db/tables/userEmailChanges.table.js.map +1 -1
  23. package/dist/db/tables/userNotificationPreferences.table.d.ts +0 -1
  24. package/dist/db/tables/userNotificationPreferences.table.js +0 -4
  25. package/dist/db/tables/userNotificationPreferences.table.js.map +1 -1
  26. package/dist/implementations/dms/layout-banners.d.ts +4 -1
  27. package/dist/implementations/dms/layout-banners.js +33 -18
  28. package/dist/implementations/dms/layout-banners.js.map +1 -1
  29. package/dist/implementations/dms/nav-badges.d.ts +6 -4
  30. package/dist/implementations/dms/nav-badges.js +6 -5
  31. package/dist/implementations/dms/nav-badges.js.map +1 -1
  32. package/dist/implementations/dms/page.d.ts +1 -0
  33. package/dist/implementations/dms/page.js +46 -8
  34. package/dist/implementations/dms/page.js.map +1 -1
  35. package/dist/implementations/dms/permission-preview.d.ts +1 -1
  36. package/dist/implementations/dms/permission-preview.js +9 -4
  37. package/dist/implementations/dms/permission-preview.js.map +1 -1
  38. package/dist/implementations/dms-auth/index.d.ts +3 -2
  39. package/dist/implementations/dms-auth/index.js +39 -35
  40. package/dist/implementations/dms-auth/index.js.map +1 -1
  41. package/dist/implementations/dms-auth/token-session.d.ts +3 -0
  42. package/dist/implementations/dms-auth/token-session.js +22 -0
  43. package/dist/implementations/dms-auth/token-session.js.map +1 -0
  44. package/dist/implementations/dms-notifications/index.d.ts +0 -1
  45. package/dist/implementations/dms-notifications/index.js +0 -7
  46. package/dist/implementations/dms-notifications/index.js.map +1 -1
  47. package/dist/pages/settings/settings-index.js +3 -2
  48. package/dist/pages/settings/settings-index.js.map +1 -1
  49. package/dist/pages/settings/users/account-activity-feed.d.ts +1 -1
  50. package/dist/pages/settings/users/account-activity-feed.js +1 -1
  51. package/dist/pages/settings/users/account-activity-feed.js.map +1 -1
  52. package/dist/pages/settings/users/account-activity.d.ts +1 -1
  53. package/dist/pages/settings/users/account-activity.js +1 -1
  54. package/dist/pages/settings/users/account-activity.js.map +1 -1
  55. package/dist/pages/settings/users/account-credentials.d.ts +3 -0
  56. package/dist/pages/settings/users/account-credentials.js +2 -0
  57. package/dist/pages/settings/users/account-credentials.js.map +1 -1
  58. package/dist/pages/settings/users/current-password.d.ts +1 -1
  59. package/dist/pages/settings/users/current-password.js +23 -2
  60. package/dist/pages/settings/users/current-password.js.map +1 -1
  61. package/dist/pages/settings/users/email-change.d.ts +1 -1
  62. package/dist/pages/settings/users/email-change.js +33 -26
  63. package/dist/pages/settings/users/email-change.js.map +1 -1
  64. package/dist/pages/settings/users/invite-resend.js +0 -1
  65. package/dist/pages/settings/users/invite-resend.js.map +1 -1
  66. package/dist/pages/settings/users/invites.d.ts +1 -2
  67. package/dist/pages/settings/users/invites.js +21 -19
  68. package/dist/pages/settings/users/invites.js.map +1 -1
  69. package/dist/pages/settings/users/member-invite-batch.js +0 -1
  70. package/dist/pages/settings/users/member-invite-batch.js.map +1 -1
  71. package/dist/pages/settings/users/member-invite-form.js +10 -22
  72. package/dist/pages/settings/users/member-invite-form.js.map +1 -1
  73. package/dist/pages/settings/users/member-role-options.d.ts +6 -4
  74. package/dist/pages/settings/users/member-role-options.js +15 -4
  75. package/dist/pages/settings/users/member-role-options.js.map +1 -1
  76. package/dist/pages/settings/users/members.d.ts +2 -3
  77. package/dist/pages/settings/users/members.js +7 -12
  78. package/dist/pages/settings/users/members.js.map +1 -1
  79. package/dist/pages/settings/users/notifications.d.ts +1 -8
  80. package/dist/pages/settings/users/notifications.js +6 -38
  81. package/dist/pages/settings/users/notifications.js.map +1 -1
  82. package/dist/pages/settings/users/permission-tree-nodes.d.ts +1 -1
  83. package/dist/pages/settings/users/permission-tree-nodes.js +23 -9
  84. package/dist/pages/settings/users/permission-tree-nodes.js.map +1 -1
  85. package/dist/pages/settings/users/permission-warnings.d.ts +7 -0
  86. package/dist/pages/settings/users/permission-warnings.js +42 -0
  87. package/dist/pages/settings/users/permission-warnings.js.map +1 -0
  88. package/dist/pages/settings/users/profile-helpers.d.ts +1 -3
  89. package/dist/pages/settings/users/profile-helpers.js +0 -16
  90. package/dist/pages/settings/users/profile-helpers.js.map +1 -1
  91. package/dist/pages/settings/users/role-editor-store.js +6 -3
  92. package/dist/pages/settings/users/role-editor-store.js.map +1 -1
  93. package/dist/pages/settings/users/role-editor.d.ts +2 -1
  94. package/dist/pages/settings/users/role-editor.js +8 -4
  95. package/dist/pages/settings/users/role-editor.js.map +1 -1
  96. package/dist/pages/settings/users/role-preview.js +2 -1
  97. package/dist/pages/settings/users/role-preview.js.map +1 -1
  98. package/dist/pages/settings/users/roles.js +5 -1
  99. package/dist/pages/settings/users/roles.js.map +1 -1
  100. package/dist/pages/settings/users/security-attention.d.ts +4 -0
  101. package/dist/pages/settings/users/security-attention.js +23 -7
  102. package/dist/pages/settings/users/security-attention.js.map +1 -1
  103. package/dist/pages/settings/users/security.d.ts +2 -1
  104. package/dist/pages/settings/users/security.js +13 -2
  105. package/dist/pages/settings/users/security.js.map +1 -1
  106. package/dist/pages/settings/users/two-factor-operations.d.ts +2 -1
  107. package/dist/pages/settings/users/two-factor-operations.js +28 -29
  108. package/dist/pages/settings/users/two-factor-operations.js.map +1 -1
  109. package/dist/routes/auth/forgot-password.js +3 -0
  110. package/dist/routes/auth/forgot-password.js.map +1 -1
  111. package/dist/routes/auth/index.d.ts +1 -0
  112. package/dist/routes/auth/index.js +1 -0
  113. package/dist/routes/auth/index.js.map +1 -1
  114. package/dist/routes/auth/invite.js +28 -4
  115. package/dist/routes/auth/invite.js.map +1 -1
  116. package/dist/routes/auth/login-throttle.d.ts +2 -0
  117. package/dist/routes/auth/login-throttle.js +5 -4
  118. package/dist/routes/auth/login-throttle.js.map +1 -1
  119. package/dist/routes/auth/request-2fa-email.js +6 -18
  120. package/dist/routes/auth/request-2fa-email.js.map +1 -1
  121. package/dist/routes/auth/reset-code.d.ts +3 -0
  122. package/dist/routes/auth/reset-code.js +37 -0
  123. package/dist/routes/auth/reset-code.js.map +1 -0
  124. package/dist/routes/auth/reset-password.d.ts +2 -2
  125. package/dist/routes/auth/reset-password.js +5 -10
  126. package/dist/routes/auth/reset-password.js.map +1 -1
  127. package/dist/routes/auth/signup.js +10 -32
  128. package/dist/routes/auth/signup.js.map +1 -1
  129. package/dist/routes/auth/two-factor-throttle.d.ts +5 -0
  130. package/dist/routes/auth/two-factor-throttle.js +81 -0
  131. package/dist/routes/auth/two-factor-throttle.js.map +1 -0
  132. package/dist/routes/auth/validate-forgot-password-token.js +2 -8
  133. package/dist/routes/auth/validate-forgot-password-token.js.map +1 -1
  134. package/dist/routes/auth/validate-invite-token.d.ts +1 -0
  135. package/dist/routes/auth/validate-invite-token.js +11 -0
  136. package/dist/routes/auth/validate-invite-token.js.map +1 -0
  137. package/dist/routes/auth/verify-2fa.js +10 -13
  138. package/dist/routes/auth/verify-2fa.js.map +1 -1
  139. package/dist/routes/auth.d.ts +1 -0
  140. package/dist/routes/auth.js +11 -1
  141. package/dist/routes/auth.js.map +1 -1
  142. package/dist/test/helpers/auth.d.ts +0 -1
  143. package/dist/test/helpers/auth.js +0 -1
  144. package/dist/test/helpers/auth.js.map +1 -1
  145. package/dist/test/helpers/emails.d.ts +10 -0
  146. package/dist/test/helpers/emails.js +36 -0
  147. package/dist/test/helpers/emails.js.map +1 -0
  148. package/dist/test/helpers/fixtures.d.ts +0 -1
  149. package/dist/test/helpers/fixtures.js +1 -2
  150. package/dist/test/helpers/fixtures.js.map +1 -1
  151. package/dist/test/helpers/page-access.d.ts +1 -0
  152. package/dist/test/helpers/page-access.js +6 -1
  153. package/dist/test/helpers/page-access.js.map +1 -1
  154. package/dist/test/integration/auth/current-password.test.d.ts +1 -0
  155. package/dist/test/integration/auth/current-password.test.js +65 -0
  156. package/dist/test/integration/auth/current-password.test.js.map +1 -0
  157. package/dist/test/integration/auth/password-reset.test.d.ts +1 -0
  158. package/dist/test/integration/auth/password-reset.test.js +126 -0
  159. package/dist/test/integration/auth/password-reset.test.js.map +1 -0
  160. package/dist/test/integration/auth/session-revocation.test.d.ts +1 -0
  161. package/dist/test/integration/auth/session-revocation.test.js +45 -0
  162. package/dist/test/integration/auth/session-revocation.test.js.map +1 -0
  163. package/dist/test/integration/auth/two-factor-codes.test.d.ts +1 -0
  164. package/dist/test/integration/auth/two-factor-codes.test.js +335 -0
  165. package/dist/test/integration/auth/two-factor-codes.test.js.map +1 -0
  166. package/dist/test/integration/auth/two-factor-password.test.js +5 -1
  167. package/dist/test/integration/auth/two-factor-password.test.js.map +1 -1
  168. package/dist/test/integration/auth/two-factor-token.test.d.ts +1 -0
  169. package/dist/test/integration/auth/two-factor-token.test.js +92 -0
  170. package/dist/test/integration/auth/two-factor-token.test.js.map +1 -0
  171. package/dist/test/integration/email-change.test.js +36 -0
  172. package/dist/test/integration/email-change.test.js.map +1 -1
  173. package/dist/test/integration/invite-extension-edit.test.js +0 -1
  174. package/dist/test/integration/invite-extension-edit.test.js.map +1 -1
  175. package/dist/test/integration/invite-link-status.test.d.ts +1 -0
  176. package/dist/test/integration/invite-link-status.test.js +110 -0
  177. package/dist/test/integration/invite-link-status.test.js.map +1 -0
  178. package/dist/test/integration/invite-resolution.test.js +0 -3
  179. package/dist/test/integration/invite-resolution.test.js.map +1 -1
  180. package/dist/test/integration/member-settings-access.test.js +17 -0
  181. package/dist/test/integration/member-settings-access.test.js.map +1 -1
  182. package/dist/test/integration/notification-unread-badge.test.d.ts +1 -0
  183. package/dist/test/integration/notification-unread-badge.test.js +92 -0
  184. package/dist/test/integration/notification-unread-badge.test.js.map +1 -0
  185. package/dist/test/integration/permission-warnings.test.d.ts +1 -0
  186. package/dist/test/integration/permission-warnings.test.js +71 -0
  187. package/dist/test/integration/permission-warnings.test.js.map +1 -0
  188. package/dist/test/integration/removed-member-notifications.test.d.ts +1 -0
  189. package/dist/test/integration/removed-member-notifications.test.js +80 -0
  190. package/dist/test/integration/removed-member-notifications.test.js.map +1 -0
  191. package/dist/test/integration/role-permission-ancestors.test.d.ts +1 -0
  192. package/dist/test/integration/role-permission-ancestors.test.js +146 -0
  193. package/dist/test/integration/role-permission-ancestors.test.js.map +1 -0
  194. package/dist/test/integration/tenant-lifecycle.test.js +0 -4
  195. package/dist/test/integration/tenant-lifecycle.test.js.map +1 -1
  196. package/dist/test/unit/auth-session-revocation.test.d.ts +1 -0
  197. package/dist/test/unit/auth-session-revocation.test.js +105 -0
  198. package/dist/test/unit/auth-session-revocation.test.js.map +1 -0
  199. package/dist/test/unit/db/email-normalization.test.js +0 -1
  200. package/dist/test/unit/db/email-normalization.test.js.map +1 -1
  201. package/dist/test/unit/db/notification-feed-filter.test.js +0 -16
  202. package/dist/test/unit/db/notification-feed-filter.test.js.map +1 -1
  203. package/dist/test/unit/db/notification-inbox.test.js +63 -13
  204. package/dist/test/unit/db/notification-inbox.test.js.map +1 -1
  205. package/dist/test/unit/db/notification-preferences.test.js +0 -17
  206. package/dist/test/unit/db/notification-preferences.test.js.map +1 -1
  207. package/dist/test/unit/implementations/dms/empty-menu-group.test.d.ts +1 -0
  208. package/dist/test/unit/implementations/dms/empty-menu-group.test.js +133 -0
  209. package/dist/test/unit/implementations/dms/empty-menu-group.test.js.map +1 -0
  210. package/dist/test/unit/implementations/dms/layout-banners.test.js +78 -1
  211. package/dist/test/unit/implementations/dms/layout-banners.test.js.map +1 -1
  212. package/dist/test/unit/implementations/dms/menu-hidden-blocks.test.d.ts +1 -0
  213. package/dist/test/unit/implementations/dms/menu-hidden-blocks.test.js +149 -0
  214. package/dist/test/unit/implementations/dms/menu-hidden-blocks.test.js.map +1 -0
  215. package/dist/test/unit/implementations/dms/nav-badges.test.js +55 -4
  216. package/dist/test/unit/implementations/dms/nav-badges.test.js.map +1 -1
  217. package/dist/test/unit/implementations/dms/page-all-components-hidden.test.d.ts +1 -0
  218. package/dist/test/unit/implementations/dms/page-all-components-hidden.test.js +118 -0
  219. package/dist/test/unit/implementations/dms/page-all-components-hidden.test.js.map +1 -0
  220. package/dist/test/unit/implementations/dms/permission-preview-aggregate.test.js +16 -0
  221. package/dist/test/unit/implementations/dms/permission-preview-aggregate.test.js.map +1 -1
  222. package/dist/test/unit/implementations/dms/permission-preview-cost.test.js +5 -3
  223. package/dist/test/unit/implementations/dms/permission-preview-cost.test.js.map +1 -1
  224. package/dist/test/unit/implementations/dms/permission-preview-menu.test.js +29 -3
  225. package/dist/test/unit/implementations/dms/permission-preview-menu.test.js.map +1 -1
  226. package/dist/test/unit/implementations/dms/quick-actions-button.test.js +4 -2
  227. package/dist/test/unit/implementations/dms/quick-actions-button.test.js.map +1 -1
  228. package/dist/test/unit/implementations/dms/user-permissions-gate.test.js +2 -1
  229. package/dist/test/unit/implementations/dms/user-permissions-gate.test.js.map +1 -1
  230. package/dist/test/unit/implementations/dms-base/table-view-shared-controller.test.js +2 -1
  231. package/dist/test/unit/implementations/dms-base/table-view-shared-controller.test.js.map +1 -1
  232. package/dist/test/unit/interfaces/dms/component-children-permissions.test.js +7 -2
  233. package/dist/test/unit/interfaces/dms/component-children-permissions.test.js.map +1 -1
  234. package/dist/test/unit/interfaces/dms/form-watch-permissions.test.d.ts +1 -0
  235. package/dist/test/unit/interfaces/dms/form-watch-permissions.test.js +133 -0
  236. package/dist/test/unit/interfaces/dms/form-watch-permissions.test.js.map +1 -0
  237. package/dist/test/unit/interfaces/dms/has-permission-ancestors.test.d.ts +1 -0
  238. package/dist/test/unit/interfaces/dms/has-permission-ancestors.test.js +149 -0
  239. package/dist/test/unit/interfaces/dms/has-permission-ancestors.test.js.map +1 -0
  240. package/dist/test/unit/interfaces/dms/invite-extension.test.js +13 -0
  241. package/dist/test/unit/interfaces/dms/invite-extension.test.js.map +1 -1
  242. package/dist/test/unit/interfaces/dms/member-access.test.js +27 -1
  243. package/dist/test/unit/interfaces/dms/member-access.test.js.map +1 -1
  244. package/dist/test/unit/interfaces/dms/nav-badge-tones.test.d.ts +1 -0
  245. package/dist/test/unit/interfaces/dms/nav-badge-tones.test.js +31 -0
  246. package/dist/test/unit/interfaces/dms/nav-badge-tones.test.js.map +1 -0
  247. package/dist/test/unit/interfaces/dms/page-extension.test.js +4 -1
  248. package/dist/test/unit/interfaces/dms/page-extension.test.js.map +1 -1
  249. package/dist/test/unit/interfaces/dms/permission-requirements.test.d.ts +1 -0
  250. package/dist/test/unit/interfaces/dms/permission-requirements.test.js +144 -0
  251. package/dist/test/unit/interfaces/dms/permission-requirements.test.js.map +1 -0
  252. package/dist/test/unit/interfaces/dms-base/column-display.test.js +70 -0
  253. package/dist/test/unit/interfaces/dms-base/column-display.test.js.map +1 -1
  254. package/dist/test/unit/interfaces/dms-base/display-blocks-catalog.test.js +38 -0
  255. package/dist/test/unit/interfaces/dms-base/display-blocks-catalog.test.js.map +1 -1
  256. package/dist/test/unit/interfaces/dms-base/layout-header-actions.test.js +6 -2
  257. package/dist/test/unit/interfaces/dms-base/layout-header-actions.test.js.map +1 -1
  258. package/dist/test/unit/interfaces/dms-base/lists-and-settings-catalog.test.js +1 -1
  259. package/dist/test/unit/interfaces/dms-base/lists-and-settings-catalog.test.js.map +1 -1
  260. package/dist/test/unit/interfaces/dms-base/table-view-export-permission.test.js +2 -1
  261. package/dist/test/unit/interfaces/dms-base/table-view-export-permission.test.js.map +1 -1
  262. package/dist/test/unit/interfaces/dms-base/table-view-reduced-chrome.test.js +2 -1
  263. package/dist/test/unit/interfaces/dms-base/table-view-reduced-chrome.test.js.map +1 -1
  264. package/dist/test/unit/interfaces/dms-base/table-view-shared-controller-permissions.test.js +2 -1
  265. package/dist/test/unit/interfaces/dms-base/table-view-shared-controller-permissions.test.js.map +1 -1
  266. package/dist/test/unit/pages/settings/account-activity-feed.test.js +2 -2
  267. package/dist/test/unit/pages/settings/account-activity-feed.test.js.map +1 -1
  268. package/dist/test/unit/pages/settings/account-activity.test.js +11 -2
  269. package/dist/test/unit/pages/settings/account-activity.test.js.map +1 -1
  270. package/dist/test/unit/pages/settings/invite-email-delivery.test.js +0 -1
  271. package/dist/test/unit/pages/settings/invite-email-delivery.test.js.map +1 -1
  272. package/dist/test/unit/pages/settings/invite-email-validation-option.test.d.ts +1 -0
  273. package/dist/test/unit/pages/settings/invite-email-validation-option.test.js +33 -0
  274. package/dist/test/unit/pages/settings/invite-email-validation-option.test.js.map +1 -0
  275. package/dist/test/unit/pages/settings/member-lists-page-size.test.d.ts +1 -0
  276. package/dist/test/unit/pages/settings/member-lists-page-size.test.js +22 -0
  277. package/dist/test/unit/pages/settings/member-lists-page-size.test.js.map +1 -0
  278. package/dist/test/unit/pages/settings/member-table-widths.test.js +2 -2
  279. package/dist/test/unit/pages/settings/member-table-widths.test.js.map +1 -1
  280. package/dist/test/unit/pages/settings/members-page.test.js +7 -10
  281. package/dist/test/unit/pages/settings/members-page.test.js.map +1 -1
  282. package/dist/test/unit/pages/settings/notifications-access-gate.test.js +3 -10
  283. package/dist/test/unit/pages/settings/notifications-access-gate.test.js.map +1 -1
  284. package/dist/test/unit/pages/settings/permission-tree-nodes.test.js +57 -0
  285. package/dist/test/unit/pages/settings/permission-tree-nodes.test.js.map +1 -1
  286. package/dist/test/unit/pages/settings/permission-warnings.test.d.ts +1 -0
  287. package/dist/test/unit/pages/settings/permission-warnings.test.js +49 -0
  288. package/dist/test/unit/pages/settings/permission-warnings.test.js.map +1 -0
  289. package/dist/test/unit/pages/settings/role-editor.test.js +16 -0
  290. package/dist/test/unit/pages/settings/role-editor.test.js.map +1 -1
  291. package/dist/test/unit/pages/settings/role-preview.test.js +7 -0
  292. package/dist/test/unit/pages/settings/role-preview.test.js.map +1 -1
  293. package/dist/test/unit/pages/settings/security-attention.test.d.ts +1 -0
  294. package/dist/test/unit/pages/settings/security-attention.test.js +74 -0
  295. package/dist/test/unit/pages/settings/security-attention.test.js.map +1 -0
  296. package/dist/test/unit/sanitize-user.test.d.ts +1 -0
  297. package/dist/test/unit/sanitize-user.test.js +21 -0
  298. package/dist/test/unit/sanitize-user.test.js.map +1 -0
  299. package/dist/test/unit/signup-email-validation.test.d.ts +1 -0
  300. package/dist/test/unit/signup-email-validation.test.js +79 -0
  301. package/dist/test/unit/signup-email-validation.test.js.map +1 -0
  302. package/dist/test/unit/validation/member-invite.schema.test.js +14 -52
  303. package/dist/test/unit/validation/member-invite.schema.test.js.map +1 -1
  304. package/dist/utils/account-notifications.d.ts +5 -0
  305. package/dist/utils/account-notifications.js +8 -0
  306. package/dist/utils/account-notifications.js.map +1 -1
  307. package/dist/utils/notification-emitter.d.ts +1 -1
  308. package/dist/utils/notification-emitter.js +1 -1
  309. package/dist/utils/notification-emitter.js.map +1 -1
  310. package/dist/utils/notification-tones.d.ts +2 -1
  311. package/dist/utils/notification-tones.js +5 -1
  312. package/dist/utils/notification-tones.js.map +1 -1
  313. package/dist/utils/one-time-code.d.ts +3 -0
  314. package/dist/utils/one-time-code.js +21 -0
  315. package/dist/utils/one-time-code.js.map +1 -0
  316. package/dist/utils/sign-in-monitor.d.ts +1 -0
  317. package/dist/utils/sign-in-monitor.js +3 -2
  318. package/dist/utils/sign-in-monitor.js.map +1 -1
  319. package/dist/utils/two-factor-codes.d.ts +10 -0
  320. package/dist/utils/two-factor-codes.js +76 -0
  321. package/dist/utils/two-factor-codes.js.map +1 -0
  322. package/dist/validation/auth.schema.d.ts +17 -0
  323. package/dist/validation/auth.schema.js +17 -6
  324. package/dist/validation/auth.schema.js.map +1 -1
  325. package/dist/validation/issue-message.d.ts +1 -0
  326. package/dist/validation/issue-message.js +9 -0
  327. package/dist/validation/issue-message.js.map +1 -0
  328. package/dist/validation/member-invite.schema.d.ts +1 -25
  329. package/dist/validation/member-invite.schema.js +2 -23
  330. package/dist/validation/member-invite.schema.js.map +1 -1
  331. package/frontend-vue/dms.frontend.ts +2 -0
  332. package/frontend-vue/layers/dms-auth/app/custom-pages/auth/forgot-validation.vue +3 -0
  333. package/frontend-vue/layers/dms-auth/app/custom-pages/auth/signup.vue +105 -5
  334. package/frontend-vue/layers/dms-auth/i18n/locales/auth-en-GB.json +20 -4
  335. package/frontend-vue/layers/dms-auth/i18n/locales/auth-fr-FR.json +20 -4
  336. package/frontend-vue/layers/dms-core/app/composables/translation/useComposedText.ts +25 -0
  337. package/frontend-vue/layers/dms-core/app/composables/useFieldErrors.ts +3 -2
  338. package/frontend-vue/layers/dms-core/app/types/composed-text.ts +64 -0
  339. package/frontend-vue/layers/dms-core/app/types/menu.ts +15 -0
  340. package/frontend-vue/layers/dms-core/app/utils/composedText.ts +227 -0
  341. package/frontend-vue/layers/dms-core/app/utils/formatter.ts +49 -0
  342. package/frontend-vue/layers/dms-core/i18n/locales/core-en-GB.json +4 -1
  343. package/frontend-vue/layers/dms-core/i18n/locales/core-fr-FR.json +4 -1
  344. package/frontend-vue/layers/dms-layout/app/assets/css/main.css +20 -0
  345. package/frontend-vue/layers/dms-layout/app/build/components/layout/CommandPaletteAssistantAnswer.vue +75 -0
  346. package/frontend-vue/layers/dms-layout/app/build/components/layout/DashboardBanners.vue +17 -3
  347. package/frontend-vue/layers/dms-layout/app/build/components/layout/DashboardFrame.vue +22 -0
  348. package/frontend-vue/layers/dms-layout/app/build/components/layout/DashboardHeader.vue +24 -10
  349. package/frontend-vue/layers/dms-layout/app/build/components/layout/DashboardSidePanel.vue +139 -0
  350. package/frontend-vue/layers/dms-layout/app/build/components/layout/Footer.vue +4 -2
  351. package/frontend-vue/layers/dms-layout/app/build/components/layout/GithubStarPrompt.vue +90 -0
  352. package/frontend-vue/layers/dms-layout/app/build/components/layout/SidePanelHost.vue +17 -0
  353. package/frontend-vue/layers/dms-layout/app/build/components/notification/NotificationPopover.vue +25 -43
  354. package/frontend-vue/layers/dms-layout/app/build/components/pages/settings/members/MemberRolePicker.vue +24 -2
  355. package/frontend-vue/layers/dms-layout/app/build/components/pages/settings/notification/NotificationMatrixCategory.vue +70 -25
  356. package/frontend-vue/layers/dms-layout/app/build/components/pages/settings/notification/NotificationPreferencesForm.vue +25 -10
  357. package/frontend-vue/layers/dms-layout/app/build/components/pages/settings/notification/notificationDisplay.ts +41 -5
  358. package/frontend-vue/layers/dms-layout/app/build/components/pages/settings/profile/ProfilePreferencesSummary.vue +2 -1
  359. package/frontend-vue/layers/dms-layout/app/build/components/pages/settings/profile/ProfileSecuritySummary.vue +20 -4
  360. package/frontend-vue/layers/dms-layout/app/build/components/pages/settings/roles/RoleEditor.vue +21 -0
  361. package/frontend-vue/layers/dms-layout/app/build/components/pages/settings/roles/RolePermissionArea.vue +16 -2
  362. package/frontend-vue/layers/dms-layout/app/build/components/pages/settings/roles/RolePermissionBranch.vue +1 -0
  363. package/frontend-vue/layers/dms-layout/app/build/components/pages/settings/roles/RolePermissionLeaf.vue +13 -1
  364. package/frontend-vue/layers/dms-layout/app/build/components/pages/settings/roles/RolePermissionTree.vue +9 -0
  365. package/frontend-vue/layers/dms-layout/app/build/components/pages/settings/roles/RolePermissionWarning.vue +46 -0
  366. package/frontend-vue/layers/dms-layout/app/build/components/pages/settings/roles/role-permissions.ts +108 -29
  367. package/frontend-vue/layers/dms-layout/app/build/components/pages/settings/roles/role-types.ts +2 -0
  368. package/frontend-vue/layers/dms-layout/app/build/components/pages/settings/security/SecurityDialogFrame.vue +6 -6
  369. package/frontend-vue/layers/dms-layout/app/build/components/pages/settings/security/SecurityEmail.vue +7 -1
  370. package/frontend-vue/layers/dms-layout/app/build/components/pages/settings/security/SecuritySessions.vue +5 -4
  371. package/frontend-vue/layers/dms-layout/app/build/components/pages/settings/security/SecurityStatus.vue +4 -3
  372. package/frontend-vue/layers/dms-layout/app/build/components/pages/settings/security/SecurityTwoFactor.vue +54 -18
  373. package/frontend-vue/layers/dms-layout/app/build/components/pages/settings/shell/SettingsNav.vue +13 -8
  374. package/frontend-vue/layers/dms-layout/app/build/composables/command-palette/assistantGroups.ts +143 -0
  375. package/frontend-vue/layers/dms-layout/app/build/composables/command-palette/useCommandPaletteAssistantMode.ts +249 -0
  376. package/frontend-vue/layers/dms-layout/app/build/composables/general/useGithubStarPrompt.ts +178 -0
  377. package/frontend-vue/layers/dms-layout/app/build/composables/layout/sidePanelState.ts +191 -0
  378. package/frontend-vue/layers/dms-layout/app/build/composables/layout/useHeaderActionControls.ts +51 -0
  379. package/frontend-vue/layers/dms-layout/app/build/composables/layout/useSidePanelWidth.ts +113 -0
  380. package/frontend-vue/layers/dms-layout/app/build/composables/navigation/useCategoryNavCards.ts +17 -10
  381. package/frontend-vue/layers/dms-layout/app/build/composables/notification/useNotificationGroupsOpen.ts +45 -0
  382. package/frontend-vue/layers/dms-layout/app/build/composables/settings/profile/useProfilePreferences.ts +8 -1
  383. package/frontend-vue/layers/dms-layout/app/build/composables/settings/security/useSecurityOverview.ts +50 -3
  384. package/frontend-vue/layers/dms-layout/app/build/composables/settings/useSettingsNavigation.ts +3 -0
  385. package/frontend-vue/layers/dms-layout/app/build/utils/categoryPages.ts +1 -2
  386. package/frontend-vue/layers/dms-layout/app/build/utils/github-repository.ts +5 -0
  387. package/frontend-vue/layers/dms-layout/app/components/layout/DashboardSearch.vue +109 -7
  388. package/frontend-vue/layers/dms-layout/app/components/navigation/NavigationMenu.vue +19 -9
  389. package/frontend-vue/layers/dms-layout/app/composables/notification/useNotifications.ts +22 -40
  390. package/frontend-vue/layers/dms-layout/app/composables/useAppSidePanels.ts +96 -0
  391. package/frontend-vue/layers/dms-layout/app/composables/useCommandPaletteAssistant.ts +129 -0
  392. package/frontend-vue/layers/dms-layout/app/composables/useHeaderActions.ts +33 -11
  393. package/frontend-vue/layers/dms-layout/app/composables/useSidePanel.ts +41 -0
  394. package/frontend-vue/layers/dms-layout/app/pages/[...slug].vue +15 -0
  395. package/frontend-vue/layers/dms-layout/app/plugins/notification-stream.client.ts +1 -7
  396. package/frontend-vue/layers/dms-layout/app/plugins/side-panel-host.ts +13 -0
  397. package/frontend-vue/layers/dms-layout/app/types/page.ts +11 -1
  398. package/frontend-vue/layers/dms-layout/i18n/locales/layout-en-GB.json +43 -13
  399. package/frontend-vue/layers/dms-layout/i18n/locales/layout-fr-FR.json +43 -13
  400. package/frontend-vue/layers/dms-ui/app/build/components/form/FormLoadError.vue +45 -0
  401. package/frontend-vue/layers/dms-ui/app/build/components/modal/ModalEscHint.vue +28 -0
  402. package/frontend-vue/layers/dms-ui/app/build/components/table-view/IdentityCell.vue +36 -7
  403. package/frontend-vue/layers/dms-ui/app/build/composables/data-types/cellHelpers.ts +57 -0
  404. package/frontend-vue/layers/dms-ui/app/build/composables/data-types/metricCells.ts +19 -5
  405. package/frontend-vue/layers/dms-ui/app/build/composables/data-types/registerDefaults.ts +22 -2
  406. package/frontend-vue/layers/dms-ui/app/build/composables/data-types/twoLineCell.ts +118 -0
  407. package/frontend-vue/layers/dms-ui/app/build/composables/data-types/useColumnValueRenderer.ts +5 -3
  408. package/frontend-vue/layers/dms-ui/app/build/composables/form/floatingSaveBars.ts +38 -0
  409. package/frontend-vue/layers/dms-ui/app/build/composables/form/formRecordLoad.ts +66 -0
  410. package/frontend-vue/layers/dms-ui/app/build/composables/navigation/useNavBadges.ts +50 -9
  411. package/frontend-vue/layers/dms-ui/app/build/composables/table/useTable.ts +7 -1
  412. package/frontend-vue/layers/dms-ui/app/build/composables/table-view/utils/chrome.ts +2 -2
  413. package/frontend-vue/layers/dms-ui/app/build/types/tree.ts +14 -10
  414. package/frontend-vue/layers/dms-ui/app/build/utils/navBadge.ts +12 -0
  415. package/frontend-vue/layers/dms-ui/app/build/utils/relativeDate.ts +4 -35
  416. package/frontend-vue/layers/dms-ui/app/build/utils/tone.ts +22 -0
  417. package/frontend-vue/layers/dms-ui/app/components/activity-feed/ActivityFeed.vue +117 -82
  418. package/frontend-vue/layers/dms-ui/app/components/blocks/BannerBlock.vue +8 -5
  419. package/frontend-vue/layers/dms-ui/app/components/blocks/KeyValueListBlock.vue +38 -18
  420. package/frontend-vue/layers/dms-ui/app/components/blocks/NavCardGridBlock.vue +12 -1
  421. package/frontend-vue/layers/dms-ui/app/components/blocks/StatGroupBlock.vue +26 -23
  422. package/frontend-vue/layers/dms-ui/app/components/card/NavCard.vue +16 -1
  423. package/frontend-vue/layers/dms-ui/app/components/confirm/ConfirmModal.vue +7 -8
  424. package/frontend-vue/layers/dms-ui/app/components/form/Form.vue +28 -6
  425. package/frontend-vue/layers/dms-ui/app/components/form/components/Display.vue +5 -1
  426. package/frontend-vue/layers/dms-ui/app/components/save-bar/SaveBar.vue +4 -0
  427. package/frontend-vue/layers/dms-ui/app/components/status-pill/StatusPill.vue +7 -2
  428. package/frontend-vue/layers/dms-ui/app/components/table-view/TableView.vue +7 -2
  429. package/frontend-vue/layers/dms-ui/app/composables/form/useForm.ts +48 -34
  430. package/frontend-vue/layers/dms-ui/app/composables/table-view/types/config.ts +13 -3
  431. package/frontend-vue/layers/dms-ui/i18n/locales/ui-en-GB.json +16 -14
  432. package/frontend-vue/layers/dms-ui/i18n/locales/ui-fr-FR.json +16 -14
  433. package/frontend-vue/package.json +2 -2
  434. package/frontend-vue/pnpm-lock.yaml +5 -5
  435. package/frontend-vue/tests/activity-feed-fill-height.test.ts +107 -0
  436. package/frontend-vue/tests/category-nav-cards.test.ts +21 -13
  437. package/frontend-vue/tests/command-palette-assistant.test.ts +344 -0
  438. package/frontend-vue/tests/composed-text-blocks.test.ts +205 -0
  439. package/frontend-vue/tests/composed-text.test.ts +265 -0
  440. package/frontend-vue/tests/fixtures/dashboard-search-stub.ts +91 -0
  441. package/frontend-vue/tests/forgot-validation-resend.test.ts +234 -0
  442. package/frontend-vue/tests/form-display-options.test.ts +64 -0
  443. package/frontend-vue/tests/form-load-error.test.ts +160 -0
  444. package/frontend-vue/tests/form-saved-before-success.test.ts +110 -0
  445. package/frontend-vue/tests/github-star-prompt.test.ts +328 -0
  446. package/frontend-vue/tests/header-actions.test.ts +191 -0
  447. package/frontend-vue/tests/invites-edit-modal.test.ts +157 -0
  448. package/frontend-vue/tests/layout-banners.test.ts +56 -0
  449. package/frontend-vue/tests/member-role-picker.test.ts +26 -0
  450. package/frontend-vue/tests/menu-hidden-page.test.ts +93 -0
  451. package/frontend-vue/tests/nav-badge-tones.test.ts +274 -0
  452. package/frontend-vue/tests/nav-card-badge.test.ts +69 -0
  453. package/frontend-vue/tests/nav-card-grid-empty-category.test.ts +163 -0
  454. package/frontend-vue/tests/notification-popover-errors.test.ts +71 -37
  455. package/frontend-vue/tests/notification-preferences-groups.test.ts +268 -0
  456. package/frontend-vue/tests/notification-tone-contract.test.ts +70 -0
  457. package/frontend-vue/tests/page-fill-height.test.ts +9 -1
  458. package/frontend-vue/tests/page-no-visible-blocks.test.ts +202 -0
  459. package/frontend-vue/tests/profile-preferences-summary.test.ts +26 -2
  460. package/frontend-vue/tests/profile-security-summary.test.ts +121 -0
  461. package/frontend-vue/tests/role-permission-tree.test.ts +102 -8
  462. package/frontend-vue/tests/role-permissions.test.ts +178 -56
  463. package/frontend-vue/tests/side-panels.test.ts +470 -0
  464. package/frontend-vue/tests/signup-invitation-link.test.ts +71 -2
  465. package/frontend-vue/tests/table-actions-column-width.test.ts +51 -1
  466. package/frontend-vue/tests/table-cell-sublines.test.ts +466 -0
  467. package/frontend-vue/tests/table-metric-cells.test.ts +4 -0
  468. package/frontend-vue/tests/table-view-chrome.test.ts +2 -2
  469. package/frontend-vue/tests/vue-inventory.test.ts +1 -1
  470. package/package.json +2 -2
  471. package/skills/dms/REFERENCE.md +1 -1
  472. package/skills/dms/SKILL.md +7 -0
@@ -36,6 +36,11 @@ interface ActivityFeedProps extends Partial<DefaultComponentProps> {
36
36
  groupByDay?: boolean;
37
37
  /** Shows at most this many entries. */
38
38
  maxItems?: number;
39
+ /**
40
+ * Fills its grid cell instead of growing with its entries, which scroll
41
+ * under the fixed head: the cards beside it set the row's height.
42
+ */
43
+ fillHeight?: boolean;
39
44
  /**
40
45
  * Placeholder rows while `fetchUrl` loads: the length the source usually
41
46
  * answers, never more than `maxItems`. Optional. Defaults to `maxItems`,
@@ -59,6 +64,7 @@ const props = withDefaults(defineProps<ActivityFeedProps>(), {
59
64
  fetchUrlMethod: undefined,
60
65
  groupByDay: true,
61
66
  maxItems: undefined,
67
+ fillHeight: false,
62
68
  skeletonCount: undefined,
63
69
  actions: () => [],
64
70
  empty: undefined,
@@ -137,6 +143,32 @@ const skeletonDays = computed<number[][]>(() => {
137
143
  }
138
144
  return days;
139
145
  });
146
+
147
+ // Filling its cell, the body is the scroll area: sized to nothing
148
+ // (`contain: size`), it leaves the row's height to the cards beside it and
149
+ // stretches to it. Once the grid stacks its cells (`--dms-grid-tracks: 1`,
150
+ // see grid/columns.ts) no neighbour sets that height: the list takes its own,
151
+ // capped like a top-list card's (24rem, about six entries under their day
152
+ // separators). Focusable, so the keyboard scrolls it too; its ring is drawn
153
+ // inside, where the card's clipped edge cannot hide it.
154
+ const scrollArea = computed(() =>
155
+ props.fillHeight
156
+ ? {
157
+ class:
158
+ "h-full overflow-y-auto overscroll-contain [scrollbar-width:thin] contain-size focus-visible:outline-2 focus-visible:-outline-offset-2 focus-visible:outline-(--dms-accent-line) [@container_style(--dms-grid-tracks:1)]:h-auto [@container_style(--dms-grid-tracks:1)]:max-h-[24rem] [@container_style(--dms-grid-tracks:1)]:contain-none",
159
+ role: "region",
160
+ tabindex: 0,
161
+ "aria-label": props.title
162
+ ? processI18n(props.title)
163
+ : t("dms.activity_feed.list_label"),
164
+ }
165
+ : {},
166
+ );
167
+ // Inside the scroll area, a day's separator stays on top of its entries.
168
+ const dayHeadClass = computed(
169
+ () => props.fillHeight && "sticky top-0 z-[1] bg-(--dms-surface-card)",
170
+ );
171
+
140
172
  const Wrapper = props.card ? resolveComponent("DmsCard") : "div";
141
173
  const wrapperProps = computed(() =>
142
174
  props.card
@@ -161,91 +193,94 @@ const wrapperProps = computed(() =>
161
193
  />
162
194
  </template>
163
195
 
164
- <!-- Rows at the loaded rows' boxes (a 18px title line over a 16px meta
165
- line beside the 30px well), split by the same hairlines. -->
166
- <div v-if="isFirstLoad" class="py-1" aria-busy="true">
167
- <div v-for="(day, dayIndex) in skeletonDays" :key="dayIndex">
168
- <div
169
- v-if="props.groupByDay"
170
- class="flex items-center gap-2.5 px-[18px] pt-3.5 pb-1.5 after:h-px after:flex-1 after:bg-(--ui-border-muted)"
171
- >
172
- <USkeleton class="my-[1.5px] h-2.5 w-24" />
173
- </div>
174
- <div class="divide-y divide-(--ui-border-muted)">
175
- <DmsRowSkeleton
176
- v-for="row in day"
177
- :key="row"
178
- class="px-[18px] py-2.5"
179
- well="size-[30px] rounded-lg"
180
- :lines="[
181
- `my-[3px] h-3 ${SKELETON_TITLE_WIDTHS[row % SKELETON_TITLE_WIDTHS.length]}`,
182
- 'my-[3px] h-2.5 w-1/3',
183
- ]"
184
- lines-class="grid gap-px"
185
- />
196
+ <div v-bind="scrollArea">
197
+ <!-- Rows at the loaded rows' boxes (a 18px title line over a 16px meta
198
+ line beside the 30px well), split by the same hairlines. -->
199
+ <div v-if="isFirstLoad" class="py-1" aria-busy="true">
200
+ <div v-for="(day, dayIndex) in skeletonDays" :key="dayIndex">
201
+ <div
202
+ v-if="props.groupByDay"
203
+ class="flex items-center gap-2.5 px-[18px] pt-3.5 pb-1.5 after:h-px after:flex-1 after:bg-(--ui-border-muted)"
204
+ >
205
+ <USkeleton class="my-[1.5px] h-2.5 w-24" />
206
+ </div>
207
+ <div class="divide-y divide-(--ui-border-muted)">
208
+ <DmsRowSkeleton
209
+ v-for="row in day"
210
+ :key="row"
211
+ class="px-[18px] py-2.5"
212
+ well="size-[30px] rounded-lg"
213
+ :lines="[
214
+ `my-[3px] h-3 ${SKELETON_TITLE_WIDTHS[row % SKELETON_TITLE_WIDTHS.length]}`,
215
+ 'my-[3px] h-2.5 w-1/3',
216
+ ]"
217
+ lines-class="grid gap-px"
218
+ />
219
+ </div>
186
220
  </div>
187
221
  </div>
188
- </div>
189
222
 
190
- <DmsEmptyState
191
- v-else-if="hasError"
192
- variant="error"
193
- size="sm"
194
- :title="t('dms.activity_feed.error_title')"
195
- :description="t('dms.activity_feed.error_description')"
196
- :actions="[
197
- {
198
- label: t('dms.activity_feed.retry'),
199
- icon: 'i-ph-arrow-clockwise',
200
- color: 'neutral',
201
- variant: 'outline',
202
- onClick: () => refresh(),
203
- },
204
- ]"
205
- />
206
-
207
- <DmsEmptyState
208
- v-else-if="!entries.length"
209
- icon="i-ph-tray"
210
- size="sm"
211
- :title="
212
- props.empty
213
- ? processI18n(props.empty.title)
214
- : t('dms.activity_feed.empty_title')
215
- "
216
- :description="
217
- props.empty?.description
218
- ? processI18n(props.empty.description)
219
- : undefined
220
- "
221
- />
222
-
223
- <div v-else class="py-1">
224
- <section v-for="day in days" :key="day.key">
225
- <!-- v2 .feed__day: "Today · Sep 29" and a hairline to the edge. -->
226
- <div
227
- v-if="props.groupByDay && day.name"
228
- class="flex items-center gap-2.5 px-[18px] pt-3.5 pb-1.5 after:h-px after:flex-1 after:bg-(--ui-border-muted)"
229
- >
230
- <DmsEyebrow as="h3">
231
- <b class="text-muted font-semibold">{{ day.name }}</b>
232
- {{ day.date ? ` · ${day.date}` : "" }}
233
- </DmsEyebrow>
234
- </div>
235
- <DmsActivityItem
236
- v-for="(item, index) in day.items"
237
- :key="item.id ?? `${day.key}-${index}`"
238
- :icon="item.icon"
239
- :icon-color="item.tone ?? 'neutral'"
240
- :title="textOf(item, item.title)"
241
- :subtitle="metaOf(item)"
242
- :trailing="trailingOf(item)"
243
- :unread="item.unread"
244
- :mono="props.mono"
245
- :to="item.to"
246
- :interactive="!!item.to"
247
- />
248
- </section>
223
+ <DmsEmptyState
224
+ v-else-if="hasError"
225
+ variant="error"
226
+ size="sm"
227
+ :title="t('dms.activity_feed.error_title')"
228
+ :description="t('dms.activity_feed.error_description')"
229
+ :actions="[
230
+ {
231
+ label: t('dms.activity_feed.retry'),
232
+ icon: 'i-ph-arrow-clockwise',
233
+ color: 'neutral',
234
+ variant: 'outline',
235
+ onClick: () => refresh(),
236
+ },
237
+ ]"
238
+ />
239
+
240
+ <DmsEmptyState
241
+ v-else-if="!entries.length"
242
+ icon="i-ph-tray"
243
+ size="sm"
244
+ :title="
245
+ props.empty
246
+ ? processI18n(props.empty.title)
247
+ : t('dms.activity_feed.empty_title')
248
+ "
249
+ :description="
250
+ props.empty?.description
251
+ ? processI18n(props.empty.description)
252
+ : undefined
253
+ "
254
+ />
255
+
256
+ <div v-else class="py-1">
257
+ <section v-for="day in days" :key="day.key">
258
+ <!-- v2 .feed__day: "Today · Sep 29" and a hairline to the edge. -->
259
+ <div
260
+ v-if="props.groupByDay && day.name"
261
+ class="flex items-center gap-2.5 px-[18px] pt-3.5 pb-1.5 after:h-px after:flex-1 after:bg-(--ui-border-muted)"
262
+ :class="dayHeadClass"
263
+ >
264
+ <DmsEyebrow as="h3">
265
+ <b class="text-muted font-semibold">{{ day.name }}</b>
266
+ {{ day.date ? ` · ${day.date}` : "" }}
267
+ </DmsEyebrow>
268
+ </div>
269
+ <DmsActivityItem
270
+ v-for="(item, index) in day.items"
271
+ :key="item.id ?? `${day.key}-${index}`"
272
+ :icon="item.icon"
273
+ :icon-color="item.tone ?? 'neutral'"
274
+ :title="textOf(item, item.title)"
275
+ :subtitle="metaOf(item)"
276
+ :trailing="trailingOf(item)"
277
+ :unread="item.unread"
278
+ :mono="props.mono"
279
+ :to="item.to"
280
+ :interactive="!!item.to"
281
+ />
282
+ </section>
283
+ </div>
249
284
  </div>
250
285
  </component>
251
286
  </template>
@@ -5,7 +5,9 @@ import DmsBlockActions, {
5
5
  type BlockAction,
6
6
  } from "../../build/components/blocks/BlockActions.vue";
7
7
  import { useWatch } from "../../../../dms-core/app/composables/watch/useWatch";
8
+ import { useComposedText } from "../../../../dms-core/app/composables/translation/useComposedText";
8
9
  import type { DefaultComponentProps } from "../../../../dms-core/app/types/component";
10
+ import type { BlockText } from "../../../../dms-core/app/types/composed-text";
9
11
 
10
12
  type BannerTone = "info" | "success" | "warning" | "error" | "primary";
11
13
 
@@ -14,8 +16,9 @@ type BannerTone = "info" | "success" | "warning" | "error" | "primary";
14
16
  // Dismissals live in a cookie (like the dashboard banners) so the server
15
17
  // render already leaves a dismissed banner out instead of flashing it.
16
18
  interface BannerBlockProps extends Partial<DefaultComponentProps> {
17
- title?: string;
18
- description?: string;
19
+ /** A string (`$` for an i18n key) or a composed text. */
20
+ title?: BlockText;
21
+ description?: BlockText;
19
22
  tone?: BannerTone;
20
23
  /** Overrides the tone's icon. */
21
24
  icon?: string;
@@ -56,7 +59,7 @@ const TONE_ICONS: Record<BannerTone, string> = {
56
59
 
57
60
  useWatch(props.watchActions || [], props.componentId);
58
61
 
59
- const { processI18n } = useTranslation();
62
+ const { processText } = useComposedText();
60
63
  const dismissed = useDmsCookie<string[]>(DISMISSED_COOKIE, {
61
64
  default: () => [],
62
65
  maxAge: DISMISSED_MAX_AGE_S,
@@ -91,9 +94,9 @@ function dismiss(): void {
91
94
  <template>
92
95
  <DmsBanner
93
96
  v-if="isVisible"
94
- :title="props.title ? processI18n(props.title) : undefined"
97
+ :title="props.title ? processText(props.title) : undefined"
95
98
  :description="
96
- props.description ? processI18n(props.description) : undefined
99
+ props.description ? processText(props.description) : undefined
97
100
  "
98
101
  :icon="props.icon ?? TONE_ICONS[props.tone]"
99
102
  :tone="props.tone"
@@ -8,13 +8,24 @@ import DmsBlockStatus, {
8
8
  type BlockEmptyText,
9
9
  } from "../../build/components/blocks/BlockStatus.vue";
10
10
  import { useBlockItems } from "../../build/composables/blocks/useBlockItems";
11
+ import { useComposedText } from "../../../../dms-core/app/composables/translation/useComposedText";
11
12
  import type { DefaultComponentProps } from "../../../../dms-core/app/types/component";
13
+ import type { BlockText } from "../../../../dms-core/app/types/composed-text";
14
+ import { isComposedText } from "../../../../dms-core/app/utils/composedText";
12
15
 
13
16
  // `KeyValueList` block (interface-dms `base/key-value-list`): label / value
14
17
  // rows (v2 .c-dl), static or from `fetchUrl` (`{ items }`), in a card by
15
- // default. Labels, details and text values follow the `$` i18n convention.
18
+ // default. Labels, details and text values follow the `$` i18n convention or
19
+ // are composed texts.
20
+ interface KeyValueListBlockItem
21
+ extends Omit<KeyValueItem, "label" | "value" | "detail"> {
22
+ label: BlockText;
23
+ value?: BlockText | number | null;
24
+ detail?: BlockText;
25
+ }
26
+
16
27
  interface KeyValueListBlockProps extends DefaultComponentProps {
17
- items?: KeyValueItem[];
28
+ items?: KeyValueListBlockItem[];
18
29
  dense?: boolean;
19
30
  columns?: number;
20
31
  currency?: string;
@@ -50,30 +61,39 @@ const props = withDefaults(defineProps<KeyValueListBlockProps>(), {
50
61
 
51
62
  const TRANSLATED_TYPES = new Set([undefined, "text", "status", "link"]);
52
63
 
53
- const { processI18n } = useTranslation();
64
+ const { processText } = useComposedText();
54
65
 
55
- const { items, isPending, hasError, refresh } = useBlockItems<KeyValueItem>({
56
- items: () => props.items,
57
- fetchUrl: props.fetchUrl,
58
- fetchUrlMethod: props.fetchUrlMethod,
59
- routeParams: () => props.routeParams,
60
- watchActions: props.watchActions,
61
- componentId: props.componentId,
62
- });
66
+ const { items, isPending, hasError, refresh } =
67
+ useBlockItems<KeyValueListBlockItem>({
68
+ items: () => props.items,
69
+ fetchUrl: props.fetchUrl,
70
+ fetchUrlMethod: props.fetchUrlMethod,
71
+ routeParams: () => props.routeParams,
72
+ watchActions: props.watchActions,
73
+ componentId: props.componentId,
74
+ });
75
+
76
+ // A composed value already says how each of its parameters is written, so it
77
+ // is composed whatever the row's type; a plain one is translated only where
78
+ // the type draws text.
79
+ function resolveValue(item: KeyValueListBlockItem): KeyValueItem["value"] {
80
+ if (isComposedText(item.value)) return processText(item.value);
81
+ if (typeof item.value === "string" && TRANSLATED_TYPES.has(item.type)) {
82
+ return processText(item.value);
83
+ }
84
+ return item.value as KeyValueItem["value"];
85
+ }
63
86
 
64
87
  const resolvedItems = computed<KeyValueItem[]>(() =>
65
88
  items.value.map((item) => ({
66
89
  ...item,
67
- label: processI18n(item.label ?? ""),
68
- detail: item.detail ? processI18n(item.detail) : undefined,
69
- value:
70
- typeof item.value === "string" && TRANSLATED_TYPES.has(item.type)
71
- ? processI18n(item.value)
72
- : item.value,
90
+ label: processText(item.label),
91
+ detail: item.detail ? processText(item.detail) : undefined,
92
+ value: resolveValue(item),
73
93
  })),
74
94
  );
75
95
  const title = computed(() =>
76
- props.title ? processI18n(props.title) : undefined,
96
+ props.title ? processText(props.title) : undefined,
77
97
  );
78
98
  const isEmpty = computed(
79
99
  () => !isPending.value && !hasError.value && resolvedItems.value.length === 0,
@@ -30,6 +30,9 @@ interface NavCardGridItem {
30
30
  stateTone?: Tone;
31
31
  tag?: string;
32
32
  readout?: string[];
33
+ /** The page's navigation badge (a category's cards), in the top corner. */
34
+ badge?: string;
35
+ badgeTone?: Tone;
33
36
  }
34
37
 
35
38
  interface NavCardGridBlockProps extends DefaultComponentProps {
@@ -125,10 +128,16 @@ const cards = computed(() =>
125
128
  // v2 .sx-grid: cards closing on a state line run a tighter rhythm, the whole
126
129
  // grid at once so the rows stay aligned.
127
130
  const hasStates = computed(() => cards.value.some((card) => !!card.state));
131
+ // A category the viewer opens no page of is left out, title included, as the
132
+ // navigation leaves out an empty group: the settings overview of a member
133
+ // without a role shows no Workspace section. `empty` shows a message instead.
134
+ const isLeftOut = computed(
135
+ () => !!props.categoryId && !props.empty && cards.value.length === 0,
136
+ );
128
137
  </script>
129
138
 
130
139
  <template>
131
- <section>
140
+ <section v-if="!isLeftOut">
132
141
  <DmsSectionHeader
133
142
  v-if="props.title || props.description"
134
143
  class="mb-3"
@@ -190,6 +199,8 @@ const hasStates = computed(() => cards.value.some((card) => !!card.state));
190
199
  :state="card.state"
191
200
  :state-tone="card.stateTone"
192
201
  :tag="card.tag"
202
+ :badge="card.badge"
203
+ :badge-tone="card.badgeTone"
193
204
  :readout="card.readout"
194
205
  :class="hasStates && 'gap-2.5'"
195
206
  />
@@ -8,13 +8,23 @@ import DmsBlockStatus, {
8
8
  type BlockEmptyText,
9
9
  } from "../../build/components/blocks/BlockStatus.vue";
10
10
  import { useBlockItems } from "../../build/composables/blocks/useBlockItems";
11
+ import { useComposedText } from "../../../../dms-core/app/composables/translation/useComposedText";
11
12
  import type { DefaultComponentProps } from "../../../../dms-core/app/types/component";
13
+ import type { BlockText } from "../../../../dms-core/app/types/composed-text";
12
14
 
13
15
  // `StatGroup` block (interface-dms `base/stat-group`): the generic StatGroup
14
16
  // fed from the block options or from `fetchUrl` (`{ items }`). Texts follow
15
- // the `$` i18n-key convention; numeric values are formatted for the locale.
17
+ // the `$` i18n-key convention or are composed texts; numeric values are
18
+ // formatted for the locale.
19
+ interface StatGroupBlockItem
20
+ extends Omit<StatGroupItem, "eyebrow" | "value" | "detail"> {
21
+ eyebrow: BlockText;
22
+ value: BlockText | number;
23
+ detail?: BlockText;
24
+ }
25
+
16
26
  interface StatGroupBlockProps extends DefaultComponentProps {
17
- items?: StatGroupItem[];
27
+ items?: StatGroupBlockItem[];
18
28
  layout?: StatGroupLayout;
19
29
  columns?: number;
20
30
  /** Accessible name of the group. */
@@ -43,31 +53,24 @@ const props = withDefaults(defineProps<StatGroupBlockProps>(), {
43
53
 
44
54
  const DEFAULT_SKELETON_COUNT = 4;
45
55
 
46
- const { locale } = useI18n();
47
- const { processI18n } = useTranslation();
56
+ const { processText } = useComposedText();
48
57
 
49
- const { items, isPending, hasError, refresh } = useBlockItems<StatGroupItem>({
50
- items: () => props.items,
51
- fetchUrl: props.fetchUrl,
52
- fetchUrlMethod: props.fetchUrlMethod,
53
- routeParams: () => props.routeParams,
54
- watchActions: props.watchActions,
55
- componentId: props.componentId,
56
- });
57
-
58
- function formatValue(value: StatGroupItem["value"]): string {
59
- if (typeof value === "number") {
60
- return new Intl.NumberFormat(locale.value).format(value);
61
- }
62
- return processI18n(String(value ?? ""));
63
- }
58
+ const { items, isPending, hasError, refresh } =
59
+ useBlockItems<StatGroupBlockItem>({
60
+ items: () => props.items,
61
+ fetchUrl: props.fetchUrl,
62
+ fetchUrlMethod: props.fetchUrlMethod,
63
+ routeParams: () => props.routeParams,
64
+ watchActions: props.watchActions,
65
+ componentId: props.componentId,
66
+ });
64
67
 
65
68
  const resolvedItems = computed<StatGroupItem[]>(() =>
66
69
  items.value.map((item) => ({
67
70
  ...item,
68
- eyebrow: processI18n(item.eyebrow ?? ""),
69
- value: formatValue(item.value),
70
- detail: item.detail ? processI18n(item.detail) : undefined,
71
+ eyebrow: processText(item.eyebrow),
72
+ value: processText(item.value),
73
+ detail: item.detail ? processText(item.detail) : undefined,
71
74
  })),
72
75
  );
73
76
  </script>
@@ -88,6 +91,6 @@ const resolvedItems = computed<StatGroupItem[]>(() =>
88
91
  :skeleton-count="
89
92
  props.skeletonCount ?? props.columns ?? DEFAULT_SKELETON_COUNT
90
93
  "
91
- :label="props.label ? processI18n(props.label) : undefined"
94
+ :label="props.label ? processText(props.label) : undefined"
92
95
  />
93
96
  </template>
@@ -6,12 +6,14 @@ import DmsStatusPill from "../status-pill/StatusPill.vue";
6
6
  import DmsAutoLink from "../link/AutoLink.vue";
7
7
  import type { Tone } from "../../types/tone";
8
8
  import { MONO_TAG_CLASS } from "../../build/utils/monoChip";
9
+ import { navBadgeClass } from "../../build/utils/navBadge";
9
10
 
10
11
  // Navigation tile (v2 .navcard): an icon well + title + description rendered
11
12
  // as a clickable card linking elsewhere (settings overview, a module's home),
12
13
  // optionally closed by the target's live state (v2 .sx-state, pinned to the
13
14
  // bottom so the states of a row line up) or a mono readout (v2
14
- // .module-tile__viz). A tag follows the title (v2 .sx-mod).
15
+ // .module-tile__viz). A tag follows the title (v2 .sx-mod); the target's
16
+ // navigation badge sits in the top corner, drawn as the settings nav draws it.
15
17
  //
16
18
  // Built on a bare <DmsAutoLink> rather than <ULink> on purpose: ULink's theme
17
19
  // injects its own `rounded-md` which would override the .dms-card radius.
@@ -34,6 +36,10 @@ interface NavCardProps {
34
36
  statePending?: boolean;
35
37
  /** Small uppercase mono tag after the title (module tag: "SAAS"). */
36
38
  tag?: string;
39
+ /** The target's navigation badge ("3"), in the card's top corner. */
40
+ badge?: string;
41
+ /** Tone of the badge; neutral grey when absent. */
42
+ badgeTone?: Tone;
37
43
  /** Mono readout lines under the description (module tile). */
38
44
  readout?: string[];
39
45
  }
@@ -46,6 +52,8 @@ const props = withDefaults(defineProps<NavCardProps>(), {
46
52
  state: undefined,
47
53
  stateTone: "neutral",
48
54
  tag: undefined,
55
+ badge: undefined,
56
+ badgeTone: undefined,
49
57
  readout: undefined,
50
58
  });
51
59
  const attrs = useAttrs();
@@ -55,6 +63,7 @@ const theme = tv({
55
63
  root: "dms-card dms-card--interactive group flex flex-col gap-3 p-[18px] text-start",
56
64
  title: "text-highlighted min-w-0 truncate text-sm font-[650]",
57
65
  tag: `${MONO_TAG_CLASS} bg-elevated shrink-0 text-dimmed`,
66
+ badge: "shrink-0",
58
67
  arrow:
59
68
  "text-dimmed group-hover:text-primary ms-auto size-4 shrink-0 -translate-x-[3px] opacity-0 transition group-hover:translate-x-0 group-hover:opacity-100",
60
69
  description: "text-muted text-[13px] leading-normal",
@@ -78,6 +87,12 @@ const passthrough = computed(() => {
78
87
  <h3 :class="ui.title()">{{ props.title }}</h3>
79
88
  <span v-if="props.tag" :class="ui.tag()">{{ props.tag }}</span>
80
89
  <UIcon name="i-ph-arrow-right" :class="ui.arrow()" :aria-hidden="true" />
90
+ <span
91
+ v-if="props.badge"
92
+ :class="ui.badge({ class: navBadgeClass(props.badgeTone) })"
93
+ >
94
+ {{ props.badge }}
95
+ </span>
81
96
  </div>
82
97
 
83
98
  <p v-if="props.description" :class="ui.description()">
@@ -2,6 +2,7 @@
2
2
  import { nextTick, useTemplateRef, watch, type FunctionalComponent } from "vue";
3
3
  import { DialogDescription, DialogTitle } from "reka-ui";
4
4
  import DmsIconWell from "../icon-well/IconWell.vue";
5
+ import DmsModalEscHint from "../../build/components/modal/ModalEscHint.vue";
5
6
  import {
6
7
  ConfirmActionError,
7
8
  type ConfirmBodyRender,
@@ -454,16 +455,14 @@ function handleCancel() {
454
455
 
455
456
  <template #footer>
456
457
  <div class="flex w-full items-center justify-end gap-2">
457
- <span
458
- class="text-dimmed me-auto hidden items-center gap-1.5 text-xs sm:flex"
459
- >
460
- <UKbd value="Esc" size="sm" />
461
- {{
458
+ <DmsModalEscHint
459
+ class="max-sm:hidden"
460
+ :label="
462
461
  $t(
463
- isSettled ? "dms.confirm.esc_close_hint" : "dms.confirm.esc_hint",
462
+ isSettled ? 'dms.confirm.esc_close_hint' : 'dms.confirm.esc_hint',
464
463
  )
465
- }}
466
- </span>
464
+ "
465
+ />
467
466
  <UButton
468
467
  :label="
469
468
  isSettled
@@ -57,6 +57,11 @@ import { useInstantForm } from "../../build/composables/form/useInstantForm";
57
57
  import { useInstantSaveHeader } from "#dms-layout/app/composables/layout/useInstantSaveHeader";
58
58
  import DmsFormEntries from "../../build/components/form/FormEntries.vue";
59
59
  import DmsFormErrorSummary from "../../build/components/form/FormErrorSummary.vue";
60
+ import DmsFormLoadError from "../../build/components/form/FormLoadError.vue";
61
+ import {
62
+ type FormRecordLoad,
63
+ trackFormRecordLoad,
64
+ } from "../../build/composables/form/formRecordLoad";
60
65
  import DmsFormRequiredLegend from "../../build/components/form/FormRequiredLegend.vue";
61
66
  import DmsFormSections from "../../build/components/form/FormSections.vue";
62
67
 
@@ -506,7 +511,7 @@ function setFieldLoading(id: string, isLoading: boolean): void {
506
511
  const isAnyFieldLoading = computed(() => fieldLoadingStates.value.size > 0);
507
512
 
508
513
  function onSubmit(event: Parameters<typeof handleSubmit>[0]) {
509
- if (!runValidators()) return;
514
+ if (loadFailure.value || !runValidators()) return;
510
515
  handleSubmit(event);
511
516
  }
512
517
 
@@ -522,6 +527,7 @@ allFields.value.forEach((field) => {
522
527
  ) as FormFieldValue;
523
528
  });
524
529
 
530
+ let recordLoad: FormRecordLoad | undefined;
525
531
  if (props.fetchUrl) {
526
532
  const formLoad = await useDmsAsyncData(
527
533
  `form-${props.componentId}-${props.pageId}`,
@@ -539,15 +545,23 @@ if (props.fetchUrl) {
539
545
  formLoad.status.value = "idle";
540
546
  });
541
547
 
542
- const payload = formLoad.data.value;
543
- if (payload) {
548
+ recordLoad = trackFormRecordLoad(formLoad, (payload) => {
544
549
  if (payload.values && Object.keys(payload.values).length > 0) {
545
550
  Object.assign(state.value, payload.values);
546
551
  }
547
552
  if (payload.initial && payload.initial !== initialValues.value) {
548
553
  initialValues.value = { ...initialValues.value, ...payload.initial };
549
554
  }
550
- }
555
+ });
556
+ }
557
+
558
+ const loadFailure = computed(() => recordLoad?.failure.value ?? null);
559
+ const isRetryingLoad = computed(() => recordLoad?.retrying.value ?? false);
560
+
561
+ /** Load the record again after a failure; it is what the form starts from. */
562
+ async function retryRecordLoad(): Promise<void> {
563
+ await recordLoad?.retry();
564
+ if (!recordLoad?.failure.value) markFormClean();
551
565
  }
552
566
 
553
567
  // Loaded (or filled with its defaults): this is what the form starts from.
@@ -868,7 +882,15 @@ onUnmounted(async () => {
868
882
  </p>
869
883
  </header>
870
884
 
871
- <div :class="surfaceClasses.body">
885
+ <div v-if="loadFailure" :class="surfaceClasses.body">
886
+ <DmsFormLoadError
887
+ :failure="loadFailure"
888
+ :retrying="isRetryingLoad"
889
+ @retry="retryRecordLoad"
890
+ />
891
+ </div>
892
+
893
+ <div v-else :class="surfaceClasses.body">
872
894
  <UAlert
873
895
  v-if="showConcurrentEditBanner"
874
896
  color="warning"
@@ -935,7 +957,7 @@ onUnmounted(async () => {
935
957
  on a page, the footer band of a card, a drawer or a modal. It holds
936
958
  its place while hidden, so its showing up never moves anything. -->
937
959
  <DmsSaveBar
938
- v-if="canSave && !isInstant"
960
+ v-if="canSave && !isInstant && !loadFailure"
939
961
  :variant="usesSaveBar ? 'floating' : 'band'"
940
962
  :kind="props.kind"
941
963
  :dirty="isDirty"