@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
@@ -20,6 +20,8 @@ interface RoleOption {
20
20
  _id: string;
21
21
  name: string;
22
22
  permissionIds: string[];
23
+ /** Set when what the role grants amounts to owner-level access. */
24
+ warnings?: string[];
23
25
  }
24
26
 
25
27
  interface RoleOptionsResponse {
@@ -77,8 +79,7 @@ const isOwner = computed(
77
79
  () => !!props.ownerField && formState?.value?.[props.ownerField] === true,
78
80
  );
79
81
  const isInert = computed(() => props.disabled || isOwner.value);
80
- // Without an owner field (the invite form), the form disables the roles for
81
- // an owner only.
82
+ // Without an owner field, the form disables the roles for an owner only.
82
83
  const showsOwnerHint = computed(() =>
83
84
  props.ownerField ? isOwner.value : props.disabled,
84
85
  );
@@ -102,6 +103,19 @@ const roleItems = computed<ChipGroupItem[]>(() =>
102
103
  const selectedRoles = computed(() =>
103
104
  options.value.roles.filter((role) => selectedIds.value.has(role._id)),
104
105
  );
106
+ // An owner holds every permission anyway: no warning then.
107
+ const ownerLevelWarning = computed(() => {
108
+ if (isOwner.value) return undefined;
109
+ const names = selectedRoles.value
110
+ .filter((role) => (role.warnings?.length ?? 0) > 0)
111
+ .map((role) => role.name);
112
+ if (names.length === 0) return undefined;
113
+ return t(
114
+ "page.settings.members.invite.roles_owner_level",
115
+ { roles: names.join(" + ") },
116
+ names.length,
117
+ );
118
+ });
105
119
  const grantedCount = computed(
106
120
  () => new Set(selectedRoles.value.flatMap((role) => role.permissionIds)).size,
107
121
  );
@@ -180,5 +194,13 @@ function toggle(roleId: string) {
180
194
  {{ t("page.settings.members.invite.compare_roles") }}
181
195
  </ULink>
182
196
  </p>
197
+ <p
198
+ v-if="ownerLevelWarning"
199
+ class="text-warning flex items-start gap-1.5 text-xs"
200
+ data-role-owner-level
201
+ >
202
+ <UIcon name="i-ph-warning" class="mt-px size-3.5 shrink-0" />
203
+ <span>{{ ownerLevelWarning }}</span>
204
+ </p>
183
205
  </div>
184
206
  </template>
@@ -17,13 +17,26 @@ interface NotificationMatrixCategoryProps {
17
17
  disabled: boolean;
18
18
  /** Directly under the column header, which already draws the rule. */
19
19
  first?: boolean;
20
+ /** The category's subjects are shown under it. */
21
+ expanded: boolean;
22
+ /** Id of the element holding the subjects, for `aria-controls`. */
23
+ controls: string;
20
24
  }
21
25
 
22
26
  const props = defineProps<NotificationMatrixCategoryProps>();
23
- const emit = defineEmits<{ toggle: [enabled: boolean] }>();
27
+ const emit = defineEmits<{
28
+ toggle: [enabled: boolean];
29
+ "toggle-expanded": [];
30
+ }>();
24
31
  const { t } = useI18n();
25
32
 
26
33
  const label = computed(() => t(props.category.labelKey));
34
+ const countLabel = computed(() =>
35
+ t("page.settings.notifications.category_count", {
36
+ count: props.enabledCount,
37
+ total: props.total,
38
+ }),
39
+ );
27
40
  const iconWellTone = computed(() =>
28
41
  props.category.tagKey ? "primary" : "muted",
29
42
  );
@@ -35,26 +48,63 @@ const iconWellTone = computed(() =>
35
48
  class="border-default min-h-14 bg-[color-mix(in_srgb,var(--dms-bg-muted)_55%,transparent)] py-2.5"
36
49
  role="row"
37
50
  >
38
- <div class="flex min-w-0 items-center gap-3" role="rowheader">
39
- <DmsIconWell :icon="props.category.icon" :tone="iconWellTone" size="xs" />
40
- <div class="min-w-0">
41
- <div
42
- class="text-highlighted flex flex-wrap items-center gap-2 text-[13px] font-[650]"
43
- >
44
- {{ label }}
45
- <span
46
- v-if="props.category.tagKey"
47
- :class="[SOURCE_TAG_CLASS, MODULE_TAG_CLASS]"
51
+ <!-- The caret folds the subjects, as in the roles editor; the title
52
+ area does too, for the pointer. The master switch and the count stay
53
+ on the row while it is folded. -->
54
+ <div class="flex min-w-0 items-center gap-2" role="rowheader">
55
+ <UButton
56
+ :icon="props.expanded ? 'i-ph-caret-down' : 'i-ph-caret-right'"
57
+ color="neutral"
58
+ variant="link"
59
+ size="xs"
60
+ class="text-muted shrink-0 p-0"
61
+ :aria-label="
62
+ props.expanded
63
+ ? t('page.settings.notifications.category_collapse', {
64
+ name: label,
65
+ })
66
+ : t('page.settings.notifications.category_expand', { name: label })
67
+ "
68
+ :aria-expanded="props.expanded"
69
+ :aria-controls="props.controls"
70
+ @click="emit('toggle-expanded')"
71
+ />
72
+ <div
73
+ class="flex min-w-0 flex-1 cursor-pointer items-center gap-3"
74
+ data-category-title
75
+ @click="emit('toggle-expanded')"
76
+ >
77
+ <DmsIconWell
78
+ :icon="props.category.icon"
79
+ :tone="iconWellTone"
80
+ size="xs"
81
+ />
82
+ <div class="min-w-0">
83
+ <div
84
+ class="text-highlighted flex flex-wrap items-center gap-2 text-[13px] font-[650]"
85
+ >
86
+ {{ label }}
87
+ <span
88
+ v-if="props.category.tagKey"
89
+ :class="[SOURCE_TAG_CLASS, MODULE_TAG_CLASS]"
90
+ >
91
+ {{ t(props.category.tagKey) }}
92
+ </span>
93
+ </div>
94
+ <p
95
+ v-if="props.category.descriptionKey"
96
+ class="text-muted mt-px text-xs"
97
+ >
98
+ {{ t(props.category.descriptionKey) }}
99
+ </p>
100
+ <!-- The count column goes on narrow matrices: the count moves under
101
+ the title, where a folded group still sums itself up. -->
102
+ <p
103
+ class="text-dimmed mt-0.5 hidden font-mono text-[11px] font-medium @max-2xl/matrix:block"
48
104
  >
49
- {{ t(props.category.tagKey) }}
50
- </span>
105
+ {{ countLabel }}
106
+ </p>
51
107
  </div>
52
- <p
53
- v-if="props.category.descriptionKey"
54
- class="text-muted mt-px text-xs"
55
- >
56
- {{ t(props.category.descriptionKey) }}
57
- </p>
58
108
  </div>
59
109
  </div>
60
110
  <div class="flex items-center justify-center" role="cell">
@@ -75,12 +125,7 @@ const iconWellTone = computed(() =>
75
125
  </div>
76
126
  <div class="flex justify-end" role="cell">
77
127
  <span class="text-dimmed font-mono text-[11px] font-medium">
78
- {{
79
- t("page.settings.notifications.category_count", {
80
- count: props.enabledCount,
81
- total: props.total,
82
- })
83
- }}
128
+ {{ countLabel }}
84
129
  </span>
85
130
  </div>
86
131
  </div>
@@ -2,10 +2,12 @@
2
2
  import { EYEBROW_CLASS } from "#dms-ui/app/build/utils/eyebrow";
3
3
  import type { NotificationCategory } from "../../../../composables/notification/useNotificationCatalog";
4
4
  import { useNotificationPreferences } from "../../../../composables/notification/useNotificationPreferences";
5
+ import { useNotificationGroupsOpen } from "../../../../composables/notification/useNotificationGroupsOpen";
5
6
  import { useInstantSaveHeader } from "../../../../../composables/layout/useInstantSaveHeader";
6
7
  import NotificationMatrixCategory from "./NotificationMatrixCategory.vue";
7
8
  import NotificationMatrixSubject from "./NotificationMatrixSubject.vue";
8
9
  import {
10
+ categorySubjectsElementId,
9
11
  MATRIX_CONTAINER_CLASS,
10
12
  MATRIX_GRID_CLASS,
11
13
  } from "./notificationDisplay";
@@ -29,6 +31,7 @@ const {
29
31
  retry,
30
32
  load,
31
33
  } = useNotificationPreferences();
34
+ const { isOpen, toggleOpen } = useNotificationGroupsOpen();
32
35
 
33
36
  const visibleCategories = computed(() =>
34
37
  categories.value.filter((category) => subjectsOf(category.id).length > 0),
@@ -90,7 +93,7 @@ onMounted(load);
90
93
  {{ t("page.settings.notifications.column_in_app") }}
91
94
  </span>
92
95
  <span
93
- class="flex items-center justify-center gap-1.5"
96
+ class="flex items-center justify-center gap-1.5 whitespace-nowrap"
94
97
  role="columnheader"
95
98
  >
96
99
  {{ t("page.settings.notifications.column_email") }}
@@ -147,17 +150,29 @@ onMounted(load);
147
150
  :total="subjectsOf(category.id).length"
148
151
  :disabled="toggleableSubjectsOf(category).length === 0"
149
152
  :first="index === 0"
153
+ :expanded="isOpen(category.id)"
154
+ :controls="categorySubjectsElementId(category.id)"
150
155
  @toggle="(enabled) => toggleCategory(category, enabled)"
156
+ @toggle-expanded="toggleOpen(category.id)"
151
157
  />
152
- <NotificationMatrixSubject
153
- v-for="subject in subjectsOf(category.id)"
154
- :key="`${category.id}:${subject.id}`"
155
- :subject="subject"
156
- :enabled="isEnabled(subject)"
157
- :state="rowState(subject)"
158
- @toggle="(enabled) => toggleSubject(subject, enabled)"
159
- @retry="retry"
160
- />
158
+ <UCollapsible
159
+ :open="isOpen(category.id)"
160
+ :ui="{ content: 'motion-reduce:animate-none' }"
161
+ >
162
+ <template #content>
163
+ <div :id="categorySubjectsElementId(category.id)" role="rowgroup">
164
+ <NotificationMatrixSubject
165
+ v-for="subject in subjectsOf(category.id)"
166
+ :key="`${category.id}:${subject.id}`"
167
+ :subject="subject"
168
+ :enabled="isEnabled(subject)"
169
+ :state="rowState(subject)"
170
+ @toggle="(enabled) => toggleSubject(subject, enabled)"
171
+ @retry="retry"
172
+ />
173
+ </div>
174
+ </template>
175
+ </UCollapsible>
161
176
  </template>
162
177
  </div>
163
178
 
@@ -9,12 +9,40 @@ import type {
9
9
  UserNotification,
10
10
  } from "../../../../../composables/notification/useNotifications";
11
11
 
12
- /** Notifications without a tone stand out in `primary` until read. */
12
+ /**
13
+ * Notifications without a tone stand out in `primary` until read. Mirrors
14
+ * the server's `resolveNotificationTone` (`src/utils/notification-tones.ts`),
15
+ * which weighs the unread badge of the bell and the navigation with it; a
16
+ * test holds the two together.
17
+ */
13
18
  export const resolveNotificationTone = (
14
19
  notification: UserNotification,
15
20
  ): NotificationTone =>
16
21
  notification.tone ?? (notification.isRead ? "neutral" : "primary");
17
22
 
23
+ /** Strongest first, as the server ranks the tones of the unread badge. */
24
+ const UNREAD_TONE_ORDER: NotificationTone[] = [
25
+ "error",
26
+ "warning",
27
+ "primary",
28
+ "success",
29
+ "neutral",
30
+ ];
31
+
32
+ /**
33
+ * The unread badge's tone once `incoming` arrives: an unread notification can
34
+ * only strengthen it, so the stronger of the current tone and its own, as
35
+ * the server would weigh the whole feed.
36
+ */
37
+ export const unreadToneWith = (
38
+ current: NotificationTone | undefined,
39
+ incoming: UserNotification,
40
+ ): NotificationTone | undefined => {
41
+ if (incoming.isRead) return current;
42
+ const tones = new Set([current, resolveNotificationTone(incoming)]);
43
+ return UNREAD_TONE_ORDER.find((tone) => tones.has(tone));
44
+ };
45
+
18
46
  /** Inbox sections, newest first. */
19
47
  export type NotificationDayGroupKey = RelativeDayBucket;
20
48
 
@@ -64,13 +92,21 @@ export const MATRIX_CONTAINER_CLASS = "@container/matrix";
64
92
  /**
65
93
  * v2 .cs-matrix grid: subject, in-app, email, state. Under 672px of matrix
66
94
  * the state column goes; under 448px (phones) only the subject and in-app
67
- * columns remain.
95
+ * columns remain. The email column fits its header on one line, the label
96
+ * and its "Soon" badge, in French too.
68
97
  */
69
98
  export const MATRIX_GRID_CLASS =
70
- "grid grid-cols-[minmax(0,1fr)_80px_96px_168px] items-center gap-x-3 px-[18px] @max-2xl/matrix:grid-cols-[minmax(0,1fr)_80px_96px] @max-2xl/matrix:[&>:nth-child(4)]:hidden @max-md/matrix:grid-cols-[minmax(0,1fr)_60px] @max-md/matrix:[&>:nth-child(n+3)]:hidden";
99
+ "grid grid-cols-[minmax(0,1fr)_80px_120px_168px] items-center gap-x-3 px-[18px] @max-2xl/matrix:grid-cols-[minmax(0,1fr)_80px_120px] @max-2xl/matrix:[&>:nth-child(4)]:hidden @max-md/matrix:grid-cols-[minmax(0,1fr)_60px] @max-md/matrix:[&>:nth-child(n+3)]:hidden";
100
+
101
+ /**
102
+ * The subject's indent under its category: past the caret and the icon
103
+ * well, under the category's title. Dropped where only two columns remain.
104
+ */
105
+ export const MATRIX_SUBJECT_INDENT_CLASS = "pl-[66px] @max-md/matrix:pl-0";
71
106
 
72
- /** The subject's indent under its category, dropped where only two columns remain. */
73
- export const MATRIX_SUBJECT_INDENT_CLASS = "pl-[42px] @max-md/matrix:pl-0";
107
+ /** Id of the element holding a category's subjects, for `aria-controls`. */
108
+ export const categorySubjectsElementId = (categoryId: string) =>
109
+ `notification-category-subjects-${categoryId}`;
74
110
 
75
111
  /** v2 .cs-mod: the mono module / source tag. */
76
112
  export const SOURCE_TAG_CLASS = `${MONO_TAG_CLASS} inline-flex h-[18px] items-center border border-accented whitespace-nowrap text-muted`;
@@ -11,6 +11,7 @@ const {
11
11
  regionSummary,
12
12
  notificationsSummary,
13
13
  hasUnread,
14
+ notificationsTone,
14
15
  appearanceSummary,
15
16
  placeholders,
16
17
  } = useProfilePreferences();
@@ -44,7 +45,7 @@ const {
44
45
  <ProfileSummaryRow
45
46
  v-if="rows.notifications.visible"
46
47
  :icon="hasUnread ? 'i-ph-bell-ringing' : 'i-ph-bell'"
47
- :tone="hasUnread ? 'warning' : 'muted'"
48
+ :tone="notificationsTone"
48
49
  :lead="t(`${KEY}.notifications_title`)"
49
50
  :loading="notificationsSummary === undefined"
50
51
  :placeholder="placeholders.notifications"
@@ -3,12 +3,28 @@ import {
3
3
  SECURITY_PAGE_PATH,
4
4
  useSecurityOverview,
5
5
  } from "../../../../composables/settings/security/useSecurityOverview";
6
+ import { iconWellToneOf } from "#dms-ui/app/build/utils/tone";
6
7
  import ProfileSummaryRow from "./ProfileSummaryRow.vue";
7
8
 
8
- const { t } = useI18n();
9
- const { overview, attention, isUnavailable, refresh } = useSecurityOverview();
9
+ const { t, locale } = useI18n();
10
+ const { overview, attention, attentionTone, isUnavailable, refresh } =
11
+ useSecurityOverview();
10
12
 
11
13
  const needsAttention = computed(() => attention.value.length > 0);
14
+ // Every point is named, in the Security page's own words, joined the way the
15
+ // language joins a list ("…, … and …").
16
+ const attentionText = computed(() =>
17
+ new Intl.ListFormat(locale.value, { type: "conjunction" }).format(
18
+ attention.value.map((item) =>
19
+ t(`page.settings.security.attention.${item}`),
20
+ ),
21
+ ),
22
+ );
23
+ // The well takes the tone of the Security page's navigation badge, as the
24
+ // server weighs what needs attention; quiet when nothing does.
25
+ const wellTone = computed(() =>
26
+ overview.value ? iconWellToneOf(attentionTone.value) : "muted",
27
+ );
12
28
 
13
29
  const facts = computed(() => {
14
30
  const data = overview.value;
@@ -44,7 +60,7 @@ onMounted(refresh);
44
60
  with what needs attention there. -->
45
61
  <ProfileSummaryRow
46
62
  :icon="needsAttention ? 'i-ph-shield-warning' : 'i-ph-shield-check'"
47
- :tone="needsAttention ? 'warning' : overview ? 'success' : 'muted'"
63
+ :tone="wellTone"
48
64
  :loading="!overview && !isUnavailable"
49
65
  :placeholder="placeholder"
50
66
  :to="SECURITY_PAGE_PATH"
@@ -63,7 +79,7 @@ onMounted(refresh);
63
79
  }}
64
80
  </b>
65
81
  <template v-if="needsAttention">
66
- — {{ t(`page.settings.security.attention.${attention[0]}`) }}.
82
+ {{ ` — ${attentionText}.` }}
67
83
  </template>
68
84
  <template v-else>{{ " — " }}</template>
69
85
  {{ facts }}
@@ -14,6 +14,7 @@ import {
14
14
  type PermissionArea,
15
15
  type PermissionIndex,
16
16
  searchPermissions,
17
+ selectedWarningLabels,
17
18
  } from "./role-permissions";
18
19
  import {
19
20
  ROLE_DESCRIPTION_MAX_LENGTH,
@@ -92,6 +93,11 @@ const hits = computed(() =>
92
93
  const hitAreaCount = computed(
93
94
  () => new Set((hits.value ?? []).map((hit) => hit.areaId)).size,
94
95
  );
96
+ // The permissions of the role that amount to owner-level access, however
97
+ // they were ticked (a parent grants its whole subtree).
98
+ const ownerLevelLabels = computed(() =>
99
+ selectedWarningLabels(props.index, props.areas, props.selection, processI18n),
100
+ );
95
101
  const selectedCount = computed(
96
102
  () => props.index.allIds.filter((id) => props.selection.has(id)).length,
97
103
  );
@@ -343,6 +349,21 @@ function toggleArea(id: string): void {
343
349
  </div>
344
350
  </div>
345
351
 
352
+ <div v-if="ownerLevelLabels.length > 0" class="px-[18px] pt-3">
353
+ <DmsBanner
354
+ size="sm"
355
+ tone="warning"
356
+ icon="i-ph-warning"
357
+ :title="t('page.settings.roles.editor.owner_level_title')"
358
+ :description="
359
+ t('page.settings.roles.editor.owner_level_description', {
360
+ names: ownerLevelLabels.join(', '),
361
+ })
362
+ "
363
+ data-role-owner-level
364
+ />
365
+ </div>
366
+
346
367
  <RolePermissionTree
347
368
  :areas="props.areas"
348
369
  :index="props.index"
@@ -1,5 +1,6 @@
1
1
  <script setup lang="ts">
2
2
  import { tv } from "tailwind-variants";
3
+ import RolePermissionWarning from "./RolePermissionWarning.vue";
3
4
  import {
4
5
  childrenElementId,
5
6
  type PermissionArea,
@@ -14,9 +15,13 @@ interface RolePermissionAreaProps {
14
15
  state: SelectionState;
15
16
  isExpanded: boolean;
16
17
  disabled: boolean;
18
+ /** Warnings of the selected permissions a closed area hides. */
19
+ hiddenWarnings?: string[];
17
20
  }
18
21
 
19
- const props = defineProps<RolePermissionAreaProps>();
22
+ const props = withDefaults(defineProps<RolePermissionAreaProps>(), {
23
+ hiddenWarnings: () => [],
24
+ });
20
25
  const emit = defineEmits<{
21
26
  toggle: [checked: boolean];
22
27
  "toggle-expanded": [];
@@ -32,7 +37,6 @@ const childrenId = computed(() => childrenElementId(props.area.node.id));
32
37
  const subtitle = computed(() =>
33
38
  processI18n(props.area.node.description ?? props.area.section ?? ""),
34
39
  );
35
-
36
40
  // v2 .cs-parea: caret, tri-state box, icon tile, title over its subtitle and
37
41
  // the "n/m" count with its bar; the count turns accent when complete. The
38
42
  // row reads the editor's width (@container/editor): the hover id goes under
@@ -111,6 +115,16 @@ const ui = computed(() => theme({ completion: completion.value }));
111
115
  >
112
116
  {{ subtitle }}
113
117
  </small>
118
+ <RolePermissionWarning
119
+ v-if="props.area.node.warning"
120
+ :warnings="[props.area.node.warning]"
121
+ />
122
+ <RolePermissionWarning
123
+ v-if="props.hiddenWarnings.length > 0"
124
+ :warnings="props.hiddenWarnings"
125
+ compact
126
+ class="mt-1"
127
+ />
114
128
  </button>
115
129
  <span :class="ui.count()">
116
130
  <span
@@ -48,6 +48,7 @@ function isExpanded(node: RolePermissionNode): boolean {
48
48
  "
49
49
  :expanded="isExpanded(node)"
50
50
  :controls="childrenElementId(node.id)"
51
+ :hidden-warnings="props.context.warningsBelowOf(node)"
51
52
  expandable
52
53
  @toggle="(checked) => props.context.toggle(node.id, checked)"
53
54
  @toggle-expanded="props.context.toggleExpanded(node.id)"
@@ -1,5 +1,6 @@
1
1
  <script setup lang="ts">
2
2
  import { tv } from "tailwind-variants";
3
+ import RolePermissionWarning from "./RolePermissionWarning.vue";
3
4
  import {
4
5
  highlightSegments,
5
6
  type PermissionChange,
@@ -31,6 +32,8 @@ interface RolePermissionLeafProps {
31
32
  controls?: string;
32
33
  /** Selected permissions of the subtree, shown by a collapsible row. */
33
34
  count?: SelectionCount;
35
+ /** Warnings of the selected permissions a closed row hides. */
36
+ hiddenWarnings?: string[];
34
37
  }
35
38
 
36
39
  const props = withDefaults(defineProps<RolePermissionLeafProps>(), {
@@ -43,6 +46,7 @@ const props = withDefaults(defineProps<RolePermissionLeafProps>(), {
43
46
  expanded: false,
44
47
  controls: undefined,
45
48
  count: undefined,
49
+ hiddenWarnings: () => [],
46
50
  });
47
51
 
48
52
  const emit = defineEmits<{
@@ -100,7 +104,6 @@ const ui = computed(() =>
100
104
 
101
105
  const label = computed(() => processI18n(props.node.label));
102
106
  const segments = computed(() => highlightSegments(label.value, props.query));
103
-
104
107
  const CHANGE_CLASSES: Record<"added" | "removed", string> = {
105
108
  added: "text-warning",
106
109
  removed: "text-error",
@@ -187,10 +190,19 @@ function onRowClick(): void {
187
190
  <UIcon name="i-ph-check" class="size-[11px]" />
188
191
  {{ props.autoAddedHint }}
189
192
  </span>
193
+ <RolePermissionWarning
194
+ v-if="props.hiddenWarnings.length > 0"
195
+ :warnings="props.hiddenWarnings"
196
+ compact
197
+ />
190
198
  </div>
191
199
  <div v-if="props.node.description" :class="ui.description()">
192
200
  {{ processI18n(props.node.description) }}
193
201
  </div>
202
+ <RolePermissionWarning
203
+ v-if="props.node.warning"
204
+ :warnings="[props.node.warning]"
205
+ />
194
206
  </div>
195
207
  <span class="flex min-w-0 items-center gap-3">
196
208
  <span :class="ui.id()" :title="props.node.id">{{ props.node.id }}</span>
@@ -12,6 +12,7 @@ import {
12
12
  type PermissionIndex,
13
13
  type PermissionRowContext,
14
14
  type PermissionSearchHit,
15
+ selectedWarningsBelow,
15
16
  type SelectionState,
16
17
  } from "./role-permissions";
17
18
  import type { RolePermissionNode } from "./role-types";
@@ -67,6 +68,12 @@ function autoAddedHintOf(id: string): string | undefined {
67
68
  return t("page.settings.roles.editor.auto_added", { name: label });
68
69
  }
69
70
 
71
+ // Only a closed row hides them: an open one shows its children's own.
72
+ function warningsBelowOf(node: RolePermissionNode): string[] {
73
+ if (props.expanded.has(node.id)) return [];
74
+ return selectedWarningsBelow(props.index, node.id, props.selection);
75
+ }
76
+
70
77
  function isDisabled(node: RolePermissionNode): boolean {
71
78
  if (props.readonly) return true;
72
79
  return stateOf(node) === false && !props.canGrant(node.id);
@@ -88,6 +95,7 @@ const rowContext = computed<PermissionRowContext>(() => ({
88
95
  changeOf,
89
96
  requiresOf,
90
97
  autoAddedHintOf,
98
+ warningsBelowOf,
91
99
  isDisabled,
92
100
  disabledHint: t("page.settings.roles.editor.not_grantable"),
93
101
  toggle: (id, checked) => emit("toggle", id, checked),
@@ -162,6 +170,7 @@ function opensSection(position: number): boolean {
162
170
  :state="stateOf(area.node)"
163
171
  :is-expanded="props.expanded.has(area.node.id)"
164
172
  :disabled="isDisabled(area.node)"
173
+ :hidden-warnings="warningsBelowOf(area.node)"
165
174
  @toggle="(checked) => emit('toggle', area.node.id, checked)"
166
175
  @toggle-expanded="emit('toggle-area', area.node.id)"
167
176
  >
@@ -0,0 +1,46 @@
1
+ <script setup lang="ts">
2
+ interface RolePermissionWarningProps {
3
+ /** i18n keys of the warnings (see the editor tree's `warning`). */
4
+ warnings: string[];
5
+ /**
6
+ * A chip naming the warnings in its tooltip, for a closed row hiding the
7
+ * permissions they come from; otherwise each warning in full.
8
+ */
9
+ compact?: boolean;
10
+ }
11
+
12
+ const props = withDefaults(defineProps<RolePermissionWarningProps>(), {
13
+ compact: false,
14
+ });
15
+ const { t } = useI18n();
16
+ const { processI18n } = useTranslation();
17
+
18
+ const texts = computed(() =>
19
+ props.warnings.map((warning) => processI18n(warning)),
20
+ );
21
+ </script>
22
+
23
+ <template>
24
+ <!-- Amber, not red: these permissions are fine to grant, as long as the
25
+ admin knows they amount to owner-level access. -->
26
+ <span
27
+ v-if="props.compact"
28
+ class="bg-warning/10 text-warning inline-flex h-[18px] items-center gap-1 rounded px-1.5 font-mono text-[10.5px] font-medium whitespace-nowrap"
29
+ :title="texts.join('\n')"
30
+ data-permission-warning-below
31
+ >
32
+ <UIcon name="i-ph-warning" class="size-[11px]" />
33
+ {{ t("page.settings.roles.editor.owner_level") }}
34
+ </span>
35
+ <span v-else class="mt-1 flex flex-col gap-1">
36
+ <span
37
+ v-for="text in texts"
38
+ :key="text"
39
+ class="text-warning flex items-start gap-1.5 text-xs"
40
+ data-permission-warning
41
+ >
42
+ <UIcon name="i-ph-warning" class="mt-px size-3.5 shrink-0" />
43
+ <span>{{ text }}</span>
44
+ </span>
45
+ </span>
46
+ </template>