@orthacms/users-admin 0.0.0-reserve.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/LICENSE +21 -0
- package/README.md +7 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +3 -0
- package/dist/lib/api/useAddWorkspaceMember/index.d.ts +16 -0
- package/dist/lib/api/useAddWorkspaceMember/index.d.ts.map +1 -0
- package/dist/lib/api/useInviteMember/index.d.ts +17 -0
- package/dist/lib/api/useInviteMember/index.d.ts.map +1 -0
- package/dist/lib/api/useMembers/index.d.ts +15 -0
- package/dist/lib/api/useMembers/index.d.ts.map +1 -0
- package/dist/lib/api/useMembersMutation/index.d.ts +13 -0
- package/dist/lib/api/useMembersMutation/index.d.ts.map +1 -0
- package/dist/lib/api/useRemoveWorkspaceMember/index.d.ts +15 -0
- package/dist/lib/api/useRemoveWorkspaceMember/index.d.ts.map +1 -0
- package/dist/lib/api/useResendInvite/index.d.ts +8 -0
- package/dist/lib/api/useResendInvite/index.d.ts.map +1 -0
- package/dist/lib/api/useRevokeInvite/index.d.ts +7 -0
- package/dist/lib/api/useRevokeInvite/index.d.ts.map +1 -0
- package/dist/lib/api/useRevokeSession/index.d.ts +15 -0
- package/dist/lib/api/useRevokeSession/index.d.ts.map +1 -0
- package/dist/lib/api/useSetMemberStatus/index.d.ts +15 -0
- package/dist/lib/api/useSetMemberStatus/index.d.ts.map +1 -0
- package/dist/lib/api/useUpdateMember/index.d.ts +15 -0
- package/dist/lib/api/useUpdateMember/index.d.ts.map +1 -0
- package/dist/lib/api/useUserDetail/index.d.ts +9 -0
- package/dist/lib/api/useUserDetail/index.d.ts.map +1 -0
- package/dist/lib/api/useUserSessions/index.d.ts +25 -0
- package/dist/lib/api/useUserSessions/index.d.ts.map +1 -0
- package/dist/lib/api/useWorkspaceOptions/index.d.ts +18 -0
- package/dist/lib/api/useWorkspaceOptions/index.d.ts.map +1 -0
- package/dist/lib/application/useAddWorkspaceMember/index.d.ts +11 -0
- package/dist/lib/application/useAddWorkspaceMember/index.d.ts.map +1 -0
- package/dist/lib/application/useAddWorkspaceMember/index.js +21 -0
- package/dist/lib/application/useInviteMember/index.d.ts +12 -0
- package/dist/lib/application/useInviteMember/index.d.ts.map +1 -0
- package/dist/lib/application/useInviteMember/index.js +12 -0
- package/dist/lib/application/useInviteMemberFlow/index.d.ts +59 -0
- package/dist/lib/application/useInviteMemberFlow/index.d.ts.map +1 -0
- package/dist/lib/application/useInviteMemberFlow/index.js +47 -0
- package/dist/lib/application/useIssuePasswordReset/index.d.ts +12 -0
- package/dist/lib/application/useIssuePasswordReset/index.d.ts.map +1 -0
- package/dist/lib/application/useIssuePasswordReset/index.js +14 -0
- package/dist/lib/application/useMembers/index.d.ts +15 -0
- package/dist/lib/application/useMembers/index.d.ts.map +1 -0
- package/dist/lib/application/useMembers/index.js +23 -0
- package/dist/lib/application/useMembersMutation/index.d.ts +14 -0
- package/dist/lib/application/useMembersMutation/index.d.ts.map +1 -0
- package/dist/lib/application/useMembersMutation/index.js +25 -0
- package/dist/lib/application/usePreferences/index.d.ts +15 -0
- package/dist/lib/application/usePreferences/index.d.ts.map +1 -0
- package/dist/lib/application/usePreferences/index.js +28 -0
- package/dist/lib/application/useRemoveWorkspaceMember/index.d.ts +10 -0
- package/dist/lib/application/useRemoveWorkspaceMember/index.d.ts.map +1 -0
- package/dist/lib/application/useRemoveWorkspaceMember/index.js +20 -0
- package/dist/lib/application/useResendInvite/index.d.ts +10 -0
- package/dist/lib/application/useResendInvite/index.d.ts.map +1 -0
- package/dist/lib/application/useResendInvite/index.js +12 -0
- package/dist/lib/application/useRevokeInvite/index.d.ts +7 -0
- package/dist/lib/application/useRevokeInvite/index.d.ts.map +1 -0
- package/dist/lib/application/useRevokeInvite/index.js +10 -0
- package/dist/lib/application/useRevokeSession/index.d.ts +10 -0
- package/dist/lib/application/useRevokeSession/index.d.ts.map +1 -0
- package/dist/lib/application/useRevokeSession/index.js +19 -0
- package/dist/lib/application/useSetMemberStatus/index.d.ts +11 -0
- package/dist/lib/application/useSetMemberStatus/index.d.ts.map +1 -0
- package/dist/lib/application/useSetMemberStatus/index.js +11 -0
- package/dist/lib/application/useUpdateMember/index.d.ts +11 -0
- package/dist/lib/application/useUpdateMember/index.d.ts.map +1 -0
- package/dist/lib/application/useUpdateMember/index.js +11 -0
- package/dist/lib/application/useUpdateTheme/index.d.ts +14 -0
- package/dist/lib/application/useUpdateTheme/index.d.ts.map +1 -0
- package/dist/lib/application/useUpdateTheme/index.js +25 -0
- package/dist/lib/application/useUserDetail/index.d.ts +9 -0
- package/dist/lib/application/useUserDetail/index.d.ts.map +1 -0
- package/dist/lib/application/useUserDetail/index.js +17 -0
- package/dist/lib/application/useUserSessions/index.d.ts +9 -0
- package/dist/lib/application/useUserSessions/index.d.ts.map +1 -0
- package/dist/lib/application/useUserSessions/index.js +17 -0
- package/dist/lib/application/useWorkspaceOptions/index.d.ts +10 -0
- package/dist/lib/application/useWorkspaceOptions/index.d.ts.map +1 -0
- package/dist/lib/application/useWorkspaceOptions/index.js +17 -0
- package/dist/lib/components/AccountMenu/index.d.ts +9 -0
- package/dist/lib/components/AccountMenu/index.d.ts.map +1 -0
- package/dist/lib/components/AddToWorkspacesDialog/index.d.ts +19 -0
- package/dist/lib/components/AddToWorkspacesDialog/index.d.ts.map +1 -0
- package/dist/lib/components/BackLink/index.d.ts +14 -0
- package/dist/lib/components/BackLink/index.d.ts.map +1 -0
- package/dist/lib/components/ConfirmDialog/index.d.ts +30 -0
- package/dist/lib/components/ConfirmDialog/index.d.ts.map +1 -0
- package/dist/lib/components/EditMemberDialog/index.d.ts +21 -0
- package/dist/lib/components/EditMemberDialog/index.d.ts.map +1 -0
- package/dist/lib/components/MemberAvatar/index.d.ts +24 -0
- package/dist/lib/components/MemberAvatar/index.d.ts.map +1 -0
- package/dist/lib/components/MembersEmpty/index.d.ts +16 -0
- package/dist/lib/components/MembersEmpty/index.d.ts.map +1 -0
- package/dist/lib/components/MembersNoAccess/index.d.ts +7 -0
- package/dist/lib/components/MembersNoAccess/index.d.ts.map +1 -0
- package/dist/lib/components/MembersPagination/index.d.ts +17 -0
- package/dist/lib/components/MembersPagination/index.d.ts.map +1 -0
- package/dist/lib/components/MembersSkeleton/index.d.ts +32 -0
- package/dist/lib/components/MembersSkeleton/index.d.ts.map +1 -0
- package/dist/lib/components/MembersTable/MemberRoleChip/index.d.ts +10 -0
- package/dist/lib/components/MembersTable/MemberRoleChip/index.d.ts.map +1 -0
- package/dist/lib/components/MembersTable/MemberRowActions/index.d.ts +16 -0
- package/dist/lib/components/MembersTable/MemberRowActions/index.d.ts.map +1 -0
- package/dist/lib/components/MembersTable/MemberStatusBadge/index.d.ts +10 -0
- package/dist/lib/components/MembersTable/MemberStatusBadge/index.d.ts.map +1 -0
- package/dist/lib/components/MembersTable/MemberWorkspaces/index.d.ts +10 -0
- package/dist/lib/components/MembersTable/MemberWorkspaces/index.d.ts.map +1 -0
- package/dist/lib/components/MembersTable/index.d.ts +12 -0
- package/dist/lib/components/MembersTable/index.d.ts.map +1 -0
- package/dist/lib/components/MembersToolbar/index.d.ts +13 -0
- package/dist/lib/components/MembersToolbar/index.d.ts.map +1 -0
- package/dist/lib/components/RolePicker/index.d.ts +18 -0
- package/dist/lib/components/RolePicker/index.d.ts.map +1 -0
- package/dist/lib/components/SessionCard/index.d.ts +15 -0
- package/dist/lib/components/SessionCard/index.d.ts.map +1 -0
- package/dist/lib/components/UserDetailLayout/UserDetailTabs/index.d.ts +13 -0
- package/dist/lib/components/UserDetailLayout/UserDetailTabs/index.d.ts.map +1 -0
- package/dist/lib/components/UserDetailLayout/UserHero/index.d.ts +10 -0
- package/dist/lib/components/UserDetailLayout/UserHero/index.d.ts.map +1 -0
- package/dist/lib/components/UserDetailLayout/UserSideRail/index.d.ts +12 -0
- package/dist/lib/components/UserDetailLayout/UserSideRail/index.d.ts.map +1 -0
- package/dist/lib/components/UserDetailLayout/UserStatsStrip/index.d.ts +10 -0
- package/dist/lib/components/UserDetailLayout/UserStatsStrip/index.d.ts.map +1 -0
- package/dist/lib/components/UserDetailLayout/index.d.ts +13 -0
- package/dist/lib/components/UserDetailLayout/index.d.ts.map +1 -0
- package/dist/lib/components/UserDetailRouter/index.d.ts +13 -0
- package/dist/lib/components/UserDetailRouter/index.d.ts.map +1 -0
- package/dist/lib/components/WorkspaceMembershipCard/index.d.ts +15 -0
- package/dist/lib/components/WorkspaceMembershipCard/index.d.ts.map +1 -0
- package/dist/lib/domain/member/index.d.ts +61 -0
- package/dist/lib/domain/member/index.d.ts.map +1 -0
- package/dist/lib/domain/member/index.js +61 -0
- package/dist/lib/domain/types/member/index.d.ts +90 -0
- package/dist/lib/domain/types/member/index.d.ts.map +1 -0
- package/dist/lib/domain/types/member/index.js +1 -0
- package/dist/lib/domain/types/session/index.d.ts +18 -0
- package/dist/lib/domain/types/session/index.d.ts.map +1 -0
- package/dist/lib/domain/types/session/index.js +1 -0
- package/dist/lib/domain/types/workspaceOption/index.d.ts +15 -0
- package/dist/lib/domain/types/workspaceOption/index.d.ts.map +1 -0
- package/dist/lib/domain/types/workspaceOption/index.js +1 -0
- package/dist/lib/domain/value-objects/email/index.d.ts +24 -0
- package/dist/lib/domain/value-objects/email/index.d.ts.map +1 -0
- package/dist/lib/domain/value-objects/email/index.js +45 -0
- package/dist/lib/infrastructure/httpMemberGateway/index.d.ts +12 -0
- package/dist/lib/infrastructure/httpMemberGateway/index.d.ts.map +1 -0
- package/dist/lib/infrastructure/httpMemberGateway/index.js +158 -0
- package/dist/lib/infrastructure/inviteLink/index.d.ts +13 -0
- package/dist/lib/infrastructure/inviteLink/index.d.ts.map +1 -0
- package/dist/lib/infrastructure/inviteLink/index.js +23 -0
- package/dist/lib/infrastructure/memberGateway/index.d.ts +103 -0
- package/dist/lib/infrastructure/memberGateway/index.d.ts.map +1 -0
- package/dist/lib/infrastructure/memberGateway/index.js +1 -0
- package/dist/lib/infrastructure/memberMapper/index.d.ts +59 -0
- package/dist/lib/infrastructure/memberMapper/index.d.ts.map +1 -0
- package/dist/lib/infrastructure/memberMapper/index.js +52 -0
- package/dist/lib/infrastructure/membersKeys/index.d.ts +37 -0
- package/dist/lib/infrastructure/membersKeys/index.d.ts.map +1 -0
- package/dist/lib/infrastructure/membersKeys/index.js +25 -0
- package/dist/lib/infrastructure/passwordResetLink/index.d.ts +13 -0
- package/dist/lib/infrastructure/passwordResetLink/index.d.ts.map +1 -0
- package/dist/lib/infrastructure/passwordResetLink/index.js +24 -0
- package/dist/lib/infrastructure/preferencesGateway/index.d.ts +37 -0
- package/dist/lib/infrastructure/preferencesGateway/index.d.ts.map +1 -0
- package/dist/lib/infrastructure/preferencesGateway/index.js +43 -0
- package/dist/lib/pages/InviteMemberPage/index.d.ts +7 -0
- package/dist/lib/pages/InviteMemberPage/index.d.ts.map +1 -0
- package/dist/lib/pages/MembersPage/index.d.ts +13 -0
- package/dist/lib/pages/MembersPage/index.d.ts.map +1 -0
- package/dist/lib/pages/UserAccessPage/index.d.ts +9 -0
- package/dist/lib/pages/UserAccessPage/index.d.ts.map +1 -0
- package/dist/lib/pages/UserActivityPage/index.d.ts +8 -0
- package/dist/lib/pages/UserActivityPage/index.d.ts.map +1 -0
- package/dist/lib/pages/UserGeneralPage/index.d.ts +7 -0
- package/dist/lib/pages/UserGeneralPage/index.d.ts.map +1 -0
- package/dist/lib/pages/UserRolesPage/index.d.ts +8 -0
- package/dist/lib/pages/UserRolesPage/index.d.ts.map +1 -0
- package/dist/lib/pages/UserSessionsPage/index.d.ts +7 -0
- package/dist/lib/pages/UserSessionsPage/index.d.ts.map +1 -0
- package/dist/lib/pages/UserWorkspacesPage/index.d.ts +8 -0
- package/dist/lib/pages/UserWorkspacesPage/index.d.ts.map +1 -0
- package/dist/lib/presentation/components/AccountMenu/index.d.ts +9 -0
- package/dist/lib/presentation/components/AccountMenu/index.d.ts.map +1 -0
- package/dist/lib/presentation/components/AccountMenu/index.js +42 -0
- package/dist/lib/presentation/components/AddToWorkspacesDialog/index.d.ts +19 -0
- package/dist/lib/presentation/components/AddToWorkspacesDialog/index.d.ts.map +1 -0
- package/dist/lib/presentation/components/AddToWorkspacesDialog/index.js +89 -0
- package/dist/lib/presentation/components/BackLink/index.d.ts +14 -0
- package/dist/lib/presentation/components/BackLink/index.d.ts.map +1 -0
- package/dist/lib/presentation/components/BackLink/index.js +12 -0
- package/dist/lib/presentation/components/InviteLinkDialog/index.d.ts +25 -0
- package/dist/lib/presentation/components/InviteLinkDialog/index.d.ts.map +1 -0
- package/dist/lib/presentation/components/InviteLinkDialog/index.js +77 -0
- package/dist/lib/presentation/components/InviteLinkPanel/index.d.ts +26 -0
- package/dist/lib/presentation/components/InviteLinkPanel/index.d.ts.map +1 -0
- package/dist/lib/presentation/components/InviteLinkPanel/index.js +59 -0
- package/dist/lib/presentation/components/InviteSent/index.d.ts +20 -0
- package/dist/lib/presentation/components/InviteSent/index.d.ts.map +1 -0
- package/dist/lib/presentation/components/InviteSent/index.js +60 -0
- package/dist/lib/presentation/components/MemberAvatar/index.d.ts +24 -0
- package/dist/lib/presentation/components/MemberAvatar/index.d.ts.map +1 -0
- package/dist/lib/presentation/components/MemberAvatar/index.js +14 -0
- package/dist/lib/presentation/components/MembersEmpty/index.d.ts +16 -0
- package/dist/lib/presentation/components/MembersEmpty/index.d.ts.map +1 -0
- package/dist/lib/presentation/components/MembersEmpty/index.js +42 -0
- package/dist/lib/presentation/components/MembersNoAccess/index.d.ts +7 -0
- package/dist/lib/presentation/components/MembersNoAccess/index.d.ts.map +1 -0
- package/dist/lib/presentation/components/MembersNoAccess/index.js +24 -0
- package/dist/lib/presentation/components/MembersPagination/index.d.ts +17 -0
- package/dist/lib/presentation/components/MembersPagination/index.d.ts.map +1 -0
- package/dist/lib/presentation/components/MembersPagination/index.js +45 -0
- package/dist/lib/presentation/components/MembersSkeleton/index.d.ts +32 -0
- package/dist/lib/presentation/components/MembersSkeleton/index.d.ts.map +1 -0
- package/dist/lib/presentation/components/MembersSkeleton/index.js +61 -0
- package/dist/lib/presentation/components/MembersTable/MemberRoleChip/index.d.ts +17 -0
- package/dist/lib/presentation/components/MembersTable/MemberRoleChip/index.d.ts.map +1 -0
- package/dist/lib/presentation/components/MembersTable/MemberRoleChip/index.js +36 -0
- package/dist/lib/presentation/components/MembersTable/MemberRowActions/index.d.ts +16 -0
- package/dist/lib/presentation/components/MembersTable/MemberRowActions/index.d.ts.map +1 -0
- package/dist/lib/presentation/components/MembersTable/MemberRowActions/index.js +284 -0
- package/dist/lib/presentation/components/MembersTable/MemberStatusBadge/index.d.ts +10 -0
- package/dist/lib/presentation/components/MembersTable/MemberStatusBadge/index.d.ts.map +1 -0
- package/dist/lib/presentation/components/MembersTable/MemberStatusBadge/index.js +49 -0
- package/dist/lib/presentation/components/MembersTable/MemberWorkspaces/index.d.ts +10 -0
- package/dist/lib/presentation/components/MembersTable/MemberWorkspaces/index.d.ts.map +1 -0
- package/dist/lib/presentation/components/MembersTable/MemberWorkspaces/index.js +37 -0
- package/dist/lib/presentation/components/MembersTable/index.d.ts +12 -0
- package/dist/lib/presentation/components/MembersTable/index.d.ts.map +1 -0
- package/dist/lib/presentation/components/MembersTable/index.js +54 -0
- package/dist/lib/presentation/components/MembersTable/membersTableAnchor/index.d.ts +14 -0
- package/dist/lib/presentation/components/MembersTable/membersTableAnchor/index.d.ts.map +1 -0
- package/dist/lib/presentation/components/MembersToolbar/index.d.ts +15 -0
- package/dist/lib/presentation/components/MembersToolbar/index.d.ts.map +1 -0
- package/dist/lib/presentation/components/MembersToolbar/index.js +23 -0
- package/dist/lib/presentation/components/PasswordResetCard/index.d.ts +19 -0
- package/dist/lib/presentation/components/PasswordResetCard/index.d.ts.map +1 -0
- package/dist/lib/presentation/components/PasswordResetCard/index.js +109 -0
- package/dist/lib/presentation/components/PasswordResetLinkDialog/index.d.ts +27 -0
- package/dist/lib/presentation/components/PasswordResetLinkDialog/index.d.ts.map +1 -0
- package/dist/lib/presentation/components/PasswordResetLinkDialog/index.js +79 -0
- package/dist/lib/presentation/components/PasswordResetLinkPanel/index.d.ts +31 -0
- package/dist/lib/presentation/components/PasswordResetLinkPanel/index.d.ts.map +1 -0
- package/dist/lib/presentation/components/PasswordResetLinkPanel/index.js +64 -0
- package/dist/lib/presentation/components/RolePicker/index.d.ts +21 -0
- package/dist/lib/presentation/components/RolePicker/index.d.ts.map +1 -0
- package/dist/lib/presentation/components/RolePicker/index.js +51 -0
- package/dist/lib/presentation/components/SessionCard/index.d.ts +15 -0
- package/dist/lib/presentation/components/SessionCard/index.d.ts.map +1 -0
- package/dist/lib/presentation/components/SessionCard/index.js +43 -0
- package/dist/lib/presentation/components/ThemeSync/index.d.ts +21 -0
- package/dist/lib/presentation/components/ThemeSync/index.d.ts.map +1 -0
- package/dist/lib/presentation/components/ThemeSync/index.js +32 -0
- package/dist/lib/presentation/components/UserDetailLayout/UserDetailTabs/index.d.ts +15 -0
- package/dist/lib/presentation/components/UserDetailLayout/UserDetailTabs/index.d.ts.map +1 -0
- package/dist/lib/presentation/components/UserDetailLayout/UserDetailTabs/index.js +52 -0
- package/dist/lib/presentation/components/UserDetailLayout/UserHero/index.d.ts +10 -0
- package/dist/lib/presentation/components/UserDetailLayout/UserHero/index.d.ts.map +1 -0
- package/dist/lib/presentation/components/UserDetailLayout/UserHero/index.js +26 -0
- package/dist/lib/presentation/components/UserDetailLayout/UserStatsStrip/index.d.ts +10 -0
- package/dist/lib/presentation/components/UserDetailLayout/UserStatsStrip/index.d.ts.map +1 -0
- package/dist/lib/presentation/components/UserDetailLayout/UserStatsStrip/index.js +39 -0
- package/dist/lib/presentation/components/UserDetailLayout/index.d.ts +13 -0
- package/dist/lib/presentation/components/UserDetailLayout/index.d.ts.map +1 -0
- package/dist/lib/presentation/components/UserDetailLayout/index.js +101 -0
- package/dist/lib/presentation/components/UserDetailRouter/index.d.ts +16 -0
- package/dist/lib/presentation/components/UserDetailRouter/index.d.ts.map +1 -0
- package/dist/lib/presentation/components/UserDetailRouter/index.js +33 -0
- package/dist/lib/presentation/components/WorkspaceMembershipCard/index.d.ts +15 -0
- package/dist/lib/presentation/components/WorkspaceMembershipCard/index.d.ts.map +1 -0
- package/dist/lib/presentation/components/WorkspaceMembershipCard/index.js +27 -0
- package/dist/lib/presentation/membersFilterFields/index.d.ts +10 -0
- package/dist/lib/presentation/membersFilterFields/index.d.ts.map +1 -0
- package/dist/lib/presentation/membersFilterFields/index.js +67 -0
- package/dist/lib/presentation/membersResultsAnchor/index.d.ts +17 -0
- package/dist/lib/presentation/membersResultsAnchor/index.d.ts.map +1 -0
- package/dist/lib/presentation/membersResultsAnchor/index.js +16 -0
- package/dist/lib/presentation/pages/InviteMemberPage/index.d.ts +7 -0
- package/dist/lib/presentation/pages/InviteMemberPage/index.d.ts.map +1 -0
- package/dist/lib/presentation/pages/InviteMemberPage/index.js +346 -0
- package/dist/lib/presentation/pages/MembersPage/index.d.ts +13 -0
- package/dist/lib/presentation/pages/MembersPage/index.d.ts.map +1 -0
- package/dist/lib/presentation/pages/MembersPage/index.js +140 -0
- package/dist/lib/presentation/pages/UserAccessPage/index.d.ts +18 -0
- package/dist/lib/presentation/pages/UserAccessPage/index.d.ts.map +1 -0
- package/dist/lib/presentation/pages/UserAccessPage/index.js +153 -0
- package/dist/lib/presentation/pages/UserActivityPage/index.d.ts +8 -0
- package/dist/lib/presentation/pages/UserActivityPage/index.d.ts.map +1 -0
- package/dist/lib/presentation/pages/UserActivityPage/index.js +228 -0
- package/dist/lib/presentation/pages/UserGeneralPage/index.d.ts +7 -0
- package/dist/lib/presentation/pages/UserGeneralPage/index.d.ts.map +1 -0
- package/dist/lib/presentation/pages/UserGeneralPage/index.js +72 -0
- package/dist/lib/presentation/pages/UserPreferencesPage/ThemePreview.d.ts +11 -0
- package/dist/lib/presentation/pages/UserPreferencesPage/ThemePreview.d.ts.map +1 -0
- package/dist/lib/presentation/pages/UserPreferencesPage/ThemePreview.js +24 -0
- package/dist/lib/presentation/pages/UserPreferencesPage/index.d.ts +10 -0
- package/dist/lib/presentation/pages/UserPreferencesPage/index.d.ts.map +1 -0
- package/dist/lib/presentation/pages/UserPreferencesPage/index.js +148 -0
- package/dist/lib/presentation/pages/UserRolesPage/index.d.ts +8 -0
- package/dist/lib/presentation/pages/UserRolesPage/index.d.ts.map +1 -0
- package/dist/lib/presentation/pages/UserRolesPage/index.js +110 -0
- package/dist/lib/presentation/pages/UserSessionsPage/index.d.ts +7 -0
- package/dist/lib/presentation/pages/UserSessionsPage/index.d.ts.map +1 -0
- package/dist/lib/presentation/pages/UserSessionsPage/index.js +121 -0
- package/dist/lib/presentation/pages/UserWorkspacesPage/index.d.ts +8 -0
- package/dist/lib/presentation/pages/UserWorkspacesPage/index.d.ts.map +1 -0
- package/dist/lib/presentation/pages/UserWorkspacesPage/index.js +111 -0
- package/dist/lib/presentation/userDetailContext/index.d.ts +13 -0
- package/dist/lib/presentation/userDetailContext/index.d.ts.map +1 -0
- package/dist/lib/presentation/userDetailContext/index.js +5 -0
- package/dist/lib/presentation/usersPlugin/index.d.ts +27 -0
- package/dist/lib/presentation/usersPlugin/index.d.ts.map +1 -0
- package/dist/lib/presentation/usersPlugin/index.js +109 -0
- package/dist/lib/types/member/index.d.ts +63 -0
- package/dist/lib/types/member/index.d.ts.map +1 -0
- package/dist/lib/utils/membersFilterFields/index.d.ts +10 -0
- package/dist/lib/utils/membersFilterFields/index.d.ts.map +1 -0
- package/dist/lib/utils/membersKeys/index.d.ts +27 -0
- package/dist/lib/utils/membersKeys/index.d.ts.map +1 -0
- package/dist/lib/utils/toMember/index.d.ts +33 -0
- package/dist/lib/utils/toMember/index.d.ts.map +1 -0
- package/dist/lib/utils/userDetailContext/index.d.ts +13 -0
- package/dist/lib/utils/userDetailContext/index.d.ts.map +1 -0
- package/dist/lib/utils/usersPlugin/index.d.ts +27 -0
- package/dist/lib/utils/usersPlugin/index.d.ts.map +1 -0
- package/package.json +50 -0
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useRef } from 'react';
|
|
3
|
+
import { defineMessages, useIntl } from 'react-intl';
|
|
4
|
+
import { AlertTriangle, Check, Monitor, Moon, Sun } from 'lucide-react';
|
|
5
|
+
import { Alert, AlertDescription, Card, CardContent, CardDescription, CardHeader, CardTitle, RadioGroup, RadioGroupItem, cn, toast, useAppearance } from '@orthacms/design-system';
|
|
6
|
+
import { usePreferences } from '../../../application/usePreferences';
|
|
7
|
+
import { useUpdateTheme } from '../../../application/useUpdateTheme';
|
|
8
|
+
import { ThemePreview } from './ThemePreview';
|
|
9
|
+
/** Intl descriptors for {@link UserPreferencesPage}, co-located here. */
|
|
10
|
+
const messages = defineMessages({
|
|
11
|
+
themeTitle: {
|
|
12
|
+
id: 'users.preferences.themeTitle',
|
|
13
|
+
defaultMessage: 'Theme'
|
|
14
|
+
},
|
|
15
|
+
themeDescription: {
|
|
16
|
+
id: 'users.preferences.themeDescription',
|
|
17
|
+
defaultMessage: 'Choose how Ortha looks. This is personal to your account and applies immediately on every device you sign in on. “System” follows your device’s appearance setting.'
|
|
18
|
+
},
|
|
19
|
+
lightLabel: { id: 'users.preferences.lightLabel', defaultMessage: 'Light' },
|
|
20
|
+
lightHint: {
|
|
21
|
+
id: 'users.preferences.lightHint',
|
|
22
|
+
defaultMessage: 'The bright, default canvas.'
|
|
23
|
+
},
|
|
24
|
+
darkLabel: { id: 'users.preferences.darkLabel', defaultMessage: 'Dark' },
|
|
25
|
+
darkHint: {
|
|
26
|
+
id: 'users.preferences.darkHint',
|
|
27
|
+
defaultMessage: 'Dimmed surfaces, easier at night.'
|
|
28
|
+
},
|
|
29
|
+
systemLabel: {
|
|
30
|
+
id: 'users.preferences.systemLabel',
|
|
31
|
+
defaultMessage: 'System'
|
|
32
|
+
},
|
|
33
|
+
systemHint: {
|
|
34
|
+
id: 'users.preferences.systemHint',
|
|
35
|
+
defaultMessage: 'Match my device automatically.'
|
|
36
|
+
},
|
|
37
|
+
systemResolved: {
|
|
38
|
+
id: 'users.preferences.systemResolved',
|
|
39
|
+
defaultMessage: 'Your device is currently set to {mode}.'
|
|
40
|
+
},
|
|
41
|
+
modeLight: { id: 'users.preferences.modeLight', defaultMessage: 'light' },
|
|
42
|
+
modeDark: { id: 'users.preferences.modeDark', defaultMessage: 'dark' },
|
|
43
|
+
groupLabel: {
|
|
44
|
+
id: 'users.preferences.groupLabel',
|
|
45
|
+
defaultMessage: 'Colour theme'
|
|
46
|
+
},
|
|
47
|
+
saved: { id: 'users.preferences.saved', defaultMessage: 'Theme saved.' },
|
|
48
|
+
failed: {
|
|
49
|
+
id: 'users.preferences.failed',
|
|
50
|
+
defaultMessage: 'Couldn’t save your theme. Please try again.'
|
|
51
|
+
},
|
|
52
|
+
loadFailed: {
|
|
53
|
+
id: 'users.preferences.loadFailed',
|
|
54
|
+
defaultMessage: 'Couldn’t load your saved theme, so this may not be the one stored on your account. Reload to try again — picking a theme below still saves normally.'
|
|
55
|
+
}
|
|
56
|
+
});
|
|
57
|
+
const OPTIONS = [
|
|
58
|
+
{
|
|
59
|
+
value: 'light',
|
|
60
|
+
icon: Sun,
|
|
61
|
+
label: messages.lightLabel,
|
|
62
|
+
hint: messages.lightHint,
|
|
63
|
+
preview: 'light'
|
|
64
|
+
},
|
|
65
|
+
{
|
|
66
|
+
value: 'dark',
|
|
67
|
+
icon: Moon,
|
|
68
|
+
label: messages.darkLabel,
|
|
69
|
+
hint: messages.darkHint,
|
|
70
|
+
preview: 'dark'
|
|
71
|
+
},
|
|
72
|
+
{
|
|
73
|
+
value: 'system',
|
|
74
|
+
icon: Monitor,
|
|
75
|
+
label: messages.systemLabel,
|
|
76
|
+
hint: messages.systemHint,
|
|
77
|
+
preview: 'system'
|
|
78
|
+
}
|
|
79
|
+
];
|
|
80
|
+
/**
|
|
81
|
+
* Stable toast id, so rapid selections (a keyboard user arrowing across the
|
|
82
|
+
* group selects each option in turn) replace one another in place instead of
|
|
83
|
+
* stacking a column of "Theme saved."
|
|
84
|
+
*/
|
|
85
|
+
const THEME_TOAST_ID = 'users.preferences.theme';
|
|
86
|
+
/**
|
|
87
|
+
* The Preferences tab (shown only on your **own** profile): pick the colour
|
|
88
|
+
* theme (Light / Dark / System). Selection is optimistic — the app re-themes
|
|
89
|
+
* the instant you choose, via the shared {@link useAppearance} provider — then
|
|
90
|
+
* persisted to the server; a failed save rolls the choice back and surfaces a
|
|
91
|
+
* toast. The radio group is the accessible backbone; each option is a full card
|
|
92
|
+
* with a live preview.
|
|
93
|
+
*/
|
|
94
|
+
export function UserPreferencesPage() {
|
|
95
|
+
const intl = useIntl();
|
|
96
|
+
const { theme, resolvedTheme, setTheme } = useAppearance();
|
|
97
|
+
const preferences = usePreferences();
|
|
98
|
+
const update = useUpdateTheme();
|
|
99
|
+
// The user's most recent choice. Selections can overlap (arrow keys fire one
|
|
100
|
+
// per keypress) and the responses can land out of order, so a save only owns
|
|
101
|
+
// the rollback if nothing has superseded it — otherwise a slow failure for
|
|
102
|
+
// an abandoned choice would yank the UI off the choice the user *did* make,
|
|
103
|
+
// and onto a `previous` that is by then two selections stale.
|
|
104
|
+
const latest = useRef(null);
|
|
105
|
+
const select = (next) => {
|
|
106
|
+
if (next === theme) {
|
|
107
|
+
return;
|
|
108
|
+
}
|
|
109
|
+
const previous = theme;
|
|
110
|
+
latest.current = next;
|
|
111
|
+
// Apply immediately so the whole UI re-themes as the user chooses…
|
|
112
|
+
setTheme(next);
|
|
113
|
+
// …then persist. On failure, roll the visible choice back.
|
|
114
|
+
update.mutate(next, {
|
|
115
|
+
onSuccess: () => {
|
|
116
|
+
if (latest.current !== next) {
|
|
117
|
+
return;
|
|
118
|
+
}
|
|
119
|
+
toast.success(intl.formatMessage(messages.saved), {
|
|
120
|
+
id: THEME_TOAST_ID
|
|
121
|
+
});
|
|
122
|
+
},
|
|
123
|
+
onError: () => {
|
|
124
|
+
if (latest.current !== next) {
|
|
125
|
+
return;
|
|
126
|
+
}
|
|
127
|
+
setTheme(previous);
|
|
128
|
+
toast.error(intl.formatMessage(messages.failed), {
|
|
129
|
+
id: THEME_TOAST_ID
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
});
|
|
133
|
+
};
|
|
134
|
+
return (_jsxs(Card, { children: [_jsxs(CardHeader, { children: [_jsx(CardTitle, { children: intl.formatMessage(messages.themeTitle) }), _jsx(CardDescription, { children: intl.formatMessage(messages.themeDescription) })] }), _jsxs(CardContent, { children: [preferences.isError ? (_jsxs(Alert, { variant: "warning", className: "mb-3", children: [_jsx(AlertTriangle, { className: "size-4", "aria-hidden": true }), _jsx(AlertDescription, { children: intl.formatMessage(messages.loadFailed) })] })) : null, _jsx(RadioGroup, { value: theme, onValueChange: (value) => select(value), "aria-label": intl.formatMessage(messages.groupLabel), className: "grid gap-3 sm:grid-cols-3", children: OPTIONS.map((option) => {
|
|
135
|
+
const selected = option.value === theme;
|
|
136
|
+
const Icon = option.icon;
|
|
137
|
+
const inputId = `theme-${option.value}`;
|
|
138
|
+
return (_jsxs("label", { htmlFor: inputId, className: cn('group relative flex cursor-pointer flex-col gap-3 rounded-lg border bg-card p-3 text-left transition-colors', 'hover:border-input focus-within:ring-2 focus-within:ring-ring', selected
|
|
139
|
+
? 'border-primary ring-1 ring-primary'
|
|
140
|
+
: 'border-border'), children: [_jsx(ThemePreview, { variant: option.preview }), _jsxs("div", { className: "flex items-start gap-2", children: [_jsx(Icon, { className: "mt-0.5 size-4 shrink-0 text-muted-foreground", "aria-hidden": true }), _jsxs("div", { className: "min-w-0 flex-1", children: [_jsx("p", { className: "text-sm font-medium", children: intl.formatMessage(option.label) }), _jsx("p", { className: "text-xs text-muted-foreground", children: intl.formatMessage(option.hint) })] }), _jsx(RadioGroupItem, { id: inputId, value: option.value, className: "sr-only" }), _jsx("span", { "aria-hidden": true, className: cn('flex size-4 shrink-0 items-center justify-center rounded-full border transition-colors', selected
|
|
141
|
+
? 'border-primary bg-primary text-primary-foreground'
|
|
142
|
+
: 'border-input'), children: selected ? (_jsx(Check, { className: "size-3" })) : null })] })] }, option.value));
|
|
143
|
+
}) }), theme === 'system' ? (_jsx("p", { className: "mt-3 text-xs text-muted-foreground", children: intl.formatMessage(messages.systemResolved, {
|
|
144
|
+
mode: intl.formatMessage(resolvedTheme === 'dark'
|
|
145
|
+
? messages.modeDark
|
|
146
|
+
: messages.modeLight)
|
|
147
|
+
}) })) : null] })] }));
|
|
148
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The Role tab: pick the member's single global role and apply it behind a
|
|
3
|
+
* confirm step (with an extra warning when escalating to Admin). The last
|
|
4
|
+
* active admin can't be re-roled; the picker locks with the reason shown.
|
|
5
|
+
* Requires `users:update`.
|
|
6
|
+
*/
|
|
7
|
+
export declare function UserRolesPage(): import("react").JSX.Element;
|
|
8
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/lib/presentation/pages/UserRolesPage/index.tsx"],"names":[],"mappings":"AA0FA;;;;;GAKG;AACH,wBAAgB,aAAa,gCA2G5B"}
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useState } from 'react';
|
|
3
|
+
import { defineMessages, useIntl } from 'react-intl';
|
|
4
|
+
import { Alert, AlertDescription, Button, Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle, toast } from '@orthacms/design-system';
|
|
5
|
+
import { useAuth, useHasPermission } from '@orthacms/identity-admin';
|
|
6
|
+
import { useUpdateMember } from '../../../application/useUpdateMember';
|
|
7
|
+
import { useUserDetailContext } from '../../userDetailContext';
|
|
8
|
+
import { RolePicker } from '../../components/RolePicker';
|
|
9
|
+
import { ConfirmDialog } from '@orthacms/design-system';
|
|
10
|
+
import { MemberEntity } from '../../../domain/member';
|
|
11
|
+
/** Intl descriptors for {@link UserRolesPage}, co-located with the component. */
|
|
12
|
+
const messages = defineMessages({
|
|
13
|
+
title: { id: 'users.roles.title', defaultMessage: 'Role' },
|
|
14
|
+
description: {
|
|
15
|
+
id: 'users.roles.description',
|
|
16
|
+
defaultMessage: 'The member’s global role decides what they can do.'
|
|
17
|
+
},
|
|
18
|
+
note: {
|
|
19
|
+
id: 'users.roles.note',
|
|
20
|
+
defaultMessage: 'Role changes take effect on their next request; existing sessions may keep the old permissions briefly.'
|
|
21
|
+
},
|
|
22
|
+
lastAdmin: {
|
|
23
|
+
id: 'users.roles.lastAdmin',
|
|
24
|
+
defaultMessage: 'This member is the last remaining admin, so their role can’t change. Promote another member to admin first.'
|
|
25
|
+
},
|
|
26
|
+
self: {
|
|
27
|
+
id: 'users.roles.self',
|
|
28
|
+
defaultMessage: 'You can’t change your own role. Ask another admin to do it for you.'
|
|
29
|
+
},
|
|
30
|
+
customRole: {
|
|
31
|
+
id: 'users.roles.customRole',
|
|
32
|
+
defaultMessage: 'This member holds the custom role “{roleName}”, which this picker can’t represent. Changing it here would replace it with a system role.'
|
|
33
|
+
},
|
|
34
|
+
apply: { id: 'users.roles.apply', defaultMessage: 'Apply role' },
|
|
35
|
+
reset: { id: 'users.roles.reset', defaultMessage: 'Reset' },
|
|
36
|
+
confirmTitle: {
|
|
37
|
+
id: 'users.roles.confirmTitle',
|
|
38
|
+
defaultMessage: 'Change {name}’s role?'
|
|
39
|
+
},
|
|
40
|
+
confirmBody: {
|
|
41
|
+
id: 'users.roles.confirmBody',
|
|
42
|
+
defaultMessage: 'They’ll get the {role} role’s permissions immediately.'
|
|
43
|
+
},
|
|
44
|
+
confirmAdminBody: {
|
|
45
|
+
id: 'users.roles.confirmAdminBody',
|
|
46
|
+
defaultMessage: 'Admins have full access — they can manage members, roles, workspaces, and content. Continue?'
|
|
47
|
+
},
|
|
48
|
+
saved: {
|
|
49
|
+
id: 'users.roles.saved',
|
|
50
|
+
defaultMessage: 'Updated {name}’s role.'
|
|
51
|
+
},
|
|
52
|
+
failed: {
|
|
53
|
+
id: 'users.roles.failed',
|
|
54
|
+
defaultMessage: 'Couldn’t change the role. Please try again.'
|
|
55
|
+
}
|
|
56
|
+
});
|
|
57
|
+
const ROLE_LABEL = {
|
|
58
|
+
admin: 'Admin',
|
|
59
|
+
contributor: 'Contributor',
|
|
60
|
+
viewer: 'Viewer'
|
|
61
|
+
};
|
|
62
|
+
/** The explanation shown when a guardrail locks the picker. */
|
|
63
|
+
const LOCK_REASON = {
|
|
64
|
+
self: messages.self,
|
|
65
|
+
lastAdmin: messages.lastAdmin,
|
|
66
|
+
customRole: messages.customRole
|
|
67
|
+
};
|
|
68
|
+
/**
|
|
69
|
+
* The Role tab: pick the member's single global role and apply it behind a
|
|
70
|
+
* confirm step (with an extra warning when escalating to Admin). The last
|
|
71
|
+
* active admin can't be re-roled; the picker locks with the reason shown.
|
|
72
|
+
* Requires `users:update`.
|
|
73
|
+
*/
|
|
74
|
+
export function UserRolesPage() {
|
|
75
|
+
const intl = useIntl();
|
|
76
|
+
const { member } = useUserDetailContext();
|
|
77
|
+
const { user } = useAuth();
|
|
78
|
+
const canManage = useHasPermission('users:update');
|
|
79
|
+
const update = useUpdateMember();
|
|
80
|
+
const [selected, setSelected] = useState(member.role);
|
|
81
|
+
const [confirming, setConfirming] = useState(false);
|
|
82
|
+
// Mirror every server guardrail the viewer can trip: their own account, the
|
|
83
|
+
// sole active admin, and a custom role the picker can't represent. Doing it
|
|
84
|
+
// here means the control explains itself instead of failing on submit with
|
|
85
|
+
// a generic "please try again" for something that can never succeed.
|
|
86
|
+
const roleChange = MemberEntity.of(member).canChangeRole(user?.id);
|
|
87
|
+
const locked = !canManage || !roleChange.ok;
|
|
88
|
+
const dirty = selected !== member.role;
|
|
89
|
+
const apply = () => {
|
|
90
|
+
if (selected === null) {
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
93
|
+
update.mutate({ id: member.id, role: selected }, {
|
|
94
|
+
onSuccess: (saved) => {
|
|
95
|
+
setConfirming(false);
|
|
96
|
+
setSelected(saved.role);
|
|
97
|
+
toast.success(intl.formatMessage(messages.saved, { name: saved.name }));
|
|
98
|
+
},
|
|
99
|
+
onError: () => {
|
|
100
|
+
setConfirming(false);
|
|
101
|
+
toast.error(intl.formatMessage(messages.failed));
|
|
102
|
+
}
|
|
103
|
+
});
|
|
104
|
+
};
|
|
105
|
+
return (_jsxs(Card, { children: [_jsxs(CardHeader, { children: [_jsx(CardTitle, { children: intl.formatMessage(messages.title) }), _jsx(CardDescription, { children: intl.formatMessage(messages.description) })] }), _jsxs(CardContent, { className: "space-y-4", children: [!roleChange.ok ? (_jsx(Alert, { children: _jsx(AlertDescription, { children: intl.formatMessage(LOCK_REASON[roleChange.reason], { roleName: member.roleName }) }) })) : (_jsx(Alert, { children: _jsx(AlertDescription, { children: intl.formatMessage(messages.note) }) })), _jsx(RolePicker, { value: selected, current: member.role, disabled: locked, onChange: setSelected })] }), canManage ? (_jsxs(CardFooter, { className: "justify-end gap-2", children: [_jsx(Button, { variant: "ghost", onClick: () => setSelected(member.role), disabled: !dirty || update.isPending, children: intl.formatMessage(messages.reset) }), _jsx(Button, { onClick: () => setConfirming(true), disabled: locked || !dirty || update.isPending, children: intl.formatMessage(messages.apply) })] })) : null, _jsx(ConfirmDialog, { open: confirming, onOpenChange: setConfirming, busy: update.isPending, title: intl.formatMessage(messages.confirmTitle, {
|
|
106
|
+
name: member.name
|
|
107
|
+
}), description: intl.formatMessage(selected === 'admin'
|
|
108
|
+
? messages.confirmAdminBody
|
|
109
|
+
: messages.confirmBody, { role: selected ? ROLE_LABEL[selected] : '' }), confirmLabel: intl.formatMessage(messages.apply), onConfirm: apply })] }));
|
|
110
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The Sessions tab: a member's live sessions with a per-device Revoke. Gated on
|
|
3
|
+
* `users:update` (the rail hides it otherwise); revoking is confirmed and drops
|
|
4
|
+
* the row on success. The viewer's own session can't be revoked from here.
|
|
5
|
+
*/
|
|
6
|
+
export declare function UserSessionsPage(): import("react").JSX.Element;
|
|
7
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/lib/presentation/pages/UserSessionsPage/index.tsx"],"names":[],"mappings":"AAuEA;;;;GAIG;AACH,wBAAgB,gBAAgB,gCA+H/B"}
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
+
import { useRef, useState } from 'react';
|
|
3
|
+
import { defineMessages, useIntl } from 'react-intl';
|
|
4
|
+
import { Alert, AlertDescription, Button, Card, CardContent, CardDescription, CardHeader, CardTitle, Skeleton, toast } from '@orthacms/design-system';
|
|
5
|
+
import { useHasPermission } from '@orthacms/identity-admin';
|
|
6
|
+
import { useUserSessions } from '../../../application/useUserSessions';
|
|
7
|
+
import { useRevokeSession } from '../../../application/useRevokeSession';
|
|
8
|
+
import { useUserDetailContext } from '../../userDetailContext';
|
|
9
|
+
import { ConfirmDialog } from '@orthacms/design-system';
|
|
10
|
+
import { SessionCard } from '../../components/SessionCard';
|
|
11
|
+
/** Intl descriptors for {@link UserSessionsPage}. */
|
|
12
|
+
const messages = defineMessages({
|
|
13
|
+
title: { id: 'users.sessions.title', defaultMessage: 'Sessions' },
|
|
14
|
+
description: {
|
|
15
|
+
id: 'users.sessions.description',
|
|
16
|
+
defaultMessage: 'Devices currently signed in as this member.'
|
|
17
|
+
},
|
|
18
|
+
empty: {
|
|
19
|
+
id: 'users.sessions.empty',
|
|
20
|
+
defaultMessage: 'No active sessions.'
|
|
21
|
+
},
|
|
22
|
+
error: {
|
|
23
|
+
id: 'users.sessions.error',
|
|
24
|
+
defaultMessage: 'Couldn’t load sessions. Please try again.'
|
|
25
|
+
},
|
|
26
|
+
retry: { id: 'users.sessions.retry', defaultMessage: 'Retry' },
|
|
27
|
+
confirmTitle: {
|
|
28
|
+
id: 'users.sessions.confirmTitle',
|
|
29
|
+
defaultMessage: 'Revoke the session on {device}?'
|
|
30
|
+
},
|
|
31
|
+
confirmBody: {
|
|
32
|
+
id: 'users.sessions.confirmBody',
|
|
33
|
+
defaultMessage: 'Last seen {when}{ip}. That device will be signed out immediately and must sign in again.'
|
|
34
|
+
},
|
|
35
|
+
confirmBodyIp: {
|
|
36
|
+
id: 'users.sessions.confirmBodyIp',
|
|
37
|
+
defaultMessage: ' from {ip}'
|
|
38
|
+
},
|
|
39
|
+
unknownDevice: {
|
|
40
|
+
id: 'users.sessions.confirmUnknownDevice',
|
|
41
|
+
defaultMessage: 'an unknown device'
|
|
42
|
+
},
|
|
43
|
+
confirmRevoke: {
|
|
44
|
+
id: 'users.sessions.confirmRevoke',
|
|
45
|
+
defaultMessage: 'Revoke'
|
|
46
|
+
},
|
|
47
|
+
revoked: {
|
|
48
|
+
id: 'users.sessions.revoked',
|
|
49
|
+
defaultMessage: 'Session revoked.'
|
|
50
|
+
},
|
|
51
|
+
failed: {
|
|
52
|
+
id: 'users.sessions.failed',
|
|
53
|
+
defaultMessage: 'Couldn’t revoke the session. Please try again.'
|
|
54
|
+
}
|
|
55
|
+
});
|
|
56
|
+
/**
|
|
57
|
+
* The Sessions tab: a member's live sessions with a per-device Revoke. Gated on
|
|
58
|
+
* `users:update` (the rail hides it otherwise); revoking is confirmed and drops
|
|
59
|
+
* the row on success. The viewer's own session can't be revoked from here.
|
|
60
|
+
*/
|
|
61
|
+
export function UserSessionsPage() {
|
|
62
|
+
const intl = useIntl();
|
|
63
|
+
const { member } = useUserDetailContext();
|
|
64
|
+
const canManage = useHasPermission('users:update');
|
|
65
|
+
const { data: sessions, isPending, isError, refetch } = useUserSessions(member.id, canManage);
|
|
66
|
+
const revoke = useRevokeSession();
|
|
67
|
+
const [revoking, setRevoking] = useState(null);
|
|
68
|
+
const headingRef = useRef(null);
|
|
69
|
+
/**
|
|
70
|
+
* The revoked card unmounts, so Radix has no trigger to hand focus back to
|
|
71
|
+
* and it falls to `<body>` (WCAG 2.4.3). Send it to the section heading
|
|
72
|
+
* instead — a stable anchor that also re-announces where the user is.
|
|
73
|
+
*/
|
|
74
|
+
const restoreFocus = () => {
|
|
75
|
+
requestAnimationFrame(() => {
|
|
76
|
+
headingRef.current?.focus();
|
|
77
|
+
});
|
|
78
|
+
};
|
|
79
|
+
const onRevoke = () => {
|
|
80
|
+
if (!revoking) {
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
83
|
+
revoke.mutate({ userId: member.id, sessionId: revoking.id }, {
|
|
84
|
+
onSuccess: () => {
|
|
85
|
+
toast.success(intl.formatMessage(messages.revoked));
|
|
86
|
+
setRevoking(null);
|
|
87
|
+
restoreFocus();
|
|
88
|
+
},
|
|
89
|
+
onError: () => {
|
|
90
|
+
toast.error(intl.formatMessage(messages.failed));
|
|
91
|
+
setRevoking(null);
|
|
92
|
+
restoreFocus();
|
|
93
|
+
}
|
|
94
|
+
});
|
|
95
|
+
};
|
|
96
|
+
return (_jsxs(Card, { children: [_jsxs(CardHeader, { ref: headingRef, tabIndex: -1, className: "outline-none", children: [_jsx(CardTitle, { children: intl.formatMessage(messages.title) }), _jsx(CardDescription, { children: intl.formatMessage(messages.description) })] }), _jsx(CardContent, { className: "space-y-3", children: isPending ? (_jsxs(_Fragment, { children: [_jsx(Skeleton, { className: "h-16 w-full rounded-xl" }), _jsx(Skeleton, { className: "h-16 w-full rounded-xl" })] })) : isError ? (_jsx(Alert, { variant: "destructive", role: "alert", children: _jsxs(AlertDescription, { className: "flex flex-wrap items-center justify-between gap-3", children: [_jsx("span", { children: intl.formatMessage(messages.error) }), _jsx(Button, { variant: "outline", size: "sm", onClick: () => refetch(), children: intl.formatMessage(messages.retry) })] }) })) : sessions.length === 0 ? (_jsx("p", { className: "py-6 text-center text-sm text-muted-foreground", children: intl.formatMessage(messages.empty) })) : (sessions.map((session) => (_jsx(SessionCard, { session: session, busy: revoke.isPending && revoking?.id === session.id, onRevoke: setRevoking }, session.id)))) }), _jsx(ConfirmDialog, { open: revoking !== null, onOpenChange: (open) => {
|
|
97
|
+
if (!open) {
|
|
98
|
+
setRevoking(null);
|
|
99
|
+
restoreFocus();
|
|
100
|
+
}
|
|
101
|
+
}, busy: revoke.isPending,
|
|
102
|
+
// Name the device: the dialog is the last thing shown before an
|
|
103
|
+
// irreversible sign-out, and on a member with several sessions
|
|
104
|
+
// an unnamed one is indistinguishable from the others.
|
|
105
|
+
title: intl.formatMessage(messages.confirmTitle, {
|
|
106
|
+
device: revoking?.userAgent?.trim() ||
|
|
107
|
+
intl.formatMessage(messages.unknownDevice)
|
|
108
|
+
}), description: intl.formatMessage(messages.confirmBody, {
|
|
109
|
+
when: revoking
|
|
110
|
+
? intl.formatDate(revoking.lastSeenAt, {
|
|
111
|
+
dateStyle: 'medium',
|
|
112
|
+
timeStyle: 'short'
|
|
113
|
+
})
|
|
114
|
+
: '',
|
|
115
|
+
ip: revoking?.ipAddress
|
|
116
|
+
? intl.formatMessage(messages.confirmBodyIp, {
|
|
117
|
+
ip: revoking.ipAddress
|
|
118
|
+
})
|
|
119
|
+
: ''
|
|
120
|
+
}), confirmLabel: intl.formatMessage(messages.confirmRevoke), confirmVariant: "destructive", onConfirm: onRevoke })] }));
|
|
121
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The Workspaces tab: the member's workspace memberships, with add (a
|
|
3
|
+
* multi-select dialog) and per-card remove (confirmed). Memberships come from
|
|
4
|
+
* the shared detail record; mutations invalidate it so the list refreshes.
|
|
5
|
+
* Editing requires `users:update`.
|
|
6
|
+
*/
|
|
7
|
+
export declare function UserWorkspacesPage(): import("react").JSX.Element;
|
|
8
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/lib/presentation/pages/UserWorkspacesPage/index.tsx"],"names":[],"mappings":"AAiEA;;;;;GAKG;AACH,wBAAgB,kBAAkB,gCAyHjC"}
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useState } from 'react';
|
|
3
|
+
import { defineMessages, useIntl } from 'react-intl';
|
|
4
|
+
import { Plus } from 'lucide-react';
|
|
5
|
+
import { Button, Card, CardContent, CardDescription, CardHeader, CardTitle, toast } from '@orthacms/design-system';
|
|
6
|
+
import { useHasPermission } from '@orthacms/identity-admin';
|
|
7
|
+
import { useAddWorkspaceMember } from '../../../application/useAddWorkspaceMember';
|
|
8
|
+
import { useRemoveWorkspaceMember } from '../../../application/useRemoveWorkspaceMember';
|
|
9
|
+
import { useUserDetailContext } from '../../userDetailContext';
|
|
10
|
+
import { AddToWorkspacesDialog } from '../../components/AddToWorkspacesDialog';
|
|
11
|
+
import { ConfirmDialog } from '@orthacms/design-system';
|
|
12
|
+
import { WorkspaceMembershipCard } from '../../components/WorkspaceMembershipCard';
|
|
13
|
+
/** Intl descriptors for {@link UserWorkspacesPage}. */
|
|
14
|
+
const messages = defineMessages({
|
|
15
|
+
title: { id: 'users.workspaces.title', defaultMessage: 'Workspaces' },
|
|
16
|
+
description: {
|
|
17
|
+
id: 'users.workspaces.description',
|
|
18
|
+
defaultMessage: 'The workspaces this member can access.'
|
|
19
|
+
},
|
|
20
|
+
add: { id: 'users.workspaces.add', defaultMessage: 'Add to workspace' },
|
|
21
|
+
empty: {
|
|
22
|
+
id: 'users.workspaces.empty',
|
|
23
|
+
defaultMessage: 'This member isn’t in any workspace yet.'
|
|
24
|
+
},
|
|
25
|
+
confirmTitle: {
|
|
26
|
+
id: 'users.workspaces.confirmTitle',
|
|
27
|
+
defaultMessage: 'Remove from {name}?'
|
|
28
|
+
},
|
|
29
|
+
confirmBody: {
|
|
30
|
+
id: 'users.workspaces.confirmBody',
|
|
31
|
+
defaultMessage: 'They’ll lose access to this workspace. You can add them back later.'
|
|
32
|
+
},
|
|
33
|
+
confirmRemove: {
|
|
34
|
+
id: 'users.workspaces.confirmRemove',
|
|
35
|
+
defaultMessage: 'Remove'
|
|
36
|
+
},
|
|
37
|
+
added: {
|
|
38
|
+
id: 'users.workspaces.added',
|
|
39
|
+
defaultMessage: 'Added to {count, plural, one {# workspace} other {# workspaces}}.'
|
|
40
|
+
},
|
|
41
|
+
removed: {
|
|
42
|
+
id: 'users.workspaces.removed',
|
|
43
|
+
defaultMessage: 'Removed from {name}.'
|
|
44
|
+
},
|
|
45
|
+
addFailed: {
|
|
46
|
+
id: 'users.workspaces.addFailed',
|
|
47
|
+
defaultMessage: 'Couldn’t add to the workspaces. Please try again.'
|
|
48
|
+
},
|
|
49
|
+
removeFailed: {
|
|
50
|
+
id: 'users.workspaces.removeFailed',
|
|
51
|
+
defaultMessage: 'Couldn’t remove from the workspace. Please try again.'
|
|
52
|
+
}
|
|
53
|
+
});
|
|
54
|
+
/**
|
|
55
|
+
* The Workspaces tab: the member's workspace memberships, with add (a
|
|
56
|
+
* multi-select dialog) and per-card remove (confirmed). Memberships come from
|
|
57
|
+
* the shared detail record; mutations invalidate it so the list refreshes.
|
|
58
|
+
* Editing requires `users:update`.
|
|
59
|
+
*/
|
|
60
|
+
export function UserWorkspacesPage() {
|
|
61
|
+
const intl = useIntl();
|
|
62
|
+
const { member } = useUserDetailContext();
|
|
63
|
+
const canManage = useHasPermission('users:update');
|
|
64
|
+
const addMember = useAddWorkspaceMember();
|
|
65
|
+
const removeMember = useRemoveWorkspaceMember();
|
|
66
|
+
const [adding, setAdding] = useState(false);
|
|
67
|
+
const [removing, setRemoving] = useState(null);
|
|
68
|
+
const onAdd = async (workspaceIds) => {
|
|
69
|
+
// Add each workspace independently so one failure (e.g. a 409 from an
|
|
70
|
+
// already-member race, or a transient network error) doesn't mask the
|
|
71
|
+
// ones that did commit. `Promise.all` would reject on the first failure
|
|
72
|
+
// and report total failure even though some adds succeeded.
|
|
73
|
+
const results = await Promise.allSettled(workspaceIds.map((workspaceId) => addMember.mutateAsync({ userId: member.id, workspaceId })));
|
|
74
|
+
const added = results.filter((result) => result.status === 'fulfilled').length;
|
|
75
|
+
// Close once anything landed (the successful mutations have already
|
|
76
|
+
// invalidated the detail, so the list reflects them); keep the dialog
|
|
77
|
+
// open only when every add failed, so the admin can retry.
|
|
78
|
+
if (added > 0) {
|
|
79
|
+
setAdding(false);
|
|
80
|
+
toast.success(intl.formatMessage(messages.added, { count: added }));
|
|
81
|
+
}
|
|
82
|
+
if (added < workspaceIds.length) {
|
|
83
|
+
toast.error(intl.formatMessage(messages.addFailed));
|
|
84
|
+
}
|
|
85
|
+
};
|
|
86
|
+
const onRemove = () => {
|
|
87
|
+
if (!removing) {
|
|
88
|
+
return;
|
|
89
|
+
}
|
|
90
|
+
removeMember.mutate({ userId: member.id, workspaceId: removing.id }, {
|
|
91
|
+
onSuccess: () => {
|
|
92
|
+
toast.success(intl.formatMessage(messages.removed, {
|
|
93
|
+
name: removing.name
|
|
94
|
+
}));
|
|
95
|
+
setRemoving(null);
|
|
96
|
+
},
|
|
97
|
+
onError: () => {
|
|
98
|
+
toast.error(intl.formatMessage(messages.removeFailed));
|
|
99
|
+
setRemoving(null);
|
|
100
|
+
}
|
|
101
|
+
});
|
|
102
|
+
};
|
|
103
|
+
return (_jsxs(Card, { children: [_jsxs(CardHeader, { className: "flex-row items-start justify-between gap-4 space-y-0", children: [_jsxs("div", { className: "space-y-1.5", children: [_jsx(CardTitle, { children: intl.formatMessage(messages.title) }), _jsx(CardDescription, { children: intl.formatMessage(messages.description) })] }), canManage ? (_jsxs(Button, { size: "sm", onClick: () => setAdding(true), children: [_jsx(Plus, { "aria-hidden": true, className: "size-4" }), intl.formatMessage(messages.add)] })) : null] }), _jsx(CardContent, { className: "space-y-3", children: member.workspaces.length === 0 ? (_jsx("p", { className: "py-6 text-center text-sm text-muted-foreground", children: intl.formatMessage(messages.empty) })) : (member.workspaces.map((workspace) => (_jsx(WorkspaceMembershipCard, { workspace: workspace, onRemove: canManage ? setRemoving : undefined, removing: removeMember.isPending &&
|
|
104
|
+
removing?.id === workspace.id }, workspace.id)))) }), _jsx(AddToWorkspacesDialog, { open: adding, onOpenChange: setAdding, existingIds: member.workspaces.map((workspace) => workspace.id), busy: addMember.isPending, onAdd: onAdd }), _jsx(ConfirmDialog, { open: removing !== null, onOpenChange: (open) => {
|
|
105
|
+
if (!open) {
|
|
106
|
+
setRemoving(null);
|
|
107
|
+
}
|
|
108
|
+
}, busy: removeMember.isPending, title: intl.formatMessage(messages.confirmTitle, {
|
|
109
|
+
name: removing?.name ?? ''
|
|
110
|
+
}), description: intl.formatMessage(messages.confirmBody), confirmLabel: intl.formatMessage(messages.confirmRemove), confirmVariant: "destructive", onConfirm: onRemove })] }));
|
|
111
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { Member } from '../../domain/types/member';
|
|
2
|
+
/**
|
|
3
|
+
* Outlet context shared by the user-detail layout with every tab. The layout
|
|
4
|
+
* fetches the member once and exposes it here, so the tabs read the same
|
|
5
|
+
* record instead of each issuing its own request.
|
|
6
|
+
*/
|
|
7
|
+
export type UserDetailContext = {
|
|
8
|
+
/** The member whose detail page is open. */
|
|
9
|
+
member: Member;
|
|
10
|
+
};
|
|
11
|
+
/** Reads the current member from the user-detail layout's Outlet context. */
|
|
12
|
+
export declare function useUserDetailContext(): UserDetailContext;
|
|
13
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/lib/presentation/userDetailContext/index.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,2BAA2B,CAAC;AAExD;;;;GAIG;AACH,MAAM,MAAM,iBAAiB,GAAG;IAC5B,4CAA4C;IAC5C,MAAM,EAAE,MAAM,CAAC;CAClB,CAAC;AAEF,6EAA6E;AAC7E,wBAAgB,oBAAoB,IAAI,iBAAiB,CAExD"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { AdminPlugin } from '@orthacms/bootstrap-admin';
|
|
2
|
+
/**
|
|
3
|
+
* Admin-side users plugin shape. A thin alias of {@link AdminPlugin}, kept
|
|
4
|
+
* named so future config (sub-routes, slots) has a home.
|
|
5
|
+
*/
|
|
6
|
+
export type UsersAdminPlugin = AdminPlugin;
|
|
7
|
+
/**
|
|
8
|
+
* Creates the admin-side users plugin. It owns the members feature: the
|
|
9
|
+
* private `/users` route (the Members page, rendered inside the shell's
|
|
10
|
+
* authenticated layout) and its toolbar nav entry, contributed to the shell's
|
|
11
|
+
* {@link NAVBAR_START_SLOT} at `order: 30` (after Workspaces). The page itself
|
|
12
|
+
* gates on the `users:read` permission.
|
|
13
|
+
*
|
|
14
|
+
* @example
|
|
15
|
+
* ```typescript
|
|
16
|
+
* createAdmin({
|
|
17
|
+
* plugins: [
|
|
18
|
+
* IdentityPlugin(),
|
|
19
|
+
* ShellPlugin(),
|
|
20
|
+
* WorkspacesPlugin(),
|
|
21
|
+
* UsersPlugin(),
|
|
22
|
+
* ],
|
|
23
|
+
* });
|
|
24
|
+
* ```
|
|
25
|
+
*/
|
|
26
|
+
export declare function UsersPlugin(): UsersAdminPlugin;
|
|
27
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/lib/presentation/usersPlugin/index.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,2BAA2B,CAAC;AAgC7D;;;GAGG;AACH,MAAM,MAAM,gBAAgB,GAAG,WAAW,CAAC;AAE3C;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,WAAW,IAAI,gBAAgB,CAiF9C"}
|