@workos-inc/widgets 1.0.0 → 1.1.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/README.md +68 -1
- package/dist/cjs/card-list.d.ts +6 -0
- package/dist/cjs/card-list.d.ts.map +1 -0
- package/dist/cjs/card-list.js +13 -0
- package/dist/cjs/card-list.js.map +1 -0
- package/dist/cjs/index.d.ts +3 -0
- package/dist/cjs/index.d.ts.map +1 -1
- package/dist/cjs/index.js +7 -1
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/lib/add-mfa-dialog.d.ts +9 -0
- package/dist/cjs/lib/add-mfa-dialog.d.ts.map +1 -0
- package/dist/cjs/lib/add-mfa-dialog.js +135 -0
- package/dist/cjs/lib/add-mfa-dialog.js.map +1 -0
- package/dist/cjs/lib/api/user.d.ts +13 -57
- package/dist/cjs/lib/api/user.d.ts.map +1 -1
- package/dist/cjs/lib/api/user.js +44 -314
- package/dist/cjs/lib/api/user.js.map +1 -1
- package/dist/cjs/lib/change-password-dialog.d.ts +8 -0
- package/dist/cjs/lib/change-password-dialog.d.ts.map +1 -0
- package/dist/cjs/lib/change-password-dialog.js +97 -0
- package/dist/cjs/lib/change-password-dialog.js.map +1 -0
- package/dist/cjs/lib/copy-button.d.ts +8 -0
- package/dist/cjs/lib/copy-button.d.ts.map +1 -0
- package/dist/cjs/lib/copy-button.js +63 -0
- package/dist/cjs/lib/copy-button.js.map +1 -0
- package/dist/cjs/lib/delete-user-dialog.d.ts +2 -2
- package/dist/cjs/lib/delete-user-dialog.d.ts.map +1 -1
- package/dist/cjs/lib/delete-user-dialog.js +1 -1
- package/dist/cjs/lib/delete-user-dialog.js.map +1 -1
- package/dist/cjs/lib/edit-user-profile-dialog.d.ts +10 -0
- package/dist/cjs/lib/edit-user-profile-dialog.d.ts.map +1 -0
- package/dist/cjs/lib/edit-user-profile-dialog.js +85 -0
- package/dist/cjs/lib/edit-user-profile-dialog.js.map +1 -0
- package/dist/cjs/lib/edit-user-role-dialog.d.ts +12 -0
- package/dist/cjs/lib/edit-user-role-dialog.d.ts.map +1 -0
- package/dist/cjs/lib/{edit-user-details-dialog.js → edit-user-role-dialog.js} +11 -7
- package/dist/cjs/lib/edit-user-role-dialog.js.map +1 -0
- package/dist/cjs/lib/elements.d.ts +1 -0
- package/dist/cjs/lib/elements.d.ts.map +1 -1
- package/dist/cjs/lib/elements.js +10 -4
- package/dist/cjs/lib/elements.js.map +1 -1
- package/dist/cjs/lib/elevated-access.d.ts +8 -0
- package/dist/cjs/lib/elevated-access.d.ts.map +1 -0
- package/dist/cjs/lib/elevated-access.js +130 -0
- package/dist/cjs/lib/elevated-access.js.map +1 -0
- package/dist/cjs/lib/generic-error.d.ts +4 -0
- package/dist/cjs/lib/generic-error.d.ts.map +1 -0
- package/dist/cjs/lib/generic-error.js +57 -0
- package/dist/cjs/lib/generic-error.js.map +1 -0
- package/dist/cjs/lib/icon-panel.d.ts +3 -0
- package/dist/cjs/lib/icon-panel.d.ts.map +1 -0
- package/dist/cjs/lib/icon-panel.js +16 -0
- package/dist/cjs/lib/icon-panel.js.map +1 -0
- package/dist/cjs/lib/icons.d.ts +3 -0
- package/dist/cjs/lib/icons.d.ts.map +1 -0
- package/dist/cjs/lib/icons.js +8 -0
- package/dist/cjs/lib/icons.js.map +1 -0
- package/dist/cjs/lib/invite-user-dialog.d.ts.map +1 -1
- package/dist/cjs/lib/invite-user-dialog.js +7 -5
- package/dist/cjs/lib/invite-user-dialog.js.map +1 -1
- package/dist/cjs/lib/logout-all-sessions-dialog.d.ts +9 -0
- package/dist/cjs/lib/logout-all-sessions-dialog.d.ts.map +1 -0
- package/dist/cjs/lib/logout-all-sessions-dialog.js +52 -0
- package/dist/cjs/lib/logout-all-sessions-dialog.js.map +1 -0
- package/dist/cjs/lib/logout-dialog.d.ts +10 -0
- package/dist/cjs/lib/logout-dialog.d.ts.map +1 -0
- package/dist/cjs/lib/logout-dialog.js +58 -0
- package/dist/cjs/lib/logout-dialog.js.map +1 -0
- package/dist/cjs/lib/marker.d.ts +14 -0
- package/dist/cjs/lib/marker.d.ts.map +1 -0
- package/dist/cjs/lib/marker.js +38 -0
- package/dist/cjs/lib/marker.js.map +1 -0
- package/dist/cjs/lib/oauth-icons.d.ts +4 -0
- package/dist/cjs/lib/oauth-icons.d.ts.map +1 -0
- package/dist/cjs/lib/oauth-icons.js +67 -0
- package/dist/cjs/lib/oauth-icons.js.map +1 -0
- package/dist/cjs/lib/organization-switcher.d.ts +24 -0
- package/dist/cjs/lib/organization-switcher.d.ts.map +1 -0
- package/dist/cjs/lib/organization-switcher.js +35 -0
- package/dist/cjs/lib/organization-switcher.js.map +1 -0
- package/dist/cjs/lib/otp-input.d.ts +20 -0
- package/dist/cjs/lib/otp-input.d.ts.map +1 -0
- package/dist/cjs/lib/otp-input.js +174 -0
- package/dist/cjs/lib/otp-input.js.map +1 -0
- package/dist/cjs/lib/resend-invite-dialog.d.ts +2 -2
- package/dist/cjs/lib/resend-invite-dialog.d.ts.map +1 -1
- package/dist/cjs/lib/resend-invite-dialog.js +1 -1
- package/dist/cjs/lib/resend-invite-dialog.js.map +1 -1
- package/dist/cjs/lib/reset-mfa-dialog.d.ts +9 -0
- package/dist/cjs/lib/reset-mfa-dialog.d.ts.map +1 -0
- package/dist/cjs/lib/reset-mfa-dialog.js +60 -0
- package/dist/cjs/lib/reset-mfa-dialog.js.map +1 -0
- package/dist/cjs/lib/revoke-invite-dialog.d.ts +2 -2
- package/dist/cjs/lib/revoke-invite-dialog.d.ts.map +1 -1
- package/dist/cjs/lib/revoke-invite-dialog.js +1 -1
- package/dist/cjs/lib/revoke-invite-dialog.js.map +1 -1
- package/dist/cjs/lib/save-button.d.ts +11 -0
- package/dist/cjs/lib/save-button.d.ts.map +1 -0
- package/dist/cjs/lib/save-button.js +47 -0
- package/dist/cjs/lib/save-button.js.map +1 -0
- package/dist/cjs/lib/set-password-dialog.d.ts +8 -0
- package/dist/cjs/lib/set-password-dialog.d.ts.map +1 -0
- package/dist/cjs/lib/set-password-dialog.js +80 -0
- package/dist/cjs/lib/set-password-dialog.js.map +1 -0
- package/dist/cjs/lib/use-dialog-close.d.ts +2 -0
- package/dist/cjs/lib/use-dialog-close.d.ts.map +1 -0
- package/dist/cjs/lib/use-dialog-close.js +43 -0
- package/dist/cjs/lib/use-dialog-close.js.map +1 -0
- package/dist/cjs/lib/use-security-settings.d.ts +11 -0
- package/dist/cjs/lib/use-security-settings.d.ts.map +1 -0
- package/dist/cjs/lib/use-security-settings.js +39 -0
- package/dist/cjs/lib/use-security-settings.js.map +1 -0
- package/dist/cjs/lib/user-actions-dropdown.d.ts +2 -2
- package/dist/cjs/lib/user-actions-dropdown.d.ts.map +1 -1
- package/dist/cjs/lib/user-actions-dropdown.js +8 -4
- package/dist/cjs/lib/user-actions-dropdown.js.map +1 -1
- package/dist/cjs/lib/user-profile.d.ts +11 -0
- package/dist/cjs/lib/user-profile.d.ts.map +1 -0
- package/dist/cjs/lib/user-profile.js +36 -0
- package/dist/cjs/lib/user-profile.js.map +1 -0
- package/dist/cjs/lib/user-security.d.ts +11 -0
- package/dist/cjs/lib/user-security.d.ts.map +1 -0
- package/dist/cjs/lib/user-security.js +64 -0
- package/dist/cjs/lib/user-security.js.map +1 -0
- package/dist/cjs/lib/user-sessions.d.ts +12 -0
- package/dist/cjs/lib/user-sessions.d.ts.map +1 -0
- package/dist/cjs/lib/user-sessions.js +72 -0
- package/dist/cjs/lib/user-sessions.js.map +1 -0
- package/dist/cjs/lib/users-filter.d.ts +2 -2
- package/dist/cjs/lib/users-filter.d.ts.map +1 -1
- package/dist/cjs/lib/users-filter.js.map +1 -1
- package/dist/cjs/lib/users-management-context.d.ts +0 -9
- package/dist/cjs/lib/users-management-context.d.ts.map +1 -1
- package/dist/cjs/lib/users-management-context.js +13 -26
- package/dist/cjs/lib/users-management-context.js.map +1 -1
- package/dist/cjs/lib/users-management-state.d.ts +3 -3
- package/dist/cjs/lib/users-management-state.d.ts.map +1 -1
- package/dist/cjs/lib/users-management-state.js.map +1 -1
- package/dist/cjs/lib/users-management.d.ts +3 -4
- package/dist/cjs/lib/users-management.d.ts.map +1 -1
- package/dist/cjs/lib/users-management.js +8 -26
- package/dist/cjs/lib/users-management.js.map +1 -1
- package/dist/cjs/lib/utils.d.ts +10 -2
- package/dist/cjs/lib/utils.d.ts.map +1 -1
- package/dist/cjs/lib/utils.js +18 -0
- package/dist/cjs/lib/utils.js.map +1 -1
- package/dist/cjs/organization-switcher.client.d.ts +8 -0
- package/dist/cjs/organization-switcher.client.d.ts.map +1 -0
- package/dist/cjs/organization-switcher.client.js +37 -0
- package/dist/cjs/organization-switcher.client.js.map +1 -0
- package/dist/cjs/user-profile.client.d.ts +7 -0
- package/dist/cjs/user-profile.client.d.ts.map +1 -0
- package/dist/cjs/user-profile.client.js +31 -0
- package/dist/cjs/user-profile.client.js.map +1 -0
- package/dist/cjs/user-security.client.d.ts +7 -0
- package/dist/cjs/user-security.client.d.ts.map +1 -0
- package/dist/cjs/user-security.client.js +27 -0
- package/dist/cjs/user-security.client.js.map +1 -0
- package/dist/cjs/user-sessions.client.d.ts +12 -0
- package/dist/cjs/user-sessions.client.d.ts.map +1 -0
- package/dist/cjs/user-sessions.client.js +48 -0
- package/dist/cjs/user-sessions.client.js.map +1 -0
- package/dist/cjs/users-management.client.d.ts +2 -1
- package/dist/cjs/users-management.client.d.ts.map +1 -1
- package/dist/cjs/users-management.client.js +12 -43
- package/dist/cjs/users-management.client.js.map +1 -1
- package/dist/esm/card-list.d.ts +6 -0
- package/dist/esm/card-list.d.ts.map +1 -0
- package/dist/esm/card-list.js +9 -0
- package/dist/esm/card-list.js.map +1 -0
- package/dist/esm/index.d.ts +3 -0
- package/dist/esm/index.d.ts.map +1 -1
- package/dist/esm/index.js +3 -0
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/lib/add-mfa-dialog.d.ts +9 -0
- package/dist/esm/lib/add-mfa-dialog.d.ts.map +1 -0
- package/dist/esm/lib/add-mfa-dialog.js +109 -0
- package/dist/esm/lib/add-mfa-dialog.js.map +1 -0
- package/dist/esm/lib/api/user.d.ts +13 -57
- package/dist/esm/lib/api/user.d.ts.map +1 -1
- package/dist/esm/lib/api/user.js +44 -313
- package/dist/esm/lib/api/user.js.map +1 -1
- package/dist/esm/lib/change-password-dialog.d.ts +8 -0
- package/dist/esm/lib/change-password-dialog.d.ts.map +1 -0
- package/dist/esm/lib/change-password-dialog.js +71 -0
- package/dist/esm/lib/change-password-dialog.js.map +1 -0
- package/dist/esm/lib/copy-button.d.ts +8 -0
- package/dist/esm/lib/copy-button.d.ts.map +1 -0
- package/dist/esm/lib/copy-button.js +37 -0
- package/dist/esm/lib/copy-button.js.map +1 -0
- package/dist/esm/lib/delete-user-dialog.d.ts +2 -2
- package/dist/esm/lib/delete-user-dialog.d.ts.map +1 -1
- package/dist/esm/lib/delete-user-dialog.js +1 -1
- package/dist/esm/lib/delete-user-dialog.js.map +1 -1
- package/dist/esm/lib/edit-user-profile-dialog.d.ts +10 -0
- package/dist/esm/lib/edit-user-profile-dialog.d.ts.map +1 -0
- package/dist/esm/lib/edit-user-profile-dialog.js +59 -0
- package/dist/esm/lib/edit-user-profile-dialog.js.map +1 -0
- package/dist/esm/lib/edit-user-role-dialog.d.ts +12 -0
- package/dist/esm/lib/edit-user-role-dialog.d.ts.map +1 -0
- package/dist/esm/lib/{edit-user-details-dialog.js → edit-user-role-dialog.js} +10 -6
- package/dist/esm/lib/edit-user-role-dialog.js.map +1 -0
- package/dist/esm/lib/elements.d.ts +1 -0
- package/dist/esm/lib/elements.d.ts.map +1 -1
- package/dist/esm/lib/elements.js +9 -3
- package/dist/esm/lib/elements.js.map +1 -1
- package/dist/esm/lib/elevated-access.d.ts +8 -0
- package/dist/esm/lib/elevated-access.d.ts.map +1 -0
- package/dist/esm/lib/elevated-access.js +104 -0
- package/dist/esm/lib/elevated-access.js.map +1 -0
- package/dist/esm/lib/generic-error.d.ts +4 -0
- package/dist/esm/lib/generic-error.d.ts.map +1 -0
- package/dist/esm/lib/generic-error.js +31 -0
- package/dist/esm/lib/generic-error.js.map +1 -0
- package/dist/esm/lib/icon-panel.d.ts +3 -0
- package/dist/esm/lib/icon-panel.d.ts.map +1 -0
- package/dist/esm/lib/icon-panel.js +13 -0
- package/dist/esm/lib/icon-panel.js.map +1 -0
- package/dist/esm/lib/icons.d.ts +3 -0
- package/dist/esm/lib/icons.d.ts.map +1 -0
- package/dist/esm/lib/icons.js +5 -0
- package/dist/esm/lib/icons.js.map +1 -0
- package/dist/esm/lib/invite-user-dialog.d.ts.map +1 -1
- package/dist/esm/lib/invite-user-dialog.js +7 -5
- package/dist/esm/lib/invite-user-dialog.js.map +1 -1
- package/dist/esm/lib/logout-all-sessions-dialog.d.ts +9 -0
- package/dist/esm/lib/logout-all-sessions-dialog.d.ts.map +1 -0
- package/dist/esm/lib/logout-all-sessions-dialog.js +26 -0
- package/dist/esm/lib/logout-all-sessions-dialog.js.map +1 -0
- package/dist/esm/lib/logout-dialog.d.ts +10 -0
- package/dist/esm/lib/logout-dialog.d.ts.map +1 -0
- package/dist/esm/lib/logout-dialog.js +32 -0
- package/dist/esm/lib/logout-dialog.js.map +1 -0
- package/dist/esm/lib/marker.d.ts +14 -0
- package/dist/esm/lib/marker.d.ts.map +1 -0
- package/dist/esm/lib/marker.js +9 -0
- package/dist/esm/lib/marker.js.map +1 -0
- package/dist/esm/lib/oauth-icons.d.ts +4 -0
- package/dist/esm/lib/oauth-icons.d.ts.map +1 -0
- package/dist/esm/lib/oauth-icons.js +39 -0
- package/dist/esm/lib/oauth-icons.js.map +1 -0
- package/dist/esm/lib/organization-switcher.d.ts +24 -0
- package/dist/esm/lib/organization-switcher.d.ts.map +1 -0
- package/dist/esm/lib/organization-switcher.js +29 -0
- package/dist/esm/lib/organization-switcher.js.map +1 -0
- package/dist/esm/lib/otp-input.d.ts +20 -0
- package/dist/esm/lib/otp-input.d.ts.map +1 -0
- package/dist/esm/lib/otp-input.js +148 -0
- package/dist/esm/lib/otp-input.js.map +1 -0
- package/dist/esm/lib/resend-invite-dialog.d.ts +2 -2
- package/dist/esm/lib/resend-invite-dialog.d.ts.map +1 -1
- package/dist/esm/lib/resend-invite-dialog.js +1 -1
- package/dist/esm/lib/resend-invite-dialog.js.map +1 -1
- package/dist/esm/lib/reset-mfa-dialog.d.ts +9 -0
- package/dist/esm/lib/reset-mfa-dialog.d.ts.map +1 -0
- package/dist/esm/lib/reset-mfa-dialog.js +34 -0
- package/dist/esm/lib/reset-mfa-dialog.js.map +1 -0
- package/dist/esm/lib/revoke-invite-dialog.d.ts +2 -2
- package/dist/esm/lib/revoke-invite-dialog.d.ts.map +1 -1
- package/dist/esm/lib/revoke-invite-dialog.js +1 -1
- package/dist/esm/lib/revoke-invite-dialog.js.map +1 -1
- package/dist/esm/lib/save-button.d.ts +11 -0
- package/dist/esm/lib/save-button.d.ts.map +1 -0
- package/dist/esm/lib/save-button.js +44 -0
- package/dist/esm/lib/save-button.js.map +1 -0
- package/dist/esm/lib/set-password-dialog.d.ts +8 -0
- package/dist/esm/lib/set-password-dialog.d.ts.map +1 -0
- package/dist/esm/lib/set-password-dialog.js +54 -0
- package/dist/esm/lib/set-password-dialog.js.map +1 -0
- package/dist/esm/lib/use-dialog-close.d.ts +2 -0
- package/dist/esm/lib/use-dialog-close.d.ts.map +1 -0
- package/dist/esm/lib/use-dialog-close.js +17 -0
- package/dist/esm/lib/use-dialog-close.js.map +1 -0
- package/dist/esm/lib/use-security-settings.d.ts +11 -0
- package/dist/esm/lib/use-security-settings.d.ts.map +1 -0
- package/dist/esm/lib/use-security-settings.js +36 -0
- package/dist/esm/lib/use-security-settings.js.map +1 -0
- package/dist/esm/lib/user-actions-dropdown.d.ts +2 -2
- package/dist/esm/lib/user-actions-dropdown.d.ts.map +1 -1
- package/dist/esm/lib/user-actions-dropdown.js +8 -4
- package/dist/esm/lib/user-actions-dropdown.js.map +1 -1
- package/dist/esm/lib/user-profile.d.ts +11 -0
- package/dist/esm/lib/user-profile.d.ts.map +1 -0
- package/dist/esm/lib/user-profile.js +27 -0
- package/dist/esm/lib/user-profile.js.map +1 -0
- package/dist/esm/lib/user-security.d.ts +11 -0
- package/dist/esm/lib/user-security.d.ts.map +1 -0
- package/dist/esm/lib/user-security.js +32 -0
- package/dist/esm/lib/user-security.js.map +1 -0
- package/dist/esm/lib/user-sessions.d.ts +12 -0
- package/dist/esm/lib/user-sessions.d.ts.map +1 -0
- package/dist/esm/lib/user-sessions.js +40 -0
- package/dist/esm/lib/user-sessions.js.map +1 -0
- package/dist/esm/lib/users-filter.d.ts +2 -2
- package/dist/esm/lib/users-filter.d.ts.map +1 -1
- package/dist/esm/lib/users-filter.js.map +1 -1
- package/dist/esm/lib/users-management-context.d.ts +0 -9
- package/dist/esm/lib/users-management-context.d.ts.map +1 -1
- package/dist/esm/lib/users-management-context.js +13 -25
- package/dist/esm/lib/users-management-context.js.map +1 -1
- package/dist/esm/lib/users-management-state.d.ts +3 -3
- package/dist/esm/lib/users-management-state.d.ts.map +1 -1
- package/dist/esm/lib/users-management-state.js.map +1 -1
- package/dist/esm/lib/users-management.d.ts +3 -4
- package/dist/esm/lib/users-management.d.ts.map +1 -1
- package/dist/esm/lib/users-management.js +9 -27
- package/dist/esm/lib/users-management.js.map +1 -1
- package/dist/esm/lib/users-search.d.ts +1 -1
- package/dist/esm/lib/users-search.d.ts.map +1 -1
- package/dist/esm/lib/utils.d.ts +10 -2
- package/dist/esm/lib/utils.d.ts.map +1 -1
- package/dist/esm/lib/utils.js +16 -0
- package/dist/esm/lib/utils.js.map +1 -1
- package/dist/esm/organization-switcher.client.d.ts +8 -0
- package/dist/esm/organization-switcher.client.d.ts.map +1 -0
- package/dist/esm/organization-switcher.client.js +33 -0
- package/dist/esm/organization-switcher.client.js.map +1 -0
- package/dist/esm/user-profile.client.d.ts +7 -0
- package/dist/esm/user-profile.client.d.ts.map +1 -0
- package/dist/esm/user-profile.client.js +27 -0
- package/dist/esm/user-profile.client.js.map +1 -0
- package/dist/esm/user-security.client.d.ts +7 -0
- package/dist/esm/user-security.client.d.ts.map +1 -0
- package/dist/esm/user-security.client.js +23 -0
- package/dist/esm/user-security.client.js.map +1 -0
- package/dist/esm/user-sessions.client.d.ts +12 -0
- package/dist/esm/user-sessions.client.d.ts.map +1 -0
- package/dist/esm/user-sessions.client.js +44 -0
- package/dist/esm/user-sessions.client.js.map +1 -0
- package/dist/esm/users-management.client.d.ts +2 -1
- package/dist/esm/users-management.client.d.ts.map +1 -1
- package/dist/esm/users-management.client.js +12 -20
- package/dist/esm/users-management.client.js.map +1 -1
- package/dist/tsconfig.cjs.tsbuildinfo +1 -1
- package/dist/tsconfig.esm.tsbuildinfo +1 -1
- package/package.json +10 -4
- package/src/card-list.tsx +26 -0
- package/src/index.ts +3 -0
- package/src/lib/add-mfa-dialog.tsx +379 -0
- package/src/lib/api/user.ts +54 -458
- package/src/lib/card-list.css +3 -0
- package/src/lib/change-password-dialog.tsx +290 -0
- package/src/lib/copy-button.tsx +53 -0
- package/src/lib/delete-user-dialog.tsx +9 -6
- package/src/lib/edit-user-profile-dialog.tsx +181 -0
- package/src/lib/{edit-user-details-dialog.tsx → edit-user-role-dialog.tsx} +12 -9
- package/src/lib/elements.tsx +34 -1
- package/src/lib/elevated-access.tsx +261 -0
- package/src/lib/generic-error.tsx +70 -0
- package/src/lib/icon-panel.tsx +26 -0
- package/src/lib/icons.tsx +21 -0
- package/src/lib/invite-user-dialog.tsx +15 -10
- package/src/lib/logout-all-sessions-dialog.tsx +82 -0
- package/src/lib/logout-dialog.tsx +89 -0
- package/src/lib/marker.css +81 -0
- package/src/lib/marker.tsx +39 -0
- package/src/lib/oauth-icons.tsx +138 -0
- package/src/lib/organization-switcher.tsx +160 -0
- package/src/lib/otp-input.tsx +276 -0
- package/src/lib/resend-invite-dialog.tsx +9 -6
- package/src/lib/reset-mfa-dialog.tsx +104 -0
- package/src/lib/revoke-invite-dialog.tsx +9 -6
- package/src/lib/save-button.css +60 -0
- package/src/lib/save-button.tsx +113 -0
- package/src/lib/set-password-dialog.tsx +204 -0
- package/src/lib/use-dialog-close.tsx +19 -0
- package/src/lib/use-security-settings.tsx +49 -0
- package/src/lib/user-actions-dropdown.tsx +10 -6
- package/src/lib/user-profile.tsx +247 -0
- package/src/lib/user-security.tsx +187 -0
- package/src/lib/user-sessions.tsx +204 -0
- package/src/lib/users-filter.tsx +2 -2
- package/src/lib/users-management-context.tsx +21 -36
- package/src/lib/users-management-state.ts +3 -3
- package/src/lib/users-management.tsx +21 -77
- package/src/lib/utils.ts +30 -2
- package/src/organization-switcher.client.tsx +77 -0
- package/src/styles.css +44 -0
- package/src/user-profile.client.tsx +51 -0
- package/src/user-security.client.tsx +55 -0
- package/src/user-sessions.client.tsx +96 -0
- package/src/users-management.client.tsx +28 -39
- package/dist/cjs/lib/api/role.d.ts +0 -9
- package/dist/cjs/lib/api/role.d.ts.map +0 -1
- package/dist/cjs/lib/api/role.js +0 -115
- package/dist/cjs/lib/api/role.js.map +0 -1
- package/dist/cjs/lib/edit-user-details-dialog.d.ts +0 -12
- package/dist/cjs/lib/edit-user-details-dialog.d.ts.map +0 -1
- package/dist/cjs/lib/edit-user-details-dialog.js.map +0 -1
- package/dist/esm/lib/api/role.d.ts +0 -9
- package/dist/esm/lib/api/role.d.ts.map +0 -1
- package/dist/esm/lib/api/role.js +0 -110
- package/dist/esm/lib/api/role.js.map +0 -1
- package/dist/esm/lib/edit-user-details-dialog.d.ts +0 -12
- package/dist/esm/lib/edit-user-details-dialog.d.ts.map +0 -1
- package/dist/esm/lib/edit-user-details-dialog.js.map +0 -1
- package/src/lib/api/role.ts +0 -147
|
@@ -0,0 +1,261 @@
|
|
|
1
|
+
import * as Form from "@radix-ui/react-form";
|
|
2
|
+
import { AlertDialog, Callout, Dialog, Flex, Text } from "@radix-ui/themes";
|
|
3
|
+
import {
|
|
4
|
+
useElevatedAccessToken,
|
|
5
|
+
useMe,
|
|
6
|
+
useSendVerification,
|
|
7
|
+
useVerify,
|
|
8
|
+
} from "@repo/api";
|
|
9
|
+
import { PropsWithChildren, useEffect, useRef, useState } from "react";
|
|
10
|
+
import { PrimaryButton, SecondaryButton } from "./elements";
|
|
11
|
+
import * as Otp from "./otp-input";
|
|
12
|
+
|
|
13
|
+
interface ElevatedAccessProps extends PropsWithChildren {
|
|
14
|
+
onVerified?: () => Promise<unknown>;
|
|
15
|
+
type?: "dialog" | "alert";
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export function ElevatedAccess({
|
|
19
|
+
type = "dialog",
|
|
20
|
+
children,
|
|
21
|
+
onVerified,
|
|
22
|
+
}: ElevatedAccessProps) {
|
|
23
|
+
const { elevatedAccess } = useElevatedAccessToken();
|
|
24
|
+
const [authenticationChallengeId, setAuthenticationChallengeId] =
|
|
25
|
+
useState<string>();
|
|
26
|
+
|
|
27
|
+
const prevAccessToken = useRef(elevatedAccess);
|
|
28
|
+
|
|
29
|
+
useEffect(() => {
|
|
30
|
+
prevAccessToken.current = elevatedAccess;
|
|
31
|
+
}, [elevatedAccess]);
|
|
32
|
+
|
|
33
|
+
if (elevatedAccess) {
|
|
34
|
+
return <>{children}</>;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
if (!authenticationChallengeId) {
|
|
38
|
+
const hasTokenExpired = !!prevAccessToken.current;
|
|
39
|
+
|
|
40
|
+
return (
|
|
41
|
+
<SendVerificationEmailForm
|
|
42
|
+
type={type}
|
|
43
|
+
hasTokenExpired={hasTokenExpired}
|
|
44
|
+
onSuccess={(challengeId) => {
|
|
45
|
+
setAuthenticationChallengeId(challengeId);
|
|
46
|
+
}}
|
|
47
|
+
/>
|
|
48
|
+
);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
if (authenticationChallengeId) {
|
|
52
|
+
return (
|
|
53
|
+
<VerificationIdentityForm
|
|
54
|
+
type={type}
|
|
55
|
+
authenticationChallengeId={authenticationChallengeId}
|
|
56
|
+
onSuccess={() => {
|
|
57
|
+
// Reset the challenge id
|
|
58
|
+
setAuthenticationChallengeId(undefined);
|
|
59
|
+
|
|
60
|
+
return onVerified?.();
|
|
61
|
+
}}
|
|
62
|
+
/>
|
|
63
|
+
);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
return null;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
interface SendVerificationEmailFormProps {
|
|
70
|
+
onSuccess: (challengeId: string) => unknown | Promise<unknown>;
|
|
71
|
+
type: "dialog" | "alert";
|
|
72
|
+
hasTokenExpired: boolean;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
function SendVerificationEmailForm({
|
|
76
|
+
onSuccess,
|
|
77
|
+
type,
|
|
78
|
+
hasTokenExpired,
|
|
79
|
+
}: SendVerificationEmailFormProps) {
|
|
80
|
+
const { data: me } = useMe();
|
|
81
|
+
const sendVerification = useSendVerification({
|
|
82
|
+
mutation: { onSuccess: (data) => onSuccess(data.authenticationChallenge) },
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
const Title = type === "dialog" ? Dialog.Title : AlertDialog.Title;
|
|
86
|
+
const Description =
|
|
87
|
+
type === "dialog" ? Dialog.Description : AlertDialog.Description;
|
|
88
|
+
const Close = type === "dialog" ? Dialog.Close : AlertDialog.Cancel;
|
|
89
|
+
|
|
90
|
+
const handleSubmit = async (event: React.FormEvent<HTMLFormElement>) => {
|
|
91
|
+
event.preventDefault();
|
|
92
|
+
|
|
93
|
+
sendVerification.mutate();
|
|
94
|
+
};
|
|
95
|
+
|
|
96
|
+
return (
|
|
97
|
+
<form onSubmit={handleSubmit}>
|
|
98
|
+
<Title>
|
|
99
|
+
{hasTokenExpired
|
|
100
|
+
? "Your verification token has expired"
|
|
101
|
+
: "Verify your identity"}
|
|
102
|
+
</Title>
|
|
103
|
+
|
|
104
|
+
<Description color="gray" mb="5">
|
|
105
|
+
To continue, we need to confirm your identity. We'll send a temporary
|
|
106
|
+
verification code to{" "}
|
|
107
|
+
<Text weight="bold" highContrast>
|
|
108
|
+
{me?.email}
|
|
109
|
+
</Text>
|
|
110
|
+
.
|
|
111
|
+
</Description>
|
|
112
|
+
|
|
113
|
+
{sendVerification.error && (
|
|
114
|
+
<Callout.Root color="red" mt="-2" mb="0">
|
|
115
|
+
<Callout.Text>
|
|
116
|
+
{getMutationErrorMessage(sendVerification.error)}
|
|
117
|
+
</Callout.Text>
|
|
118
|
+
</Callout.Root>
|
|
119
|
+
)}
|
|
120
|
+
|
|
121
|
+
<Flex justify="end" align="center" gap="3" mt="5">
|
|
122
|
+
<Close>
|
|
123
|
+
<SecondaryButton type="button" disabled={sendVerification.isPending}>
|
|
124
|
+
Cancel
|
|
125
|
+
</SecondaryButton>
|
|
126
|
+
</Close>
|
|
127
|
+
<PrimaryButton type="submit" loading={sendVerification.isPending}>
|
|
128
|
+
Send verification code
|
|
129
|
+
</PrimaryButton>
|
|
130
|
+
</Flex>
|
|
131
|
+
</form>
|
|
132
|
+
);
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
interface VerificationIdentityFormProps {
|
|
136
|
+
onSuccess?: () => unknown | Promise<unknown>;
|
|
137
|
+
authenticationChallengeId: string;
|
|
138
|
+
type: "dialog" | "alert";
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
function VerificationIdentityForm({
|
|
142
|
+
onSuccess,
|
|
143
|
+
authenticationChallengeId,
|
|
144
|
+
type,
|
|
145
|
+
}: VerificationIdentityFormProps) {
|
|
146
|
+
const { data: me } = useMe();
|
|
147
|
+
const { setElevatedAccess } = useElevatedAccessToken();
|
|
148
|
+
const verifyIdentity = useVerify();
|
|
149
|
+
const [isSubmitting, setIsSubmitting] = useState(false);
|
|
150
|
+
|
|
151
|
+
const Title = type === "dialog" ? Dialog.Title : AlertDialog.Title;
|
|
152
|
+
const Description =
|
|
153
|
+
type === "dialog" ? Dialog.Description : AlertDialog.Description;
|
|
154
|
+
const Close = type === "dialog" ? Dialog.Close : AlertDialog.Cancel;
|
|
155
|
+
const handleSubmit = async (event: React.FormEvent<HTMLFormElement>) => {
|
|
156
|
+
event.preventDefault();
|
|
157
|
+
|
|
158
|
+
const formData = new FormData(event.currentTarget);
|
|
159
|
+
const code = formData.get("otp-code")?.toString() ?? "";
|
|
160
|
+
|
|
161
|
+
setIsSubmitting(true);
|
|
162
|
+
|
|
163
|
+
try {
|
|
164
|
+
// Mutate async so we can wait for the onSuccess callback as well
|
|
165
|
+
const newAuthState = await verifyIdentity.mutateAsync({
|
|
166
|
+
data: {
|
|
167
|
+
code,
|
|
168
|
+
authenticationChallengeId,
|
|
169
|
+
},
|
|
170
|
+
});
|
|
171
|
+
|
|
172
|
+
const in10Seconds = new Date(Date.now() + 5 * 1000);
|
|
173
|
+
|
|
174
|
+
setElevatedAccess({
|
|
175
|
+
token: newAuthState.elevatedAccessToken,
|
|
176
|
+
// expiresAt: newAuthState.expiresAt,
|
|
177
|
+
expiresAt: in10Seconds.toISOString(),
|
|
178
|
+
});
|
|
179
|
+
|
|
180
|
+
if (onSuccess) {
|
|
181
|
+
await new Promise((resolve) => setTimeout(resolve, 200));
|
|
182
|
+
await onSuccess();
|
|
183
|
+
}
|
|
184
|
+
} catch (error) {
|
|
185
|
+
console.error(error);
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
setIsSubmitting(false);
|
|
189
|
+
};
|
|
190
|
+
|
|
191
|
+
return (
|
|
192
|
+
<Form.Root onSubmit={handleSubmit}>
|
|
193
|
+
<Title>Verify your identity</Title>
|
|
194
|
+
|
|
195
|
+
<Description color="gray">
|
|
196
|
+
A verification code was sent to{" "}
|
|
197
|
+
<Text weight="bold" highContrast>
|
|
198
|
+
{me?.email}
|
|
199
|
+
</Text>
|
|
200
|
+
. Please enter it below.
|
|
201
|
+
</Description>
|
|
202
|
+
|
|
203
|
+
<Flex direction="column" gap="2" mt="5" mx="auto" width="fit-content">
|
|
204
|
+
<Otp.Root
|
|
205
|
+
autoSubmit
|
|
206
|
+
gap="2"
|
|
207
|
+
justify="center"
|
|
208
|
+
columns="repeat(6, 48px)"
|
|
209
|
+
width="fit-content"
|
|
210
|
+
rows="48px"
|
|
211
|
+
name="otp-code"
|
|
212
|
+
readOnly={isSubmitting}
|
|
213
|
+
>
|
|
214
|
+
<Otp.Input required autoFocus autoComplete="off" />
|
|
215
|
+
<Otp.Input required />
|
|
216
|
+
<Otp.Input required />
|
|
217
|
+
<Otp.Input required />
|
|
218
|
+
<Otp.Input required />
|
|
219
|
+
<Otp.Input required />
|
|
220
|
+
</Otp.Root>
|
|
221
|
+
|
|
222
|
+
{verifyIdentity.error && (
|
|
223
|
+
<Text color="red" size="2" as="p">
|
|
224
|
+
{getMutationErrorMessage(verifyIdentity.error)}
|
|
225
|
+
</Text>
|
|
226
|
+
)}
|
|
227
|
+
</Flex>
|
|
228
|
+
|
|
229
|
+
<Flex justify="end" align="center" gap="3" mt="5">
|
|
230
|
+
<Close>
|
|
231
|
+
<SecondaryButton type="button">Cancel</SecondaryButton>
|
|
232
|
+
</Close>
|
|
233
|
+
|
|
234
|
+
<PrimaryButton type="submit" loading={isSubmitting}>
|
|
235
|
+
Confirm
|
|
236
|
+
</PrimaryButton>
|
|
237
|
+
</Flex>
|
|
238
|
+
</Form.Root>
|
|
239
|
+
);
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
function getMutationErrorMessage(error: unknown) {
|
|
243
|
+
let message = typeof error === "string" ? error : "";
|
|
244
|
+
|
|
245
|
+
if (error instanceof Error) {
|
|
246
|
+
message = error.message;
|
|
247
|
+
} else if (
|
|
248
|
+
typeof error === "object" &&
|
|
249
|
+
error !== null &&
|
|
250
|
+
"message" in error &&
|
|
251
|
+
typeof error.message === "string"
|
|
252
|
+
) {
|
|
253
|
+
message = error.message;
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
if (!message || message === "Bad Request") {
|
|
257
|
+
message = "Invalid code, please try again.";
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
return message;
|
|
261
|
+
}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
import { Flex, Heading, Text } from "@radix-ui/themes";
|
|
3
|
+
import { ApiError, FetchError, NoAuthTokenError } from "./errors";
|
|
4
|
+
import { Cross2Icon } from "@radix-ui/react-icons";
|
|
5
|
+
|
|
6
|
+
export function GenericError({ error }: { error: unknown }) {
|
|
7
|
+
React.useEffect(() => {
|
|
8
|
+
console.error(error);
|
|
9
|
+
}, [error]);
|
|
10
|
+
|
|
11
|
+
const render = (heading: string, message: React.ReactNode) => (
|
|
12
|
+
<Flex p="6" justify="center" align="center" direction="column">
|
|
13
|
+
<Flex
|
|
14
|
+
align="center"
|
|
15
|
+
justify="center"
|
|
16
|
+
width="32px"
|
|
17
|
+
height="32px"
|
|
18
|
+
mb="2"
|
|
19
|
+
style={{
|
|
20
|
+
borderRadius: "9999px",
|
|
21
|
+
backgroundColor: "var(--red-a4)",
|
|
22
|
+
color: "var(--red-a11)",
|
|
23
|
+
}}
|
|
24
|
+
>
|
|
25
|
+
<Cross2Icon width="24px" height="24px" />
|
|
26
|
+
</Flex>
|
|
27
|
+
|
|
28
|
+
<Flex direction="column" gap="1" maxWidth="420px">
|
|
29
|
+
<Heading size="5" align="center" mb="1" wrap="balance" as="h3">
|
|
30
|
+
{heading}
|
|
31
|
+
</Heading>
|
|
32
|
+
|
|
33
|
+
<Text as="p" align="center" wrap="balance" color="gray">
|
|
34
|
+
{message}
|
|
35
|
+
</Text>
|
|
36
|
+
</Flex>
|
|
37
|
+
</Flex>
|
|
38
|
+
);
|
|
39
|
+
|
|
40
|
+
if (error instanceof FetchError) {
|
|
41
|
+
return render(
|
|
42
|
+
"Error fetching data",
|
|
43
|
+
"An error occurred. You may need to configure CORS in the WorkOS Dashboard. " +
|
|
44
|
+
"Contact your organization admin for support.",
|
|
45
|
+
);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
if (error instanceof NoAuthTokenError) {
|
|
49
|
+
return render(
|
|
50
|
+
"Error fetching data",
|
|
51
|
+
"Authorization error. You likely forgot to provide an authorization " +
|
|
52
|
+
"token to the Users Management Widget.",
|
|
53
|
+
);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
if (error instanceof ApiError && error.status === 404) {
|
|
57
|
+
// The widgets API treats all authorization errors as 404s. If there is a
|
|
58
|
+
// legitimate 404, it's a bug on our end but there's currently no way to
|
|
59
|
+
// distinguish between the two.
|
|
60
|
+
return render(
|
|
61
|
+
"Error fetching data",
|
|
62
|
+
"Authorization error. Contact your organization admin for support.",
|
|
63
|
+
);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
return render(
|
|
67
|
+
"Error fetching data",
|
|
68
|
+
"An unknown error occurred. If the problem continues, contact the site owner.",
|
|
69
|
+
);
|
|
70
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { Flex, FlexProps } from "@radix-ui/themes";
|
|
2
|
+
import { forwardRef } from "react";
|
|
3
|
+
|
|
4
|
+
export const IconPanel = forwardRef<HTMLDivElement, FlexProps>(
|
|
5
|
+
function IconPanel({ children, ...props }, ref) {
|
|
6
|
+
return (
|
|
7
|
+
<Flex
|
|
8
|
+
ref={ref}
|
|
9
|
+
width="32px"
|
|
10
|
+
height="32px"
|
|
11
|
+
align="center"
|
|
12
|
+
justify="center"
|
|
13
|
+
style={{
|
|
14
|
+
borderWidth: 1,
|
|
15
|
+
borderStyle: "solid",
|
|
16
|
+
borderColor: "var(--gray-4)",
|
|
17
|
+
borderRadius: "var(--radius-3)",
|
|
18
|
+
backgroundColor: "var(--gray-2)",
|
|
19
|
+
}}
|
|
20
|
+
{...props}
|
|
21
|
+
>
|
|
22
|
+
{children}
|
|
23
|
+
</Flex>
|
|
24
|
+
);
|
|
25
|
+
},
|
|
26
|
+
);
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { SVGProps } from "react";
|
|
2
|
+
|
|
3
|
+
export function PasskeyIcon(props: SVGProps<SVGSVGElement>) {
|
|
4
|
+
return (
|
|
5
|
+
<svg
|
|
6
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
7
|
+
width={16}
|
|
8
|
+
height={16}
|
|
9
|
+
viewBox="0 0 16 16"
|
|
10
|
+
fill="none"
|
|
11
|
+
{...props}
|
|
12
|
+
>
|
|
13
|
+
<path
|
|
14
|
+
fill="currentColor"
|
|
15
|
+
fillRule="evenodd"
|
|
16
|
+
d="M5.86 1.005a2.86 2.86 0 1 0 0 5.719 2.86 2.86 0 0 0 0-5.72ZM2 3.865a3.86 3.86 0 1 1 4.899 3.717c.974.166 1.699.58 2.368 1.196a.5.5 0 1 1-.678.735C7.882 8.862 7.136 8.5 5.859 8.5c-2.036 0-3.195.693-3.867 1.613-.602.824-.86 1.893-.917 2.986h8.618a.5.5 0 0 1 0 1H.563a.5.5 0 0 1-.5-.5c0-1.356.248-2.88 1.121-4.076.743-1.018 1.897-1.741 3.582-1.957A3.861 3.861 0 0 1 2 3.864Zm12.185 6.509a2.892 2.892 0 1 0-2.212-.024v4.428L13.197 16l2.036-2.037-1.271-1.27 1.271-1.272-1.046-1.047Zm-.212-3.423a.847.847 0 1 1-1.695 0 .847.847 0 0 1 1.695 0Z"
|
|
17
|
+
clipRule="evenodd"
|
|
18
|
+
/>
|
|
19
|
+
</svg>
|
|
20
|
+
);
|
|
21
|
+
}
|
|
@@ -9,8 +9,6 @@ import {
|
|
|
9
9
|
VisuallyHidden,
|
|
10
10
|
} from "@radix-ui/themes";
|
|
11
11
|
import * as React from "react";
|
|
12
|
-
import { type Role, useRoles } from "./api/role";
|
|
13
|
-
import { type InviteUserPayload, useInviteUser } from "./api/user";
|
|
14
12
|
import {
|
|
15
13
|
DialogContent,
|
|
16
14
|
PrimaryButton,
|
|
@@ -22,6 +20,8 @@ import {
|
|
|
22
20
|
} from "./elements";
|
|
23
21
|
import { Label } from "./elements";
|
|
24
22
|
import { isErrorLike } from "./utils";
|
|
23
|
+
import { useInviteUser } from "./api/user";
|
|
24
|
+
import { InviteMemberInput, MemberRole, useRoles } from "@repo/api";
|
|
25
25
|
|
|
26
26
|
/**
|
|
27
27
|
* Used to stub a fake value for the role select. It will be selected by default
|
|
@@ -41,7 +41,9 @@ export function InviteUserDialog({ children }: InviteUserDialogProps) {
|
|
|
41
41
|
const formId = toId(dialogId, "form");
|
|
42
42
|
|
|
43
43
|
const inviteUser = useInviteUser();
|
|
44
|
-
const rolesQuery = useRoles(
|
|
44
|
+
const rolesQuery = useRoles({
|
|
45
|
+
query: { initialData: [] },
|
|
46
|
+
});
|
|
45
47
|
const roles = rolesQuery.data;
|
|
46
48
|
const [selectedRole, setSelectedRole] = React.useState(
|
|
47
49
|
() => getDefaultRole(roles)?.slug || PLACEHOLDER_ROLE,
|
|
@@ -58,15 +60,18 @@ export function InviteUserDialog({ children }: InviteUserDialogProps) {
|
|
|
58
60
|
});
|
|
59
61
|
}, [roles]);
|
|
60
62
|
|
|
61
|
-
const onSubmitForm = (data:
|
|
63
|
+
const onSubmitForm = (data: InviteMemberInput) => {
|
|
62
64
|
if (inviteUser.isPending || rolesQuery.status !== "success") {
|
|
63
65
|
return;
|
|
64
66
|
}
|
|
65
|
-
inviteUser.mutate(
|
|
66
|
-
|
|
67
|
-
|
|
67
|
+
inviteUser.mutate(
|
|
68
|
+
{ data },
|
|
69
|
+
{
|
|
70
|
+
onSuccess: () => {
|
|
71
|
+
setOpen(false);
|
|
72
|
+
},
|
|
68
73
|
},
|
|
69
|
-
|
|
74
|
+
);
|
|
70
75
|
};
|
|
71
76
|
|
|
72
77
|
const formErrors = getFormErrors(inviteUser.error);
|
|
@@ -88,7 +93,7 @@ export function InviteUserDialog({ children }: InviteUserDialogProps) {
|
|
|
88
93
|
event.preventDefault();
|
|
89
94
|
onSubmitForm({
|
|
90
95
|
email: event.currentTarget.email.value,
|
|
91
|
-
|
|
96
|
+
roles: [selectedRole],
|
|
92
97
|
});
|
|
93
98
|
}}
|
|
94
99
|
>
|
|
@@ -317,6 +322,6 @@ function useFormFieldFocusOnError(dialogId: string, queryError: unknown) {
|
|
|
317
322
|
}, [dialogId, queryError]);
|
|
318
323
|
}
|
|
319
324
|
|
|
320
|
-
function getDefaultRole(roles:
|
|
325
|
+
function getDefaultRole(roles: MemberRole[]) {
|
|
321
326
|
return roles.find((role) => role.default) || roles[0];
|
|
322
327
|
}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import * as React from "react";
|
|
4
|
+
import { AlertDialog, Flex } from "@radix-ui/themes";
|
|
5
|
+
import { type ReactNode } from "react";
|
|
6
|
+
import {
|
|
7
|
+
AlertDialogContent,
|
|
8
|
+
DestructiveButton,
|
|
9
|
+
SecondaryButton,
|
|
10
|
+
} from "./elements";
|
|
11
|
+
import { getSessionsQueryKey, useRevokeAllSessions } from "@repo/api";
|
|
12
|
+
import { useQueryClient } from "@tanstack/react-query";
|
|
13
|
+
import { SaveButton } from "./save-button";
|
|
14
|
+
|
|
15
|
+
interface LogoutAllSessionsDialogProps extends AlertDialog.RootProps {
|
|
16
|
+
children?: ReactNode;
|
|
17
|
+
currentSessionId: string;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export function LogoutAllSessionsDialog({
|
|
21
|
+
open,
|
|
22
|
+
onOpenChange,
|
|
23
|
+
children,
|
|
24
|
+
currentSessionId,
|
|
25
|
+
...props
|
|
26
|
+
}: LogoutAllSessionsDialogProps) {
|
|
27
|
+
const client = useQueryClient();
|
|
28
|
+
|
|
29
|
+
const revokeAllSessions = useRevokeAllSessions();
|
|
30
|
+
|
|
31
|
+
const onSubmitForm = () => {
|
|
32
|
+
revokeAllSessions.mutate({ data: { currentSessionId } });
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
const handleDone = React.useCallback(() => {
|
|
36
|
+
onOpenChange?.(false);
|
|
37
|
+
|
|
38
|
+
client.invalidateQueries({
|
|
39
|
+
queryKey: getSessionsQueryKey(),
|
|
40
|
+
});
|
|
41
|
+
}, [client, onOpenChange]);
|
|
42
|
+
|
|
43
|
+
return (
|
|
44
|
+
<AlertDialog.Root open={open} onOpenChange={onOpenChange} {...props}>
|
|
45
|
+
<AlertDialogContent maxWidth="480px">
|
|
46
|
+
<AlertDialog.Title>Sign out of all other devices?</AlertDialog.Title>
|
|
47
|
+
<AlertDialog.Description>
|
|
48
|
+
You will be logged out of all other active sessions on other devices,
|
|
49
|
+
except this one.
|
|
50
|
+
</AlertDialog.Description>
|
|
51
|
+
|
|
52
|
+
<Flex gap="3" justify="end" mt="5" asChild>
|
|
53
|
+
<form
|
|
54
|
+
onSubmit={(event) => {
|
|
55
|
+
event.preventDefault();
|
|
56
|
+
onSubmitForm();
|
|
57
|
+
}}
|
|
58
|
+
>
|
|
59
|
+
<AlertDialog.Cancel>
|
|
60
|
+
<SecondaryButton
|
|
61
|
+
disabled={
|
|
62
|
+
revokeAllSessions.isPending || revokeAllSessions.isSuccess
|
|
63
|
+
}
|
|
64
|
+
>
|
|
65
|
+
Cancel
|
|
66
|
+
</SecondaryButton>
|
|
67
|
+
</AlertDialog.Cancel>
|
|
68
|
+
|
|
69
|
+
<SaveButton
|
|
70
|
+
asChild
|
|
71
|
+
loading={revokeAllSessions.isPending}
|
|
72
|
+
done={revokeAllSessions.isSuccess}
|
|
73
|
+
onDone={handleDone}
|
|
74
|
+
>
|
|
75
|
+
<DestructiveButton type="submit">Sign out</DestructiveButton>
|
|
76
|
+
</SaveButton>
|
|
77
|
+
</form>
|
|
78
|
+
</Flex>
|
|
79
|
+
</AlertDialogContent>
|
|
80
|
+
</AlertDialog.Root>
|
|
81
|
+
);
|
|
82
|
+
}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import * as React from "react";
|
|
4
|
+
import { AlertDialog, Flex, Strong } from "@radix-ui/themes";
|
|
5
|
+
import { type ReactNode } from "react";
|
|
6
|
+
import {
|
|
7
|
+
AlertDialogContent,
|
|
8
|
+
DestructiveButton,
|
|
9
|
+
SecondaryButton,
|
|
10
|
+
} from "./elements";
|
|
11
|
+
import {
|
|
12
|
+
ActiveSession,
|
|
13
|
+
getSessionsQueryKey,
|
|
14
|
+
useRevokeSession,
|
|
15
|
+
} from "@repo/api";
|
|
16
|
+
import { useQueryClient } from "@tanstack/react-query";
|
|
17
|
+
import { SaveButton } from "./save-button";
|
|
18
|
+
import { parseUserAgent } from "./utils";
|
|
19
|
+
|
|
20
|
+
interface LogoutDialogProps extends AlertDialog.RootProps {
|
|
21
|
+
children?: ReactNode;
|
|
22
|
+
session: ActiveSession;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export function LogoutDialog({
|
|
26
|
+
children,
|
|
27
|
+
session,
|
|
28
|
+
open,
|
|
29
|
+
onOpenChange,
|
|
30
|
+
...props
|
|
31
|
+
}: LogoutDialogProps) {
|
|
32
|
+
const client = useQueryClient();
|
|
33
|
+
const userAgent = parseUserAgent(session.userAgent);
|
|
34
|
+
const device = userAgent.pretty;
|
|
35
|
+
|
|
36
|
+
const revokeSession = useRevokeSession();
|
|
37
|
+
|
|
38
|
+
const handleDone = React.useCallback(() => {
|
|
39
|
+
onOpenChange?.(false);
|
|
40
|
+
|
|
41
|
+
client.invalidateQueries({
|
|
42
|
+
queryKey: getSessionsQueryKey(),
|
|
43
|
+
exact: false,
|
|
44
|
+
});
|
|
45
|
+
}, [onOpenChange, client]);
|
|
46
|
+
|
|
47
|
+
const onSubmitForm = () => {
|
|
48
|
+
revokeSession.mutate({
|
|
49
|
+
sessionId: session.id,
|
|
50
|
+
});
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
return (
|
|
54
|
+
<AlertDialog.Root open={open} onOpenChange={onOpenChange} {...props}>
|
|
55
|
+
<AlertDialogContent maxWidth="480px">
|
|
56
|
+
<AlertDialog.Title>Sign out of device?</AlertDialog.Title>
|
|
57
|
+
<AlertDialog.Description>
|
|
58
|
+
You will be signed out of <Strong>{device}.</Strong>
|
|
59
|
+
</AlertDialog.Description>
|
|
60
|
+
|
|
61
|
+
<Flex gap="3" justify="end" mt="5" asChild>
|
|
62
|
+
<form
|
|
63
|
+
onSubmit={(event) => {
|
|
64
|
+
event.preventDefault();
|
|
65
|
+
onSubmitForm();
|
|
66
|
+
}}
|
|
67
|
+
>
|
|
68
|
+
<AlertDialog.Cancel>
|
|
69
|
+
<SecondaryButton
|
|
70
|
+
disabled={revokeSession.isPending || revokeSession.isSuccess}
|
|
71
|
+
>
|
|
72
|
+
Cancel
|
|
73
|
+
</SecondaryButton>
|
|
74
|
+
</AlertDialog.Cancel>
|
|
75
|
+
|
|
76
|
+
<SaveButton
|
|
77
|
+
asChild
|
|
78
|
+
loading={revokeSession.isPending}
|
|
79
|
+
done={revokeSession.isSuccess}
|
|
80
|
+
onDone={handleDone}
|
|
81
|
+
>
|
|
82
|
+
<DestructiveButton type="submit">Sign out</DestructiveButton>
|
|
83
|
+
</SaveButton>
|
|
84
|
+
</form>
|
|
85
|
+
</Flex>
|
|
86
|
+
</AlertDialogContent>
|
|
87
|
+
</AlertDialog.Root>
|
|
88
|
+
);
|
|
89
|
+
}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
.woswidgets-marker {
|
|
2
|
+
/* Reset letter-spacing so the Marker content doesn’t appear off-center when nested in other elements */
|
|
3
|
+
letter-spacing: 0;
|
|
4
|
+
line-height: normal;
|
|
5
|
+
}
|
|
6
|
+
.woswidgets-marker-circle::before {
|
|
7
|
+
background-color: var(--gray-a4);
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
.woswidgets-marker[data-accent-color] {
|
|
11
|
+
color: var(--accent-a11);
|
|
12
|
+
}
|
|
13
|
+
.woswidgets-marker[data-accent-color] .woswidgets-marker-circle::before {
|
|
14
|
+
background-color: var(--accent-a4);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
.woswidgets-marker {
|
|
18
|
+
color: var(--gray-11);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
.woswidgets-marker-circle {
|
|
22
|
+
position: relative;
|
|
23
|
+
text-align: center;
|
|
24
|
+
user-select: none;
|
|
25
|
+
height: 1em;
|
|
26
|
+
min-width: 1em;
|
|
27
|
+
padding-left: 0.05em;
|
|
28
|
+
padding-right: 0.05em;
|
|
29
|
+
box-sizing: border-box;
|
|
30
|
+
|
|
31
|
+
/* Would be easier to use "inline-flex", but that messes up copy-pasted text formatting */
|
|
32
|
+
display: inline-block;
|
|
33
|
+
|
|
34
|
+
/* Align middle of the element with the baseline plus half the x-height of the parent */
|
|
35
|
+
vertical-align: middle;
|
|
36
|
+
|
|
37
|
+
/* Add the missing half of the x-height to align with the middle of the parent */
|
|
38
|
+
top: -0.11em;
|
|
39
|
+
|
|
40
|
+
/* Collapse own line height so it doesn't influence the inner element position */
|
|
41
|
+
line-height: 0;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
.woswidgets-marker-circle::before {
|
|
45
|
+
content: "";
|
|
46
|
+
position: absolute;
|
|
47
|
+
inset: -10%;
|
|
48
|
+
border-radius: 1em;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
.woswidgets-marker-circle svg {
|
|
52
|
+
width: 1.125em;
|
|
53
|
+
height: 1.125em;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
.woswidgets-marker-content {
|
|
57
|
+
position: relative;
|
|
58
|
+
display: inline-block;
|
|
59
|
+
vertical-align: middle;
|
|
60
|
+
font-size: calc(0.8em * var(--marker-font-size-adjust, 1));
|
|
61
|
+
font-weight: var(--marker-font-weight, bold);
|
|
62
|
+
line-height: 1;
|
|
63
|
+
transform: translateY(-50%);
|
|
64
|
+
top: 50%;
|
|
65
|
+
|
|
66
|
+
/* We are trying to achieve "cursor: default", but also have the pointer finger cursor when Marker is inside a link */
|
|
67
|
+
/* Its ::before element will get pointer events anyway, so we are just getting rid of the text cursor on content. */
|
|
68
|
+
pointer-events: none;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
.woswidgets-marker-hidden {
|
|
72
|
+
/* Make the text visually hidden without breaking copy-paste */
|
|
73
|
+
font-size: 0;
|
|
74
|
+
line-height: 0;
|
|
75
|
+
|
|
76
|
+
/* Prevent the dot from making it into copy-pasted text without the marker */
|
|
77
|
+
user-select: none;
|
|
78
|
+
|
|
79
|
+
/* Prevent copy-pasted whitespace from being collapsed when used in lists */
|
|
80
|
+
white-space: pre;
|
|
81
|
+
}
|