@antelopejs/dms 0.6.2 → 0.7.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 (444) hide show
  1. package/CHANGELOG.md +30 -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/nav-badges.d.ts +6 -4
  27. package/dist/implementations/dms/nav-badges.js +6 -5
  28. package/dist/implementations/dms/nav-badges.js.map +1 -1
  29. package/dist/implementations/dms/page.d.ts +1 -0
  30. package/dist/implementations/dms/page.js +46 -8
  31. package/dist/implementations/dms/page.js.map +1 -1
  32. package/dist/implementations/dms/permission-preview.d.ts +1 -1
  33. package/dist/implementations/dms/permission-preview.js +9 -4
  34. package/dist/implementations/dms/permission-preview.js.map +1 -1
  35. package/dist/implementations/dms-auth/index.d.ts +3 -2
  36. package/dist/implementations/dms-auth/index.js +39 -35
  37. package/dist/implementations/dms-auth/index.js.map +1 -1
  38. package/dist/implementations/dms-auth/token-session.d.ts +3 -0
  39. package/dist/implementations/dms-auth/token-session.js +22 -0
  40. package/dist/implementations/dms-auth/token-session.js.map +1 -0
  41. package/dist/implementations/dms-notifications/index.d.ts +0 -1
  42. package/dist/implementations/dms-notifications/index.js +0 -7
  43. package/dist/implementations/dms-notifications/index.js.map +1 -1
  44. package/dist/pages/settings/settings-index.js +3 -2
  45. package/dist/pages/settings/settings-index.js.map +1 -1
  46. package/dist/pages/settings/users/account-activity-feed.d.ts +1 -1
  47. package/dist/pages/settings/users/account-activity-feed.js +1 -1
  48. package/dist/pages/settings/users/account-activity-feed.js.map +1 -1
  49. package/dist/pages/settings/users/account-activity.d.ts +1 -1
  50. package/dist/pages/settings/users/account-activity.js +1 -1
  51. package/dist/pages/settings/users/account-activity.js.map +1 -1
  52. package/dist/pages/settings/users/account-credentials.d.ts +3 -0
  53. package/dist/pages/settings/users/account-credentials.js +2 -0
  54. package/dist/pages/settings/users/account-credentials.js.map +1 -1
  55. package/dist/pages/settings/users/current-password.d.ts +1 -1
  56. package/dist/pages/settings/users/current-password.js +23 -2
  57. package/dist/pages/settings/users/current-password.js.map +1 -1
  58. package/dist/pages/settings/users/email-change.d.ts +1 -1
  59. package/dist/pages/settings/users/email-change.js +33 -26
  60. package/dist/pages/settings/users/email-change.js.map +1 -1
  61. package/dist/pages/settings/users/invite-resend.js +0 -1
  62. package/dist/pages/settings/users/invite-resend.js.map +1 -1
  63. package/dist/pages/settings/users/invites.d.ts +1 -2
  64. package/dist/pages/settings/users/invites.js +21 -19
  65. package/dist/pages/settings/users/invites.js.map +1 -1
  66. package/dist/pages/settings/users/member-invite-batch.js +0 -1
  67. package/dist/pages/settings/users/member-invite-batch.js.map +1 -1
  68. package/dist/pages/settings/users/member-invite-form.js +10 -22
  69. package/dist/pages/settings/users/member-invite-form.js.map +1 -1
  70. package/dist/pages/settings/users/member-role-options.d.ts +6 -4
  71. package/dist/pages/settings/users/member-role-options.js +15 -4
  72. package/dist/pages/settings/users/member-role-options.js.map +1 -1
  73. package/dist/pages/settings/users/members.d.ts +2 -3
  74. package/dist/pages/settings/users/members.js +7 -12
  75. package/dist/pages/settings/users/members.js.map +1 -1
  76. package/dist/pages/settings/users/notifications.d.ts +1 -8
  77. package/dist/pages/settings/users/notifications.js +6 -38
  78. package/dist/pages/settings/users/notifications.js.map +1 -1
  79. package/dist/pages/settings/users/permission-tree-nodes.d.ts +1 -1
  80. package/dist/pages/settings/users/permission-tree-nodes.js +23 -9
  81. package/dist/pages/settings/users/permission-tree-nodes.js.map +1 -1
  82. package/dist/pages/settings/users/permission-warnings.d.ts +7 -0
  83. package/dist/pages/settings/users/permission-warnings.js +42 -0
  84. package/dist/pages/settings/users/permission-warnings.js.map +1 -0
  85. package/dist/pages/settings/users/profile-helpers.d.ts +1 -3
  86. package/dist/pages/settings/users/profile-helpers.js +0 -16
  87. package/dist/pages/settings/users/profile-helpers.js.map +1 -1
  88. package/dist/pages/settings/users/role-editor-store.js +6 -3
  89. package/dist/pages/settings/users/role-editor-store.js.map +1 -1
  90. package/dist/pages/settings/users/role-editor.d.ts +2 -1
  91. package/dist/pages/settings/users/role-editor.js +8 -4
  92. package/dist/pages/settings/users/role-editor.js.map +1 -1
  93. package/dist/pages/settings/users/role-preview.js +2 -1
  94. package/dist/pages/settings/users/role-preview.js.map +1 -1
  95. package/dist/pages/settings/users/roles.js +5 -1
  96. package/dist/pages/settings/users/roles.js.map +1 -1
  97. package/dist/pages/settings/users/security-attention.d.ts +4 -0
  98. package/dist/pages/settings/users/security-attention.js +23 -7
  99. package/dist/pages/settings/users/security-attention.js.map +1 -1
  100. package/dist/pages/settings/users/security.d.ts +2 -1
  101. package/dist/pages/settings/users/security.js +13 -2
  102. package/dist/pages/settings/users/security.js.map +1 -1
  103. package/dist/pages/settings/users/two-factor-operations.d.ts +2 -1
  104. package/dist/pages/settings/users/two-factor-operations.js +28 -29
  105. package/dist/pages/settings/users/two-factor-operations.js.map +1 -1
  106. package/dist/routes/auth/forgot-password.js +3 -0
  107. package/dist/routes/auth/forgot-password.js.map +1 -1
  108. package/dist/routes/auth/index.d.ts +1 -0
  109. package/dist/routes/auth/index.js +1 -0
  110. package/dist/routes/auth/index.js.map +1 -1
  111. package/dist/routes/auth/invite.js +28 -4
  112. package/dist/routes/auth/invite.js.map +1 -1
  113. package/dist/routes/auth/login-throttle.d.ts +2 -0
  114. package/dist/routes/auth/login-throttle.js +5 -4
  115. package/dist/routes/auth/login-throttle.js.map +1 -1
  116. package/dist/routes/auth/request-2fa-email.js +6 -18
  117. package/dist/routes/auth/request-2fa-email.js.map +1 -1
  118. package/dist/routes/auth/reset-code.d.ts +3 -0
  119. package/dist/routes/auth/reset-code.js +37 -0
  120. package/dist/routes/auth/reset-code.js.map +1 -0
  121. package/dist/routes/auth/reset-password.d.ts +2 -2
  122. package/dist/routes/auth/reset-password.js +5 -10
  123. package/dist/routes/auth/reset-password.js.map +1 -1
  124. package/dist/routes/auth/signup.js +10 -32
  125. package/dist/routes/auth/signup.js.map +1 -1
  126. package/dist/routes/auth/two-factor-throttle.d.ts +5 -0
  127. package/dist/routes/auth/two-factor-throttle.js +81 -0
  128. package/dist/routes/auth/two-factor-throttle.js.map +1 -0
  129. package/dist/routes/auth/validate-forgot-password-token.js +2 -8
  130. package/dist/routes/auth/validate-forgot-password-token.js.map +1 -1
  131. package/dist/routes/auth/validate-invite-token.d.ts +1 -0
  132. package/dist/routes/auth/validate-invite-token.js +11 -0
  133. package/dist/routes/auth/validate-invite-token.js.map +1 -0
  134. package/dist/routes/auth/verify-2fa.js +10 -13
  135. package/dist/routes/auth/verify-2fa.js.map +1 -1
  136. package/dist/routes/auth.d.ts +1 -0
  137. package/dist/routes/auth.js +11 -1
  138. package/dist/routes/auth.js.map +1 -1
  139. package/dist/test/helpers/auth.d.ts +0 -1
  140. package/dist/test/helpers/auth.js +0 -1
  141. package/dist/test/helpers/auth.js.map +1 -1
  142. package/dist/test/helpers/emails.d.ts +10 -0
  143. package/dist/test/helpers/emails.js +36 -0
  144. package/dist/test/helpers/emails.js.map +1 -0
  145. package/dist/test/helpers/fixtures.d.ts +0 -1
  146. package/dist/test/helpers/fixtures.js +1 -2
  147. package/dist/test/helpers/fixtures.js.map +1 -1
  148. package/dist/test/helpers/page-access.d.ts +1 -0
  149. package/dist/test/helpers/page-access.js +6 -1
  150. package/dist/test/helpers/page-access.js.map +1 -1
  151. package/dist/test/integration/auth/current-password.test.d.ts +1 -0
  152. package/dist/test/integration/auth/current-password.test.js +65 -0
  153. package/dist/test/integration/auth/current-password.test.js.map +1 -0
  154. package/dist/test/integration/auth/password-reset.test.d.ts +1 -0
  155. package/dist/test/integration/auth/password-reset.test.js +126 -0
  156. package/dist/test/integration/auth/password-reset.test.js.map +1 -0
  157. package/dist/test/integration/auth/session-revocation.test.d.ts +1 -0
  158. package/dist/test/integration/auth/session-revocation.test.js +45 -0
  159. package/dist/test/integration/auth/session-revocation.test.js.map +1 -0
  160. package/dist/test/integration/auth/two-factor-codes.test.d.ts +1 -0
  161. package/dist/test/integration/auth/two-factor-codes.test.js +335 -0
  162. package/dist/test/integration/auth/two-factor-codes.test.js.map +1 -0
  163. package/dist/test/integration/auth/two-factor-password.test.js +5 -1
  164. package/dist/test/integration/auth/two-factor-password.test.js.map +1 -1
  165. package/dist/test/integration/auth/two-factor-token.test.d.ts +1 -0
  166. package/dist/test/integration/auth/two-factor-token.test.js +92 -0
  167. package/dist/test/integration/auth/two-factor-token.test.js.map +1 -0
  168. package/dist/test/integration/email-change.test.js +36 -0
  169. package/dist/test/integration/email-change.test.js.map +1 -1
  170. package/dist/test/integration/invite-extension-edit.test.js +0 -1
  171. package/dist/test/integration/invite-extension-edit.test.js.map +1 -1
  172. package/dist/test/integration/invite-link-status.test.d.ts +1 -0
  173. package/dist/test/integration/invite-link-status.test.js +110 -0
  174. package/dist/test/integration/invite-link-status.test.js.map +1 -0
  175. package/dist/test/integration/invite-resolution.test.js +0 -3
  176. package/dist/test/integration/invite-resolution.test.js.map +1 -1
  177. package/dist/test/integration/member-settings-access.test.js +17 -0
  178. package/dist/test/integration/member-settings-access.test.js.map +1 -1
  179. package/dist/test/integration/notification-unread-badge.test.d.ts +1 -0
  180. package/dist/test/integration/notification-unread-badge.test.js +92 -0
  181. package/dist/test/integration/notification-unread-badge.test.js.map +1 -0
  182. package/dist/test/integration/permission-warnings.test.d.ts +1 -0
  183. package/dist/test/integration/permission-warnings.test.js +71 -0
  184. package/dist/test/integration/permission-warnings.test.js.map +1 -0
  185. package/dist/test/integration/removed-member-notifications.test.d.ts +1 -0
  186. package/dist/test/integration/removed-member-notifications.test.js +80 -0
  187. package/dist/test/integration/removed-member-notifications.test.js.map +1 -0
  188. package/dist/test/integration/role-permission-ancestors.test.d.ts +1 -0
  189. package/dist/test/integration/role-permission-ancestors.test.js +146 -0
  190. package/dist/test/integration/role-permission-ancestors.test.js.map +1 -0
  191. package/dist/test/integration/tenant-lifecycle.test.js +0 -4
  192. package/dist/test/integration/tenant-lifecycle.test.js.map +1 -1
  193. package/dist/test/unit/auth-session-revocation.test.d.ts +1 -0
  194. package/dist/test/unit/auth-session-revocation.test.js +105 -0
  195. package/dist/test/unit/auth-session-revocation.test.js.map +1 -0
  196. package/dist/test/unit/db/email-normalization.test.js +0 -1
  197. package/dist/test/unit/db/email-normalization.test.js.map +1 -1
  198. package/dist/test/unit/db/notification-feed-filter.test.js +0 -16
  199. package/dist/test/unit/db/notification-feed-filter.test.js.map +1 -1
  200. package/dist/test/unit/db/notification-inbox.test.js +63 -13
  201. package/dist/test/unit/db/notification-inbox.test.js.map +1 -1
  202. package/dist/test/unit/db/notification-preferences.test.js +0 -17
  203. package/dist/test/unit/db/notification-preferences.test.js.map +1 -1
  204. package/dist/test/unit/implementations/dms/empty-menu-group.test.d.ts +1 -0
  205. package/dist/test/unit/implementations/dms/empty-menu-group.test.js +133 -0
  206. package/dist/test/unit/implementations/dms/empty-menu-group.test.js.map +1 -0
  207. package/dist/test/unit/implementations/dms/layout-banners.test.js +2 -1
  208. package/dist/test/unit/implementations/dms/layout-banners.test.js.map +1 -1
  209. package/dist/test/unit/implementations/dms/menu-hidden-blocks.test.d.ts +1 -0
  210. package/dist/test/unit/implementations/dms/menu-hidden-blocks.test.js +149 -0
  211. package/dist/test/unit/implementations/dms/menu-hidden-blocks.test.js.map +1 -0
  212. package/dist/test/unit/implementations/dms/nav-badges.test.js +55 -4
  213. package/dist/test/unit/implementations/dms/nav-badges.test.js.map +1 -1
  214. package/dist/test/unit/implementations/dms/page-all-components-hidden.test.d.ts +1 -0
  215. package/dist/test/unit/implementations/dms/page-all-components-hidden.test.js +118 -0
  216. package/dist/test/unit/implementations/dms/page-all-components-hidden.test.js.map +1 -0
  217. package/dist/test/unit/implementations/dms/permission-preview-aggregate.test.js +16 -0
  218. package/dist/test/unit/implementations/dms/permission-preview-aggregate.test.js.map +1 -1
  219. package/dist/test/unit/implementations/dms/permission-preview-cost.test.js +5 -3
  220. package/dist/test/unit/implementations/dms/permission-preview-cost.test.js.map +1 -1
  221. package/dist/test/unit/implementations/dms/permission-preview-menu.test.js +29 -3
  222. package/dist/test/unit/implementations/dms/permission-preview-menu.test.js.map +1 -1
  223. package/dist/test/unit/implementations/dms/quick-actions-button.test.js +4 -2
  224. package/dist/test/unit/implementations/dms/quick-actions-button.test.js.map +1 -1
  225. package/dist/test/unit/implementations/dms/user-permissions-gate.test.js +2 -1
  226. package/dist/test/unit/implementations/dms/user-permissions-gate.test.js.map +1 -1
  227. package/dist/test/unit/implementations/dms-base/table-view-shared-controller.test.js +2 -1
  228. package/dist/test/unit/implementations/dms-base/table-view-shared-controller.test.js.map +1 -1
  229. package/dist/test/unit/interfaces/dms/component-children-permissions.test.js +7 -2
  230. package/dist/test/unit/interfaces/dms/component-children-permissions.test.js.map +1 -1
  231. package/dist/test/unit/interfaces/dms/form-watch-permissions.test.d.ts +1 -0
  232. package/dist/test/unit/interfaces/dms/form-watch-permissions.test.js +133 -0
  233. package/dist/test/unit/interfaces/dms/form-watch-permissions.test.js.map +1 -0
  234. package/dist/test/unit/interfaces/dms/has-permission-ancestors.test.d.ts +1 -0
  235. package/dist/test/unit/interfaces/dms/has-permission-ancestors.test.js +149 -0
  236. package/dist/test/unit/interfaces/dms/has-permission-ancestors.test.js.map +1 -0
  237. package/dist/test/unit/interfaces/dms/invite-extension.test.js +13 -0
  238. package/dist/test/unit/interfaces/dms/invite-extension.test.js.map +1 -1
  239. package/dist/test/unit/interfaces/dms/member-access.test.js +27 -1
  240. package/dist/test/unit/interfaces/dms/member-access.test.js.map +1 -1
  241. package/dist/test/unit/interfaces/dms/nav-badge-tones.test.d.ts +1 -0
  242. package/dist/test/unit/interfaces/dms/nav-badge-tones.test.js +31 -0
  243. package/dist/test/unit/interfaces/dms/nav-badge-tones.test.js.map +1 -0
  244. package/dist/test/unit/interfaces/dms/page-extension.test.js +4 -1
  245. package/dist/test/unit/interfaces/dms/page-extension.test.js.map +1 -1
  246. package/dist/test/unit/interfaces/dms/permission-requirements.test.d.ts +1 -0
  247. package/dist/test/unit/interfaces/dms/permission-requirements.test.js +144 -0
  248. package/dist/test/unit/interfaces/dms/permission-requirements.test.js.map +1 -0
  249. package/dist/test/unit/interfaces/dms-base/layout-header-actions.test.js +6 -2
  250. package/dist/test/unit/interfaces/dms-base/layout-header-actions.test.js.map +1 -1
  251. package/dist/test/unit/interfaces/dms-base/lists-and-settings-catalog.test.js +1 -1
  252. package/dist/test/unit/interfaces/dms-base/lists-and-settings-catalog.test.js.map +1 -1
  253. package/dist/test/unit/interfaces/dms-base/table-view-export-permission.test.js +2 -1
  254. package/dist/test/unit/interfaces/dms-base/table-view-export-permission.test.js.map +1 -1
  255. package/dist/test/unit/interfaces/dms-base/table-view-reduced-chrome.test.js +2 -1
  256. package/dist/test/unit/interfaces/dms-base/table-view-reduced-chrome.test.js.map +1 -1
  257. package/dist/test/unit/interfaces/dms-base/table-view-shared-controller-permissions.test.js +2 -1
  258. package/dist/test/unit/interfaces/dms-base/table-view-shared-controller-permissions.test.js.map +1 -1
  259. package/dist/test/unit/pages/settings/account-activity-feed.test.js +2 -2
  260. package/dist/test/unit/pages/settings/account-activity-feed.test.js.map +1 -1
  261. package/dist/test/unit/pages/settings/account-activity.test.js +11 -2
  262. package/dist/test/unit/pages/settings/account-activity.test.js.map +1 -1
  263. package/dist/test/unit/pages/settings/invite-email-delivery.test.js +0 -1
  264. package/dist/test/unit/pages/settings/invite-email-delivery.test.js.map +1 -1
  265. package/dist/test/unit/pages/settings/invite-email-validation-option.test.d.ts +1 -0
  266. package/dist/test/unit/pages/settings/invite-email-validation-option.test.js +33 -0
  267. package/dist/test/unit/pages/settings/invite-email-validation-option.test.js.map +1 -0
  268. package/dist/test/unit/pages/settings/member-lists-page-size.test.d.ts +1 -0
  269. package/dist/test/unit/pages/settings/member-lists-page-size.test.js +22 -0
  270. package/dist/test/unit/pages/settings/member-lists-page-size.test.js.map +1 -0
  271. package/dist/test/unit/pages/settings/member-table-widths.test.js +2 -2
  272. package/dist/test/unit/pages/settings/member-table-widths.test.js.map +1 -1
  273. package/dist/test/unit/pages/settings/members-page.test.js +7 -10
  274. package/dist/test/unit/pages/settings/members-page.test.js.map +1 -1
  275. package/dist/test/unit/pages/settings/notifications-access-gate.test.js +3 -10
  276. package/dist/test/unit/pages/settings/notifications-access-gate.test.js.map +1 -1
  277. package/dist/test/unit/pages/settings/permission-tree-nodes.test.js +57 -0
  278. package/dist/test/unit/pages/settings/permission-tree-nodes.test.js.map +1 -1
  279. package/dist/test/unit/pages/settings/permission-warnings.test.d.ts +1 -0
  280. package/dist/test/unit/pages/settings/permission-warnings.test.js +49 -0
  281. package/dist/test/unit/pages/settings/permission-warnings.test.js.map +1 -0
  282. package/dist/test/unit/pages/settings/role-editor.test.js +16 -0
  283. package/dist/test/unit/pages/settings/role-editor.test.js.map +1 -1
  284. package/dist/test/unit/pages/settings/role-preview.test.js +7 -0
  285. package/dist/test/unit/pages/settings/role-preview.test.js.map +1 -1
  286. package/dist/test/unit/pages/settings/security-attention.test.d.ts +1 -0
  287. package/dist/test/unit/pages/settings/security-attention.test.js +74 -0
  288. package/dist/test/unit/pages/settings/security-attention.test.js.map +1 -0
  289. package/dist/test/unit/sanitize-user.test.d.ts +1 -0
  290. package/dist/test/unit/sanitize-user.test.js +21 -0
  291. package/dist/test/unit/sanitize-user.test.js.map +1 -0
  292. package/dist/test/unit/signup-email-validation.test.d.ts +1 -0
  293. package/dist/test/unit/signup-email-validation.test.js +79 -0
  294. package/dist/test/unit/signup-email-validation.test.js.map +1 -0
  295. package/dist/test/unit/validation/member-invite.schema.test.js +14 -52
  296. package/dist/test/unit/validation/member-invite.schema.test.js.map +1 -1
  297. package/dist/utils/account-notifications.d.ts +5 -0
  298. package/dist/utils/account-notifications.js +8 -0
  299. package/dist/utils/account-notifications.js.map +1 -1
  300. package/dist/utils/notification-emitter.d.ts +1 -1
  301. package/dist/utils/notification-emitter.js +1 -1
  302. package/dist/utils/notification-emitter.js.map +1 -1
  303. package/dist/utils/notification-tones.d.ts +2 -1
  304. package/dist/utils/notification-tones.js +5 -1
  305. package/dist/utils/notification-tones.js.map +1 -1
  306. package/dist/utils/one-time-code.d.ts +3 -0
  307. package/dist/utils/one-time-code.js +21 -0
  308. package/dist/utils/one-time-code.js.map +1 -0
  309. package/dist/utils/sign-in-monitor.d.ts +1 -0
  310. package/dist/utils/sign-in-monitor.js +3 -2
  311. package/dist/utils/sign-in-monitor.js.map +1 -1
  312. package/dist/utils/two-factor-codes.d.ts +10 -0
  313. package/dist/utils/two-factor-codes.js +76 -0
  314. package/dist/utils/two-factor-codes.js.map +1 -0
  315. package/dist/validation/auth.schema.d.ts +17 -0
  316. package/dist/validation/auth.schema.js +17 -6
  317. package/dist/validation/auth.schema.js.map +1 -1
  318. package/dist/validation/issue-message.d.ts +1 -0
  319. package/dist/validation/issue-message.js +9 -0
  320. package/dist/validation/issue-message.js.map +1 -0
  321. package/dist/validation/member-invite.schema.d.ts +1 -25
  322. package/dist/validation/member-invite.schema.js +2 -23
  323. package/dist/validation/member-invite.schema.js.map +1 -1
  324. package/frontend-vue/dms.frontend.ts +2 -0
  325. package/frontend-vue/layers/dms-auth/app/custom-pages/auth/forgot-validation.vue +3 -0
  326. package/frontend-vue/layers/dms-auth/app/custom-pages/auth/signup.vue +105 -5
  327. package/frontend-vue/layers/dms-auth/i18n/locales/auth-en-GB.json +20 -4
  328. package/frontend-vue/layers/dms-auth/i18n/locales/auth-fr-FR.json +20 -4
  329. package/frontend-vue/layers/dms-core/app/composables/useFieldErrors.ts +3 -2
  330. package/frontend-vue/layers/dms-core/app/types/menu.ts +15 -0
  331. package/frontend-vue/layers/dms-core/i18n/locales/core-en-GB.json +4 -1
  332. package/frontend-vue/layers/dms-core/i18n/locales/core-fr-FR.json +4 -1
  333. package/frontend-vue/layers/dms-layout/app/assets/css/main.css +20 -0
  334. package/frontend-vue/layers/dms-layout/app/build/components/layout/CommandPaletteAssistantAnswer.vue +75 -0
  335. package/frontend-vue/layers/dms-layout/app/build/components/layout/DashboardFrame.vue +22 -0
  336. package/frontend-vue/layers/dms-layout/app/build/components/layout/DashboardHeader.vue +24 -10
  337. package/frontend-vue/layers/dms-layout/app/build/components/layout/DashboardSidePanel.vue +139 -0
  338. package/frontend-vue/layers/dms-layout/app/build/components/layout/Footer.vue +4 -2
  339. package/frontend-vue/layers/dms-layout/app/build/components/layout/GithubStarPrompt.vue +90 -0
  340. package/frontend-vue/layers/dms-layout/app/build/components/layout/SidePanelHost.vue +17 -0
  341. package/frontend-vue/layers/dms-layout/app/build/components/notification/NotificationPopover.vue +25 -43
  342. package/frontend-vue/layers/dms-layout/app/build/components/pages/settings/members/MemberRolePicker.vue +24 -2
  343. package/frontend-vue/layers/dms-layout/app/build/components/pages/settings/notification/NotificationMatrixCategory.vue +70 -25
  344. package/frontend-vue/layers/dms-layout/app/build/components/pages/settings/notification/NotificationPreferencesForm.vue +25 -10
  345. package/frontend-vue/layers/dms-layout/app/build/components/pages/settings/notification/notificationDisplay.ts +41 -5
  346. package/frontend-vue/layers/dms-layout/app/build/components/pages/settings/profile/ProfilePreferencesSummary.vue +2 -1
  347. package/frontend-vue/layers/dms-layout/app/build/components/pages/settings/profile/ProfileSecuritySummary.vue +20 -4
  348. package/frontend-vue/layers/dms-layout/app/build/components/pages/settings/roles/RoleEditor.vue +21 -0
  349. package/frontend-vue/layers/dms-layout/app/build/components/pages/settings/roles/RolePermissionArea.vue +16 -2
  350. package/frontend-vue/layers/dms-layout/app/build/components/pages/settings/roles/RolePermissionBranch.vue +1 -0
  351. package/frontend-vue/layers/dms-layout/app/build/components/pages/settings/roles/RolePermissionLeaf.vue +13 -1
  352. package/frontend-vue/layers/dms-layout/app/build/components/pages/settings/roles/RolePermissionTree.vue +9 -0
  353. package/frontend-vue/layers/dms-layout/app/build/components/pages/settings/roles/RolePermissionWarning.vue +46 -0
  354. package/frontend-vue/layers/dms-layout/app/build/components/pages/settings/roles/role-permissions.ts +108 -29
  355. package/frontend-vue/layers/dms-layout/app/build/components/pages/settings/roles/role-types.ts +2 -0
  356. package/frontend-vue/layers/dms-layout/app/build/components/pages/settings/security/SecurityDialogFrame.vue +6 -6
  357. package/frontend-vue/layers/dms-layout/app/build/components/pages/settings/security/SecurityEmail.vue +7 -1
  358. package/frontend-vue/layers/dms-layout/app/build/components/pages/settings/security/SecuritySessions.vue +5 -4
  359. package/frontend-vue/layers/dms-layout/app/build/components/pages/settings/security/SecurityStatus.vue +4 -3
  360. package/frontend-vue/layers/dms-layout/app/build/components/pages/settings/security/SecurityTwoFactor.vue +54 -18
  361. package/frontend-vue/layers/dms-layout/app/build/components/pages/settings/shell/SettingsNav.vue +13 -8
  362. package/frontend-vue/layers/dms-layout/app/build/composables/command-palette/assistantGroups.ts +143 -0
  363. package/frontend-vue/layers/dms-layout/app/build/composables/command-palette/useCommandPaletteAssistantMode.ts +249 -0
  364. package/frontend-vue/layers/dms-layout/app/build/composables/general/useGithubStarPrompt.ts +178 -0
  365. package/frontend-vue/layers/dms-layout/app/build/composables/layout/sidePanelState.ts +191 -0
  366. package/frontend-vue/layers/dms-layout/app/build/composables/layout/useHeaderActionControls.ts +51 -0
  367. package/frontend-vue/layers/dms-layout/app/build/composables/layout/useSidePanelWidth.ts +113 -0
  368. package/frontend-vue/layers/dms-layout/app/build/composables/navigation/useCategoryNavCards.ts +17 -10
  369. package/frontend-vue/layers/dms-layout/app/build/composables/notification/useNotificationGroupsOpen.ts +45 -0
  370. package/frontend-vue/layers/dms-layout/app/build/composables/settings/profile/useProfilePreferences.ts +8 -1
  371. package/frontend-vue/layers/dms-layout/app/build/composables/settings/security/useSecurityOverview.ts +50 -3
  372. package/frontend-vue/layers/dms-layout/app/build/composables/settings/useSettingsNavigation.ts +3 -0
  373. package/frontend-vue/layers/dms-layout/app/build/utils/categoryPages.ts +1 -2
  374. package/frontend-vue/layers/dms-layout/app/build/utils/github-repository.ts +5 -0
  375. package/frontend-vue/layers/dms-layout/app/components/layout/DashboardSearch.vue +109 -7
  376. package/frontend-vue/layers/dms-layout/app/components/navigation/NavigationMenu.vue +19 -9
  377. package/frontend-vue/layers/dms-layout/app/composables/notification/useNotifications.ts +22 -40
  378. package/frontend-vue/layers/dms-layout/app/composables/useAppSidePanels.ts +96 -0
  379. package/frontend-vue/layers/dms-layout/app/composables/useCommandPaletteAssistant.ts +129 -0
  380. package/frontend-vue/layers/dms-layout/app/composables/useHeaderActions.ts +33 -11
  381. package/frontend-vue/layers/dms-layout/app/composables/useSidePanel.ts +41 -0
  382. package/frontend-vue/layers/dms-layout/app/pages/[...slug].vue +15 -0
  383. package/frontend-vue/layers/dms-layout/app/plugins/notification-stream.client.ts +1 -7
  384. package/frontend-vue/layers/dms-layout/app/plugins/side-panel-host.ts +13 -0
  385. package/frontend-vue/layers/dms-layout/app/types/page.ts +4 -0
  386. package/frontend-vue/layers/dms-layout/i18n/locales/layout-en-GB.json +43 -13
  387. package/frontend-vue/layers/dms-layout/i18n/locales/layout-fr-FR.json +43 -13
  388. package/frontend-vue/layers/dms-ui/app/build/components/form/FormLoadError.vue +45 -0
  389. package/frontend-vue/layers/dms-ui/app/build/components/modal/ModalEscHint.vue +28 -0
  390. package/frontend-vue/layers/dms-ui/app/build/composables/form/floatingSaveBars.ts +38 -0
  391. package/frontend-vue/layers/dms-ui/app/build/composables/form/formRecordLoad.ts +66 -0
  392. package/frontend-vue/layers/dms-ui/app/build/composables/navigation/useNavBadges.ts +50 -9
  393. package/frontend-vue/layers/dms-ui/app/build/composables/table/useTable.ts +7 -1
  394. package/frontend-vue/layers/dms-ui/app/build/composables/table-view/utils/chrome.ts +2 -2
  395. package/frontend-vue/layers/dms-ui/app/build/types/tree.ts +14 -10
  396. package/frontend-vue/layers/dms-ui/app/build/utils/navBadge.ts +12 -0
  397. package/frontend-vue/layers/dms-ui/app/build/utils/tone.ts +22 -0
  398. package/frontend-vue/layers/dms-ui/app/components/activity-feed/ActivityFeed.vue +117 -82
  399. package/frontend-vue/layers/dms-ui/app/components/blocks/NavCardGridBlock.vue +12 -1
  400. package/frontend-vue/layers/dms-ui/app/components/card/NavCard.vue +16 -1
  401. package/frontend-vue/layers/dms-ui/app/components/confirm/ConfirmModal.vue +7 -8
  402. package/frontend-vue/layers/dms-ui/app/components/form/Form.vue +28 -6
  403. package/frontend-vue/layers/dms-ui/app/components/form/components/Display.vue +5 -1
  404. package/frontend-vue/layers/dms-ui/app/components/save-bar/SaveBar.vue +4 -0
  405. package/frontend-vue/layers/dms-ui/app/components/status-pill/StatusPill.vue +7 -2
  406. package/frontend-vue/layers/dms-ui/app/components/table-view/TableView.vue +7 -2
  407. package/frontend-vue/layers/dms-ui/app/composables/form/useForm.ts +48 -34
  408. package/frontend-vue/layers/dms-ui/app/composables/table-view/types/config.ts +13 -3
  409. package/frontend-vue/layers/dms-ui/i18n/locales/ui-en-GB.json +16 -14
  410. package/frontend-vue/layers/dms-ui/i18n/locales/ui-fr-FR.json +16 -14
  411. package/frontend-vue/package.json +2 -2
  412. package/frontend-vue/pnpm-lock.yaml +5 -5
  413. package/frontend-vue/tests/activity-feed-fill-height.test.ts +107 -0
  414. package/frontend-vue/tests/category-nav-cards.test.ts +21 -13
  415. package/frontend-vue/tests/command-palette-assistant.test.ts +344 -0
  416. package/frontend-vue/tests/fixtures/dashboard-search-stub.ts +91 -0
  417. package/frontend-vue/tests/forgot-validation-resend.test.ts +234 -0
  418. package/frontend-vue/tests/form-display-options.test.ts +64 -0
  419. package/frontend-vue/tests/form-load-error.test.ts +160 -0
  420. package/frontend-vue/tests/form-saved-before-success.test.ts +110 -0
  421. package/frontend-vue/tests/github-star-prompt.test.ts +328 -0
  422. package/frontend-vue/tests/header-actions.test.ts +191 -0
  423. package/frontend-vue/tests/invites-edit-modal.test.ts +157 -0
  424. package/frontend-vue/tests/member-role-picker.test.ts +26 -0
  425. package/frontend-vue/tests/menu-hidden-page.test.ts +93 -0
  426. package/frontend-vue/tests/nav-badge-tones.test.ts +274 -0
  427. package/frontend-vue/tests/nav-card-badge.test.ts +69 -0
  428. package/frontend-vue/tests/nav-card-grid-empty-category.test.ts +163 -0
  429. package/frontend-vue/tests/notification-popover-errors.test.ts +71 -37
  430. package/frontend-vue/tests/notification-preferences-groups.test.ts +268 -0
  431. package/frontend-vue/tests/notification-tone-contract.test.ts +70 -0
  432. package/frontend-vue/tests/page-fill-height.test.ts +9 -1
  433. package/frontend-vue/tests/page-no-visible-blocks.test.ts +202 -0
  434. package/frontend-vue/tests/profile-preferences-summary.test.ts +26 -2
  435. package/frontend-vue/tests/profile-security-summary.test.ts +121 -0
  436. package/frontend-vue/tests/role-permission-tree.test.ts +102 -8
  437. package/frontend-vue/tests/role-permissions.test.ts +178 -56
  438. package/frontend-vue/tests/side-panels.test.ts +470 -0
  439. package/frontend-vue/tests/signup-invitation-link.test.ts +71 -2
  440. package/frontend-vue/tests/table-actions-column-width.test.ts +51 -1
  441. package/frontend-vue/tests/table-view-chrome.test.ts +2 -2
  442. package/frontend-vue/tests/vue-inventory.test.ts +1 -1
  443. package/package.json +2 -2
  444. package/skills/dms/REFERENCE.md +1 -1
