@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.
- package/CHANGELOG.md +39 -0
- package/dist/db/models/notification-feed-filter.d.ts +0 -1
- package/dist/db/models/notification-feed-filter.js +0 -4
- package/dist/db/models/notification-feed-filter.js.map +1 -1
- package/dist/db/models/signInAttempts.model.d.ts +18 -0
- package/dist/db/models/signInAttempts.model.js +83 -12
- package/dist/db/models/signInAttempts.model.js.map +1 -1
- package/dist/db/models/userEmailChanges.model.d.ts +8 -1
- package/dist/db/models/userEmailChanges.model.js +27 -2
- package/dist/db/models/userEmailChanges.model.js.map +1 -1
- package/dist/db/models/userNotificationPreferences.model.d.ts +0 -2
- package/dist/db/models/userNotificationPreferences.model.js +0 -13
- package/dist/db/models/userNotificationPreferences.model.js.map +1 -1
- package/dist/db/models/userNotifications.model.d.ts +5 -2
- package/dist/db/models/userNotifications.model.js +19 -2
- package/dist/db/models/userNotifications.model.js.map +1 -1
- package/dist/db/tables/signInAttempts.table.d.ts +2 -1
- package/dist/db/tables/signInAttempts.table.js +4 -0
- package/dist/db/tables/signInAttempts.table.js.map +1 -1
- package/dist/db/tables/userEmailChanges.table.d.ts +2 -1
- package/dist/db/tables/userEmailChanges.table.js +6 -1
- package/dist/db/tables/userEmailChanges.table.js.map +1 -1
- package/dist/db/tables/userNotificationPreferences.table.d.ts +0 -1
- package/dist/db/tables/userNotificationPreferences.table.js +0 -4
- package/dist/db/tables/userNotificationPreferences.table.js.map +1 -1
- package/dist/implementations/dms/layout-banners.d.ts +4 -1
- package/dist/implementations/dms/layout-banners.js +33 -18
- package/dist/implementations/dms/layout-banners.js.map +1 -1
- package/dist/implementations/dms/nav-badges.d.ts +6 -4
- package/dist/implementations/dms/nav-badges.js +6 -5
- package/dist/implementations/dms/nav-badges.js.map +1 -1
- package/dist/implementations/dms/page.d.ts +1 -0
- package/dist/implementations/dms/page.js +46 -8
- package/dist/implementations/dms/page.js.map +1 -1
- package/dist/implementations/dms/permission-preview.d.ts +1 -1
- package/dist/implementations/dms/permission-preview.js +9 -4
- package/dist/implementations/dms/permission-preview.js.map +1 -1
- package/dist/implementations/dms-auth/index.d.ts +3 -2
- package/dist/implementations/dms-auth/index.js +39 -35
- package/dist/implementations/dms-auth/index.js.map +1 -1
- package/dist/implementations/dms-auth/token-session.d.ts +3 -0
- package/dist/implementations/dms-auth/token-session.js +22 -0
- package/dist/implementations/dms-auth/token-session.js.map +1 -0
- package/dist/implementations/dms-notifications/index.d.ts +0 -1
- package/dist/implementations/dms-notifications/index.js +0 -7
- package/dist/implementations/dms-notifications/index.js.map +1 -1
- package/dist/pages/settings/settings-index.js +3 -2
- package/dist/pages/settings/settings-index.js.map +1 -1
- package/dist/pages/settings/users/account-activity-feed.d.ts +1 -1
- package/dist/pages/settings/users/account-activity-feed.js +1 -1
- package/dist/pages/settings/users/account-activity-feed.js.map +1 -1
- package/dist/pages/settings/users/account-activity.d.ts +1 -1
- package/dist/pages/settings/users/account-activity.js +1 -1
- package/dist/pages/settings/users/account-activity.js.map +1 -1
- package/dist/pages/settings/users/account-credentials.d.ts +3 -0
- package/dist/pages/settings/users/account-credentials.js +2 -0
- package/dist/pages/settings/users/account-credentials.js.map +1 -1
- package/dist/pages/settings/users/current-password.d.ts +1 -1
- package/dist/pages/settings/users/current-password.js +23 -2
- package/dist/pages/settings/users/current-password.js.map +1 -1
- package/dist/pages/settings/users/email-change.d.ts +1 -1
- package/dist/pages/settings/users/email-change.js +33 -26
- package/dist/pages/settings/users/email-change.js.map +1 -1
- package/dist/pages/settings/users/invite-resend.js +0 -1
- package/dist/pages/settings/users/invite-resend.js.map +1 -1
- package/dist/pages/settings/users/invites.d.ts +1 -2
- package/dist/pages/settings/users/invites.js +21 -19
- package/dist/pages/settings/users/invites.js.map +1 -1
- package/dist/pages/settings/users/member-invite-batch.js +0 -1
- package/dist/pages/settings/users/member-invite-batch.js.map +1 -1
- package/dist/pages/settings/users/member-invite-form.js +10 -22
- package/dist/pages/settings/users/member-invite-form.js.map +1 -1
- package/dist/pages/settings/users/member-role-options.d.ts +6 -4
- package/dist/pages/settings/users/member-role-options.js +15 -4
- package/dist/pages/settings/users/member-role-options.js.map +1 -1
- package/dist/pages/settings/users/members.d.ts +2 -3
- package/dist/pages/settings/users/members.js +7 -12
- package/dist/pages/settings/users/members.js.map +1 -1
- package/dist/pages/settings/users/notifications.d.ts +1 -8
- package/dist/pages/settings/users/notifications.js +6 -38
- package/dist/pages/settings/users/notifications.js.map +1 -1
- package/dist/pages/settings/users/permission-tree-nodes.d.ts +1 -1
- package/dist/pages/settings/users/permission-tree-nodes.js +23 -9
- package/dist/pages/settings/users/permission-tree-nodes.js.map +1 -1
- package/dist/pages/settings/users/permission-warnings.d.ts +7 -0
- package/dist/pages/settings/users/permission-warnings.js +42 -0
- package/dist/pages/settings/users/permission-warnings.js.map +1 -0
- package/dist/pages/settings/users/profile-helpers.d.ts +1 -3
- package/dist/pages/settings/users/profile-helpers.js +0 -16
- package/dist/pages/settings/users/profile-helpers.js.map +1 -1
- package/dist/pages/settings/users/role-editor-store.js +6 -3
- package/dist/pages/settings/users/role-editor-store.js.map +1 -1
- package/dist/pages/settings/users/role-editor.d.ts +2 -1
- package/dist/pages/settings/users/role-editor.js +8 -4
- package/dist/pages/settings/users/role-editor.js.map +1 -1
- package/dist/pages/settings/users/role-preview.js +2 -1
- package/dist/pages/settings/users/role-preview.js.map +1 -1
- package/dist/pages/settings/users/roles.js +5 -1
- package/dist/pages/settings/users/roles.js.map +1 -1
- package/dist/pages/settings/users/security-attention.d.ts +4 -0
- package/dist/pages/settings/users/security-attention.js +23 -7
- package/dist/pages/settings/users/security-attention.js.map +1 -1
- package/dist/pages/settings/users/security.d.ts +2 -1
- package/dist/pages/settings/users/security.js +13 -2
- package/dist/pages/settings/users/security.js.map +1 -1
- package/dist/pages/settings/users/two-factor-operations.d.ts +2 -1
- package/dist/pages/settings/users/two-factor-operations.js +28 -29
- package/dist/pages/settings/users/two-factor-operations.js.map +1 -1
- package/dist/routes/auth/forgot-password.js +3 -0
- package/dist/routes/auth/forgot-password.js.map +1 -1
- package/dist/routes/auth/index.d.ts +1 -0
- package/dist/routes/auth/index.js +1 -0
- package/dist/routes/auth/index.js.map +1 -1
- package/dist/routes/auth/invite.js +28 -4
- package/dist/routes/auth/invite.js.map +1 -1
- package/dist/routes/auth/login-throttle.d.ts +2 -0
- package/dist/routes/auth/login-throttle.js +5 -4
- package/dist/routes/auth/login-throttle.js.map +1 -1
- package/dist/routes/auth/request-2fa-email.js +6 -18
- package/dist/routes/auth/request-2fa-email.js.map +1 -1
- package/dist/routes/auth/reset-code.d.ts +3 -0
- package/dist/routes/auth/reset-code.js +37 -0
- package/dist/routes/auth/reset-code.js.map +1 -0
- package/dist/routes/auth/reset-password.d.ts +2 -2
- package/dist/routes/auth/reset-password.js +5 -10
- package/dist/routes/auth/reset-password.js.map +1 -1
- package/dist/routes/auth/signup.js +10 -32
- package/dist/routes/auth/signup.js.map +1 -1
- package/dist/routes/auth/two-factor-throttle.d.ts +5 -0
- package/dist/routes/auth/two-factor-throttle.js +81 -0
- package/dist/routes/auth/two-factor-throttle.js.map +1 -0
- package/dist/routes/auth/validate-forgot-password-token.js +2 -8
- package/dist/routes/auth/validate-forgot-password-token.js.map +1 -1
- package/dist/routes/auth/validate-invite-token.d.ts +1 -0
- package/dist/routes/auth/validate-invite-token.js +11 -0
- package/dist/routes/auth/validate-invite-token.js.map +1 -0
- package/dist/routes/auth/verify-2fa.js +10 -13
- package/dist/routes/auth/verify-2fa.js.map +1 -1
- package/dist/routes/auth.d.ts +1 -0
- package/dist/routes/auth.js +11 -1
- package/dist/routes/auth.js.map +1 -1
- package/dist/test/helpers/auth.d.ts +0 -1
- package/dist/test/helpers/auth.js +0 -1
- package/dist/test/helpers/auth.js.map +1 -1
- package/dist/test/helpers/emails.d.ts +10 -0
- package/dist/test/helpers/emails.js +36 -0
- package/dist/test/helpers/emails.js.map +1 -0
- package/dist/test/helpers/fixtures.d.ts +0 -1
- package/dist/test/helpers/fixtures.js +1 -2
- package/dist/test/helpers/fixtures.js.map +1 -1
- package/dist/test/helpers/page-access.d.ts +1 -0
- package/dist/test/helpers/page-access.js +6 -1
- package/dist/test/helpers/page-access.js.map +1 -1
- package/dist/test/integration/auth/current-password.test.d.ts +1 -0
- package/dist/test/integration/auth/current-password.test.js +65 -0
- package/dist/test/integration/auth/current-password.test.js.map +1 -0
- package/dist/test/integration/auth/password-reset.test.d.ts +1 -0
- package/dist/test/integration/auth/password-reset.test.js +126 -0
- package/dist/test/integration/auth/password-reset.test.js.map +1 -0
- package/dist/test/integration/auth/session-revocation.test.d.ts +1 -0
- package/dist/test/integration/auth/session-revocation.test.js +45 -0
- package/dist/test/integration/auth/session-revocation.test.js.map +1 -0
- package/dist/test/integration/auth/two-factor-codes.test.d.ts +1 -0
- package/dist/test/integration/auth/two-factor-codes.test.js +335 -0
- package/dist/test/integration/auth/two-factor-codes.test.js.map +1 -0
- package/dist/test/integration/auth/two-factor-password.test.js +5 -1
- package/dist/test/integration/auth/two-factor-password.test.js.map +1 -1
- package/dist/test/integration/auth/two-factor-token.test.d.ts +1 -0
- package/dist/test/integration/auth/two-factor-token.test.js +92 -0
- package/dist/test/integration/auth/two-factor-token.test.js.map +1 -0
- package/dist/test/integration/email-change.test.js +36 -0
- package/dist/test/integration/email-change.test.js.map +1 -1
- package/dist/test/integration/invite-extension-edit.test.js +0 -1
- package/dist/test/integration/invite-extension-edit.test.js.map +1 -1
- package/dist/test/integration/invite-link-status.test.d.ts +1 -0
- package/dist/test/integration/invite-link-status.test.js +110 -0
- package/dist/test/integration/invite-link-status.test.js.map +1 -0
- package/dist/test/integration/invite-resolution.test.js +0 -3
- package/dist/test/integration/invite-resolution.test.js.map +1 -1
- package/dist/test/integration/member-settings-access.test.js +17 -0
- package/dist/test/integration/member-settings-access.test.js.map +1 -1
- package/dist/test/integration/notification-unread-badge.test.d.ts +1 -0
- package/dist/test/integration/notification-unread-badge.test.js +92 -0
- package/dist/test/integration/notification-unread-badge.test.js.map +1 -0
- package/dist/test/integration/permission-warnings.test.d.ts +1 -0
- package/dist/test/integration/permission-warnings.test.js +71 -0
- package/dist/test/integration/permission-warnings.test.js.map +1 -0
- package/dist/test/integration/removed-member-notifications.test.d.ts +1 -0
- package/dist/test/integration/removed-member-notifications.test.js +80 -0
- package/dist/test/integration/removed-member-notifications.test.js.map +1 -0
- package/dist/test/integration/role-permission-ancestors.test.d.ts +1 -0
- package/dist/test/integration/role-permission-ancestors.test.js +146 -0
- package/dist/test/integration/role-permission-ancestors.test.js.map +1 -0
- package/dist/test/integration/tenant-lifecycle.test.js +0 -4
- package/dist/test/integration/tenant-lifecycle.test.js.map +1 -1
- package/dist/test/unit/auth-session-revocation.test.d.ts +1 -0
- package/dist/test/unit/auth-session-revocation.test.js +105 -0
- package/dist/test/unit/auth-session-revocation.test.js.map +1 -0
- package/dist/test/unit/db/email-normalization.test.js +0 -1
- package/dist/test/unit/db/email-normalization.test.js.map +1 -1
- package/dist/test/unit/db/notification-feed-filter.test.js +0 -16
- package/dist/test/unit/db/notification-feed-filter.test.js.map +1 -1
- package/dist/test/unit/db/notification-inbox.test.js +63 -13
- package/dist/test/unit/db/notification-inbox.test.js.map +1 -1
- package/dist/test/unit/db/notification-preferences.test.js +0 -17
- package/dist/test/unit/db/notification-preferences.test.js.map +1 -1
- package/dist/test/unit/implementations/dms/empty-menu-group.test.d.ts +1 -0
- package/dist/test/unit/implementations/dms/empty-menu-group.test.js +133 -0
- package/dist/test/unit/implementations/dms/empty-menu-group.test.js.map +1 -0
- package/dist/test/unit/implementations/dms/layout-banners.test.js +78 -1
- package/dist/test/unit/implementations/dms/layout-banners.test.js.map +1 -1
- package/dist/test/unit/implementations/dms/menu-hidden-blocks.test.d.ts +1 -0
- package/dist/test/unit/implementations/dms/menu-hidden-blocks.test.js +149 -0
- package/dist/test/unit/implementations/dms/menu-hidden-blocks.test.js.map +1 -0
- package/dist/test/unit/implementations/dms/nav-badges.test.js +55 -4
- package/dist/test/unit/implementations/dms/nav-badges.test.js.map +1 -1
- package/dist/test/unit/implementations/dms/page-all-components-hidden.test.d.ts +1 -0
- package/dist/test/unit/implementations/dms/page-all-components-hidden.test.js +118 -0
- package/dist/test/unit/implementations/dms/page-all-components-hidden.test.js.map +1 -0
- package/dist/test/unit/implementations/dms/permission-preview-aggregate.test.js +16 -0
- package/dist/test/unit/implementations/dms/permission-preview-aggregate.test.js.map +1 -1
- package/dist/test/unit/implementations/dms/permission-preview-cost.test.js +5 -3
- package/dist/test/unit/implementations/dms/permission-preview-cost.test.js.map +1 -1
- package/dist/test/unit/implementations/dms/permission-preview-menu.test.js +29 -3
- package/dist/test/unit/implementations/dms/permission-preview-menu.test.js.map +1 -1
- package/dist/test/unit/implementations/dms/quick-actions-button.test.js +4 -2
- package/dist/test/unit/implementations/dms/quick-actions-button.test.js.map +1 -1
- package/dist/test/unit/implementations/dms/user-permissions-gate.test.js +2 -1
- package/dist/test/unit/implementations/dms/user-permissions-gate.test.js.map +1 -1
- package/dist/test/unit/implementations/dms-base/table-view-shared-controller.test.js +2 -1
- package/dist/test/unit/implementations/dms-base/table-view-shared-controller.test.js.map +1 -1
- package/dist/test/unit/interfaces/dms/component-children-permissions.test.js +7 -2
- package/dist/test/unit/interfaces/dms/component-children-permissions.test.js.map +1 -1
- package/dist/test/unit/interfaces/dms/form-watch-permissions.test.d.ts +1 -0
- package/dist/test/unit/interfaces/dms/form-watch-permissions.test.js +133 -0
- package/dist/test/unit/interfaces/dms/form-watch-permissions.test.js.map +1 -0
- package/dist/test/unit/interfaces/dms/has-permission-ancestors.test.d.ts +1 -0
- package/dist/test/unit/interfaces/dms/has-permission-ancestors.test.js +149 -0
- package/dist/test/unit/interfaces/dms/has-permission-ancestors.test.js.map +1 -0
- package/dist/test/unit/interfaces/dms/invite-extension.test.js +13 -0
- package/dist/test/unit/interfaces/dms/invite-extension.test.js.map +1 -1
- package/dist/test/unit/interfaces/dms/member-access.test.js +27 -1
- package/dist/test/unit/interfaces/dms/member-access.test.js.map +1 -1
- package/dist/test/unit/interfaces/dms/nav-badge-tones.test.d.ts +1 -0
- package/dist/test/unit/interfaces/dms/nav-badge-tones.test.js +31 -0
- package/dist/test/unit/interfaces/dms/nav-badge-tones.test.js.map +1 -0
- package/dist/test/unit/interfaces/dms/page-extension.test.js +4 -1
- package/dist/test/unit/interfaces/dms/page-extension.test.js.map +1 -1
- package/dist/test/unit/interfaces/dms/permission-requirements.test.d.ts +1 -0
- package/dist/test/unit/interfaces/dms/permission-requirements.test.js +144 -0
- package/dist/test/unit/interfaces/dms/permission-requirements.test.js.map +1 -0
- package/dist/test/unit/interfaces/dms-base/column-display.test.js +70 -0
- package/dist/test/unit/interfaces/dms-base/column-display.test.js.map +1 -1
- package/dist/test/unit/interfaces/dms-base/display-blocks-catalog.test.js +38 -0
- package/dist/test/unit/interfaces/dms-base/display-blocks-catalog.test.js.map +1 -1
- package/dist/test/unit/interfaces/dms-base/layout-header-actions.test.js +6 -2
- package/dist/test/unit/interfaces/dms-base/layout-header-actions.test.js.map +1 -1
- package/dist/test/unit/interfaces/dms-base/lists-and-settings-catalog.test.js +1 -1
- package/dist/test/unit/interfaces/dms-base/lists-and-settings-catalog.test.js.map +1 -1
- package/dist/test/unit/interfaces/dms-base/table-view-export-permission.test.js +2 -1
- package/dist/test/unit/interfaces/dms-base/table-view-export-permission.test.js.map +1 -1
- package/dist/test/unit/interfaces/dms-base/table-view-reduced-chrome.test.js +2 -1
- package/dist/test/unit/interfaces/dms-base/table-view-reduced-chrome.test.js.map +1 -1
- package/dist/test/unit/interfaces/dms-base/table-view-shared-controller-permissions.test.js +2 -1
- package/dist/test/unit/interfaces/dms-base/table-view-shared-controller-permissions.test.js.map +1 -1
- package/dist/test/unit/pages/settings/account-activity-feed.test.js +2 -2
- package/dist/test/unit/pages/settings/account-activity-feed.test.js.map +1 -1
- package/dist/test/unit/pages/settings/account-activity.test.js +11 -2
- package/dist/test/unit/pages/settings/account-activity.test.js.map +1 -1
- package/dist/test/unit/pages/settings/invite-email-delivery.test.js +0 -1
- package/dist/test/unit/pages/settings/invite-email-delivery.test.js.map +1 -1
- package/dist/test/unit/pages/settings/invite-email-validation-option.test.d.ts +1 -0
- package/dist/test/unit/pages/settings/invite-email-validation-option.test.js +33 -0
- package/dist/test/unit/pages/settings/invite-email-validation-option.test.js.map +1 -0
- package/dist/test/unit/pages/settings/member-lists-page-size.test.d.ts +1 -0
- package/dist/test/unit/pages/settings/member-lists-page-size.test.js +22 -0
- package/dist/test/unit/pages/settings/member-lists-page-size.test.js.map +1 -0
- package/dist/test/unit/pages/settings/member-table-widths.test.js +2 -2
- package/dist/test/unit/pages/settings/member-table-widths.test.js.map +1 -1
- package/dist/test/unit/pages/settings/members-page.test.js +7 -10
- package/dist/test/unit/pages/settings/members-page.test.js.map +1 -1
- package/dist/test/unit/pages/settings/notifications-access-gate.test.js +3 -10
- package/dist/test/unit/pages/settings/notifications-access-gate.test.js.map +1 -1
- package/dist/test/unit/pages/settings/permission-tree-nodes.test.js +57 -0
- package/dist/test/unit/pages/settings/permission-tree-nodes.test.js.map +1 -1
- package/dist/test/unit/pages/settings/permission-warnings.test.d.ts +1 -0
- package/dist/test/unit/pages/settings/permission-warnings.test.js +49 -0
- package/dist/test/unit/pages/settings/permission-warnings.test.js.map +1 -0
- package/dist/test/unit/pages/settings/role-editor.test.js +16 -0
- package/dist/test/unit/pages/settings/role-editor.test.js.map +1 -1
- package/dist/test/unit/pages/settings/role-preview.test.js +7 -0
- package/dist/test/unit/pages/settings/role-preview.test.js.map +1 -1
- package/dist/test/unit/pages/settings/security-attention.test.d.ts +1 -0
- package/dist/test/unit/pages/settings/security-attention.test.js +74 -0
- package/dist/test/unit/pages/settings/security-attention.test.js.map +1 -0
- package/dist/test/unit/sanitize-user.test.d.ts +1 -0
- package/dist/test/unit/sanitize-user.test.js +21 -0
- package/dist/test/unit/sanitize-user.test.js.map +1 -0
- package/dist/test/unit/signup-email-validation.test.d.ts +1 -0
- package/dist/test/unit/signup-email-validation.test.js +79 -0
- package/dist/test/unit/signup-email-validation.test.js.map +1 -0
- package/dist/test/unit/validation/member-invite.schema.test.js +14 -52
- package/dist/test/unit/validation/member-invite.schema.test.js.map +1 -1
- package/dist/utils/account-notifications.d.ts +5 -0
- package/dist/utils/account-notifications.js +8 -0
- package/dist/utils/account-notifications.js.map +1 -1
- package/dist/utils/notification-emitter.d.ts +1 -1
- package/dist/utils/notification-emitter.js +1 -1
- package/dist/utils/notification-emitter.js.map +1 -1
- package/dist/utils/notification-tones.d.ts +2 -1
- package/dist/utils/notification-tones.js +5 -1
- package/dist/utils/notification-tones.js.map +1 -1
- package/dist/utils/one-time-code.d.ts +3 -0
- package/dist/utils/one-time-code.js +21 -0
- package/dist/utils/one-time-code.js.map +1 -0
- package/dist/utils/sign-in-monitor.d.ts +1 -0
- package/dist/utils/sign-in-monitor.js +3 -2
- package/dist/utils/sign-in-monitor.js.map +1 -1
- package/dist/utils/two-factor-codes.d.ts +10 -0
- package/dist/utils/two-factor-codes.js +76 -0
- package/dist/utils/two-factor-codes.js.map +1 -0
- package/dist/validation/auth.schema.d.ts +17 -0
- package/dist/validation/auth.schema.js +17 -6
- package/dist/validation/auth.schema.js.map +1 -1
- package/dist/validation/issue-message.d.ts +1 -0
- package/dist/validation/issue-message.js +9 -0
- package/dist/validation/issue-message.js.map +1 -0
- package/dist/validation/member-invite.schema.d.ts +1 -25
- package/dist/validation/member-invite.schema.js +2 -23
- package/dist/validation/member-invite.schema.js.map +1 -1
- package/frontend-vue/dms.frontend.ts +2 -0
- package/frontend-vue/layers/dms-auth/app/custom-pages/auth/forgot-validation.vue +3 -0
- package/frontend-vue/layers/dms-auth/app/custom-pages/auth/signup.vue +105 -5
- package/frontend-vue/layers/dms-auth/i18n/locales/auth-en-GB.json +20 -4
- package/frontend-vue/layers/dms-auth/i18n/locales/auth-fr-FR.json +20 -4
- package/frontend-vue/layers/dms-core/app/composables/translation/useComposedText.ts +25 -0
- package/frontend-vue/layers/dms-core/app/composables/useFieldErrors.ts +3 -2
- package/frontend-vue/layers/dms-core/app/types/composed-text.ts +64 -0
- package/frontend-vue/layers/dms-core/app/types/menu.ts +15 -0
- package/frontend-vue/layers/dms-core/app/utils/composedText.ts +227 -0
- package/frontend-vue/layers/dms-core/app/utils/formatter.ts +49 -0
- package/frontend-vue/layers/dms-core/i18n/locales/core-en-GB.json +4 -1
- package/frontend-vue/layers/dms-core/i18n/locales/core-fr-FR.json +4 -1
- package/frontend-vue/layers/dms-layout/app/assets/css/main.css +20 -0
- package/frontend-vue/layers/dms-layout/app/build/components/layout/CommandPaletteAssistantAnswer.vue +75 -0
- package/frontend-vue/layers/dms-layout/app/build/components/layout/DashboardBanners.vue +17 -3
- package/frontend-vue/layers/dms-layout/app/build/components/layout/DashboardFrame.vue +22 -0
- package/frontend-vue/layers/dms-layout/app/build/components/layout/DashboardHeader.vue +24 -10
- package/frontend-vue/layers/dms-layout/app/build/components/layout/DashboardSidePanel.vue +139 -0
- package/frontend-vue/layers/dms-layout/app/build/components/layout/Footer.vue +4 -2
- package/frontend-vue/layers/dms-layout/app/build/components/layout/GithubStarPrompt.vue +90 -0
- package/frontend-vue/layers/dms-layout/app/build/components/layout/SidePanelHost.vue +17 -0
- package/frontend-vue/layers/dms-layout/app/build/components/notification/NotificationPopover.vue +25 -43
- package/frontend-vue/layers/dms-layout/app/build/components/pages/settings/members/MemberRolePicker.vue +24 -2
- package/frontend-vue/layers/dms-layout/app/build/components/pages/settings/notification/NotificationMatrixCategory.vue +70 -25
- package/frontend-vue/layers/dms-layout/app/build/components/pages/settings/notification/NotificationPreferencesForm.vue +25 -10
- package/frontend-vue/layers/dms-layout/app/build/components/pages/settings/notification/notificationDisplay.ts +41 -5
- package/frontend-vue/layers/dms-layout/app/build/components/pages/settings/profile/ProfilePreferencesSummary.vue +2 -1
- package/frontend-vue/layers/dms-layout/app/build/components/pages/settings/profile/ProfileSecuritySummary.vue +20 -4
- package/frontend-vue/layers/dms-layout/app/build/components/pages/settings/roles/RoleEditor.vue +21 -0
- package/frontend-vue/layers/dms-layout/app/build/components/pages/settings/roles/RolePermissionArea.vue +16 -2
- package/frontend-vue/layers/dms-layout/app/build/components/pages/settings/roles/RolePermissionBranch.vue +1 -0
- package/frontend-vue/layers/dms-layout/app/build/components/pages/settings/roles/RolePermissionLeaf.vue +13 -1
- package/frontend-vue/layers/dms-layout/app/build/components/pages/settings/roles/RolePermissionTree.vue +9 -0
- package/frontend-vue/layers/dms-layout/app/build/components/pages/settings/roles/RolePermissionWarning.vue +46 -0
- package/frontend-vue/layers/dms-layout/app/build/components/pages/settings/roles/role-permissions.ts +108 -29
- package/frontend-vue/layers/dms-layout/app/build/components/pages/settings/roles/role-types.ts +2 -0
- package/frontend-vue/layers/dms-layout/app/build/components/pages/settings/security/SecurityDialogFrame.vue +6 -6
- package/frontend-vue/layers/dms-layout/app/build/components/pages/settings/security/SecurityEmail.vue +7 -1
- package/frontend-vue/layers/dms-layout/app/build/components/pages/settings/security/SecuritySessions.vue +5 -4
- package/frontend-vue/layers/dms-layout/app/build/components/pages/settings/security/SecurityStatus.vue +4 -3
- package/frontend-vue/layers/dms-layout/app/build/components/pages/settings/security/SecurityTwoFactor.vue +54 -18
- package/frontend-vue/layers/dms-layout/app/build/components/pages/settings/shell/SettingsNav.vue +13 -8
- package/frontend-vue/layers/dms-layout/app/build/composables/command-palette/assistantGroups.ts +143 -0
- package/frontend-vue/layers/dms-layout/app/build/composables/command-palette/useCommandPaletteAssistantMode.ts +249 -0
- package/frontend-vue/layers/dms-layout/app/build/composables/general/useGithubStarPrompt.ts +178 -0
- package/frontend-vue/layers/dms-layout/app/build/composables/layout/sidePanelState.ts +191 -0
- package/frontend-vue/layers/dms-layout/app/build/composables/layout/useHeaderActionControls.ts +51 -0
- package/frontend-vue/layers/dms-layout/app/build/composables/layout/useSidePanelWidth.ts +113 -0
- package/frontend-vue/layers/dms-layout/app/build/composables/navigation/useCategoryNavCards.ts +17 -10
- package/frontend-vue/layers/dms-layout/app/build/composables/notification/useNotificationGroupsOpen.ts +45 -0
- package/frontend-vue/layers/dms-layout/app/build/composables/settings/profile/useProfilePreferences.ts +8 -1
- package/frontend-vue/layers/dms-layout/app/build/composables/settings/security/useSecurityOverview.ts +50 -3
- package/frontend-vue/layers/dms-layout/app/build/composables/settings/useSettingsNavigation.ts +3 -0
- package/frontend-vue/layers/dms-layout/app/build/utils/categoryPages.ts +1 -2
- package/frontend-vue/layers/dms-layout/app/build/utils/github-repository.ts +5 -0
- package/frontend-vue/layers/dms-layout/app/components/layout/DashboardSearch.vue +109 -7
- package/frontend-vue/layers/dms-layout/app/components/navigation/NavigationMenu.vue +19 -9
- package/frontend-vue/layers/dms-layout/app/composables/notification/useNotifications.ts +22 -40
- package/frontend-vue/layers/dms-layout/app/composables/useAppSidePanels.ts +96 -0
- package/frontend-vue/layers/dms-layout/app/composables/useCommandPaletteAssistant.ts +129 -0
- package/frontend-vue/layers/dms-layout/app/composables/useHeaderActions.ts +33 -11
- package/frontend-vue/layers/dms-layout/app/composables/useSidePanel.ts +41 -0
- package/frontend-vue/layers/dms-layout/app/pages/[...slug].vue +15 -0
- package/frontend-vue/layers/dms-layout/app/plugins/notification-stream.client.ts +1 -7
- package/frontend-vue/layers/dms-layout/app/plugins/side-panel-host.ts +13 -0
- package/frontend-vue/layers/dms-layout/app/types/page.ts +11 -1
- package/frontend-vue/layers/dms-layout/i18n/locales/layout-en-GB.json +43 -13
- package/frontend-vue/layers/dms-layout/i18n/locales/layout-fr-FR.json +43 -13
- package/frontend-vue/layers/dms-ui/app/build/components/form/FormLoadError.vue +45 -0
- package/frontend-vue/layers/dms-ui/app/build/components/modal/ModalEscHint.vue +28 -0
- package/frontend-vue/layers/dms-ui/app/build/components/table-view/IdentityCell.vue +36 -7
- package/frontend-vue/layers/dms-ui/app/build/composables/data-types/cellHelpers.ts +57 -0
- package/frontend-vue/layers/dms-ui/app/build/composables/data-types/metricCells.ts +19 -5
- package/frontend-vue/layers/dms-ui/app/build/composables/data-types/registerDefaults.ts +22 -2
- package/frontend-vue/layers/dms-ui/app/build/composables/data-types/twoLineCell.ts +118 -0
- package/frontend-vue/layers/dms-ui/app/build/composables/data-types/useColumnValueRenderer.ts +5 -3
- package/frontend-vue/layers/dms-ui/app/build/composables/form/floatingSaveBars.ts +38 -0
- package/frontend-vue/layers/dms-ui/app/build/composables/form/formRecordLoad.ts +66 -0
- package/frontend-vue/layers/dms-ui/app/build/composables/navigation/useNavBadges.ts +50 -9
- package/frontend-vue/layers/dms-ui/app/build/composables/table/useTable.ts +7 -1
- package/frontend-vue/layers/dms-ui/app/build/composables/table-view/utils/chrome.ts +2 -2
- package/frontend-vue/layers/dms-ui/app/build/types/tree.ts +14 -10
- package/frontend-vue/layers/dms-ui/app/build/utils/navBadge.ts +12 -0
- package/frontend-vue/layers/dms-ui/app/build/utils/relativeDate.ts +4 -35
- package/frontend-vue/layers/dms-ui/app/build/utils/tone.ts +22 -0
- package/frontend-vue/layers/dms-ui/app/components/activity-feed/ActivityFeed.vue +117 -82
- package/frontend-vue/layers/dms-ui/app/components/blocks/BannerBlock.vue +8 -5
- package/frontend-vue/layers/dms-ui/app/components/blocks/KeyValueListBlock.vue +38 -18
- package/frontend-vue/layers/dms-ui/app/components/blocks/NavCardGridBlock.vue +12 -1
- package/frontend-vue/layers/dms-ui/app/components/blocks/StatGroupBlock.vue +26 -23
- package/frontend-vue/layers/dms-ui/app/components/card/NavCard.vue +16 -1
- package/frontend-vue/layers/dms-ui/app/components/confirm/ConfirmModal.vue +7 -8
- package/frontend-vue/layers/dms-ui/app/components/form/Form.vue +28 -6
- package/frontend-vue/layers/dms-ui/app/components/form/components/Display.vue +5 -1
- package/frontend-vue/layers/dms-ui/app/components/save-bar/SaveBar.vue +4 -0
- package/frontend-vue/layers/dms-ui/app/components/status-pill/StatusPill.vue +7 -2
- package/frontend-vue/layers/dms-ui/app/components/table-view/TableView.vue +7 -2
- package/frontend-vue/layers/dms-ui/app/composables/form/useForm.ts +48 -34
- package/frontend-vue/layers/dms-ui/app/composables/table-view/types/config.ts +13 -3
- package/frontend-vue/layers/dms-ui/i18n/locales/ui-en-GB.json +16 -14
- package/frontend-vue/layers/dms-ui/i18n/locales/ui-fr-FR.json +16 -14
- package/frontend-vue/package.json +2 -2
- package/frontend-vue/pnpm-lock.yaml +5 -5
- package/frontend-vue/tests/activity-feed-fill-height.test.ts +107 -0
- package/frontend-vue/tests/category-nav-cards.test.ts +21 -13
- package/frontend-vue/tests/command-palette-assistant.test.ts +344 -0
- package/frontend-vue/tests/composed-text-blocks.test.ts +205 -0
- package/frontend-vue/tests/composed-text.test.ts +265 -0
- package/frontend-vue/tests/fixtures/dashboard-search-stub.ts +91 -0
- package/frontend-vue/tests/forgot-validation-resend.test.ts +234 -0
- package/frontend-vue/tests/form-display-options.test.ts +64 -0
- package/frontend-vue/tests/form-load-error.test.ts +160 -0
- package/frontend-vue/tests/form-saved-before-success.test.ts +110 -0
- package/frontend-vue/tests/github-star-prompt.test.ts +328 -0
- package/frontend-vue/tests/header-actions.test.ts +191 -0
- package/frontend-vue/tests/invites-edit-modal.test.ts +157 -0
- package/frontend-vue/tests/layout-banners.test.ts +56 -0
- package/frontend-vue/tests/member-role-picker.test.ts +26 -0
- package/frontend-vue/tests/menu-hidden-page.test.ts +93 -0
- package/frontend-vue/tests/nav-badge-tones.test.ts +274 -0
- package/frontend-vue/tests/nav-card-badge.test.ts +69 -0
- package/frontend-vue/tests/nav-card-grid-empty-category.test.ts +163 -0
- package/frontend-vue/tests/notification-popover-errors.test.ts +71 -37
- package/frontend-vue/tests/notification-preferences-groups.test.ts +268 -0
- package/frontend-vue/tests/notification-tone-contract.test.ts +70 -0
- package/frontend-vue/tests/page-fill-height.test.ts +9 -1
- package/frontend-vue/tests/page-no-visible-blocks.test.ts +202 -0
- package/frontend-vue/tests/profile-preferences-summary.test.ts +26 -2
- package/frontend-vue/tests/profile-security-summary.test.ts +121 -0
- package/frontend-vue/tests/role-permission-tree.test.ts +102 -8
- package/frontend-vue/tests/role-permissions.test.ts +178 -56
- package/frontend-vue/tests/side-panels.test.ts +470 -0
- package/frontend-vue/tests/signup-invitation-link.test.ts +71 -2
- package/frontend-vue/tests/table-actions-column-width.test.ts +51 -1
- package/frontend-vue/tests/table-cell-sublines.test.ts +466 -0
- package/frontend-vue/tests/table-metric-cells.test.ts +4 -0
- package/frontend-vue/tests/table-view-chrome.test.ts +2 -2
- package/frontend-vue/tests/vue-inventory.test.ts +1 -1
- package/package.json +2 -2
- package/skills/dms/REFERENCE.md +1 -1
- package/skills/dms/SKILL.md +7 -0
package/frontend-vue/layers/dms-layout/app/build/components/pages/settings/roles/role-permissions.ts
CHANGED
|
@@ -50,6 +50,8 @@ export interface PermissionRowContext {
|
|
|
50
50
|
changeOf: (id: string) => PermissionChange;
|
|
51
51
|
requiresOf: (node: RolePermissionNode) => string[];
|
|
52
52
|
autoAddedHintOf: (id: string) => string | undefined;
|
|
53
|
+
/** Warnings a closed row hides (see `selectedWarningsBelow`). */
|
|
54
|
+
warningsBelowOf: (node: RolePermissionNode) => string[];
|
|
53
55
|
isDisabled: (node: RolePermissionNode) => boolean;
|
|
54
56
|
disabledHint: string;
|
|
55
57
|
toggle: (id: string, checked: boolean) => void;
|
|
@@ -289,25 +291,36 @@ export function selectionState(count: SelectionCount): SelectionState {
|
|
|
289
291
|
return count.selected === count.total ? true : "indeterminate";
|
|
290
292
|
}
|
|
291
293
|
|
|
294
|
+
/** The permissions a node declares it needs, as far as the tree knows them. */
|
|
295
|
+
function dependenciesOf(index: PermissionIndex, id: string): string[] {
|
|
296
|
+
return (index.nodes.get(id)?.dependencies ?? []).filter((dependency) =>
|
|
297
|
+
index.nodes.has(dependency),
|
|
298
|
+
);
|
|
299
|
+
}
|
|
300
|
+
|
|
292
301
|
/**
|
|
293
|
-
*
|
|
294
|
-
*
|
|
295
|
-
* the original roles form did: a registered `media.upload` lifted to the top
|
|
296
|
-
* of the tree still grants `media` with it.
|
|
302
|
+
* Ids a set of permissions needs, the set included: the nodes above each one
|
|
303
|
+
* and the permissions each one depends on, with what those need in turn.
|
|
297
304
|
*/
|
|
298
|
-
|
|
299
|
-
const
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
305
|
+
function requiredIds(index: PermissionIndex, ids: string[]): Set<string> {
|
|
306
|
+
const required = new Set<string>();
|
|
307
|
+
const pending = [...ids];
|
|
308
|
+
for (let id = pending.shift(); id !== undefined; id = pending.shift()) {
|
|
309
|
+
if (required.has(id)) continue;
|
|
310
|
+
required.add(id);
|
|
311
|
+
pending.push(...ancestorIds(index, id), ...dependenciesOf(index, id));
|
|
312
|
+
}
|
|
313
|
+
return required;
|
|
303
314
|
}
|
|
304
315
|
|
|
305
316
|
/**
|
|
306
|
-
* Grant a node's whole subtree with
|
|
307
|
-
* needs its page, a page its category)
|
|
308
|
-
*
|
|
309
|
-
*
|
|
310
|
-
*
|
|
317
|
+
* Grant a node's whole subtree with everything it needs: every node above it
|
|
318
|
+
* (a component needs its page, a page its category) and the permissions it
|
|
319
|
+
* depends on (a table's edit needs its view, which loads the row). The tree
|
|
320
|
+
* nests by id, so the nodes above are the registered ids it sits under; the
|
|
321
|
+
* server completes a saved role the same way, with the unregistered rest (a
|
|
322
|
+
* lifted `media.upload` gets `media` there). Ids the user may not grant are
|
|
323
|
+
* skipped.
|
|
311
324
|
*/
|
|
312
325
|
export function grantPermission(
|
|
313
326
|
index: PermissionIndex,
|
|
@@ -316,25 +329,48 @@ export function grantPermission(
|
|
|
316
329
|
canGrant: (permissionId: string) => boolean,
|
|
317
330
|
): PermissionGrant {
|
|
318
331
|
const subtree = new Set(index.subtrees.get(id) ?? [id]);
|
|
319
|
-
const wanted =
|
|
332
|
+
const wanted = requiredIds(index, [...subtree]);
|
|
320
333
|
const added = [...wanted].filter(
|
|
321
334
|
(wantedId) => !selection.has(wantedId) && canGrant(wantedId),
|
|
322
335
|
);
|
|
323
336
|
return {
|
|
324
337
|
selection: new Set([...selection, ...added]),
|
|
325
|
-
autoAdded: added.filter(
|
|
326
|
-
(addedId) => !subtree.has(addedId) && index.nodes.has(addedId),
|
|
327
|
-
),
|
|
338
|
+
autoAdded: added.filter((addedId) => !subtree.has(addedId)),
|
|
328
339
|
};
|
|
329
340
|
}
|
|
330
341
|
|
|
331
342
|
/**
|
|
332
|
-
*
|
|
333
|
-
*
|
|
334
|
-
*
|
|
335
|
-
*
|
|
336
|
-
|
|
337
|
-
|
|
343
|
+
* The selected nodes that depend on a removed one, with their subtrees added
|
|
344
|
+
* to `removed`, until none is left: a table's edit goes with its view, which
|
|
345
|
+
* the server would otherwise put back when the role is saved. Returns the
|
|
346
|
+
* nodes taken this way.
|
|
347
|
+
*/
|
|
348
|
+
function removeDependents(
|
|
349
|
+
index: PermissionIndex,
|
|
350
|
+
selection: Set<string>,
|
|
351
|
+
removed: Set<string>,
|
|
352
|
+
): string[] {
|
|
353
|
+
const dependents: string[] = [];
|
|
354
|
+
const dependsOnRemoved = (id: string) =>
|
|
355
|
+
!removed.has(id) &&
|
|
356
|
+
dependenciesOf(index, id).some((dependency) => removed.has(dependency));
|
|
357
|
+
for (let next = [...selection].find(dependsOnRemoved); next; ) {
|
|
358
|
+
dependents.push(next);
|
|
359
|
+
for (const descendant of index.subtrees.get(next) ?? [next]) {
|
|
360
|
+
removed.add(descendant);
|
|
361
|
+
}
|
|
362
|
+
next = [...selection].find(dependsOnRemoved);
|
|
363
|
+
}
|
|
364
|
+
return dependents;
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
/**
|
|
368
|
+
* Revoke a node's subtree, and what depends on it. A node above them goes
|
|
369
|
+
* too when none of its descendants is left once they are gone: a page is
|
|
370
|
+
* granted for its components. Same rule as the original roles form, which
|
|
371
|
+
* judges every ancestor against that one state, before any ancestor is
|
|
372
|
+
* dropped: an ancestor above one dropped this way still saw it selected, and
|
|
373
|
+
* stays.
|
|
338
374
|
*/
|
|
339
375
|
export function revokePermission(
|
|
340
376
|
index: PermissionIndex,
|
|
@@ -342,15 +378,16 @@ export function revokePermission(
|
|
|
342
378
|
id: string,
|
|
343
379
|
): Set<string> {
|
|
344
380
|
const removed = new Set(index.subtrees.get(id) ?? [id]);
|
|
381
|
+
const dependents = removeDependents(index, selection, removed);
|
|
345
382
|
const remaining = new Set(
|
|
346
383
|
[...selection].filter((kept) => !removed.has(kept)),
|
|
347
384
|
);
|
|
348
|
-
const
|
|
385
|
+
const judged = new Set(
|
|
386
|
+
[id, ...dependents].flatMap((revoked) => ancestorIds(index, revoked)),
|
|
387
|
+
);
|
|
388
|
+
const emptied = [...judged].filter((ancestor) => {
|
|
349
389
|
const descendants = (index.subtrees.get(ancestor) ?? []).slice(1);
|
|
350
|
-
return (
|
|
351
|
-
descendants.length > 0 &&
|
|
352
|
-
!descendants.some((descendant) => remaining.has(descendant))
|
|
353
|
-
);
|
|
390
|
+
return !descendants.some((descendant) => remaining.has(descendant));
|
|
354
391
|
});
|
|
355
392
|
for (const ancestor of emptied) remaining.delete(ancestor);
|
|
356
393
|
return remaining;
|
|
@@ -408,6 +445,48 @@ export function searchPermissions(
|
|
|
408
445
|
}));
|
|
409
446
|
}
|
|
410
447
|
|
|
448
|
+
function warningOf(index: PermissionIndex, id: string): string | undefined {
|
|
449
|
+
return index.nodes.get(id)?.warning;
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
/**
|
|
453
|
+
* Distinct warnings of the selected permissions below a node, itself
|
|
454
|
+
* excluded: what a closed row hides once a parent ticked them.
|
|
455
|
+
*/
|
|
456
|
+
export function selectedWarningsBelow(
|
|
457
|
+
index: PermissionIndex,
|
|
458
|
+
id: string,
|
|
459
|
+
selection: Set<string>,
|
|
460
|
+
): string[] {
|
|
461
|
+
const descendants = (index.subtrees.get(id) ?? []).slice(1);
|
|
462
|
+
const warnings = descendants
|
|
463
|
+
.filter((descendant) => selection.has(descendant))
|
|
464
|
+
.map((descendant) => warningOf(index, descendant))
|
|
465
|
+
.filter((warning): warning is string => Boolean(warning));
|
|
466
|
+
return [...new Set(warnings)];
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
/**
|
|
470
|
+
* The selected permissions that carry a warning, in tree order, each named
|
|
471
|
+
* under its area ("Members › Edit") so a summary can list them.
|
|
472
|
+
*/
|
|
473
|
+
export function selectedWarningLabels(
|
|
474
|
+
index: PermissionIndex,
|
|
475
|
+
areas: PermissionArea[],
|
|
476
|
+
selection: Set<string>,
|
|
477
|
+
translate: (label: string) => string,
|
|
478
|
+
): string[] {
|
|
479
|
+
const areaIds = new Set(areas.map((area) => area.node.id));
|
|
480
|
+
return index.allIds
|
|
481
|
+
.filter((id) => selection.has(id) && warningOf(index, id))
|
|
482
|
+
.map((id) => {
|
|
483
|
+
const areaId = areaIdOf(index, areaIds, id);
|
|
484
|
+
const labels = [index.nodes.get(id)?.label ?? id];
|
|
485
|
+
if (areaId !== id) labels.unshift(index.nodes.get(areaId)?.label ?? "");
|
|
486
|
+
return joinPath(labels.map((label) => translate(label)));
|
|
487
|
+
});
|
|
488
|
+
}
|
|
489
|
+
|
|
411
490
|
/** Joins path labels the way the editor shows them. */
|
|
412
491
|
export function joinPath(labels: string[]): string {
|
|
413
492
|
return labels.join(PATH_SEPARATOR);
|
package/frontend-vue/layers/dms-layout/app/build/components/pages/settings/roles/role-types.ts
CHANGED
|
@@ -6,6 +6,8 @@ export interface RolePermissionNode {
|
|
|
6
6
|
description?: string;
|
|
7
7
|
/** Permissions this one needs; granting it grants them too. */
|
|
8
8
|
dependencies?: string[];
|
|
9
|
+
/** What granting it really allows, beyond its label (an i18n key). */
|
|
10
|
+
warning?: string;
|
|
9
11
|
children?: RolePermissionNode[];
|
|
10
12
|
}
|
|
11
13
|
|
|
@@ -3,6 +3,8 @@ export type SecurityDialogTone = "primary" | "error" | "warning";
|
|
|
3
3
|
</script>
|
|
4
4
|
|
|
5
5
|
<script setup lang="ts">
|
|
6
|
+
import DmsModalEscHint from "#dms-ui/app/build/components/modal/ModalEscHint.vue";
|
|
7
|
+
|
|
6
8
|
interface SecurityDialogFrameProps {
|
|
7
9
|
title: string;
|
|
8
10
|
icon: string;
|
|
@@ -51,12 +53,10 @@ const { t } = useI18n();
|
|
|
51
53
|
<template #footer>
|
|
52
54
|
<!-- Phones: no Esc hint (no keyboard) and the buttons may wrap. -->
|
|
53
55
|
<div class="flex w-full flex-wrap items-center justify-end gap-2">
|
|
54
|
-
<
|
|
55
|
-
class="
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
{{ t("page.settings.security.esc_to_cancel") }}
|
|
59
|
-
</span>
|
|
56
|
+
<DmsModalEscHint
|
|
57
|
+
class="max-sm:hidden"
|
|
58
|
+
:label="t('page.settings.security.esc_to_cancel')"
|
|
59
|
+
/>
|
|
60
60
|
<UButton
|
|
61
61
|
color="neutral"
|
|
62
62
|
variant="outline"
|
|
@@ -21,6 +21,8 @@ const CODE_ERRORS = {
|
|
|
21
21
|
"error.invalid_token": "code",
|
|
22
22
|
"error.token_expired": "code",
|
|
23
23
|
} as const;
|
|
24
|
+
// Too many wrong codes: the change is dropped and a new code must be asked.
|
|
25
|
+
const CODE_BURNT = "error.email_change_too_many_attempts";
|
|
24
26
|
const FORGOT_PASSWORD_PATH = "/auth/forgot";
|
|
25
27
|
const INVALID_CURRENT_PASSWORD = "error.invalid_current_password";
|
|
26
28
|
const EMAIL_ALREADY_USED = "error.email_already_used";
|
|
@@ -39,7 +41,7 @@ const toast = useToast();
|
|
|
39
41
|
const { $authFetch } = useAuthFetch();
|
|
40
42
|
const { refresh: refreshSession } = useCurrentUser();
|
|
41
43
|
const { overview, refresh } = useSecurityOverview();
|
|
42
|
-
const { errorMessage } = useSecurityFormat();
|
|
44
|
+
const { errorMessage, errorCode } = useSecurityFormat();
|
|
43
45
|
const { processApiMessage } = useTranslation();
|
|
44
46
|
|
|
45
47
|
const isEditing = ref(false);
|
|
@@ -218,6 +220,10 @@ async function confirmCode(code: string): Promise<void> {
|
|
|
218
220
|
title: errorMessage(error, "page.settings.security.email.error"),
|
|
219
221
|
color: "error",
|
|
220
222
|
});
|
|
223
|
+
if (errorCode(error) === CODE_BURNT) {
|
|
224
|
+
isCodeOpen.value = false;
|
|
225
|
+
await refresh();
|
|
226
|
+
}
|
|
221
227
|
} finally {
|
|
222
228
|
isConfirming.value = false;
|
|
223
229
|
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
2
|
import { MONO_CHIP_CLASS } from "#dms-ui/app/build/utils/monoChip";
|
|
3
|
+
import DmsModalEscHint from "#dms-ui/app/build/components/modal/ModalEscHint.vue";
|
|
3
4
|
import { useSecurityFormat } from "../../../../composables/settings/security/useSecurityFormat";
|
|
4
5
|
import {
|
|
5
6
|
SECURITY_ENDPOINT,
|
|
@@ -340,10 +341,10 @@ onMounted(loadSessions);
|
|
|
340
341
|
</template>
|
|
341
342
|
<template #footer>
|
|
342
343
|
<div class="flex w-full items-center justify-end gap-2">
|
|
343
|
-
<
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
344
|
+
<DmsModalEscHint
|
|
345
|
+
class="max-sm:hidden"
|
|
346
|
+
:label="t('page.settings.security.esc_to_cancel')"
|
|
347
|
+
/>
|
|
347
348
|
<UButton
|
|
348
349
|
color="neutral"
|
|
349
350
|
variant="outline"
|
|
@@ -14,7 +14,9 @@ const METHODS_LABEL_KEYS: Record<string, string> = {
|
|
|
14
14
|
const SKELETON_COUNT = 4;
|
|
15
15
|
|
|
16
16
|
const { t } = useI18n();
|
|
17
|
-
const { overview, attention, isUnavailable, refresh } =
|
|
17
|
+
const { overview, attention, attentionToneOf, isUnavailable, refresh } =
|
|
18
|
+
useSecurityOverview();
|
|
19
|
+
const BACKUP_ATTENTION = ["backup_codes_low", "backup_codes_unsaved"] as const;
|
|
18
20
|
const { formatDate, daysSince } = useSecurityFormat();
|
|
19
21
|
|
|
20
22
|
function twoFactorItem(data: SecurityOverview): StatGroupItem {
|
|
@@ -53,12 +55,11 @@ function backupDetail(
|
|
|
53
55
|
function backupItem({ twoFactor }: SecurityOverview): StatGroupItem {
|
|
54
56
|
const isOn = twoFactor.methods.length > 0;
|
|
55
57
|
const isUnsaved = attention.value.includes("backup_codes_unsaved");
|
|
56
|
-
const isLow = attention.value.includes("backup_codes_low");
|
|
57
58
|
return {
|
|
58
59
|
id: "backup-codes",
|
|
59
60
|
to: "#backup-codes",
|
|
60
61
|
icon: "i-ph-key",
|
|
61
|
-
tone: isOn && (
|
|
62
|
+
tone: (isOn && attentionToneOf([...BACKUP_ATTENTION])) || "muted",
|
|
62
63
|
eyebrow: t("page.settings.security.status.backup_codes"),
|
|
63
64
|
value: isOn
|
|
64
65
|
? t("page.settings.security.codes_left", {
|
|
@@ -67,7 +67,7 @@ const METHODS: MethodConfig[] = [
|
|
|
67
67
|
const { t } = useI18n();
|
|
68
68
|
const toast = useToast();
|
|
69
69
|
const { $authFetch } = useAuthFetch();
|
|
70
|
-
const { overview, attention, refresh } = useSecurityOverview();
|
|
70
|
+
const { overview, attention, attentionToneOf, refresh } = useSecurityOverview();
|
|
71
71
|
const { formatDate, errorMessage } = useSecurityFormat();
|
|
72
72
|
|
|
73
73
|
const isProcessing = ref(false);
|
|
@@ -81,6 +81,8 @@ const {
|
|
|
81
81
|
reveal: revealCodes,
|
|
82
82
|
} = useRevealedBackupCodes(computed(() => user.value?._id));
|
|
83
83
|
const isRemoveOpen = ref(false);
|
|
84
|
+
const isEmailSetupOpen = ref(false);
|
|
85
|
+
const emailSetupCodeError = ref<string>();
|
|
84
86
|
const totpCodeError = ref<string>();
|
|
85
87
|
const removeCodeError = ref<string>();
|
|
86
88
|
const regenerateCodeError = ref<string>();
|
|
@@ -112,6 +114,10 @@ const isUnsaved = computed(() =>
|
|
|
112
114
|
attention.value.includes("backup_codes_unsaved"),
|
|
113
115
|
);
|
|
114
116
|
const isLow = computed(() => attention.value.includes("backup_codes_low"));
|
|
117
|
+
// The backup codes row and its pill, in the tone the server gives them.
|
|
118
|
+
const backupTone = computed(() =>
|
|
119
|
+
attentionToneOf(["backup_codes_low", "backup_codes_unsaved"]),
|
|
120
|
+
);
|
|
115
121
|
|
|
116
122
|
const addItems = computed<DropdownMenuItem[]>(() =>
|
|
117
123
|
addableMethods.value.map((method) => ({
|
|
@@ -256,22 +262,38 @@ async function confirmTotp(code: string): Promise<void> {
|
|
|
256
262
|
);
|
|
257
263
|
}
|
|
258
264
|
|
|
259
|
-
|
|
265
|
+
// Like the app, email codes turn on only once a code proves they arrive: a
|
|
266
|
+
// mistyped address would otherwise lock the user out at the next sign-in.
|
|
267
|
+
async function startEmail(currentPassword?: string): Promise<void> {
|
|
268
|
+
await run(
|
|
269
|
+
async () => {
|
|
270
|
+
await $authFetch(`${TWO_FACTOR_URL}/enable-email`, {
|
|
271
|
+
method: "POST",
|
|
272
|
+
body: { currentPassword },
|
|
273
|
+
});
|
|
274
|
+
leavePasswordDialog(() => (isEmailSetupOpen.value = true));
|
|
275
|
+
},
|
|
276
|
+
"page.settings.two_factor.setup_error",
|
|
277
|
+
passwordRefusal,
|
|
278
|
+
);
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
async function confirmEmail(code: string): Promise<void> {
|
|
260
282
|
await run(
|
|
261
283
|
async () => {
|
|
262
284
|
const response = await $authFetch<MethodEnabledResponse>(
|
|
263
|
-
`${TWO_FACTOR_URL}/
|
|
264
|
-
{ method: "POST", body: {
|
|
285
|
+
`${TWO_FACTOR_URL}/confirm-email`,
|
|
286
|
+
{ method: "POST", body: { code } },
|
|
265
287
|
);
|
|
266
|
-
|
|
288
|
+
isEmailSetupOpen.value = false;
|
|
267
289
|
toast.add({
|
|
268
290
|
title: t("page.settings.two_factor.enable_success"),
|
|
269
291
|
color: "success",
|
|
270
292
|
});
|
|
271
293
|
showCodes(response.backupCodes);
|
|
272
294
|
},
|
|
273
|
-
|
|
274
|
-
|
|
295
|
+
INVALID_CODE_KEY,
|
|
296
|
+
codeRefusal(emailSetupCodeError),
|
|
275
297
|
);
|
|
276
298
|
}
|
|
277
299
|
|
|
@@ -280,7 +302,7 @@ const ADD_HANDLERS: Record<
|
|
|
280
302
|
(currentPassword?: string) => Promise<void>
|
|
281
303
|
> = {
|
|
282
304
|
totp: startTotp,
|
|
283
|
-
email:
|
|
305
|
+
email: startEmail,
|
|
284
306
|
};
|
|
285
307
|
|
|
286
308
|
// Adding a method asks for the account password first, so a borrowed
|
|
@@ -440,22 +462,18 @@ async function markSaved(): Promise<void> {
|
|
|
440
462
|
|
|
441
463
|
<DmsFieldRow v-if="isOn" id="backup-codes" class="scroll-mt-6">
|
|
442
464
|
<template #label>
|
|
443
|
-
<DmsListRow
|
|
444
|
-
bare
|
|
445
|
-
icon="i-ph-key"
|
|
446
|
-
:tone="isUnsaved || isLow ? 'warning' : 'muted'"
|
|
447
|
-
>
|
|
465
|
+
<DmsListRow bare icon="i-ph-key" :tone="backupTone ?? 'muted'">
|
|
448
466
|
{{ t("page.settings.security.backup.title") }}
|
|
449
467
|
<UBadge
|
|
450
|
-
v-if="
|
|
451
|
-
color="
|
|
468
|
+
v-if="backupTone"
|
|
469
|
+
:color="backupTone"
|
|
452
470
|
variant="subtle"
|
|
453
471
|
size="sm"
|
|
454
472
|
icon="i-ph-warning"
|
|
455
473
|
:label="
|
|
456
|
-
|
|
457
|
-
? t('page.settings.security.backup.
|
|
458
|
-
: t('page.settings.security.backup.
|
|
474
|
+
isLow
|
|
475
|
+
? t('page.settings.security.backup.running_low')
|
|
476
|
+
: t('page.settings.security.backup.not_saved')
|
|
459
477
|
"
|
|
460
478
|
/>
|
|
461
479
|
<template #meta>
|
|
@@ -554,6 +572,24 @@ async function markSaved(): Promise<void> {
|
|
|
554
572
|
:loading="isProcessing"
|
|
555
573
|
@confirm="confirmTotp"
|
|
556
574
|
/>
|
|
575
|
+
<SecurityCodeModal
|
|
576
|
+
v-model:open="isEmailSetupOpen"
|
|
577
|
+
v-model:error="emailSetupCodeError"
|
|
578
|
+
:title="t('page.settings.two_factor.email_enable')"
|
|
579
|
+
:description="
|
|
580
|
+
t('page.settings.security.two_factor.email_setup_description', {
|
|
581
|
+
email,
|
|
582
|
+
})
|
|
583
|
+
"
|
|
584
|
+
icon="i-ph-envelope-simple"
|
|
585
|
+
tone="primary"
|
|
586
|
+
:code-label="t('page.settings.security.two_factor.code_label_email')"
|
|
587
|
+
:confirm-label="t('page.settings.security.totp.submit')"
|
|
588
|
+
:loading="isProcessing"
|
|
589
|
+
can-send-email-code
|
|
590
|
+
@confirm="confirmEmail"
|
|
591
|
+
@send-code="sendEmailCode"
|
|
592
|
+
/>
|
|
557
593
|
<SecurityBackupCodesModal
|
|
558
594
|
v-model:open="isCodesOpen"
|
|
559
595
|
:codes="codes"
|
package/frontend-vue/layers/dms-layout/app/build/components/pages/settings/shell/SettingsNav.vue
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
import { tv } from "tailwind-variants";
|
|
3
3
|
import { usePermissionPreview } from "#dms-core/app/build/composables/auth/usePermissionPreview";
|
|
4
4
|
import { useNavBadges } from "#dms-ui/app/build/composables/navigation/useNavBadges";
|
|
5
|
+
import { navBadgeClass } from "#dms-ui/app/build/utils/navBadge";
|
|
5
6
|
import DmsSearchInput from "#dms-ui/app/build/components/form/SearchInput.vue";
|
|
6
7
|
import {
|
|
7
8
|
findActiveSettingsPath,
|
|
@@ -27,8 +28,7 @@ const theme = tv({
|
|
|
27
28
|
item: "flex h-8 shrink-0 items-center gap-2.5 rounded-md px-2.5 text-[13.5px] font-medium whitespace-nowrap text-muted transition-colors hover:bg-elevated hover:text-highlighted max-lg:border max-lg:border-default",
|
|
28
29
|
itemIcon: "size-[17px] shrink-0",
|
|
29
30
|
itemLabel: "min-w-0 truncate",
|
|
30
|
-
trailBadge:
|
|
31
|
-
"ms-auto hidden rounded-full bg-elevated px-1.5 font-mono text-[10.5px] font-semibold tabular-nums text-muted lg:inline",
|
|
31
|
+
trailBadge: "ms-auto hidden lg:inline",
|
|
32
32
|
trailDot: "ms-auto hidden size-[7px] shrink-0 rounded-full lg:block",
|
|
33
33
|
empty: "hidden px-2.5 text-[12.5px] text-muted lg:block",
|
|
34
34
|
previewLock: "ms-auto size-3.5 shrink-0",
|
|
@@ -116,10 +116,12 @@ onMounted(revealActiveItem);
|
|
|
116
116
|
watch(() => route.path, revealActiveItem, { flush: "post" });
|
|
117
117
|
|
|
118
118
|
// The page's badge, counted by the server when the menu loads (`navBadge`)
|
|
119
|
-
// or declared, then kept fresh by the page that shows the count
|
|
120
|
-
|
|
121
|
-
const
|
|
122
|
-
|
|
119
|
+
// or declared, then kept fresh by the page that shows the count; drawn in
|
|
120
|
+
// its tone, as a status pill is.
|
|
121
|
+
const { navBadgeOf } = useNavBadges();
|
|
122
|
+
const badgeOf = (page: SettingsNavPage) => navBadgeOf(page);
|
|
123
|
+
const badgeClass = (page: SettingsNavPage): string =>
|
|
124
|
+
navBadgeClass(badgeOf(page)?.tone);
|
|
123
125
|
|
|
124
126
|
// "Preview as role": a settings page the role could not open stays listed,
|
|
125
127
|
// locked, so the preview shows what the role loses; one it opens without all
|
|
@@ -207,8 +209,11 @@ const previewStateLabel = (
|
|
|
207
209
|
role="img"
|
|
208
210
|
:aria-label="previewStateLabel(preview.entryState(page.fullId))"
|
|
209
211
|
/>
|
|
210
|
-
<span
|
|
211
|
-
|
|
212
|
+
<span
|
|
213
|
+
v-else-if="badgeOf(page)"
|
|
214
|
+
:class="ui.trailBadge({ class: badgeClass(page) })"
|
|
215
|
+
>
|
|
216
|
+
{{ badgeOf(page)?.label }}
|
|
212
217
|
</span>
|
|
213
218
|
<span
|
|
214
219
|
v-else-if="page.status && page.status !== 'neutral'"
|
package/frontend-vue/layers/dms-layout/app/build/composables/command-palette/assistantGroups.ts
ADDED
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
import type { CommandPaletteGroup, CommandPaletteItem } from "@nuxt/ui";
|
|
2
|
+
|
|
3
|
+
/** @internal */
|
|
4
|
+
export const ASSISTANT_ASK_GROUP_ID = "dms-assistant-ask";
|
|
5
|
+
/** @internal */
|
|
6
|
+
export const ASSISTANT_PROMPT_GROUP_ID = "dms-assistant-prompt";
|
|
7
|
+
/** @internal */
|
|
8
|
+
export const ASSISTANT_SUGGESTIONS_GROUP_ID = "dms-assistant-suggestions";
|
|
9
|
+
/** @internal The hint shown on the item that Tab also reaches. */
|
|
10
|
+
export const ASSISTANT_MODE_KEY = "Tab";
|
|
11
|
+
|
|
12
|
+
// The assistant's items take the violet accent instead of the primary one, on
|
|
13
|
+
// the row and on its icon well.
|
|
14
|
+
const ASSISTANT_ITEM_CLASS = [
|
|
15
|
+
"data-highlighted:before:bg-(--dms-assistant-tint)",
|
|
16
|
+
"[&_[data-slot=itemLeadingIcon]]:border-(--dms-assistant-line)",
|
|
17
|
+
"[&_[data-slot=itemLeadingIcon]]:bg-(--dms-assistant-tint)",
|
|
18
|
+
"[&_[data-slot=itemLeadingIcon]]:text-secondary",
|
|
19
|
+
].join(" ");
|
|
20
|
+
|
|
21
|
+
/** @internal A suggestion with its label and prompt resolved for display. */
|
|
22
|
+
export interface ResolvedAssistantSuggestion {
|
|
23
|
+
label: string;
|
|
24
|
+
prompt: string;
|
|
25
|
+
icon: string;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/** @internal What the search-mode "Ask the assistant" group needs. */
|
|
29
|
+
export interface AssistantAskGroupOptions {
|
|
30
|
+
/** Group header: the assistant's resolved label. */
|
|
31
|
+
label: string;
|
|
32
|
+
icon: string;
|
|
33
|
+
askLabel: (query: string) => string;
|
|
34
|
+
onAsk: (query: string) => void;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/** @internal What the assistant-mode groups need. */
|
|
38
|
+
export interface AssistantModeGroupsOptions {
|
|
39
|
+
icon: string;
|
|
40
|
+
promptLabel: string;
|
|
41
|
+
suggestionsLabel: string;
|
|
42
|
+
sendLabel: (prompt: string) => string;
|
|
43
|
+
suggestions: ResolvedAssistantSuggestion[];
|
|
44
|
+
onSubmit: (prompt: string) => void;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function assistantItem(
|
|
48
|
+
label: string,
|
|
49
|
+
icon: string,
|
|
50
|
+
onChoose: () => void,
|
|
51
|
+
): CommandPaletteItem {
|
|
52
|
+
return {
|
|
53
|
+
label,
|
|
54
|
+
icon,
|
|
55
|
+
class: ASSISTANT_ITEM_CLASS,
|
|
56
|
+
// Cancelling the selection keeps the palette open: `UDashboardSearch`
|
|
57
|
+
// closes on every selection that reaches its model.
|
|
58
|
+
onSelect: (event: Event) => {
|
|
59
|
+
event.preventDefault();
|
|
60
|
+
onChoose();
|
|
61
|
+
},
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Appends the "Ask the assistant “query”" group after the search groups once
|
|
67
|
+
* the query is non-empty. The group ignores the palette's filter, so the item
|
|
68
|
+
* stays listed whatever matched, and is the only, highlighted item when
|
|
69
|
+
* nothing did: Enter then asks.
|
|
70
|
+
*
|
|
71
|
+
* @internal
|
|
72
|
+
*/
|
|
73
|
+
export function appendAssistantAskGroup(
|
|
74
|
+
groups: CommandPaletteGroup[],
|
|
75
|
+
query: string,
|
|
76
|
+
options: AssistantAskGroupOptions,
|
|
77
|
+
): CommandPaletteGroup[] {
|
|
78
|
+
if (!query) return groups;
|
|
79
|
+
|
|
80
|
+
const item = assistantItem(options.askLabel(query), options.icon, () =>
|
|
81
|
+
options.onAsk(query),
|
|
82
|
+
);
|
|
83
|
+
const askGroup: CommandPaletteGroup = {
|
|
84
|
+
id: ASSISTANT_ASK_GROUP_ID,
|
|
85
|
+
label: options.label,
|
|
86
|
+
ignoreFilter: true,
|
|
87
|
+
items: [{ ...item, kbds: [ASSISTANT_MODE_KEY] }],
|
|
88
|
+
};
|
|
89
|
+
|
|
90
|
+
return [...groups, askGroup];
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
function promptGroup(
|
|
94
|
+
prompt: string,
|
|
95
|
+
options: AssistantModeGroupsOptions,
|
|
96
|
+
): CommandPaletteGroup[] {
|
|
97
|
+
if (!prompt) return [];
|
|
98
|
+
|
|
99
|
+
const item = assistantItem(options.sendLabel(prompt), options.icon, () =>
|
|
100
|
+
options.onSubmit(prompt),
|
|
101
|
+
);
|
|
102
|
+
return [
|
|
103
|
+
{
|
|
104
|
+
id: ASSISTANT_PROMPT_GROUP_ID,
|
|
105
|
+
label: options.promptLabel,
|
|
106
|
+
ignoreFilter: true,
|
|
107
|
+
items: [item],
|
|
108
|
+
},
|
|
109
|
+
];
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
function suggestionsGroup(
|
|
113
|
+
options: AssistantModeGroupsOptions,
|
|
114
|
+
): CommandPaletteGroup[] {
|
|
115
|
+
if (!options.suggestions.length) return [];
|
|
116
|
+
|
|
117
|
+
return [
|
|
118
|
+
{
|
|
119
|
+
id: ASSISTANT_SUGGESTIONS_GROUP_ID,
|
|
120
|
+
label: options.suggestionsLabel,
|
|
121
|
+
ignoreFilter: true,
|
|
122
|
+
items: options.suggestions.map((suggestion) =>
|
|
123
|
+
assistantItem(suggestion.label, suggestion.icon, () =>
|
|
124
|
+
options.onSubmit(suggestion.prompt),
|
|
125
|
+
),
|
|
126
|
+
),
|
|
127
|
+
},
|
|
128
|
+
];
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* The groups of assistant mode: the typed prompt first, so Enter on the
|
|
133
|
+
* highlighted first item sends it, then the suggestions, which stay listed
|
|
134
|
+
* while the user types and are reached with the arrow keys.
|
|
135
|
+
*
|
|
136
|
+
* @internal
|
|
137
|
+
*/
|
|
138
|
+
export function buildAssistantModeGroups(
|
|
139
|
+
prompt: string,
|
|
140
|
+
options: AssistantModeGroupsOptions,
|
|
141
|
+
): CommandPaletteGroup[] {
|
|
142
|
+
return [...promptGroup(prompt, options), ...suggestionsGroup(options)];
|
|
143
|
+
}
|