@workos-inc/widgets 1.6.1 → 1.7.0-pre.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +3 -1
- package/dist/cjs/admin-portal-domain-verification.client.d.cts +11 -0
- package/dist/cjs/admin-portal-sso-connection.client.d.cts +11 -0
- package/dist/cjs/alert-dialog-BlG3_awx.d.cts +25 -0
- package/dist/cjs/api-keys.client.d.cts +11 -0
- package/dist/cjs/dialog-C15qCLN3.d.cts +23 -0
- package/dist/cjs/dropdown-menu-BQ5LtvdR.d.cts +48 -0
- package/dist/cjs/index.d.cts +8 -0
- package/dist/cjs/lib/add-mfa-dialog.cjs +22 -14
- package/dist/cjs/lib/add-mfa-dialog.cjs.map +1 -1
- package/dist/cjs/lib/add-mfa-dialog.d.cts +2 -2
- package/dist/cjs/lib/admin-portal-domain-verification.cjs +6 -8
- package/dist/cjs/lib/admin-portal-domain-verification.cjs.map +1 -1
- package/dist/cjs/lib/admin-portal-domain-verification.d.cts +11 -0
- package/dist/cjs/lib/admin-portal-sso-connection.cjs +7 -8
- package/dist/cjs/lib/admin-portal-sso-connection.cjs.map +1 -1
- package/dist/cjs/lib/admin-portal-sso-connection.d.cts +11 -0
- package/dist/cjs/lib/api-keys/api-key-details-dialog.cjs +3 -3
- package/dist/cjs/lib/api-keys/api-key-details-dialog.cjs.map +1 -1
- package/dist/cjs/lib/api-keys/api-keys-search.cjs +2 -6
- package/dist/cjs/lib/api-keys/api-keys-search.cjs.map +1 -1
- package/dist/cjs/lib/api-keys/api-keys-table.cjs +18 -19
- package/dist/cjs/lib/api-keys/api-keys-table.cjs.map +1 -1
- package/dist/cjs/lib/api-keys/api-keys.cjs +2 -2
- package/dist/cjs/lib/api-keys/api-keys.cjs.map +1 -1
- package/dist/cjs/lib/api-keys/api-keys.d.cts +12 -0
- package/dist/cjs/lib/api-keys/create-api-key.cjs +20 -14
- package/dist/cjs/lib/api-keys/create-api-key.cjs.map +1 -1
- package/dist/cjs/lib/api-keys/revoke-api-key-dialog.cjs +7 -7
- package/dist/cjs/lib/api-keys/revoke-api-key-dialog.cjs.map +1 -1
- package/dist/cjs/lib/api-keys/skeleton-table.cjs +3 -2
- package/dist/cjs/lib/api-keys/skeleton-table.cjs.map +1 -1
- package/dist/cjs/lib/change-password-dialog.cjs +11 -9
- package/dist/cjs/lib/change-password-dialog.cjs.map +1 -1
- package/dist/cjs/lib/change-password-dialog.d.cts +2 -2
- package/dist/cjs/lib/copy-button.cjs +51 -29
- package/dist/cjs/lib/copy-button.cjs.map +1 -1
- package/dist/cjs/lib/copy-button.d.cts +22 -4
- package/dist/cjs/lib/delete-domain-dialog.cjs +8 -7
- package/dist/cjs/lib/delete-domain-dialog.cjs.map +1 -1
- package/dist/cjs/lib/delete-user-dialog.cjs +15 -7
- package/dist/cjs/lib/delete-user-dialog.cjs.map +1 -1
- package/dist/cjs/lib/delete-user-dialog.d.cts +2 -2
- package/dist/cjs/lib/domain-actions.cjs +8 -8
- package/dist/cjs/lib/domain-actions.cjs.map +1 -1
- package/dist/cjs/lib/edit-user-profile-dialog.cjs +10 -9
- package/dist/cjs/lib/edit-user-profile-dialog.cjs.map +1 -1
- package/dist/cjs/lib/edit-user-profile-dialog.d.cts +2 -2
- package/dist/cjs/lib/edit-user-role-dialog.cjs +15 -15
- package/dist/cjs/lib/edit-user-role-dialog.cjs.map +1 -1
- package/dist/cjs/lib/edit-user-role-dialog.d.cts +2 -2
- package/dist/cjs/lib/elements/alert-dialog.cjs +76 -0
- package/dist/cjs/lib/elements/alert-dialog.cjs.map +1 -0
- package/dist/cjs/lib/elements/alert-dialog.d.cts +3 -0
- package/dist/cjs/lib/elements/dialog.cjs +74 -0
- package/dist/cjs/lib/elements/dialog.cjs.map +1 -0
- package/dist/cjs/lib/elements/dialog.d.cts +3 -0
- package/dist/cjs/lib/elements/dropdown-menu.cjs +162 -0
- package/dist/cjs/lib/elements/dropdown-menu.cjs.map +1 -0
- package/dist/cjs/lib/elements/dropdown-menu.d.cts +3 -0
- package/dist/cjs/lib/elements/select.cjs +112 -0
- package/dist/cjs/lib/elements/select.cjs.map +1 -0
- package/dist/cjs/lib/elements/select.d.cts +4 -0
- package/dist/cjs/lib/elements/utils.cjs +54 -0
- package/dist/cjs/lib/elements/utils.cjs.map +1 -0
- package/dist/cjs/lib/elements/utils.d.cts +15 -0
- package/dist/cjs/lib/elements.cjs +73 -219
- package/dist/cjs/lib/elements.cjs.map +1 -1
- package/dist/cjs/lib/elements.d.cts +16 -13
- package/dist/cjs/lib/elevated-access.cjs +18 -10
- package/dist/cjs/lib/elevated-access.cjs.map +1 -1
- package/dist/cjs/lib/empty-state.d.cts +12 -0
- package/dist/cjs/lib/invite-user-dialog.cjs +13 -12
- package/dist/cjs/lib/invite-user-dialog.cjs.map +1 -1
- package/dist/cjs/lib/logout-all-sessions-dialog.cjs +7 -6
- package/dist/cjs/lib/logout-all-sessions-dialog.cjs.map +1 -1
- package/dist/cjs/lib/logout-all-sessions-dialog.d.cts +2 -2
- package/dist/cjs/lib/logout-dialog.cjs +7 -6
- package/dist/cjs/lib/logout-dialog.cjs.map +1 -1
- package/dist/cjs/lib/logout-dialog.d.cts +2 -2
- package/dist/cjs/lib/organization-switcher.cjs +38 -20
- package/dist/cjs/lib/organization-switcher.cjs.map +1 -1
- package/dist/cjs/lib/organization-switcher.d.cts +16 -2
- package/dist/cjs/lib/otp-input.d.cts +8 -0
- package/dist/cjs/lib/pipes.cjs +31 -42
- package/dist/cjs/lib/pipes.cjs.map +1 -1
- package/dist/cjs/lib/pipes.d.cts +12 -0
- package/dist/cjs/lib/resend-invite-dialog.cjs +23 -13
- package/dist/cjs/lib/resend-invite-dialog.cjs.map +1 -1
- package/dist/cjs/lib/resend-invite-dialog.d.cts +2 -2
- package/dist/cjs/lib/reset-mfa-dialog.cjs +9 -8
- package/dist/cjs/lib/reset-mfa-dialog.cjs.map +1 -1
- package/dist/cjs/lib/reset-mfa-dialog.d.cts +2 -2
- package/dist/cjs/lib/revoke-invite-dialog.cjs +17 -8
- package/dist/cjs/lib/revoke-invite-dialog.cjs.map +1 -1
- package/dist/cjs/lib/revoke-invite-dialog.d.cts +2 -2
- package/dist/cjs/lib/save-button.cjs +3 -2
- package/dist/cjs/lib/save-button.cjs.map +1 -1
- package/dist/cjs/lib/save-button.d.cts +12 -1
- package/dist/cjs/lib/set-password-dialog.cjs +11 -9
- package/dist/cjs/lib/set-password-dialog.cjs.map +1 -1
- package/dist/cjs/lib/set-password-dialog.d.cts +2 -2
- package/dist/cjs/lib/user-actions-dropdown.cjs +9 -8
- package/dist/cjs/lib/user-actions-dropdown.cjs.map +1 -1
- package/dist/cjs/lib/user-profile.cjs +1 -1
- package/dist/cjs/lib/user-profile.cjs.map +1 -1
- package/dist/cjs/lib/user-profile.d.cts +11 -0
- package/dist/cjs/lib/user-security.cjs +3 -3
- package/dist/cjs/lib/user-security.cjs.map +1 -1
- package/dist/cjs/lib/user-security.d.cts +12 -0
- package/dist/cjs/lib/user-sessions.cjs +3 -11
- package/dist/cjs/lib/user-sessions.cjs.map +1 -1
- package/dist/cjs/lib/user-sessions.d.cts +12 -0
- package/dist/cjs/lib/users-filter.cjs +5 -6
- package/dist/cjs/lib/users-filter.cjs.map +1 -1
- package/dist/cjs/lib/users-filter.d.cts +2 -2
- package/dist/cjs/lib/users-management.cjs +22 -34
- package/dist/cjs/lib/users-management.cjs.map +1 -1
- package/dist/cjs/lib/users-management.d.cts +11 -0
- package/dist/cjs/lib/users-search.cjs +2 -6
- package/dist/cjs/lib/users-search.cjs.map +1 -1
- package/dist/cjs/lib/utils.cjs +25 -2
- package/dist/cjs/lib/utils.cjs.map +1 -1
- package/dist/cjs/lib/utils.d.cts +17 -3
- package/dist/cjs/lib/view-dns-record-dialog.cjs +9 -8
- package/dist/cjs/lib/view-dns-record-dialog.cjs.map +1 -1
- package/dist/cjs/lib/widgets-context.d.cts +8 -0
- package/dist/cjs/organization-switcher.client.cjs +33 -5
- package/dist/cjs/organization-switcher.client.cjs.map +1 -1
- package/dist/cjs/organization-switcher.client.d.cts +11 -0
- package/dist/cjs/pipes.client.d.cts +11 -0
- package/dist/cjs/select-KR89Qnvm.d.cts +30 -0
- package/dist/cjs/user-profile.client.d.cts +11 -0
- package/dist/cjs/user-security.client.d.cts +11 -0
- package/dist/cjs/user-sessions.client.d.cts +11 -0
- package/dist/cjs/users-management.client.d.cts +11 -0
- package/dist/cjs/utils.cjs +59 -0
- package/dist/cjs/utils.cjs.map +1 -0
- package/dist/cjs/utils.d.cts +3 -0
- package/dist/cjs/workos-widgets.client.d.cts +8 -0
- package/dist/css/lib/provider-icon.css +6 -0
- package/dist/esm/admin-portal-domain-verification.client.d.ts +11 -0
- package/dist/esm/admin-portal-sso-connection.client.d.ts +11 -0
- package/dist/esm/alert-dialog-BlG3_awx.d.ts +25 -0
- package/dist/esm/api-keys.client.d.ts +11 -0
- package/dist/esm/dialog-C15qCLN3.d.ts +23 -0
- package/dist/esm/dropdown-menu-BQ5LtvdR.d.ts +48 -0
- package/dist/esm/index.d.ts +8 -0
- package/dist/esm/lib/add-mfa-dialog.d.ts +2 -2
- package/dist/esm/lib/add-mfa-dialog.js +16 -9
- package/dist/esm/lib/add-mfa-dialog.js.map +1 -1
- package/dist/esm/lib/admin-portal-domain-verification.d.ts +11 -0
- package/dist/esm/lib/admin-portal-domain-verification.js +6 -8
- package/dist/esm/lib/admin-portal-domain-verification.js.map +1 -1
- package/dist/esm/lib/admin-portal-sso-connection.d.ts +11 -0
- package/dist/esm/lib/admin-portal-sso-connection.js +8 -9
- package/dist/esm/lib/admin-portal-sso-connection.js.map +1 -1
- package/dist/esm/lib/api-keys/api-key-details-dialog.js +3 -3
- package/dist/esm/lib/api-keys/api-key-details-dialog.js.map +1 -1
- package/dist/esm/lib/api-keys/api-keys-search.js +2 -6
- package/dist/esm/lib/api-keys/api-keys-search.js.map +1 -1
- package/dist/esm/lib/api-keys/api-keys-table.js +18 -32
- package/dist/esm/lib/api-keys/api-keys-table.js.map +1 -1
- package/dist/esm/lib/api-keys/api-keys.d.ts +12 -0
- package/dist/esm/lib/api-keys/api-keys.js +2 -2
- package/dist/esm/lib/api-keys/api-keys.js.map +1 -1
- package/dist/esm/lib/api-keys/create-api-key.js +17 -14
- package/dist/esm/lib/api-keys/create-api-key.js.map +1 -1
- package/dist/esm/lib/api-keys/revoke-api-key-dialog.js +4 -4
- package/dist/esm/lib/api-keys/revoke-api-key-dialog.js.map +1 -1
- package/dist/esm/lib/api-keys/skeleton-table.js +2 -1
- package/dist/esm/lib/api-keys/skeleton-table.js.map +1 -1
- package/dist/esm/lib/change-password-dialog.d.ts +2 -2
- package/dist/esm/lib/change-password-dialog.js +8 -12
- package/dist/esm/lib/change-password-dialog.js.map +1 -1
- package/dist/esm/lib/copy-button.d.ts +22 -4
- package/dist/esm/lib/copy-button.js +49 -28
- package/dist/esm/lib/copy-button.js.map +1 -1
- package/dist/esm/lib/delete-domain-dialog.js +4 -3
- package/dist/esm/lib/delete-domain-dialog.js.map +1 -1
- package/dist/esm/lib/delete-user-dialog.d.ts +2 -2
- package/dist/esm/lib/delete-user-dialog.js +13 -15
- package/dist/esm/lib/delete-user-dialog.js.map +1 -1
- package/dist/esm/lib/domain-actions.js +4 -4
- package/dist/esm/lib/domain-actions.js.map +1 -1
- package/dist/esm/lib/edit-user-profile-dialog.d.ts +2 -2
- package/dist/esm/lib/edit-user-profile-dialog.js +7 -12
- package/dist/esm/lib/edit-user-profile-dialog.js.map +1 -1
- package/dist/esm/lib/edit-user-role-dialog.d.ts +2 -2
- package/dist/esm/lib/edit-user-role-dialog.js +9 -19
- package/dist/esm/lib/edit-user-role-dialog.js.map +1 -1
- package/dist/esm/lib/elements/alert-dialog.d.ts +3 -0
- package/dist/esm/lib/elements/alert-dialog.js +45 -0
- package/dist/esm/lib/elements/alert-dialog.js.map +1 -0
- package/dist/esm/lib/elements/dialog.d.ts +3 -0
- package/dist/esm/lib/elements/dialog.js +43 -0
- package/dist/esm/lib/elements/dialog.js.map +1 -0
- package/dist/esm/lib/elements/dropdown-menu.d.ts +3 -0
- package/dist/esm/lib/elements/dropdown-menu.js +131 -0
- package/dist/esm/lib/elements/dropdown-menu.js.map +1 -0
- package/dist/esm/lib/elements/select.d.ts +4 -0
- package/dist/esm/lib/elements/select.js +77 -0
- package/dist/esm/lib/elements/select.js.map +1 -0
- package/dist/esm/lib/elements/utils.d.ts +15 -0
- package/dist/esm/lib/elements/utils.js +20 -0
- package/dist/esm/lib/elements/utils.js.map +1 -0
- package/dist/esm/lib/elements.d.ts +16 -13
- package/dist/esm/lib/elements.js +71 -215
- package/dist/esm/lib/elements.js.map +1 -1
- package/dist/esm/lib/elevated-access.js +14 -6
- package/dist/esm/lib/elevated-access.js.map +1 -1
- package/dist/esm/lib/empty-state.d.ts +12 -0
- package/dist/esm/lib/invite-user-dialog.js +10 -24
- package/dist/esm/lib/invite-user-dialog.js.map +1 -1
- package/dist/esm/lib/logout-all-sessions-dialog.d.ts +2 -2
- package/dist/esm/lib/logout-all-sessions-dialog.js +6 -9
- package/dist/esm/lib/logout-all-sessions-dialog.js.map +1 -1
- package/dist/esm/lib/logout-dialog.d.ts +2 -2
- package/dist/esm/lib/logout-dialog.js +6 -9
- package/dist/esm/lib/logout-dialog.js.map +1 -1
- package/dist/esm/lib/organization-switcher.d.ts +16 -2
- package/dist/esm/lib/organization-switcher.js +33 -13
- package/dist/esm/lib/organization-switcher.js.map +1 -1
- package/dist/esm/lib/otp-input.d.ts +8 -0
- package/dist/esm/lib/pipes.d.ts +12 -0
- package/dist/esm/lib/pipes.js +27 -47
- package/dist/esm/lib/pipes.js.map +1 -1
- package/dist/esm/lib/resend-invite-dialog.d.ts +2 -2
- package/dist/esm/lib/resend-invite-dialog.js +17 -20
- package/dist/esm/lib/resend-invite-dialog.js.map +1 -1
- package/dist/esm/lib/reset-mfa-dialog.d.ts +2 -2
- package/dist/esm/lib/reset-mfa-dialog.js +6 -9
- package/dist/esm/lib/reset-mfa-dialog.js.map +1 -1
- package/dist/esm/lib/revoke-invite-dialog.d.ts +2 -2
- package/dist/esm/lib/revoke-invite-dialog.js +14 -15
- package/dist/esm/lib/revoke-invite-dialog.js.map +1 -1
- package/dist/esm/lib/save-button.d.ts +12 -1
- package/dist/esm/lib/save-button.js +4 -9
- package/dist/esm/lib/save-button.js.map +1 -1
- package/dist/esm/lib/set-password-dialog.d.ts +2 -2
- package/dist/esm/lib/set-password-dialog.js +8 -12
- package/dist/esm/lib/set-password-dialog.js.map +1 -1
- package/dist/esm/lib/user-actions-dropdown.js +8 -11
- 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.js +2 -2
- package/dist/esm/lib/user-profile.js.map +1 -1
- package/dist/esm/lib/user-security.d.ts +12 -0
- package/dist/esm/lib/user-security.js +4 -4
- package/dist/esm/lib/user-security.js.map +1 -1
- package/dist/esm/lib/user-sessions.d.ts +12 -0
- package/dist/esm/lib/user-sessions.js +5 -13
- package/dist/esm/lib/user-sessions.js.map +1 -1
- package/dist/esm/lib/users-filter.d.ts +2 -2
- package/dist/esm/lib/users-filter.js +5 -6
- package/dist/esm/lib/users-filter.js.map +1 -1
- package/dist/esm/lib/users-management.d.ts +11 -0
- package/dist/esm/lib/users-management.js +23 -39
- package/dist/esm/lib/users-management.js.map +1 -1
- package/dist/esm/lib/users-search.js +2 -6
- package/dist/esm/lib/users-search.js.map +1 -1
- package/dist/esm/lib/utils.d.ts +17 -3
- package/dist/esm/lib/utils.js +24 -2
- package/dist/esm/lib/utils.js.map +1 -1
- package/dist/esm/lib/view-dns-record-dialog.js +7 -17
- package/dist/esm/lib/view-dns-record-dialog.js.map +1 -1
- package/dist/esm/lib/widgets-context.d.ts +8 -0
- package/dist/esm/organization-switcher.client.d.ts +11 -0
- package/dist/esm/organization-switcher.client.js +33 -5
- package/dist/esm/organization-switcher.client.js.map +1 -1
- package/dist/esm/pipes.client.d.ts +11 -0
- package/dist/esm/select-KR89Qnvm.d.ts +30 -0
- package/dist/esm/user-profile.client.d.ts +11 -0
- package/dist/esm/user-security.client.d.ts +11 -0
- package/dist/esm/user-sessions.client.d.ts +11 -0
- package/dist/esm/users-management.client.d.ts +11 -0
- package/dist/esm/utils.d.ts +3 -0
- package/dist/esm/utils.js +25 -0
- package/dist/esm/utils.js.map +1 -0
- package/dist/esm/workos-widgets.client.d.ts +8 -0
- package/package.json +11 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/lib/elevated-access.tsx"],"sourcesContent":["import * as Form from \"@radix-ui/react-form\";\nimport { AlertDialog, Callout, Dialog, Flex, Text } from \"@radix-ui/themes\";\nimport { useMe, useSendVerification, useVerify } from \"../api/endpoint.js\";\nimport { useElevatedAccessToken } from \"../api/api-provider.js\";\nimport { PropsWithChildren, useEffect, useRef, useState } from \"react\";\nimport { PrimaryButton, SecondaryButton } from \"./elements.js\";\nimport * as Otp from \"./otp-input.js\";\n\ninterface ElevatedAccessProps extends PropsWithChildren {\n onVerified?: () => Promise<unknown>;\n type?: \"dialog\" | \"alert\";\n}\n\nexport function ElevatedAccess({\n type = \"dialog\",\n children,\n onVerified,\n}: ElevatedAccessProps) {\n const { elevatedAccess } = useElevatedAccessToken();\n const [authenticationChallengeId, setAuthenticationChallengeId] =\n useState<string>();\n\n const prevAccessToken = useRef(elevatedAccess);\n\n useEffect(() => {\n prevAccessToken.current = elevatedAccess;\n }, [elevatedAccess]);\n\n if (elevatedAccess) {\n return <>{children}</>;\n }\n\n if (!authenticationChallengeId) {\n // FIXME: This should be refactored\n // eslint-disable-next-line react-hooks/refs\n const hasTokenExpired = !!prevAccessToken.current;\n\n return (\n <SendVerificationEmailForm\n type={type}\n hasTokenExpired={hasTokenExpired}\n onSuccess={(challengeId) => {\n setAuthenticationChallengeId(challengeId);\n }}\n />\n );\n }\n\n if (authenticationChallengeId) {\n return (\n <VerificationIdentityForm\n type={type}\n authenticationChallengeId={authenticationChallengeId}\n onSuccess={() => {\n // Reset the challenge id\n setAuthenticationChallengeId(undefined);\n\n return onVerified?.();\n }}\n />\n );\n }\n\n return null;\n}\n\ninterface SendVerificationEmailFormProps {\n onSuccess: (challengeId: string) => unknown | Promise<unknown>;\n type: \"dialog\" | \"alert\";\n hasTokenExpired: boolean;\n}\n\nfunction SendVerificationEmailForm({\n onSuccess,\n type,\n hasTokenExpired,\n}: SendVerificationEmailFormProps) {\n const { data: me } = useMe();\n const sendVerification = useSendVerification({\n mutation: { onSuccess: (data) => onSuccess(data.authenticationChallenge) },\n });\n\n const Title = type === \"dialog\" ? Dialog.Title : AlertDialog.Title;\n const Description =\n type === \"dialog\" ? Dialog.Description : AlertDialog.Description;\n const Close = type === \"dialog\" ? Dialog.Close : AlertDialog.Cancel;\n\n const handleSubmit = async (event: React.FormEvent<HTMLFormElement>) => {\n event.preventDefault();\n\n sendVerification.mutate();\n };\n\n return (\n <form onSubmit={handleSubmit}>\n <Title>\n {hasTokenExpired\n ? \"Your verification token has expired\"\n : \"Verify your identity\"}\n </Title>\n\n <Description color=\"gray\" mb=\"5\">\n To continue, we need to confirm your identity. We'll send a temporary\n verification code to{\" \"}\n <Text weight=\"bold\" highContrast>\n {me?.email}\n </Text>\n .\n </Description>\n\n {sendVerification.error && (\n <Callout.Root color=\"red\" mt=\"-2\" mb=\"0\">\n <Callout.Text>\n {getMutationErrorMessage(sendVerification.error)}\n </Callout.Text>\n </Callout.Root>\n )}\n\n <Flex justify=\"end\" align=\"center\" gap=\"3\" mt=\"5\">\n <Close>\n <SecondaryButton type=\"button\" disabled={sendVerification.isPending}>\n Cancel\n </SecondaryButton>\n </Close>\n <PrimaryButton type=\"submit\" loading={sendVerification.isPending}>\n Send verification code\n </PrimaryButton>\n </Flex>\n </form>\n );\n}\n\ninterface VerificationIdentityFormProps {\n onSuccess?: () => unknown | Promise<unknown>;\n authenticationChallengeId: string;\n type: \"dialog\" | \"alert\";\n}\n\nfunction VerificationIdentityForm({\n onSuccess,\n authenticationChallengeId,\n type,\n}: VerificationIdentityFormProps) {\n const { data: me } = useMe();\n const { setElevatedAccess } = useElevatedAccessToken();\n const verifyIdentity = useVerify();\n const [isSubmitting, setIsSubmitting] = useState(false);\n\n const Title = type === \"dialog\" ? Dialog.Title : AlertDialog.Title;\n const Description =\n type === \"dialog\" ? Dialog.Description : AlertDialog.Description;\n const Close = type === \"dialog\" ? Dialog.Close : AlertDialog.Cancel;\n const handleSubmit = async (event: React.FormEvent<HTMLFormElement>) => {\n event.preventDefault();\n\n const formData = new FormData(event.currentTarget);\n const code = formData.get(\"otp-code\")?.toString() ?? \"\";\n\n setIsSubmitting(true);\n\n try {\n // Mutate async so we can wait for the onSuccess callback as well\n const newAuthState = await verifyIdentity.mutateAsync({\n data: {\n code,\n authenticationChallengeId,\n },\n });\n\n const in10Seconds = new Date(Date.now() + 5 * 1000);\n\n setElevatedAccess({\n token: newAuthState.elevatedAccessToken,\n // expiresAt: newAuthState.expiresAt,\n expiresAt: in10Seconds.toISOString(),\n });\n\n if (onSuccess) {\n await new Promise((resolve) => setTimeout(resolve, 200));\n await onSuccess();\n }\n } catch (error) {\n console.error(error);\n }\n\n setIsSubmitting(false);\n };\n\n return (\n <Form.Root onSubmit={handleSubmit}>\n <Title>Verify your identity</Title>\n\n <Description color=\"gray\">\n A verification code was sent to{\" \"}\n <Text weight=\"bold\" highContrast>\n {me?.email}\n </Text>\n . Please enter it below.\n </Description>\n\n <Flex direction=\"column\" gap=\"2\" mt=\"5\" mx=\"auto\" width=\"fit-content\">\n <Otp.Root\n autoSubmit\n gap=\"2\"\n justify=\"center\"\n columns=\"repeat(6, 48px)\"\n width=\"fit-content\"\n rows=\"48px\"\n name=\"otp-code\"\n readOnly={isSubmitting}\n >\n <Otp.Input required autoFocus autoComplete=\"off\" />\n <Otp.Input required />\n <Otp.Input required />\n <Otp.Input required />\n <Otp.Input required />\n <Otp.Input required />\n </Otp.Root>\n\n {verifyIdentity.error && (\n <Text color=\"red\" size=\"2\" as=\"p\">\n {getMutationErrorMessage(verifyIdentity.error)}\n </Text>\n )}\n </Flex>\n\n <Flex justify=\"end\" align=\"center\" gap=\"3\" mt=\"5\">\n <Close>\n <SecondaryButton type=\"button\">Cancel</SecondaryButton>\n </Close>\n\n <PrimaryButton type=\"submit\" loading={isSubmitting}>\n Confirm\n </PrimaryButton>\n </Flex>\n </Form.Root>\n );\n}\n\nfunction getMutationErrorMessage(error: unknown) {\n let message = typeof error === \"string\" ? error : \"\";\n\n if (error instanceof Error) {\n message = error.message;\n } else if (\n typeof error === \"object\" &&\n error !== null &&\n \"message\" in error &&\n typeof error.message === \"string\"\n ) {\n message = error.message;\n }\n\n if (!message || message === \"Bad Request\") {\n message = \"Invalid code, please try again.\";\n }\n\n return message;\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../../src/lib/elevated-access.tsx"],"sourcesContent":["import * as Form from \"@radix-ui/react-form\";\nimport { Callout, Flex, Text } from \"@radix-ui/themes\";\nimport { useMe, useSendVerification, useVerify } from \"../api/endpoint.js\";\nimport { useElevatedAccessToken } from \"../api/api-provider.js\";\nimport { PropsWithChildren, useEffect, useRef, useState } from \"react\";\nimport { AlertDialog, Dialog, Button } from \"./elements.js\";\nimport * as Otp from \"./otp-input.js\";\n\ninterface ElevatedAccessProps extends PropsWithChildren {\n onVerified?: () => Promise<unknown>;\n type?: \"dialog\" | \"alert\";\n}\n\nexport function ElevatedAccess({\n type = \"dialog\",\n children,\n onVerified,\n}: ElevatedAccessProps) {\n const { elevatedAccess } = useElevatedAccessToken();\n const [authenticationChallengeId, setAuthenticationChallengeId] =\n useState<string>();\n\n const prevAccessToken = useRef(elevatedAccess);\n\n useEffect(() => {\n prevAccessToken.current = elevatedAccess;\n }, [elevatedAccess]);\n\n if (elevatedAccess) {\n return <>{children}</>;\n }\n\n if (!authenticationChallengeId) {\n // FIXME: This should be refactored\n // eslint-disable-next-line react-hooks/refs\n const hasTokenExpired = !!prevAccessToken.current;\n\n return (\n <SendVerificationEmailForm\n type={type}\n hasTokenExpired={hasTokenExpired}\n onSuccess={(challengeId) => {\n setAuthenticationChallengeId(challengeId);\n }}\n />\n );\n }\n\n if (authenticationChallengeId) {\n return (\n <VerificationIdentityForm\n type={type}\n authenticationChallengeId={authenticationChallengeId}\n onSuccess={() => {\n // Reset the challenge id\n setAuthenticationChallengeId(undefined);\n\n return onVerified?.();\n }}\n />\n );\n }\n\n return null;\n}\n\ninterface SendVerificationEmailFormProps {\n onSuccess: (challengeId: string) => unknown | Promise<unknown>;\n type: \"dialog\" | \"alert\";\n hasTokenExpired: boolean;\n}\n\nfunction SendVerificationEmailForm({\n onSuccess,\n type,\n hasTokenExpired,\n}: SendVerificationEmailFormProps) {\n const { data: me } = useMe();\n const sendVerification = useSendVerification({\n mutation: { onSuccess: (data) => onSuccess(data.authenticationChallenge) },\n });\n\n const Title = type === \"dialog\" ? Dialog.Title : AlertDialog.Title;\n const Description =\n type === \"dialog\" ? Dialog.Description : AlertDialog.Description;\n const Close = type === \"dialog\" ? Dialog.Close : AlertDialog.Cancel;\n\n const handleSubmit = async (event: React.FormEvent<HTMLFormElement>) => {\n event.preventDefault();\n\n sendVerification.mutate();\n };\n\n return (\n <form onSubmit={handleSubmit}>\n <Title>\n {hasTokenExpired\n ? \"Your verification token has expired\"\n : \"Verify your identity\"}\n </Title>\n\n <Description color=\"gray\" mb=\"5\">\n To continue, we need to confirm your identity. We'll send a temporary\n verification code to{\" \"}\n <Text weight=\"bold\" highContrast>\n {me?.email}\n </Text>\n .\n </Description>\n\n {sendVerification.error && (\n <Callout.Root color=\"red\" mt=\"-2\" mb=\"0\">\n <Callout.Text>\n {getMutationErrorMessage(sendVerification.error)}\n </Callout.Text>\n </Callout.Root>\n )}\n\n <Flex justify=\"end\" align=\"center\" gap=\"3\" mt=\"5\">\n <Close>\n <Button\n variant=\"secondary\"\n type=\"button\"\n disabled={sendVerification.isPending}\n >\n Cancel\n </Button>\n </Close>\n <Button type=\"submit\" loading={sendVerification.isPending}>\n Send verification code\n </Button>\n </Flex>\n </form>\n );\n}\n\ninterface VerificationIdentityFormProps {\n onSuccess?: () => unknown | Promise<unknown>;\n authenticationChallengeId: string;\n type: \"dialog\" | \"alert\";\n}\n\nfunction VerificationIdentityForm({\n onSuccess,\n authenticationChallengeId,\n type,\n}: VerificationIdentityFormProps) {\n const { data: me } = useMe();\n const { setElevatedAccess } = useElevatedAccessToken();\n const verifyIdentity = useVerify();\n const [isSubmitting, setIsSubmitting] = useState(false);\n\n const Title = type === \"dialog\" ? Dialog.Title : AlertDialog.Title;\n const Description =\n type === \"dialog\" ? Dialog.Description : AlertDialog.Description;\n const Close = type === \"dialog\" ? Dialog.Close : AlertDialog.Cancel;\n const handleSubmit = async (event: React.FormEvent<HTMLFormElement>) => {\n event.preventDefault();\n\n const formData = new FormData(event.currentTarget);\n const code = formData.get(\"otp-code\")?.toString() ?? \"\";\n\n setIsSubmitting(true);\n\n try {\n // Mutate async so we can wait for the onSuccess callback as well\n const newAuthState = await verifyIdentity.mutateAsync({\n data: {\n code,\n authenticationChallengeId,\n },\n });\n\n const in10Seconds = new Date(Date.now() + 5 * 1000);\n\n setElevatedAccess({\n token: newAuthState.elevatedAccessToken,\n // expiresAt: newAuthState.expiresAt,\n expiresAt: in10Seconds.toISOString(),\n });\n\n if (onSuccess) {\n await new Promise((resolve) => setTimeout(resolve, 200));\n await onSuccess();\n }\n } catch (error) {\n console.error(error);\n }\n\n setIsSubmitting(false);\n };\n\n return (\n <Form.Root onSubmit={handleSubmit}>\n <Title>Verify your identity</Title>\n\n <Description color=\"gray\">\n A verification code was sent to{\" \"}\n <Text weight=\"bold\" highContrast>\n {me?.email}\n </Text>\n . Please enter it below.\n </Description>\n\n <Flex direction=\"column\" gap=\"2\" mt=\"5\" mx=\"auto\" width=\"fit-content\">\n <Otp.Root\n autoSubmit\n gap=\"2\"\n justify=\"center\"\n columns=\"repeat(6, 48px)\"\n width=\"fit-content\"\n rows=\"48px\"\n name=\"otp-code\"\n readOnly={isSubmitting}\n >\n <Otp.Input required autoFocus autoComplete=\"off\" />\n <Otp.Input required />\n <Otp.Input required />\n <Otp.Input required />\n <Otp.Input required />\n <Otp.Input required />\n </Otp.Root>\n\n {verifyIdentity.error && (\n <Text color=\"red\" size=\"2\" as=\"p\">\n {getMutationErrorMessage(verifyIdentity.error)}\n </Text>\n )}\n </Flex>\n\n <Flex justify=\"end\" align=\"center\" gap=\"3\" mt=\"5\">\n <Close>\n <Button variant=\"secondary\" type=\"button\">\n Cancel\n </Button>\n </Close>\n <Button type=\"submit\" loading={isSubmitting}>\n Confirm\n </Button>\n </Flex>\n </Form.Root>\n );\n}\n\nfunction getMutationErrorMessage(error: unknown) {\n let message = typeof error === \"string\" ? error : \"\";\n\n if (error instanceof Error) {\n message = error.message;\n } else if (\n typeof error === \"object\" &&\n error !== null &&\n \"message\" in error &&\n typeof error.message === \"string\"\n ) {\n message = error.message;\n }\n\n if (!message || message === \"Bad Request\") {\n message = \"Invalid code, please try again.\";\n }\n\n return message;\n}\n"],"mappings":"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","names":[]}
|
|
@@ -3,6 +3,18 @@ import { WidgetRootDomProps } from './utils.cjs';
|
|
|
3
3
|
import '../api/endpoint.cjs';
|
|
4
4
|
import '@tanstack/react-query';
|
|
5
5
|
import '../api/widgets-api-client.cjs';
|
|
6
|
+
import './elements.cjs';
|
|
7
|
+
import 'react';
|
|
8
|
+
import '@radix-ui/themes';
|
|
9
|
+
import '@radix-ui/themes/props';
|
|
10
|
+
import '../dialog-C15qCLN3.cjs';
|
|
11
|
+
import '@radix-ui/themes/components/dialog';
|
|
12
|
+
import '../alert-dialog-BlG3_awx.cjs';
|
|
13
|
+
import '@radix-ui/themes/components/alert-dialog';
|
|
14
|
+
import '../dropdown-menu-BQ5LtvdR.cjs';
|
|
15
|
+
import '@radix-ui/themes/components/dropdown-menu';
|
|
16
|
+
import '../select-KR89Qnvm.cjs';
|
|
17
|
+
import '@radix-ui/themes/components/select';
|
|
6
18
|
|
|
7
19
|
interface EmptyStateProps extends WidgetRootDomProps {
|
|
8
20
|
heading: string;
|
|
@@ -76,11 +76,11 @@ function InviteUserDialog({ children }) {
|
|
|
76
76
|
};
|
|
77
77
|
const formErrors = getFormErrors(inviteUser.error);
|
|
78
78
|
useFormFieldFocusOnError(dialogId, inviteUser.error);
|
|
79
|
-
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
80
|
-
children && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
81
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_elements.
|
|
82
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
83
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
79
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_elements.Dialog.Root, { open, onOpenChange: setOpen, children: [
|
|
80
|
+
children && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_elements.Dialog.Trigger, { children }),
|
|
81
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_elements.Dialog.Content, { maxWidth: "480px", children: [
|
|
82
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_elements.Dialog.Title, { children: "Invite user" }),
|
|
83
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_elements.Dialog.Description, { children: "An invitation will be sent to this email address with a link to complete their account." }),
|
|
84
84
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_themes.Flex, { direction: "column", gap: "4", mt: "5", asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
85
85
|
"form",
|
|
86
86
|
{
|
|
@@ -134,23 +134,23 @@ function InviteUserDialog({ children }) {
|
|
|
134
134
|
"aria-describedby": ariaDescribedBy,
|
|
135
135
|
...props
|
|
136
136
|
}) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
137
|
-
|
|
137
|
+
import_elements.Select.Root,
|
|
138
138
|
{
|
|
139
139
|
...props,
|
|
140
140
|
value: selectedRole,
|
|
141
141
|
onValueChange: setSelectedRole,
|
|
142
142
|
children: [
|
|
143
143
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
144
|
-
import_elements.
|
|
144
|
+
import_elements.Select.Trigger,
|
|
145
145
|
{
|
|
146
146
|
id,
|
|
147
147
|
"aria-invalid": ariaInvalid,
|
|
148
148
|
"aria-describedby": ariaDescribedBy
|
|
149
149
|
}
|
|
150
150
|
),
|
|
151
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_elements.
|
|
152
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_elements.
|
|
153
|
-
roles.map((role) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_elements.
|
|
151
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_elements.Select.Content, { children: [
|
|
152
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_elements.Select.Item, { value: PLACEHOLDER_ROLE, disabled: true, children: "Select a role" }),
|
|
153
|
+
roles.map((role) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_elements.Select.Item, { value: role.slug, children: role.name }, role.slug))
|
|
154
154
|
] })
|
|
155
155
|
]
|
|
156
156
|
}
|
|
@@ -162,10 +162,11 @@ function InviteUserDialog({ children }) {
|
|
|
162
162
|
) }),
|
|
163
163
|
formErrors.form ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_themes.Callout.Root, { color: "red", mt: "4", mb: "-2", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_themes.Callout.Text, { children: formErrors.form }) }) : null,
|
|
164
164
|
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_themes.Flex, { mt: "5", gap: "3", justify: "end", children: [
|
|
165
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
165
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_elements.Dialog.Close, { children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_elements.Button, { variant: "secondary", disabled: inviteUser.isPending, children: "Cancel" }) }),
|
|
166
166
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
167
|
-
import_elements.
|
|
167
|
+
import_elements.Button,
|
|
168
168
|
{
|
|
169
|
+
type: "submit",
|
|
169
170
|
form: formId,
|
|
170
171
|
loading: inviteUser.isPending,
|
|
171
172
|
disabled: rolesQuery.isPending || void 0,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/lib/invite-user-dialog.tsx"],"sourcesContent":["\"use client\";\n\nimport {\n Callout,\n Dialog,\n Flex,\n Select,\n Text,\n VisuallyHidden,\n} from \"@radix-ui/themes\";\nimport * as React from \"react\";\nimport {\n DialogContent,\n PrimaryButton,\n SecondaryButton,\n SelectContent,\n SelectItem,\n SelectTrigger,\n TextField,\n} from \"./elements.js\";\nimport { Label } from \"./elements.js\";\nimport { isErrorLike } from \"./utils.js\";\nimport { useInviteUser } from \"./api/user.js\";\nimport { InviteMemberInput, MemberRole, useRoles } from \"../api/endpoint.js\";\n\n/**\n * Used to stub a fake value for the role select. It will be selected by default\n * before the role query resolves, or if the query results in an error. We do\n * this because we need to provide _any_ value to the select to avoid\n * controlled/uncontrolled bugs.\n */\nconst PLACEHOLDER_ROLE = \"_rolePlaceholder\";\n\ninterface InviteUserDialogProps {\n children?: React.ReactNode;\n}\n\nexport function InviteUserDialog({ children }: InviteUserDialogProps) {\n const [open, setOpen] = React.useState(false);\n const dialogId = toId(\"invite-user\", React.useId());\n const formId = toId(dialogId, \"form\");\n\n const inviteUser = useInviteUser();\n const rolesQuery = useRoles({\n query: { initialData: [] },\n });\n const roles = rolesQuery.data;\n const [selectedRole, setSelectedRole] = React.useState(\n () => getDefaultRole(roles)?.slug || PLACEHOLDER_ROLE,\n );\n React.useEffect(() => {\n // Update the selected role if it's not in the list (eg if the list was\n // previously empty and the query resolved)\n setSelectedRole((selectedRole) => {\n if (roles.find((role) => role.slug === selectedRole)) {\n // if current selected role is in the new list, don't change it\n return selectedRole;\n }\n return getDefaultRole(roles)?.slug || PLACEHOLDER_ROLE;\n });\n }, [roles]);\n\n const onSubmitForm = (data: InviteMemberInput) => {\n if (inviteUser.isPending || rolesQuery.status !== \"success\") {\n return;\n }\n inviteUser.mutate(\n { data },\n {\n onSuccess: () => {\n setOpen(false);\n },\n },\n );\n };\n\n const formErrors = getFormErrors(inviteUser.error);\n useFormFieldFocusOnError(dialogId, inviteUser.error);\n\n return (\n <Dialog.Root open={open} onOpenChange={setOpen}>\n {children && <Dialog.Trigger>{children}</Dialog.Trigger>}\n <DialogContent maxWidth=\"480px\" key={String(open)}>\n <Dialog.Title>Invite user</Dialog.Title>\n <Dialog.Description>\n An invitation will be sent to this email address with a link to\n complete their account.\n </Dialog.Description>\n <Flex direction=\"column\" gap=\"4\" mt=\"5\" asChild>\n <form\n id={formId}\n onSubmit={async (event) => {\n event.preventDefault();\n onSubmitForm({\n email: event.currentTarget.email.value,\n roles: [selectedRole],\n });\n }}\n >\n <FormField\n rootId={dialogId}\n name=\"email\"\n label=\"Email address\"\n error={formErrors.fields.email}\n required\n control={(props) => (\n <TextField\n {...props}\n data-1p-ignore=\"true\"\n data-lpignore=\"true\"\n type=\"email\"\n autoComplete=\"off\"\n placeholder=\"Enter an email address\"\n />\n )}\n />\n\n <FormField\n rootId={dialogId}\n name=\"role\"\n label=\"Role\"\n error={formErrors.fields.role}\n disabled={rolesQuery.isPending || roles.length <= 1}\n info={\n roles.length === 1 ? (\n <>\n New users will be invited with the{\" \"}\n <Text weight=\"bold\">{roles[0].name}</Text> role, as it is\n the only one available.\n </>\n ) : undefined\n }\n control={({\n id,\n \"aria-invalid\": ariaInvalid,\n \"aria-describedby\": ariaDescribedBy,\n ...props\n }) => (\n <Select.Root\n {...props}\n value={selectedRole}\n onValueChange={setSelectedRole}\n >\n <SelectTrigger\n id={id}\n aria-invalid={ariaInvalid}\n aria-describedby={ariaDescribedBy}\n />\n <SelectContent>\n <SelectItem value={PLACEHOLDER_ROLE} disabled>\n Select a role\n </SelectItem>\n {roles.map((role) => (\n <SelectItem key={role.slug} value={role.slug}>\n {role.name}\n </SelectItem>\n ))}\n </SelectContent>\n </Select.Root>\n )}\n />\n </form>\n </Flex>\n\n {formErrors.form ? (\n <Callout.Root color=\"red\" mt=\"4\" mb=\"-2\">\n <Callout.Text>{formErrors.form}</Callout.Text>\n </Callout.Root>\n ) : null}\n\n <Flex mt=\"5\" gap=\"3\" justify=\"end\">\n <Dialog.Close>\n <SecondaryButton disabled={inviteUser.isPending}>\n Cancel\n </SecondaryButton>\n </Dialog.Close>\n <PrimaryButton\n form={formId}\n loading={inviteUser.isPending}\n disabled={rolesQuery.isPending || undefined}\n >\n Invite\n </PrimaryButton>\n </Flex>\n {/* mirror errors in a live region */}\n <VisuallyHidden asChild>\n <section aria-live=\"polite\">{formErrors.form}</section>\n </VisuallyHidden>\n </DialogContent>\n </Dialog.Root>\n );\n}\n\ninterface FormControlRenderProps {\n id: string;\n name: string;\n \"aria-describedby\": string | undefined;\n \"aria-invalid\"?: boolean;\n required: boolean | undefined;\n disabled: boolean | undefined;\n}\n\nfunction FormField({\n rootId,\n name,\n label,\n error,\n info,\n control,\n required,\n disabled,\n}: {\n rootId: string;\n name: string;\n label: string;\n error?: React.ReactNode;\n info?: React.ReactNode;\n control: (props: FormControlRenderProps) => React.ReactNode;\n required?: boolean;\n disabled?: boolean;\n}) {\n const fieldId = toId(rootId, name);\n const errorId = toId(rootId, name, \"error\");\n const infoId = toId(rootId, name, \"info\");\n return (\n <Flex direction=\"column\" gap=\"1\">\n <Label htmlFor={fieldId}>{label}</Label>\n {control({\n id: fieldId,\n name,\n \"aria-describedby\": (() => {\n const tags: string[] = [];\n if (error) {\n tags.push(errorId);\n }\n if (info) {\n tags.push(infoId);\n }\n if (tags.length === 0) {\n return undefined;\n }\n return tags.join(\" \");\n })(),\n \"aria-invalid\": !!error || undefined,\n required: required || undefined,\n disabled: disabled || undefined,\n })}\n\n {error ? (\n <Text color=\"red\" size=\"2\" id={errorId}>\n {error}\n </Text>\n ) : null}\n {info ? (\n <Text color=\"gray\" size=\"2\" id={infoId} mt=\"1\">\n {info}\n </Text>\n ) : null}\n </Flex>\n );\n}\n\nfunction toId(...parts: string[]) {\n return parts.join(\"-\");\n}\n\nfunction getFormErrors(queryError: unknown) {\n const formErrors = {\n form: null as string | null,\n fields: {\n email: null as string | null,\n role: null as string | null,\n },\n };\n\n if (queryError) {\n if (!isErrorLike(queryError)) {\n return {\n ...formErrors,\n form: \"An unexpected error occurred. Please try again.\",\n };\n }\n\n switch (queryError.message.toLowerCase()) {\n case \"user already exists\":\n case \"user already invited\":\n case \"invalid email\":\n formErrors.fields.email = queryError.message;\n break;\n case \"invalid role\":\n formErrors.fields.role = queryError.message;\n break;\n default:\n // TODO handle more cases for various server errors\n formErrors.form =\n \"There was an error inviting this user. Please refresh the page and try again.\";\n break;\n }\n }\n\n return formErrors;\n}\n\nfunction useFormFieldFocusOnError(dialogId: string, queryError: unknown) {\n React.useEffect(() => {\n const fieldErrors = getFormErrors(queryError).fields;\n for (const [name, error] of Object.entries(fieldErrors)) {\n if (error) {\n const fieldElement = document.getElementById(toId(dialogId, name)) as\n | HTMLInputElement\n | HTMLButtonElement\n | null;\n if (fieldElement) {\n fieldElement?.focus();\n if (\"select\" in fieldElement) {\n fieldElement.select();\n }\n }\n break;\n }\n }\n }, [dialogId, queryError]);\n}\n\nfunction getDefaultRole(roles: MemberRole[]) {\n return roles.find((role) => role.default) || roles[0];\n}\n"],"mappings":"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","names":["import_elements","selectedRole"]}
|
|
1
|
+
{"version":3,"sources":["../../../src/lib/invite-user-dialog.tsx"],"sourcesContent":["\"use client\";\n\nimport { Callout, Flex, Text, VisuallyHidden } from \"@radix-ui/themes\";\nimport * as React from \"react\";\nimport { Dialog, Button, Select, TextField } from \"./elements.js\";\nimport { Label } from \"./elements.js\";\nimport { isErrorLike } from \"./utils.js\";\nimport { useInviteUser } from \"./api/user.js\";\nimport { InviteMemberInput, MemberRole, useRoles } from \"../api/endpoint.js\";\n\n/**\n * Used to stub a fake value for the role select. It will be selected by default\n * before the role query resolves, or if the query results in an error. We do\n * this because we need to provide _any_ value to the select to avoid\n * controlled/uncontrolled bugs.\n */\nconst PLACEHOLDER_ROLE = \"_rolePlaceholder\";\n\ninterface InviteUserDialogProps {\n children?: React.ReactNode;\n}\n\nexport function InviteUserDialog({ children }: InviteUserDialogProps) {\n const [open, setOpen] = React.useState(false);\n const dialogId = toId(\"invite-user\", React.useId());\n const formId = toId(dialogId, \"form\");\n\n const inviteUser = useInviteUser();\n const rolesQuery = useRoles({\n query: { initialData: [] },\n });\n const roles = rolesQuery.data;\n const [selectedRole, setSelectedRole] = React.useState(\n () => getDefaultRole(roles)?.slug || PLACEHOLDER_ROLE,\n );\n React.useEffect(() => {\n // Update the selected role if it's not in the list (eg if the list was\n // previously empty and the query resolved)\n setSelectedRole((selectedRole) => {\n if (roles.find((role) => role.slug === selectedRole)) {\n // if current selected role is in the new list, don't change it\n return selectedRole;\n }\n return getDefaultRole(roles)?.slug || PLACEHOLDER_ROLE;\n });\n }, [roles]);\n\n const onSubmitForm = (data: InviteMemberInput) => {\n if (inviteUser.isPending || rolesQuery.status !== \"success\") {\n return;\n }\n inviteUser.mutate(\n { data },\n {\n onSuccess: () => {\n setOpen(false);\n },\n },\n );\n };\n\n const formErrors = getFormErrors(inviteUser.error);\n useFormFieldFocusOnError(dialogId, inviteUser.error);\n\n return (\n <Dialog.Root open={open} onOpenChange={setOpen}>\n {children && <Dialog.Trigger>{children}</Dialog.Trigger>}\n <Dialog.Content maxWidth=\"480px\" key={String(open)}>\n <Dialog.Title>Invite user</Dialog.Title>\n <Dialog.Description>\n An invitation will be sent to this email address with a link to\n complete their account.\n </Dialog.Description>\n <Flex direction=\"column\" gap=\"4\" mt=\"5\" asChild>\n <form\n id={formId}\n onSubmit={async (event) => {\n event.preventDefault();\n onSubmitForm({\n email: event.currentTarget.email.value,\n roles: [selectedRole],\n });\n }}\n >\n <FormField\n rootId={dialogId}\n name=\"email\"\n label=\"Email address\"\n error={formErrors.fields.email}\n required\n control={(props) => (\n <TextField\n {...props}\n data-1p-ignore=\"true\"\n data-lpignore=\"true\"\n type=\"email\"\n autoComplete=\"off\"\n placeholder=\"Enter an email address\"\n />\n )}\n />\n\n <FormField\n rootId={dialogId}\n name=\"role\"\n label=\"Role\"\n error={formErrors.fields.role}\n disabled={rolesQuery.isPending || roles.length <= 1}\n info={\n roles.length === 1 ? (\n <>\n New users will be invited with the{\" \"}\n <Text weight=\"bold\">{roles[0].name}</Text> role, as it is\n the only one available.\n </>\n ) : undefined\n }\n control={({\n id,\n \"aria-invalid\": ariaInvalid,\n \"aria-describedby\": ariaDescribedBy,\n ...props\n }) => (\n <Select.Root\n {...props}\n value={selectedRole}\n onValueChange={setSelectedRole}\n >\n <Select.Trigger\n id={id}\n aria-invalid={ariaInvalid}\n aria-describedby={ariaDescribedBy}\n />\n <Select.Content>\n <Select.Item value={PLACEHOLDER_ROLE} disabled>\n Select a role\n </Select.Item>\n {roles.map((role) => (\n <Select.Item key={role.slug} value={role.slug}>\n {role.name}\n </Select.Item>\n ))}\n </Select.Content>\n </Select.Root>\n )}\n />\n </form>\n </Flex>\n\n {formErrors.form ? (\n <Callout.Root color=\"red\" mt=\"4\" mb=\"-2\">\n <Callout.Text>{formErrors.form}</Callout.Text>\n </Callout.Root>\n ) : null}\n\n <Flex mt=\"5\" gap=\"3\" justify=\"end\">\n <Dialog.Close>\n <Button variant=\"secondary\" disabled={inviteUser.isPending}>\n Cancel\n </Button>\n </Dialog.Close>\n <Button\n type=\"submit\"\n form={formId}\n loading={inviteUser.isPending}\n disabled={rolesQuery.isPending || undefined}\n >\n Invite\n </Button>\n </Flex>\n {/* mirror errors in a live region */}\n <VisuallyHidden asChild>\n <section aria-live=\"polite\">{formErrors.form}</section>\n </VisuallyHidden>\n </Dialog.Content>\n </Dialog.Root>\n );\n}\n\ninterface FormControlRenderProps {\n id: string;\n name: string;\n \"aria-describedby\": string | undefined;\n \"aria-invalid\"?: boolean;\n required: boolean | undefined;\n disabled: boolean | undefined;\n}\n\nfunction FormField({\n rootId,\n name,\n label,\n error,\n info,\n control,\n required,\n disabled,\n}: {\n rootId: string;\n name: string;\n label: string;\n error?: React.ReactNode;\n info?: React.ReactNode;\n control: (props: FormControlRenderProps) => React.ReactNode;\n required?: boolean;\n disabled?: boolean;\n}) {\n const fieldId = toId(rootId, name);\n const errorId = toId(rootId, name, \"error\");\n const infoId = toId(rootId, name, \"info\");\n return (\n <Flex direction=\"column\" gap=\"1\">\n <Label htmlFor={fieldId}>{label}</Label>\n {control({\n id: fieldId,\n name,\n \"aria-describedby\": (() => {\n const tags: string[] = [];\n if (error) {\n tags.push(errorId);\n }\n if (info) {\n tags.push(infoId);\n }\n if (tags.length === 0) {\n return undefined;\n }\n return tags.join(\" \");\n })(),\n \"aria-invalid\": !!error || undefined,\n required: required || undefined,\n disabled: disabled || undefined,\n })}\n\n {error ? (\n <Text color=\"red\" size=\"2\" id={errorId}>\n {error}\n </Text>\n ) : null}\n {info ? (\n <Text color=\"gray\" size=\"2\" id={infoId} mt=\"1\">\n {info}\n </Text>\n ) : null}\n </Flex>\n );\n}\n\nfunction toId(...parts: string[]) {\n return parts.join(\"-\");\n}\n\nfunction getFormErrors(queryError: unknown) {\n const formErrors = {\n form: null as string | null,\n fields: {\n email: null as string | null,\n role: null as string | null,\n },\n };\n\n if (queryError) {\n if (!isErrorLike(queryError)) {\n return {\n ...formErrors,\n form: \"An unexpected error occurred. Please try again.\",\n };\n }\n\n switch (queryError.message.toLowerCase()) {\n case \"user already exists\":\n case \"user already invited\":\n case \"invalid email\":\n formErrors.fields.email = queryError.message;\n break;\n case \"invalid role\":\n formErrors.fields.role = queryError.message;\n break;\n default:\n // TODO handle more cases for various server errors\n formErrors.form =\n \"There was an error inviting this user. Please refresh the page and try again.\";\n break;\n }\n }\n\n return formErrors;\n}\n\nfunction useFormFieldFocusOnError(dialogId: string, queryError: unknown) {\n React.useEffect(() => {\n const fieldErrors = getFormErrors(queryError).fields;\n for (const [name, error] of Object.entries(fieldErrors)) {\n if (error) {\n const fieldElement = document.getElementById(toId(dialogId, name)) as\n | HTMLInputElement\n | HTMLButtonElement\n | null;\n if (fieldElement) {\n fieldElement?.focus();\n if (\"select\" in fieldElement) {\n fieldElement.select();\n }\n }\n break;\n }\n }\n }, [dialogId, queryError]);\n}\n\nfunction getDefaultRole(roles: MemberRole[]) {\n return roles.find((role) => role.default) || roles[0];\n}\n"],"mappings":"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","names":["import_elements","selectedRole"]}
|
|
@@ -57,9 +57,9 @@ function LogoutAllSessionsDialog({
|
|
|
57
57
|
queryKey: (0, import_endpoint.getSessionsQueryKey)()
|
|
58
58
|
});
|
|
59
59
|
}, [client, onOpenChange]);
|
|
60
|
-
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
61
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
62
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
60
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_elements.AlertDialog.Root, { open, onOpenChange, ...props, children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_elements.AlertDialog.Content, { maxWidth: "480px", children: [
|
|
61
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_elements.AlertDialog.Title, { children: "Sign out of all other devices?" }),
|
|
62
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_elements.AlertDialog.Description, { children: "You will be logged out of all other active sessions on other devices, except this one." }),
|
|
63
63
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_themes.Flex, { gap: "3", justify: "end", mt: "5", asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
64
64
|
"form",
|
|
65
65
|
{
|
|
@@ -68,9 +68,10 @@ function LogoutAllSessionsDialog({
|
|
|
68
68
|
onSubmitForm();
|
|
69
69
|
},
|
|
70
70
|
children: [
|
|
71
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
72
|
-
import_elements.
|
|
71
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_elements.AlertDialog.Cancel, { children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
72
|
+
import_elements.Button,
|
|
73
73
|
{
|
|
74
|
+
variant: "secondary",
|
|
74
75
|
disabled: revokeAllSessions.isPending || revokeAllSessions.isSuccess,
|
|
75
76
|
children: "Cancel"
|
|
76
77
|
}
|
|
@@ -82,7 +83,7 @@ function LogoutAllSessionsDialog({
|
|
|
82
83
|
loading: revokeAllSessions.isPending,
|
|
83
84
|
done: revokeAllSessions.isSuccess,
|
|
84
85
|
onDone: handleDone,
|
|
85
|
-
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_elements.
|
|
86
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_elements.Button, { variant: "destructive", type: "submit", children: "Sign out" })
|
|
86
87
|
}
|
|
87
88
|
)
|
|
88
89
|
]
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/lib/logout-all-sessions-dialog.tsx"],"sourcesContent":["\"use client\";\n\nimport * as React from \"react\";\nimport {
|
|
1
|
+
{"version":3,"sources":["../../../src/lib/logout-all-sessions-dialog.tsx"],"sourcesContent":["\"use client\";\n\nimport * as React from \"react\";\nimport { Flex } from \"@radix-ui/themes\";\nimport { type ReactNode } from \"react\";\nimport { AlertDialog, Button } from \"./elements.js\";\nimport { getSessionsQueryKey, useRevokeAllSessions } from \"../api/endpoint.js\";\nimport { useQueryClient } from \"@tanstack/react-query\";\nimport { SaveButton } from \"./save-button.js\";\n\ninterface LogoutAllSessionsDialogProps extends AlertDialog.RootProps {\n children?: ReactNode;\n currentSessionId: string;\n}\n\nexport function LogoutAllSessionsDialog({\n open,\n onOpenChange,\n children,\n currentSessionId,\n ...props\n}: LogoutAllSessionsDialogProps) {\n const client = useQueryClient();\n\n const revokeAllSessions = useRevokeAllSessions();\n\n const onSubmitForm = () => {\n revokeAllSessions.mutate({ data: { currentSessionId } });\n };\n\n const handleDone = React.useCallback(() => {\n onOpenChange?.(false);\n\n client.invalidateQueries({\n queryKey: getSessionsQueryKey(),\n });\n }, [client, onOpenChange]);\n\n return (\n <AlertDialog.Root open={open} onOpenChange={onOpenChange} {...props}>\n <AlertDialog.Content maxWidth=\"480px\">\n <AlertDialog.Title>Sign out of all other devices?</AlertDialog.Title>\n <AlertDialog.Description>\n You will be logged out of all other active sessions on other devices,\n except this one.\n </AlertDialog.Description>\n\n <Flex gap=\"3\" justify=\"end\" mt=\"5\" asChild>\n <form\n onSubmit={(event) => {\n event.preventDefault();\n onSubmitForm();\n }}\n >\n <AlertDialog.Cancel>\n <Button\n variant=\"secondary\"\n disabled={\n revokeAllSessions.isPending || revokeAllSessions.isSuccess\n }\n >\n Cancel\n </Button>\n </AlertDialog.Cancel>\n\n <SaveButton\n asChild\n loading={revokeAllSessions.isPending}\n done={revokeAllSessions.isSuccess}\n onDone={handleDone}\n >\n <Button variant=\"destructive\" type=\"submit\">\n Sign out\n </Button>\n </SaveButton>\n </form>\n </Flex>\n </AlertDialog.Content>\n </AlertDialog.Root>\n );\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAyCQ;AAvCR,YAAuB;AACvB,oBAAqB;AAErB,sBAAoC;AACpC,sBAA0D;AAC1D,yBAA+B;AAC/B,yBAA2B;AAOpB,SAAS,wBAAwB;AAAA,EACtC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,GAAG;AACL,GAAiC;AAC/B,QAAM,aAAS,mCAAe;AAE9B,QAAM,wBAAoB,sCAAqB;AAE/C,QAAM,eAAe,MAAM;AACzB,sBAAkB,OAAO,EAAE,MAAM,EAAE,iBAAiB,EAAE,CAAC;AAAA,EACzD;AAEA,QAAM,aAAa,MAAM,YAAY,MAAM;AACzC,mBAAe,KAAK;AAEpB,WAAO,kBAAkB;AAAA,MACvB,cAAU,qCAAoB;AAAA,IAChC,CAAC;AAAA,EACH,GAAG,CAAC,QAAQ,YAAY,CAAC;AAEzB,SACE,4CAAC,4BAAY,MAAZ,EAAiB,MAAY,cAA6B,GAAG,OAC5D,uDAAC,4BAAY,SAAZ,EAAoB,UAAS,SAC5B;AAAA,gDAAC,4BAAY,OAAZ,EAAkB,4CAA8B;AAAA,IACjD,4CAAC,4BAAY,aAAZ,EAAwB,oGAGzB;AAAA,IAEA,4CAAC,sBAAK,KAAI,KAAI,SAAQ,OAAM,IAAG,KAAI,SAAO,MACxC;AAAA,MAAC;AAAA;AAAA,QACC,UAAU,CAAC,UAAU;AACnB,gBAAM,eAAe;AACrB,uBAAa;AAAA,QACf;AAAA,QAEA;AAAA,sDAAC,4BAAY,QAAZ,EACC;AAAA,YAAC;AAAA;AAAA,cACC,SAAQ;AAAA,cACR,UACE,kBAAkB,aAAa,kBAAkB;AAAA,cAEpD;AAAA;AAAA,UAED,GACF;AAAA,UAEA;AAAA,YAAC;AAAA;AAAA,cACC,SAAO;AAAA,cACP,SAAS,kBAAkB;AAAA,cAC3B,MAAM,kBAAkB;AAAA,cACxB,QAAQ;AAAA,cAER,sDAAC,0BAAO,SAAQ,eAAc,MAAK,UAAS,sBAE5C;AAAA;AAAA,UACF;AAAA;AAAA;AAAA,IACF,GACF;AAAA,KACF,GACF;AAEJ;","names":[]}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
-
import { AlertDialog } from '@radix-ui/themes';
|
|
3
2
|
import { ReactNode } from 'react';
|
|
3
|
+
import { RootProps } from '@radix-ui/themes/components/alert-dialog';
|
|
4
4
|
|
|
5
|
-
interface LogoutAllSessionsDialogProps extends
|
|
5
|
+
interface LogoutAllSessionsDialogProps extends RootProps {
|
|
6
6
|
children?: ReactNode;
|
|
7
7
|
currentSessionId: string;
|
|
8
8
|
}
|
|
@@ -63,9 +63,9 @@ function LogoutDialog({
|
|
|
63
63
|
sessionId: session.id
|
|
64
64
|
});
|
|
65
65
|
};
|
|
66
|
-
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
67
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
68
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
66
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_elements.AlertDialog.Root, { open, onOpenChange, ...props, children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_elements.AlertDialog.Content, { maxWidth: "480px", children: [
|
|
67
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_elements.AlertDialog.Title, { children: "Sign out of device?" }),
|
|
68
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_elements.AlertDialog.Description, { children: [
|
|
69
69
|
"You will be signed out of ",
|
|
70
70
|
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_themes.Strong, { children: [
|
|
71
71
|
device,
|
|
@@ -80,9 +80,10 @@ function LogoutDialog({
|
|
|
80
80
|
onSubmitForm();
|
|
81
81
|
},
|
|
82
82
|
children: [
|
|
83
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
84
|
-
import_elements.
|
|
83
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_elements.AlertDialog.Cancel, { children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
84
|
+
import_elements.Button,
|
|
85
85
|
{
|
|
86
|
+
variant: "secondary",
|
|
86
87
|
disabled: revokeSession.isPending || revokeSession.isSuccess,
|
|
87
88
|
children: "Cancel"
|
|
88
89
|
}
|
|
@@ -94,7 +95,7 @@ function LogoutDialog({
|
|
|
94
95
|
loading: revokeSession.isPending,
|
|
95
96
|
done: revokeSession.isSuccess,
|
|
96
97
|
onDone: handleDone,
|
|
97
|
-
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_elements.
|
|
98
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_elements.Button, { variant: "destructive", type: "submit", children: "Sign out" })
|
|
98
99
|
}
|
|
99
100
|
)
|
|
100
101
|
]
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/lib/logout-dialog.tsx"],"sourcesContent":["\"use client\";\n\nimport * as React from \"react\";\nimport {
|
|
1
|
+
{"version":3,"sources":["../../../src/lib/logout-dialog.tsx"],"sourcesContent":["\"use client\";\n\nimport * as React from \"react\";\nimport { Flex, Strong } from \"@radix-ui/themes\";\nimport { type ReactNode } from \"react\";\nimport { AlertDialog, Button } from \"./elements.js\";\nimport {\n ActiveSession,\n getSessionsQueryKey,\n useRevokeSession,\n} from \"../api/endpoint.js\";\nimport { useQueryClient } from \"@tanstack/react-query\";\nimport { SaveButton } from \"./save-button.js\";\nimport { parseUserAgent } from \"./utils.js\";\n\ninterface LogoutDialogProps extends AlertDialog.RootProps {\n children?: ReactNode;\n session: ActiveSession;\n}\n\nexport function LogoutDialog({\n children,\n session,\n open,\n onOpenChange,\n ...props\n}: LogoutDialogProps) {\n const client = useQueryClient();\n const userAgent = parseUserAgent(session.userAgent);\n const device = userAgent.pretty;\n\n const revokeSession = useRevokeSession();\n\n const handleDone = React.useCallback(() => {\n onOpenChange?.(false);\n\n client.invalidateQueries({\n queryKey: getSessionsQueryKey(),\n exact: false,\n });\n }, [onOpenChange, client]);\n\n const onSubmitForm = () => {\n revokeSession.mutate({\n sessionId: session.id,\n });\n };\n\n return (\n <AlertDialog.Root open={open} onOpenChange={onOpenChange} {...props}>\n <AlertDialog.Content maxWidth=\"480px\">\n <AlertDialog.Title>Sign out of device?</AlertDialog.Title>\n <AlertDialog.Description>\n You will be signed out of <Strong>{device}.</Strong>\n </AlertDialog.Description>\n\n <Flex gap=\"3\" justify=\"end\" mt=\"5\" asChild>\n <form\n onSubmit={(event) => {\n event.preventDefault();\n onSubmitForm();\n }}\n >\n <AlertDialog.Cancel>\n <Button\n variant=\"secondary\"\n disabled={revokeSession.isPending || revokeSession.isSuccess}\n >\n Cancel\n </Button>\n </AlertDialog.Cancel>\n\n <SaveButton\n asChild\n loading={revokeSession.isPending}\n done={revokeSession.isSuccess}\n onDone={handleDone}\n >\n <Button variant=\"destructive\" type=\"submit\">\n Sign out\n </Button>\n </SaveButton>\n </form>\n </Flex>\n </AlertDialog.Content>\n </AlertDialog.Root>\n );\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAmDQ;AAjDR,YAAuB;AACvB,oBAA6B;AAE7B,sBAAoC;AACpC,sBAIO;AACP,yBAA+B;AAC/B,yBAA2B;AAC3B,mBAA+B;AAOxB,SAAS,aAAa;AAAA,EAC3B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,GAAG;AACL,GAAsB;AACpB,QAAM,aAAS,mCAAe;AAC9B,QAAM,gBAAY,6BAAe,QAAQ,SAAS;AAClD,QAAM,SAAS,UAAU;AAEzB,QAAM,oBAAgB,kCAAiB;AAEvC,QAAM,aAAa,MAAM,YAAY,MAAM;AACzC,mBAAe,KAAK;AAEpB,WAAO,kBAAkB;AAAA,MACvB,cAAU,qCAAoB;AAAA,MAC9B,OAAO;AAAA,IACT,CAAC;AAAA,EACH,GAAG,CAAC,cAAc,MAAM,CAAC;AAEzB,QAAM,eAAe,MAAM;AACzB,kBAAc,OAAO;AAAA,MACnB,WAAW,QAAQ;AAAA,IACrB,CAAC;AAAA,EACH;AAEA,SACE,4CAAC,4BAAY,MAAZ,EAAiB,MAAY,cAA6B,GAAG,OAC5D,uDAAC,4BAAY,SAAZ,EAAoB,UAAS,SAC5B;AAAA,gDAAC,4BAAY,OAAZ,EAAkB,iCAAmB;AAAA,IACtC,6CAAC,4BAAY,aAAZ,EAAwB;AAAA;AAAA,MACG,6CAAC,wBAAQ;AAAA;AAAA,QAAO;AAAA,SAAC;AAAA,OAC7C;AAAA,IAEA,4CAAC,sBAAK,KAAI,KAAI,SAAQ,OAAM,IAAG,KAAI,SAAO,MACxC;AAAA,MAAC;AAAA;AAAA,QACC,UAAU,CAAC,UAAU;AACnB,gBAAM,eAAe;AACrB,uBAAa;AAAA,QACf;AAAA,QAEA;AAAA,sDAAC,4BAAY,QAAZ,EACC;AAAA,YAAC;AAAA;AAAA,cACC,SAAQ;AAAA,cACR,UAAU,cAAc,aAAa,cAAc;AAAA,cACpD;AAAA;AAAA,UAED,GACF;AAAA,UAEA;AAAA,YAAC;AAAA;AAAA,cACC,SAAO;AAAA,cACP,SAAS,cAAc;AAAA,cACvB,MAAM,cAAc;AAAA,cACpB,QAAQ;AAAA,cAER,sDAAC,0BAAO,SAAQ,eAAc,MAAK,UAAS,sBAE5C;AAAA;AAAA,UACF;AAAA;AAAA;AAAA,IACF,GACF;AAAA,KACF,GACF;AAEJ;","names":[]}
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
-
import { AlertDialog } from '@radix-ui/themes';
|
|
3
2
|
import { ReactNode } from 'react';
|
|
3
|
+
import { RootProps } from '@radix-ui/themes/components/alert-dialog';
|
|
4
4
|
import { ActiveSession } from '../api/endpoint.cjs';
|
|
5
5
|
import '@tanstack/react-query';
|
|
6
6
|
import '../api/widgets-api-client.cjs';
|
|
7
7
|
|
|
8
|
-
interface LogoutDialogProps extends
|
|
8
|
+
interface LogoutDialogProps extends RootProps {
|
|
9
9
|
children?: ReactNode;
|
|
10
10
|
session: ActiveSession;
|
|
11
11
|
}
|
|
@@ -40,10 +40,12 @@ var import_themes = require("@radix-ui/themes");
|
|
|
40
40
|
var import_clsx = __toESM(require("clsx"), 1);
|
|
41
41
|
var import_utils = require("./utils.js");
|
|
42
42
|
var import_generic_error = require("./generic-error.js");
|
|
43
|
+
var import_elements = require("./elements.js");
|
|
44
|
+
var import_utils2 = require("../utils.js");
|
|
43
45
|
const OrganizationSwitcher = ({
|
|
44
46
|
organizations,
|
|
45
47
|
switchToOrganization,
|
|
46
|
-
variant
|
|
48
|
+
variant,
|
|
47
49
|
organizationLabel = "Organizations",
|
|
48
50
|
truncateBehavior = "right",
|
|
49
51
|
children,
|
|
@@ -52,15 +54,16 @@ const OrganizationSwitcher = ({
|
|
|
52
54
|
const currentOrganization = organizations.find(
|
|
53
55
|
(organization) => organization.current
|
|
54
56
|
);
|
|
57
|
+
const invalidateAllWidgets = (0, import_utils2.unstable_useWidgetsInvalidator)();
|
|
55
58
|
if (!currentOrganization) {
|
|
56
59
|
return null;
|
|
57
60
|
}
|
|
58
|
-
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
59
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
60
|
-
|
|
61
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_elements.DropdownMenu.Root, { children: [
|
|
62
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_elements.DropdownMenu.Trigger, { children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
63
|
+
import_elements.Button,
|
|
61
64
|
{
|
|
62
|
-
|
|
63
|
-
variant,
|
|
65
|
+
variant: "secondary",
|
|
66
|
+
...mapVariantProps(variant),
|
|
64
67
|
...getWidgetRootDomProps("resolved", {
|
|
65
68
|
...domProps,
|
|
66
69
|
// TODO: Remove `OrganizationSwitcherTrigger` in the next major
|
|
@@ -85,15 +88,15 @@ const OrganizationSwitcher = ({
|
|
|
85
88
|
truncateBehavior
|
|
86
89
|
}
|
|
87
90
|
),
|
|
88
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_themes.Flex, { asChild: true, flexShrink: "0", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
91
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_themes.Flex, { asChild: true, flexShrink: "0", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_elements.DropdownMenu.TriggerIcon, {}) })
|
|
89
92
|
]
|
|
90
93
|
}
|
|
91
94
|
)
|
|
92
95
|
}
|
|
93
96
|
) }),
|
|
94
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
95
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
96
|
-
organizationLabel ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
97
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_elements.DropdownMenu.Content, { children: [
|
|
98
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_elements.DropdownMenu.Group, { children: [
|
|
99
|
+
organizationLabel ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_elements.DropdownMenu.Label, { children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_themes.Text, { children: organizationLabel }) }) : null,
|
|
97
100
|
organizations.map((organization) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
98
101
|
import_themes.Flex,
|
|
99
102
|
{
|
|
@@ -102,11 +105,18 @@ const OrganizationSwitcher = ({
|
|
|
102
105
|
maxWidth: "280px",
|
|
103
106
|
minWidth: "180px",
|
|
104
107
|
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
105
|
-
|
|
108
|
+
import_elements.DropdownMenu.Item,
|
|
106
109
|
{
|
|
107
110
|
onClick: () => {
|
|
108
111
|
if (organization.id !== currentOrganization.id) {
|
|
109
|
-
switchToOrganization({
|
|
112
|
+
const result = switchToOrganization({
|
|
113
|
+
organizationId: organization.id
|
|
114
|
+
});
|
|
115
|
+
if ((0, import_utils.isPromiseLike)(result)) {
|
|
116
|
+
result.then(invalidateAllWidgets);
|
|
117
|
+
} else {
|
|
118
|
+
invalidateAllWidgets();
|
|
119
|
+
}
|
|
110
120
|
}
|
|
111
121
|
},
|
|
112
122
|
children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
@@ -152,18 +162,18 @@ const OrganizationSwitcher = ({
|
|
|
152
162
|
] })
|
|
153
163
|
] });
|
|
154
164
|
};
|
|
155
|
-
const OrganizationSwitcherLoading = (props) => {
|
|
165
|
+
const OrganizationSwitcherLoading = ({ variant, ...props }) => {
|
|
156
166
|
return (
|
|
157
167
|
// Always need DropdownMenu.Root to wrap children than may include
|
|
158
168
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
159
|
-
|
|
169
|
+
import_elements.Button,
|
|
160
170
|
{
|
|
161
|
-
|
|
162
|
-
variant: "outline",
|
|
171
|
+
variant: "secondary",
|
|
163
172
|
disabled: true,
|
|
173
|
+
...mapVariantProps(variant),
|
|
164
174
|
...getWidgetRootDomProps("loading", props),
|
|
165
175
|
children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_themes.Flex, { align: "center", gap: "2", children: [
|
|
166
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
176
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_elements.Skeleton, { children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_themes.Text, { children: "Loading..." }) }),
|
|
167
177
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_themes.ChevronDownIcon, {})
|
|
168
178
|
] })
|
|
169
179
|
}
|
|
@@ -172,15 +182,16 @@ const OrganizationSwitcherLoading = (props) => {
|
|
|
172
182
|
};
|
|
173
183
|
function OrganizationSwitcherError({
|
|
174
184
|
error,
|
|
185
|
+
variant,
|
|
175
186
|
...domProps
|
|
176
187
|
}) {
|
|
177
188
|
const { heading } = (0, import_generic_error.getErrorMessage)(error);
|
|
178
189
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
179
|
-
|
|
190
|
+
import_elements.Button,
|
|
180
191
|
{
|
|
181
|
-
|
|
182
|
-
variant: "outline",
|
|
192
|
+
variant: "secondary",
|
|
183
193
|
disabled: true,
|
|
194
|
+
...mapVariantProps(variant),
|
|
184
195
|
...getWidgetRootDomProps("error", domProps),
|
|
185
196
|
children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_themes.Flex, { align: "center", gap: "2", children: [
|
|
186
197
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_themes.Text, { children: heading }),
|
|
@@ -224,6 +235,13 @@ const TruncatedOrganizationName = ({
|
|
|
224
235
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_themes.Text, { "aria-hidden": true, children: organizationNameRight })
|
|
225
236
|
] });
|
|
226
237
|
};
|
|
238
|
+
function mapVariantProps(variant) {
|
|
239
|
+
const variantProps = {};
|
|
240
|
+
if (variant) {
|
|
241
|
+
variantProps.unsafe_radixVariant = variant;
|
|
242
|
+
}
|
|
243
|
+
return variantProps;
|
|
244
|
+
}
|
|
227
245
|
function getWidgetRootDomProps(state, domProps) {
|
|
228
246
|
return (0, import_utils.getDomProps)({
|
|
229
247
|
...domProps,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/lib/organization-switcher.tsx"],"sourcesContent":["\"use client\";\n\nimport { CheckIcon } from \"@radix-ui/react-icons\";\nimport {\n Box,\n Button,\n ChevronDownIcon,\n DropdownMenu,\n Flex,\n Skeleton,\n Text,\n VisuallyHidden,\n} from \"@radix-ui/themes\";\nimport type { OrganizationInfo } from \"../api/endpoint.js\";\nimport cx from \"clsx\";\nimport {\n getDomProps,\n type WidgetRootDomProps,\n type WidgetRootState,\n} from \"./utils.js\";\nimport { getErrorMessage } from \"./generic-error.js\";\n\ntype OrganizationSwitcherVariant = \"ghost\" | \"outline\";\n\n// Rename all uses of `org` to `organization`\ninterface OrganizationSwitcherPassthroughProps extends WidgetRootDomProps {\n switchToOrganization: ({\n organizationId,\n }: {\n organizationId: string;\n }) => void;\n // Simple props to affect the overall style\n variant?: OrganizationSwitcherVariant;\n organizationLabel?: string | null;\n children?: React.ReactNode;\n /**\n * Choose where to truncate organization name in the trigger and dropdown\n * items.\n *\n * - `right`: Truncate the right side of the organization name\n * - `middle`: Truncate the middle of the organization name, trying to keep\n * words whole\n */\n truncateBehavior?: \"right\" | \"middle\";\n}\n\ninterface OrganizationSwitcherProps\n extends OrganizationSwitcherPassthroughProps {\n organizations: OrganizationInfo[];\n}\n\nconst OrganizationSwitcher: React.FC<OrganizationSwitcherProps> = ({\n organizations,\n switchToOrganization,\n variant = \"outline\",\n organizationLabel = \"Organizations\",\n truncateBehavior = \"right\",\n children,\n ...domProps\n}) => {\n const currentOrganization = organizations.find(\n (organization) => organization.current,\n );\n\n // Possible if the user has no organizations - we should figure out what to do in this case\n if (!currentOrganization) {\n return null;\n }\n\n return (\n <DropdownMenu.Root>\n <DropdownMenu.Trigger>\n <Button\n color=\"gray\"\n variant={variant}\n {...getWidgetRootDomProps(\"resolved\", {\n ...domProps,\n // TODO: Remove `OrganizationSwitcherTrigger` in the next major\n // version. This should follow conventions of all other widgets\n // using classnames in getWidgetRootDomProps.\n className: cx(domProps.className, \"OrganizationSwitcherTrigger\"),\n })}\n >\n <Flex\n align=\"center\"\n justify=\"between\"\n gap=\"2\"\n flexGrow=\"1\"\n overflow=\"hidden\"\n minWidth=\"0\"\n >\n <TruncatedOrganizationName\n organizationName={currentOrganization.name}\n truncateBehavior={truncateBehavior}\n />\n <Flex asChild flexShrink=\"0\">\n <DropdownMenu.TriggerIcon />\n </Flex>\n </Flex>\n </Button>\n </DropdownMenu.Trigger>\n <DropdownMenu.Content>\n <DropdownMenu.Group>\n {organizationLabel ? (\n <DropdownMenu.Label>\n <Text>{organizationLabel}</Text>\n </DropdownMenu.Label>\n ) : null}\n {organizations.map((organization) => (\n <Flex\n key={organization.id}\n asChild\n pr=\"2\"\n maxWidth=\"280px\"\n minWidth=\"180px\"\n >\n <DropdownMenu.Item\n onClick={() => {\n if (organization.id !== currentOrganization.id) {\n switchToOrganization({ organizationId: organization.id });\n }\n }}\n >\n <Flex\n justify=\"between\"\n align=\"center\"\n gap=\"4\"\n flexGrow=\"1\"\n overflow=\"hidden\"\n >\n <TruncatedOrganizationName\n organizationName={organization.name}\n truncateBehavior={truncateBehavior}\n />\n {organization.current && (\n <VisuallyHidden> (current)</VisuallyHidden>\n )}\n <Flex\n aria-hidden\n align=\"center\"\n justify=\"center\"\n flexShrink=\"0\"\n >\n {organization.current ? (\n <CheckIcon width=\"18px\" height=\"18px\" />\n ) : (\n // make the extra space for\n <Box width=\"18px\" height=\"18px\" />\n )}\n </Flex>\n </Flex>\n </DropdownMenu.Item>\n </Flex>\n ))}\n </DropdownMenu.Group>\n {children}\n </DropdownMenu.Content>\n </DropdownMenu.Root>\n );\n};\n\ninterface OrganizationSwitcherLoadingProps extends WidgetRootDomProps {}\n\nconst OrganizationSwitcherLoading: React.FC<\n OrganizationSwitcherLoadingProps\n> = (props) => {\n return (\n // Always need DropdownMenu.Root to wrap children than may include\n <Button\n color=\"gray\"\n variant=\"outline\"\n disabled\n {...getWidgetRootDomProps(\"loading\", props)}\n >\n <Flex align=\"center\" gap=\"2\">\n <Skeleton>\n <Text>Loading...</Text>\n </Skeleton>\n <ChevronDownIcon />\n </Flex>\n </Button>\n );\n};\n\ninterface OrganizationSwitcherErrorProps extends WidgetRootDomProps {\n error: unknown;\n}\n\nfunction OrganizationSwitcherError({\n error,\n ...domProps\n}: OrganizationSwitcherErrorProps) {\n const { heading } = getErrorMessage(error);\n return (\n <Button\n color=\"gray\"\n variant=\"outline\"\n disabled\n {...getWidgetRootDomProps(\"error\", domProps)}\n >\n <Flex align=\"center\" gap=\"2\">\n <Text>{heading}</Text>\n <ChevronDownIcon />\n </Flex>\n </Button>\n );\n}\n\nconst MAX_TRUNCATED_SUFFIX_LENGTH = 10;\nconst MIN_TRUNCATED_SUFFIX_LENGTH = 3;\n\nconst WHITE_SPACE_REGEX = /\\s/;\n\nconst getSplitPosition = (organizationName: string) => {\n if (organizationName.length <= MAX_TRUNCATED_SUFFIX_LENGTH) {\n return organizationName.length;\n }\n\n for (\n let i = organizationName.length - MAX_TRUNCATED_SUFFIX_LENGTH;\n i < organizationName.length - MIN_TRUNCATED_SUFFIX_LENGTH;\n i++\n ) {\n if (WHITE_SPACE_REGEX.test(organizationName[i - 1])) {\n return i;\n }\n }\n\n return organizationName.length - MAX_TRUNCATED_SUFFIX_LENGTH;\n};\n\nconst splitOrganizationName = (organizationName: string) => {\n const splitPosition = getSplitPosition(organizationName);\n return [\n organizationName.slice(0, splitPosition),\n organizationName.slice(splitPosition),\n ];\n};\n\nconst TruncatedOrganizationName = ({\n organizationName,\n truncateBehavior,\n}: {\n organizationName: string;\n truncateBehavior: \"right\" | \"middle\";\n}) => {\n if (truncateBehavior === \"right\") {\n return <Text truncate>{organizationName}</Text>;\n }\n\n const [organizationNameLeft, organizationNameRight] =\n splitOrganizationName(organizationName);\n\n return (\n <Flex overflow=\"hidden\">\n <VisuallyHidden>\n <Text>{organizationName}</Text>\n </VisuallyHidden>\n <Text aria-hidden truncate style={{ whiteSpace: \"pre\" }}>\n {organizationNameLeft}\n </Text>\n <Text aria-hidden>{organizationNameRight}</Text>\n </Flex>\n );\n};\n\nfunction getWidgetRootDomProps(\n state: WidgetRootState,\n domProps: WidgetRootDomProps,\n) {\n return getDomProps({\n ...domProps,\n isWidgetRoot: true,\n widgetId: \"organization-switcher\",\n widgetState: state,\n });\n}\n\nexport type {\n OrganizationSwitcherProps,\n OrganizationSwitcherLoadingProps,\n OrganizationSwitcherErrorProps,\n /** @internal */\n OrganizationSwitcherPassthroughProps,\n};\nexport {\n OrganizationSwitcher,\n OrganizationSwitcherLoading,\n OrganizationSwitcherError,\n};\n"],"mappings":"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","names":["cx"]}
|
|
1
|
+
{"version":3,"sources":["../../../src/lib/organization-switcher.tsx"],"sourcesContent":["\"use client\";\n\nimport { CheckIcon } from \"@radix-ui/react-icons\";\nimport {\n Box,\n ChevronDownIcon,\n Flex,\n Text,\n VisuallyHidden,\n} from \"@radix-ui/themes\";\nimport type { OrganizationInfo } from \"../api/endpoint.js\";\nimport cx from \"clsx\";\nimport {\n getDomProps,\n isPromiseLike,\n type WidgetRootDomProps,\n type WidgetRootState,\n} from \"./utils.js\";\nimport { getErrorMessage } from \"./generic-error.js\";\nimport {\n Button,\n type ButtonProps,\n Skeleton,\n DropdownMenu,\n} from \"./elements.js\";\nimport { unstable_useWidgetsInvalidator as useWidgetsInvalidator } from \"../utils.js\";\n\ntype OrganizationSwitcherVariant = \"ghost\" | \"outline\";\n\n// Rename all uses of `org` to `organization`\ninterface OrganizationSwitcherPassthroughProps extends WidgetRootDomProps {\n switchToOrganization: ({\n organizationId,\n }: {\n organizationId: string;\n }) => void | Promise<void>;\n // Simple props to affect the overall style\n variant?: OrganizationSwitcherVariant;\n organizationLabel?: string | null;\n children?: React.ReactNode;\n /**\n * Choose where to truncate organization name in the trigger and dropdown\n * items.\n *\n * - `right`: Truncate the right side of the organization name\n * - `middle`: Truncate the middle of the organization name, trying to keep\n * words whole\n */\n truncateBehavior?: \"right\" | \"middle\";\n}\n\ninterface OrganizationSwitcherProps\n extends OrganizationSwitcherPassthroughProps {\n organizations: OrganizationInfo[];\n}\n\nconst OrganizationSwitcher: React.FC<OrganizationSwitcherProps> = ({\n organizations,\n switchToOrganization,\n variant,\n organizationLabel = \"Organizations\",\n truncateBehavior = \"right\",\n children,\n ...domProps\n}) => {\n const currentOrganization = organizations.find(\n (organization) => organization.current,\n );\n const invalidateAllWidgets = useWidgetsInvalidator();\n\n // TODO: Possible if the user has no organizations - we should figure out what\n // to do in this case\n if (!currentOrganization) {\n return null;\n }\n\n return (\n <DropdownMenu.Root>\n <DropdownMenu.Trigger>\n <Button\n variant=\"secondary\"\n {...mapVariantProps(variant)}\n {...getWidgetRootDomProps(\"resolved\", {\n ...domProps,\n // TODO: Remove `OrganizationSwitcherTrigger` in the next major\n // version. This should follow conventions of all other widgets\n // using classnames in getWidgetRootDomProps.\n className: cx(domProps.className, \"OrganizationSwitcherTrigger\"),\n })}\n >\n <Flex\n align=\"center\"\n justify=\"between\"\n gap=\"2\"\n flexGrow=\"1\"\n overflow=\"hidden\"\n minWidth=\"0\"\n >\n <TruncatedOrganizationName\n organizationName={currentOrganization.name}\n truncateBehavior={truncateBehavior}\n />\n <Flex asChild flexShrink=\"0\">\n <DropdownMenu.TriggerIcon />\n </Flex>\n </Flex>\n </Button>\n </DropdownMenu.Trigger>\n <DropdownMenu.Content>\n <DropdownMenu.Group>\n {organizationLabel ? (\n <DropdownMenu.Label>\n <Text>{organizationLabel}</Text>\n </DropdownMenu.Label>\n ) : null}\n {organizations.map((organization) => (\n <Flex\n key={organization.id}\n asChild\n pr=\"2\"\n maxWidth=\"280px\"\n minWidth=\"180px\"\n >\n <DropdownMenu.Item\n onClick={() => {\n if (organization.id !== currentOrganization.id) {\n const result = switchToOrganization({\n organizationId: organization.id,\n });\n if (isPromiseLike(result)) {\n result.then(invalidateAllWidgets);\n } else {\n invalidateAllWidgets();\n }\n }\n }}\n >\n <Flex\n justify=\"between\"\n align=\"center\"\n gap=\"4\"\n flexGrow=\"1\"\n overflow=\"hidden\"\n >\n <TruncatedOrganizationName\n organizationName={organization.name}\n truncateBehavior={truncateBehavior}\n />\n {organization.current && (\n <VisuallyHidden> (current)</VisuallyHidden>\n )}\n <Flex\n aria-hidden\n align=\"center\"\n justify=\"center\"\n flexShrink=\"0\"\n >\n {organization.current ? (\n <CheckIcon width=\"18px\" height=\"18px\" />\n ) : (\n // make the extra space for\n <Box width=\"18px\" height=\"18px\" />\n )}\n </Flex>\n </Flex>\n </DropdownMenu.Item>\n </Flex>\n ))}\n </DropdownMenu.Group>\n {children}\n </DropdownMenu.Content>\n </DropdownMenu.Root>\n );\n};\n\ninterface OrganizationSwitcherLoadingProps extends WidgetRootDomProps {\n variant?: OrganizationSwitcherVariant;\n}\n\nconst OrganizationSwitcherLoading: React.FC<\n OrganizationSwitcherLoadingProps\n> = ({ variant, ...props }: OrganizationSwitcherLoadingProps) => {\n return (\n // Always need DropdownMenu.Root to wrap children than may include\n <Button\n variant=\"secondary\"\n disabled\n {...mapVariantProps(variant)}\n {...getWidgetRootDomProps(\"loading\", props)}\n >\n <Flex align=\"center\" gap=\"2\">\n <Skeleton>\n <Text>Loading...</Text>\n </Skeleton>\n <ChevronDownIcon />\n </Flex>\n </Button>\n );\n};\n\ninterface OrganizationSwitcherErrorProps extends WidgetRootDomProps {\n error: unknown;\n variant?: OrganizationSwitcherVariant;\n}\n\nfunction OrganizationSwitcherError({\n error,\n variant,\n ...domProps\n}: OrganizationSwitcherErrorProps) {\n const { heading } = getErrorMessage(error);\n\n return (\n <Button\n variant=\"secondary\"\n disabled\n {...mapVariantProps(variant)}\n {...getWidgetRootDomProps(\"error\", domProps)}\n >\n <Flex align=\"center\" gap=\"2\">\n <Text>{heading}</Text>\n <ChevronDownIcon />\n </Flex>\n </Button>\n );\n}\n\nconst MAX_TRUNCATED_SUFFIX_LENGTH = 10;\nconst MIN_TRUNCATED_SUFFIX_LENGTH = 3;\n\nconst WHITE_SPACE_REGEX = /\\s/;\n\nconst getSplitPosition = (organizationName: string) => {\n if (organizationName.length <= MAX_TRUNCATED_SUFFIX_LENGTH) {\n return organizationName.length;\n }\n\n for (\n let i = organizationName.length - MAX_TRUNCATED_SUFFIX_LENGTH;\n i < organizationName.length - MIN_TRUNCATED_SUFFIX_LENGTH;\n i++\n ) {\n if (WHITE_SPACE_REGEX.test(organizationName[i - 1])) {\n return i;\n }\n }\n\n return organizationName.length - MAX_TRUNCATED_SUFFIX_LENGTH;\n};\n\nconst splitOrganizationName = (organizationName: string) => {\n const splitPosition = getSplitPosition(organizationName);\n return [\n organizationName.slice(0, splitPosition),\n organizationName.slice(splitPosition),\n ];\n};\n\nconst TruncatedOrganizationName = ({\n organizationName,\n truncateBehavior,\n}: {\n organizationName: string;\n truncateBehavior: \"right\" | \"middle\";\n}) => {\n if (truncateBehavior === \"right\") {\n return <Text truncate>{organizationName}</Text>;\n }\n\n const [organizationNameLeft, organizationNameRight] =\n splitOrganizationName(organizationName);\n\n return (\n <Flex overflow=\"hidden\">\n <VisuallyHidden>\n <Text>{organizationName}</Text>\n </VisuallyHidden>\n <Text aria-hidden truncate style={{ whiteSpace: \"pre\" }}>\n {organizationNameLeft}\n </Text>\n <Text aria-hidden>{organizationNameRight}</Text>\n </Flex>\n );\n};\n\nfunction mapVariantProps(variant?: OrganizationSwitcherVariant): ButtonProps {\n const variantProps: ButtonProps = {};\n // Passing `undefined` to the variant prop will result in overrides to props we\n // set internally. This should be addressed in Radix Themes, but we can\n // explicitly set it only when it's provided and _not_ undefined.\n if (variant) {\n variantProps.unsafe_radixVariant = variant;\n }\n return variantProps;\n}\n\nfunction getWidgetRootDomProps(\n state: WidgetRootState,\n domProps: WidgetRootDomProps,\n) {\n return getDomProps({\n ...domProps,\n isWidgetRoot: true,\n widgetId: \"organization-switcher\",\n widgetState: state,\n });\n}\n\nexport type {\n OrganizationSwitcherProps,\n OrganizationSwitcherLoadingProps,\n OrganizationSwitcherErrorProps,\n /** @internal */\n OrganizationSwitcherPassthroughProps,\n};\nexport {\n OrganizationSwitcher,\n OrganizationSwitcherLoading,\n OrganizationSwitcherError,\n};\n"],"mappings":"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","names":["import_utils","useWidgetsInvalidator","cx"]}
|
|
@@ -3,12 +3,24 @@ import { OrganizationInfo } from '../api/endpoint.cjs';
|
|
|
3
3
|
import { WidgetRootDomProps } from './utils.cjs';
|
|
4
4
|
import '@tanstack/react-query';
|
|
5
5
|
import '../api/widgets-api-client.cjs';
|
|
6
|
+
import './elements.cjs';
|
|
7
|
+
import 'react';
|
|
8
|
+
import '@radix-ui/themes';
|
|
9
|
+
import '@radix-ui/themes/props';
|
|
10
|
+
import '../dialog-C15qCLN3.cjs';
|
|
11
|
+
import '@radix-ui/themes/components/dialog';
|
|
12
|
+
import '../alert-dialog-BlG3_awx.cjs';
|
|
13
|
+
import '@radix-ui/themes/components/alert-dialog';
|
|
14
|
+
import '../dropdown-menu-BQ5LtvdR.cjs';
|
|
15
|
+
import '@radix-ui/themes/components/dropdown-menu';
|
|
16
|
+
import '../select-KR89Qnvm.cjs';
|
|
17
|
+
import '@radix-ui/themes/components/select';
|
|
6
18
|
|
|
7
19
|
type OrganizationSwitcherVariant = "ghost" | "outline";
|
|
8
20
|
interface OrganizationSwitcherPassthroughProps extends WidgetRootDomProps {
|
|
9
21
|
switchToOrganization: ({ organizationId, }: {
|
|
10
22
|
organizationId: string;
|
|
11
|
-
}) => void
|
|
23
|
+
}) => void | Promise<void>;
|
|
12
24
|
variant?: OrganizationSwitcherVariant;
|
|
13
25
|
organizationLabel?: string | null;
|
|
14
26
|
children?: React.ReactNode;
|
|
@@ -27,11 +39,13 @@ interface OrganizationSwitcherProps extends OrganizationSwitcherPassthroughProps
|
|
|
27
39
|
}
|
|
28
40
|
declare const OrganizationSwitcher: React.FC<OrganizationSwitcherProps>;
|
|
29
41
|
interface OrganizationSwitcherLoadingProps extends WidgetRootDomProps {
|
|
42
|
+
variant?: OrganizationSwitcherVariant;
|
|
30
43
|
}
|
|
31
44
|
declare const OrganizationSwitcherLoading: React.FC<OrganizationSwitcherLoadingProps>;
|
|
32
45
|
interface OrganizationSwitcherErrorProps extends WidgetRootDomProps {
|
|
33
46
|
error: unknown;
|
|
47
|
+
variant?: OrganizationSwitcherVariant;
|
|
34
48
|
}
|
|
35
|
-
declare function OrganizationSwitcherError({ error, ...domProps }: OrganizationSwitcherErrorProps): react_jsx_runtime.JSX.Element;
|
|
49
|
+
declare function OrganizationSwitcherError({ error, variant, ...domProps }: OrganizationSwitcherErrorProps): react_jsx_runtime.JSX.Element;
|
|
36
50
|
|
|
37
51
|
export { OrganizationSwitcher, OrganizationSwitcherError, type OrganizationSwitcherErrorProps, OrganizationSwitcherLoading, type OrganizationSwitcherLoadingProps, type OrganizationSwitcherPassthroughProps, type OrganizationSwitcherProps };
|