@@ -43,6 +43,20 @@ export const DMS_TONE_SOFT: Record<Tone, string> = {
43
43
  info: "bg-info/12 text-info",
44
44
  };
45
45
 
46
+ /**
47
+ * The solid fills of the v2 badges (the `solid` variant's theme): a count
48
+ * floating over an icon, where a tint would let the icon show through.
49
+ */
50
+ export const DMS_TONE_SOLID: Record<Tone, string> = {
51
+ neutral: "bg-inverted text-inverted",
52
+ primary: "bg-(--dms-accent-fill) text-(--dms-accent-on-fill)",
53
+ secondary: "bg-(--ui-color-secondary-400) text-(--ui-color-secondary-950)",
54
+ success: "bg-(--ui-color-success-500) text-(--ui-color-success-950)",
55
+ warning: "bg-(--ui-color-warning-400) text-(--ui-color-warning-950)",
56
+ error: "bg-(--ui-color-error-500) text-white",
57
+ info: "bg-(--ui-color-info-400) text-(--ui-color-info-950)",
58
+ };
59
+
46
60
  /** Tone as a text color only. */
47
61
  export const DMS_TONE_TEXT: Record<Tone, string> = {
48
62
  neutral: "text-muted",
@@ -72,3 +86,11 @@ export const DMS_TONE_OUTLINE: Record<Tone, string> = {
72
86
  export function toneTextClass(tone: string | undefined): string {
73
87
  return tone && isDmsTone(tone) ? DMS_TONE_TEXT[tone] : "";
74
88
  }
89
+
90
+ /**
91
+ * A tone drawn as an icon well's: neutral, or no tone, is the quiet `muted`
92
+ * well. A summary row coloured by a navigation badge's tone reads it so.
93
+ */
94
+ export function iconWellToneOf(tone: Tone | undefined): Tone | "muted" {
95
+ return !tone || tone === "neutral" ? "muted" : tone;
96
+ }
@@ -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>
@@ -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
  />
@@ -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"
@@ -8,6 +8,10 @@ interface DisplayProps {
8
8
  }
9
9
 
10
10
  const props = defineProps<DisplayProps>();
11
+ // The field's options, spread on the display as on its input: the
12
+ // formatter reads them as a table cell does (a status' labels and tones,
13
+ // a select's items).
14
+ const options = useAttrs();
11
15
 
12
16
  const { getDataType } = useDataTypes();
13
17
  const { locale, t } = useI18n();
@@ -29,7 +33,7 @@ const formattedValue = computed(() => {
29
33
  if (isEmptyValue(props.modelValue)) return EMPTY_FALLBACK;
30
34
  const formatter = dataType.value?.formatter?.default;
31
35
  if (!formatter) return String(props.modelValue);
32
- return formatter(props.modelValue, locale.value, props);
36
+ return formatter(props.modelValue, locale.value, options);
33
37
  });
34
38
 
35
39
  const isVNodeValue = computed(() => isVNode(formattedValue.value));
@@ -5,6 +5,7 @@ import {
5
5
  type FormKind,
6
6
  saveBarState,
7
7
  } from "../../build/composables/form/formFooter";
8
+ import { trackFloatingSaveBar } from "../../build/composables/form/floatingSaveBars";
8
9
  import DmsUnsavedStatus from "../../build/components/form/UnsavedStatus.vue";
9
10
 
10
11
  /**
@@ -107,6 +108,9 @@ const ui = computed(() =>
107
108
  theme({ variant: props.variant, hidden: state.value.isHidden }),
108
109
  );
109
110
  const buttons = computed(() => BUTTONS[props.variant]);
111
+ trackFloatingSaveBar(
112
+ () => props.variant === "floating" && !state.value.isHidden,
113
+ );
110
114
 
111
115
  // Empty while there is nothing to save: the hidden bar keeps its line.
112
116
  const statusText = computed(() => {
@@ -70,8 +70,13 @@ const theme = tv({
70
70
  },
71
71
  variants: {
72
72
  variant: {
73
- soft: { root: "rounded-full" },
74
- outline: { root: "rounded-full border bg-transparent" },
73
+ // A pill wider than its cell keeps its shape: the label gives way
74
+ // with an ellipsis instead of the pill being cut at the cell's edge.
75
+ soft: { root: "max-w-full rounded-full", label: "min-w-0 truncate" },
76
+ outline: {
77
+ root: "max-w-full rounded-full border bg-transparent",
78
+ label: "min-w-0 truncate",
79
+ },
75
80
  // A state line may run long: it wraps like text instead of a pill.
76
81
  text: { root: "whitespace-normal" },
77
82
  },
@@ -33,6 +33,7 @@ import type {
33
33
  TableViewPaginationMode,
34
34
  TableViewSourceConfig,
35
35
  TableViewReorderConfig,
36
+ TableViewTab,
36
37
  } from "../../composables/table-view/types";
37
38
  import {
38
39
  TABLE_DISPLAY_ID,
@@ -563,7 +564,7 @@ interface ResolvedTab {
563
564
  to?: string;
564
565
  toPage?: string;
565
566
  countFrom?: string;
566
- navBadge?: boolean;
567
+ navBadge?: TableViewTab["navBadge"];
567
568
  }
568
569
 
569
570
  // A configured "all" tab stands in for the implicit one, at its own place.
@@ -1175,7 +1176,11 @@ watch(
1175
1176
  const source = resolvedTabs.value.find((entry) => entry.id === tab.id);
1176
1177
  if (!source?.navBadge || tab.count === undefined) continue;
1177
1178
  const fullId = source.to ? source.toPage : pageId;
1178
- if (fullId) setNavBadge(fullId, tab.count > 0 ? String(tab.count) : "");
1179
+ const tone =
1180
+ typeof source.navBadge === "object" ? source.navBadge.tone : undefined;
1181
+ if (fullId) {
1182
+ setNavBadge(fullId, tab.count > 0 ? String(tab.count) : "", tone);
1183
+ }
1179
1184
  }
1180
1185
  },
1181
1186
  { immediate: true },