@workos-inc/widgets 1.5.0 → 1.5.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 +19 -8
- package/dist/cjs/admin-portal-domain-verification.client.cjs +2 -3
- package/dist/cjs/admin-portal-domain-verification.client.cjs.map +1 -1
- package/dist/cjs/admin-portal-sso-connection-client.cjs +3 -4
- package/dist/cjs/admin-portal-sso-connection-client.cjs.map +1 -1
- package/dist/cjs/api/api-provider.cjs +27 -19
- package/dist/cjs/api/api-provider.cjs.map +1 -1
- package/dist/cjs/api/api-provider.d.cts +4 -3
- package/dist/cjs/api/utils.cjs +10 -0
- package/dist/cjs/api/utils.cjs.map +1 -1
- package/dist/cjs/api/utils.d.cts +7 -2
- package/dist/cjs/api/widgets-api-client.cjs +11 -5
- package/dist/cjs/api/widgets-api-client.cjs.map +1 -1
- package/dist/cjs/api-keys-client.cjs +3 -8
- package/dist/cjs/api-keys-client.cjs.map +1 -1
- package/dist/cjs/lib/add-mfa-dialog.cjs +1 -1
- package/dist/cjs/lib/add-mfa-dialog.cjs.map +1 -1
- package/dist/cjs/lib/admin-portal-domain-verification.cjs +25 -18
- package/dist/cjs/lib/admin-portal-domain-verification.cjs.map +1 -1
- package/dist/cjs/lib/admin-portal-sso-connection.cjs +5 -27
- package/dist/cjs/lib/admin-portal-sso-connection.cjs.map +1 -1
- package/dist/cjs/lib/card-list.cjs.map +1 -0
- package/dist/cjs/lib/errors.cjs +1 -1
- package/dist/cjs/lib/errors.cjs.map +1 -1
- package/dist/cjs/lib/generic-error.cjs +27 -38
- package/dist/cjs/lib/generic-error.cjs.map +1 -1
- package/dist/cjs/lib/generic-error.d.cts +5 -1
- package/dist/cjs/lib/use-permissions.cjs +7 -14
- package/dist/cjs/lib/use-permissions.cjs.map +1 -1
- package/dist/cjs/lib/use-permissions.d.cts +1 -1
- package/dist/cjs/lib/user-security.cjs +1 -1
- package/dist/cjs/lib/user-security.cjs.map +1 -1
- package/dist/cjs/lib/user-sessions.cjs +1 -1
- package/dist/cjs/lib/user-sessions.cjs.map +1 -1
- package/dist/cjs/organization-switcher.client.cjs +2 -4
- package/dist/cjs/organization-switcher.client.cjs.map +1 -1
- package/dist/cjs/user-profile.client.cjs +2 -6
- package/dist/cjs/user-profile.client.cjs.map +1 -1
- package/dist/cjs/user-security.client.cjs +5 -4
- package/dist/cjs/user-security.client.cjs.map +1 -1
- package/dist/cjs/user-sessions.client.cjs +8 -12
- package/dist/cjs/user-sessions.client.cjs.map +1 -1
- package/dist/cjs/users-management.client.cjs +3 -9
- package/dist/cjs/users-management.client.cjs.map +1 -1
- package/dist/esm/admin-portal-domain-verification.client.js +3 -4
- package/dist/esm/admin-portal-domain-verification.client.js.map +1 -1
- package/dist/esm/admin-portal-sso-connection-client.js +4 -5
- package/dist/esm/admin-portal-sso-connection-client.js.map +1 -1
- package/dist/esm/api/api-provider.d.ts +4 -3
- package/dist/esm/api/api-provider.js +26 -19
- package/dist/esm/api/api-provider.js.map +1 -1
- package/dist/esm/api/utils.d.ts +7 -2
- package/dist/esm/api/utils.js +9 -0
- package/dist/esm/api/utils.js.map +1 -1
- package/dist/esm/api/widgets-api-client.js +11 -5
- package/dist/esm/api/widgets-api-client.js.map +1 -1
- package/dist/esm/api-keys-client.js +4 -9
- package/dist/esm/api-keys-client.js.map +1 -1
- package/dist/esm/lib/add-mfa-dialog.js +1 -1
- package/dist/esm/lib/add-mfa-dialog.js.map +1 -1
- package/dist/esm/lib/admin-portal-domain-verification.js +25 -18
- package/dist/esm/lib/admin-portal-domain-verification.js.map +1 -1
- package/dist/esm/lib/admin-portal-sso-connection.js +5 -27
- package/dist/esm/lib/admin-portal-sso-connection.js.map +1 -1
- package/dist/esm/lib/card-list.js.map +1 -0
- package/dist/esm/lib/errors.js +1 -1
- package/dist/esm/lib/errors.js.map +1 -1
- package/dist/esm/lib/generic-error.d.ts +5 -1
- package/dist/esm/lib/generic-error.js +27 -40
- package/dist/esm/lib/generic-error.js.map +1 -1
- package/dist/esm/lib/use-permissions.d.ts +1 -1
- package/dist/esm/lib/use-permissions.js +8 -15
- package/dist/esm/lib/use-permissions.js.map +1 -1
- package/dist/esm/lib/user-security.js +1 -1
- package/dist/esm/lib/user-security.js.map +1 -1
- package/dist/esm/lib/user-sessions.js +1 -1
- package/dist/esm/lib/user-sessions.js.map +1 -1
- package/dist/esm/organization-switcher.client.js +3 -5
- package/dist/esm/organization-switcher.client.js.map +1 -1
- package/dist/esm/user-profile.client.js +3 -7
- package/dist/esm/user-profile.client.js.map +1 -1
- package/dist/esm/user-security.client.js +6 -5
- package/dist/esm/user-security.client.js.map +1 -1
- package/dist/esm/user-sessions.client.js +10 -14
- package/dist/esm/user-sessions.client.js.map +1 -1
- package/dist/esm/users-management.client.js +4 -10
- package/dist/esm/users-management.client.js.map +1 -1
- package/package.json +4 -1
- package/dist/cjs/card-list.cjs.map +0 -1
- package/dist/esm/card-list.js.map +0 -1
- /package/dist/cjs/{card-list.cjs → lib/card-list.cjs} +0 -0
- /package/dist/cjs/{card-list.d.cts → lib/card-list.d.cts} +0 -0
- /package/dist/esm/{card-list.d.ts → lib/card-list.d.ts} +0 -0
- /package/dist/esm/{card-list.js → lib/card-list.js} +0 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/lib/add-mfa-dialog.tsx"],"sourcesContent":["\"use client\";\n\nimport {\n Box,\n Code,\n Dialog,\n Flex,\n Grid,\n Link,\n Separator,\n Text,\n VisuallyHidden,\n} from \"@radix-ui/themes\";\nimport * as React from \"react\";\nimport { type ReactNode } from \"react\";\nimport * as Otp from \"./otp-input.js\";\nimport { DialogContent, PrimaryButton, SecondaryButton } from \"./elements.js\";\nimport {\n CreateTotpFactorResponse,\n CreateTotpFactorResponseAuthenticationFactorAllOfTotpAnyOf,\n useCreateTotpFactor,\n useVerifyTotpFactor,\n} from \"../api/endpoint.js\";\nimport { useElevatedAccessToken } from \"../api/api-provider.js\";\nimport * as Form from \"@radix-ui/react-form\";\nimport { Marker } from \"./marker.js\";\nimport { CopyButton } from \"./copy-button.js\";\nimport { useSecuritySettings } from \"./use-security-settings.js\";\nimport { ElevatedAccess } from \"./elevated-access.js\";\nimport { SaveButton } from \"./save-button.js\";\nimport { useDialogClose } from \"./use-dialog-close.js\";\n\ninterface AddMfaDialogProps extends Dialog.RootProps {\n children?: ReactNode;\n onSuccess?: () => void;\n}\n\nexport function AddMfaDialog({\n children,\n onSuccess,\n ...props\n}: AddMfaDialogProps) {\n const [open, setOpen] = React.useState(false);\n const [manuallyTriggered, setManuallyTriggered] = React.useState(false);\n const { elevatedAccess } = useElevatedAccessToken();\n const createAuthFactor = useCreateTotpFactor();\n\n const handleVerified = async () => {\n await createAuthFactor.mutateAsync(undefined);\n };\n\n const onTriggerClick = (event: React.MouseEvent<HTMLButtonElement>) => {\n if (elevatedAccess && !createAuthFactor.data) {\n event.preventDefault();\n setManuallyTriggered(true);\n createAuthFactor.mutate(undefined, {\n onSuccess: () => {\n setOpen(true);\n },\n });\n } else {\n setManuallyTriggered(false);\n }\n };\n\n const handleClose = React.useCallback(() => {\n setOpen(false);\n }, []);\n\n return (\n <Dialog.Root\n {...props}\n open={props.open || open}\n onOpenChange={props.onOpenChange || setOpen}\n >\n <Dialog.Trigger\n onClick={onTriggerClick}\n // @ts-ignore I've to find a way to pass the loading state to the trigger\n loading={manuallyTriggered && createAuthFactor.isPending}\n >\n {children}\n </Dialog.Trigger>\n\n <DialogContent maxWidth=\"480px\">\n <ElevatedAccess onVerified={handleVerified}>\n <Content onClose={handleClose} totpFactor={createAuthFactor.data} />\n </ElevatedAccess>\n </DialogContent>\n </Dialog.Root>\n );\n}\n\ninterface ContentProps {\n totpFactor?: CreateTotpFactorResponse;\n onClose?: () => void;\n}\n\nfunction Content({ onClose, totpFactor }: ContentProps) {\n const securitySettings = useSecuritySettings();\n\n const [customError, setCustomError] = React.useState<string | null>(null);\n const totp = hasQrCode(totpFactor)\n ? totpFactor.authenticationFactor.totp\n : undefined;\n\n const verifyTotp = useVerifyTotpFactor({\n mutation: {\n onSuccess: ({ success }) => {\n if (!success) {\n setCustomError(\"Invalid passcode\");\n }\n },\n },\n });\n\n const serverError = verifyTotp.error || customError;\n const isSuccess = verifyTotp.isSuccess && !serverError;\n\n const handleSubmit = async (event: React.FormEvent<HTMLFormElement>) => {\n event.preventDefault();\n setCustomError(null);\n\n const formData = new FormData(event.currentTarget);\n const otpCode = formData.get(\"otp-code\")?.toString();\n\n verifyTotp.mutate({\n data: {\n authenticationChallengeId: totpFactor?.authenticationChallenge.id ?? \"\",\n code: otpCode ?? \"\",\n },\n });\n };\n\n useDialogClose(isSuccess, () => {\n securitySettings.update(\"Mfa\", true);\n });\n\n return (\n <>\n <Dialog.Title mb=\"5\">Set up an authenticator app</Dialog.Title>\n\n <Form.Root onSubmit={handleSubmit}>\n <Grid columns=\"auto 1fr\" rows=\"repeat(4, auto)\" gapX=\"3\" gapY=\"1\">\n <Grid\n rows=\"subgrid\"\n gridRow=\"span 4\"\n style={{ placeItems: \"center\" }}\n >\n <Marker>1</Marker>\n <Separator\n orientation=\"vertical\"\n size=\"4\"\n style={{ width: \"2px\" }}\n />\n <Marker>2</Marker>\n <div />\n </Grid>\n\n <Grid rows=\"subgrid\" gridRow=\"span 4\">\n <Text as=\"p\" size=\"3\" weight=\"bold\">\n Scan the QR code\n </Text>\n <Flex direction=\"column\" gap=\"1\">\n <Text as=\"p\" size=\"2\">\n Use an authenticator app like{\" \"}\n <Link\n href=\"https://1password.com/\"\n rel=\"noopener noreferrer\"\n target=\"_blank\"\n >\n 1Password\n </Link>\n ,{\" \"}\n <Link\n href=\"https://apps.apple.com/us/app/google-authenticator/id388497605\"\n rel=\"noopener noreferrer\"\n target=\"_blank\"\n >\n Google Authenticator\n </Link>\n ,{\" \"}\n <Link\n href=\"https://authy.com/\"\n rel=\"noopener noreferrer\"\n target=\"_blank\"\n >\n Authy\n </Link>\n , or{\" \"}\n <Link\n href=\"https://www.microsoft.com/en-gb/security/mobile-authenticator-app\"\n rel=\"noopener noreferrer\"\n target=\"_blank\"\n >\n Microsoft Authenticator\n </Link>{\" \"}\n to scan the QR code below.\n </Text>\n <Flex align=\"center\" gap=\"5\" my=\"5\">\n <Grid\n position=\"relative\"\n width=\"160px\"\n height=\"160px\"\n p=\"2\"\n style={{\n border: \"1px solid var(--gray-7)\",\n borderRadius: \"var(--radius-4)\",\n background: \"var(--gray-2)\",\n overflow: \"hidden\",\n }}\n >\n {totp?.qr_code && (\n <Box asChild width=\"100%\" height=\"auto\">\n <img\n alt=\"Scan this QR code to enroll\"\n aria-describedby=\"secret-note\"\n height=\"160\"\n src={totp.qr_code}\n style={{ userSelect: \"none\", background: \"white\" }}\n width=\"160\"\n />\n </Box>\n )}\n </Grid>\n\n <Flex direction=\"column\" gap=\"1\" align=\"start\">\n <Text color=\"gray\" id=\"secret-note\" size=\"2\">\n Can‘t scan the code?{\" \"}\n </Text>\n\n <SecretDialog setupKey={totp?.secret ?? \"\"}>\n <SecondaryButton\n size=\"1\"\n disabled={verifyTotp.isPending || isSuccess}\n >\n View setup key\n </SecondaryButton>\n </SecretDialog>\n </Flex>\n </Flex>\n </Flex>\n <Text as=\"p\" size=\"3\" weight=\"bold\">\n Get verification passcode\n </Text>\n <Flex direction=\"column\" gap=\"4\">\n <Text as=\"p\" size=\"2\">\n Enter the 6-digit passcode from your authenticator app.\n </Text>\n\n <Flex direction=\"column\" gap=\"2\">\n <Otp.Root\n autoSubmit\n gap=\"3\"\n justify=\"start\"\n name=\"otp-code\"\n rows=\"48px\"\n columns=\"repeat(6, 48px)\"\n readOnly={verifyTotp.isPending || isSuccess}\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 {serverError && (\n <Text size=\"2\" color=\"red\">\n {getMutationErrorMessage(serverError)}\n </Text>\n )}\n </Flex>\n </Flex>\n </Grid>\n </Grid>\n\n <Flex mt=\"5\" gap=\"3\" justify=\"end\">\n <Dialog.Close>\n <SecondaryButton disabled={verifyTotp.isPending || isSuccess}>\n Cancel\n </SecondaryButton>\n </Dialog.Close>\n\n <SaveButton\n asChild\n loading={verifyTotp.isPending}\n done={isSuccess}\n onDone={onClose}\n >\n <PrimaryButton type=\"submit\">Confirm</PrimaryButton>\n </SaveButton>\n </Flex>\n </Form.Root>\n\n {/* mirror errors in a live region */}\n <VisuallyHidden asChild>\n <section aria-live=\"polite\">\n {getMutationErrorMessage(serverError)}\n </section>\n </VisuallyHidden>\n </>\n );\n}\n\ninterface SecretDialogProps extends React.PropsWithChildren {\n setupKey: string;\n}\n\nfunction SecretDialog({ children, setupKey }: SecretDialogProps) {\n return (\n <Dialog.Root>\n <Dialog.Trigger>{children}</Dialog.Trigger>\n <Dialog.Content\n maxWidth=\"90vw\"\n size={{ initial: \"3\", sm: \"4\" }}\n minWidth=\"300px\"\n width=\"fit-content\"\n >\n <Dialog.Title size=\"2\" weight=\"regular\">\n Your setup key\n </Dialog.Title>\n <Dialog.Description>\n <Text size=\"6\">\n <Code variant=\"ghost\" style={{ letterSpacing: \"0.15rem\" }}>\n {setupKey}\n </Code>\n </Text>\n </Dialog.Description>\n\n <Flex align=\"center\" gap=\"3\" justify=\"end\" mt=\"5\">\n <Dialog.Close>\n <CopyButton asChild value={setupKey}>\n <PrimaryButton>Copy and close</PrimaryButton>\n </CopyButton>\n </Dialog.Close>\n </Flex>\n </Dialog.Content>\n </Dialog.Root>\n );\n}\n\nfunction getMutationErrorMessage(error: unknown) {\n let message = \"Something went wrong, please try again\";\n\n if (typeof error === \"string\") {\n message = error;\n }\n\n if (error instanceof Error) {\n message = error.message;\n }\n\n 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 === \"Invalid passcode\") {\n message = \"Invalid passcode, please try again\";\n }\n\n return message;\n}\n\nfunction hasQrCode(\n response?: CreateTotpFactorResponse,\n): response is CreateTotpFactorResponse & {\n authenticationFactor: {\n totp: NonNullable<CreateTotpFactorResponseAuthenticationFactorAllOfTotpAnyOf>;\n };\n} {\n const totp = response?.authenticationFactor.totp;\n return totp != null && \"qr_code\" in totp;\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../../src/lib/add-mfa-dialog.tsx"],"sourcesContent":["\"use client\";\n\nimport {\n Box,\n Code,\n Dialog,\n Flex,\n Grid,\n Link,\n Separator,\n Text,\n VisuallyHidden,\n} from \"@radix-ui/themes\";\nimport * as React from \"react\";\nimport { type ReactNode } from \"react\";\nimport * as Otp from \"./otp-input.js\";\nimport { DialogContent, PrimaryButton, SecondaryButton } from \"./elements.js\";\nimport {\n CreateTotpFactorResponse,\n CreateTotpFactorResponseAuthenticationFactorAllOfTotpAnyOf,\n useCreateTotpFactor,\n useVerifyTotpFactor,\n} from \"../api/endpoint.js\";\nimport { useElevatedAccessToken } from \"../api/api-provider.js\";\nimport * as Form from \"@radix-ui/react-form\";\nimport { Marker } from \"./marker.js\";\nimport { CopyButton } from \"./copy-button.js\";\nimport { useSecuritySettings } from \"./use-security-settings.js\";\nimport { ElevatedAccess } from \"./elevated-access.js\";\nimport { SaveButton } from \"./save-button.js\";\nimport { useDialogClose } from \"./use-dialog-close.js\";\n\ninterface AddMfaDialogProps extends Dialog.RootProps {\n children?: ReactNode;\n onSuccess?: () => void;\n}\n\nexport function AddMfaDialog({\n children,\n onSuccess,\n ...props\n}: AddMfaDialogProps) {\n const [open, setOpen] = React.useState(false);\n const [manuallyTriggered, setManuallyTriggered] = React.useState(false);\n const { elevatedAccess } = useElevatedAccessToken();\n const createAuthFactor = useCreateTotpFactor();\n\n const handleVerified = async () => {\n await createAuthFactor.mutateAsync(undefined);\n };\n\n const onTriggerClick = (event: React.MouseEvent<HTMLButtonElement>) => {\n if (elevatedAccess && !createAuthFactor.data) {\n event.preventDefault();\n setManuallyTriggered(true);\n createAuthFactor.mutate(undefined, {\n onSuccess: () => {\n setOpen(true);\n },\n });\n } else {\n setManuallyTriggered(false);\n }\n };\n\n const handleClose = React.useCallback(() => {\n setOpen(false);\n }, []);\n\n return (\n <Dialog.Root\n {...props}\n open={props.open || open}\n onOpenChange={props.onOpenChange || setOpen}\n >\n <Dialog.Trigger\n onClick={onTriggerClick}\n // @ts-ignore I've to find a way to pass the loading state to the trigger\n loading={manuallyTriggered && createAuthFactor.isPending}\n >\n {children}\n </Dialog.Trigger>\n\n <DialogContent maxWidth=\"480px\">\n <ElevatedAccess onVerified={handleVerified}>\n <Content onClose={handleClose} totpFactor={createAuthFactor.data} />\n </ElevatedAccess>\n </DialogContent>\n </Dialog.Root>\n );\n}\n\ninterface ContentProps {\n totpFactor?: CreateTotpFactorResponse;\n onClose?: () => void;\n}\n\nfunction Content({ onClose, totpFactor }: ContentProps) {\n const securitySettings = useSecuritySettings();\n\n const [customError, setCustomError] = React.useState<string | null>(null);\n const totp = hasQrCode(totpFactor)\n ? totpFactor.authenticationFactor.totp\n : undefined;\n\n const verifyTotp = useVerifyTotpFactor({\n mutation: {\n onSuccess: ({ success }) => {\n if (!success) {\n setCustomError(\"Invalid passcode\");\n }\n },\n },\n });\n\n const serverError = verifyTotp.error || customError;\n const isSuccess = verifyTotp.isSuccess && !serverError;\n\n const handleSubmit = async (event: React.FormEvent<HTMLFormElement>) => {\n event.preventDefault();\n setCustomError(null);\n\n const formData = new FormData(event.currentTarget);\n const otpCode = formData.get(\"otp-code\")?.toString();\n\n verifyTotp.mutate({\n data: {\n authenticationChallengeId: totpFactor?.authenticationChallenge.id ?? \"\",\n code: otpCode ?? \"\",\n },\n });\n };\n\n useDialogClose(isSuccess, () => {\n securitySettings.update(\"Mfa\", true);\n });\n\n return (\n <>\n <Dialog.Title mb=\"5\">Set up an authenticator app</Dialog.Title>\n\n <Form.Root onSubmit={handleSubmit}>\n <Grid columns=\"auto 1fr\" rows=\"repeat(4, auto)\" gapX=\"3\" gapY=\"1\">\n <Grid\n rows=\"subgrid\"\n gridRow=\"span 4\"\n style={{ placeItems: \"center\" }}\n >\n <Marker>1</Marker>\n <Separator\n orientation=\"vertical\"\n size=\"4\"\n style={{ width: \"2px\" }}\n />\n <Marker>2</Marker>\n <div />\n </Grid>\n\n <Grid rows=\"subgrid\" gridRow=\"span 4\">\n <Text as=\"p\" size=\"3\" weight=\"bold\">\n Scan the QR code\n </Text>\n <Flex direction=\"column\" gap=\"1\">\n <Text as=\"p\" size=\"2\">\n Use an authenticator app like{\" \"}\n <Link\n href=\"https://1password.com/\"\n rel=\"noopener noreferrer\"\n target=\"_blank\"\n >\n 1Password\n </Link>\n ,{\" \"}\n <Link\n href=\"https://apps.apple.com/us/app/google-authenticator/id388497605\"\n rel=\"noopener noreferrer\"\n target=\"_blank\"\n >\n Google Authenticator\n </Link>\n ,{\" \"}\n <Link\n href=\"https://authy.com/\"\n rel=\"noopener noreferrer\"\n target=\"_blank\"\n >\n Authy\n </Link>\n , or{\" \"}\n <Link\n href=\"https://www.microsoft.com/en-gb/security/mobile-authenticator-app\"\n rel=\"noopener noreferrer\"\n target=\"_blank\"\n >\n Microsoft Authenticator\n </Link>{\" \"}\n to scan the QR code below.\n </Text>\n <Flex align=\"center\" gap=\"5\" my=\"5\">\n <Grid\n position=\"relative\"\n width=\"160px\"\n height=\"160px\"\n p=\"2\"\n style={{\n border: \"1px solid var(--gray-7)\",\n borderRadius: \"var(--radius-4)\",\n background: \"var(--gray-2)\",\n overflow: \"hidden\",\n }}\n >\n {totp?.qr_code && (\n <Box asChild width=\"100%\" height=\"auto\">\n <img\n alt=\"Scan this QR code to enroll\"\n aria-describedby=\"secret-note\"\n height=\"160\"\n src={totp.qr_code}\n style={{ userSelect: \"none\", background: \"white\" }}\n width=\"160\"\n />\n </Box>\n )}\n </Grid>\n\n <Flex direction=\"column\" gap=\"1\" align=\"start\">\n <Text color=\"gray\" id=\"secret-note\" size=\"2\">\n Can‘t scan the code?{\" \"}\n </Text>\n\n <SecretDialog setupKey={totp?.secret ?? \"\"}>\n <SecondaryButton\n size=\"1\"\n disabled={verifyTotp.isPending || isSuccess}\n >\n View setup key\n </SecondaryButton>\n </SecretDialog>\n </Flex>\n </Flex>\n </Flex>\n <Text as=\"p\" size=\"3\" weight=\"bold\">\n Get verification passcode\n </Text>\n <Flex direction=\"column\" gap=\"4\">\n <Text as=\"p\" size=\"2\">\n Enter the 6-digit passcode from your authenticator app.\n </Text>\n\n <Flex direction=\"column\" gap=\"2\">\n <Otp.Root\n autoSubmit\n gap=\"3\"\n justify=\"start\"\n name=\"otp-code\"\n rows=\"48px\"\n columns=\"repeat(6, 48px)\"\n readOnly={verifyTotp.isPending || isSuccess}\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 {serverError && (\n <Text size=\"2\" color=\"red\">\n {getMutationErrorMessage(serverError)}\n </Text>\n )}\n </Flex>\n </Flex>\n </Grid>\n </Grid>\n\n <Flex mt=\"5\" gap=\"3\" justify=\"end\">\n <Dialog.Close>\n <SecondaryButton disabled={verifyTotp.isPending || isSuccess}>\n Cancel\n </SecondaryButton>\n </Dialog.Close>\n\n <SaveButton\n asChild\n loading={verifyTotp.isPending}\n done={isSuccess}\n onDone={onClose}\n >\n <PrimaryButton type=\"submit\">Confirm</PrimaryButton>\n </SaveButton>\n </Flex>\n </Form.Root>\n\n {/* mirror errors in a live region */}\n <VisuallyHidden asChild>\n <section aria-live=\"polite\">\n {getMutationErrorMessage(serverError)}\n </section>\n </VisuallyHidden>\n </>\n );\n}\n\ninterface SecretDialogProps extends React.PropsWithChildren {\n setupKey: string;\n}\n\nfunction SecretDialog({ children, setupKey }: SecretDialogProps) {\n return (\n <Dialog.Root>\n <Dialog.Trigger>{children}</Dialog.Trigger>\n <DialogContent\n maxWidth=\"90vw\"\n size={{ initial: \"3\", sm: \"4\" }}\n minWidth=\"300px\"\n width=\"fit-content\"\n >\n <Dialog.Title size=\"2\" weight=\"regular\">\n Your setup key\n </Dialog.Title>\n <Dialog.Description>\n <Text size=\"6\">\n <Code variant=\"ghost\" style={{ letterSpacing: \"0.15rem\" }}>\n {setupKey}\n </Code>\n </Text>\n </Dialog.Description>\n\n <Flex align=\"center\" gap=\"3\" justify=\"end\" mt=\"5\">\n <Dialog.Close>\n <CopyButton asChild value={setupKey}>\n <PrimaryButton>Copy and close</PrimaryButton>\n </CopyButton>\n </Dialog.Close>\n </Flex>\n </DialogContent>\n </Dialog.Root>\n );\n}\n\nfunction getMutationErrorMessage(error: unknown) {\n let message = \"Something went wrong, please try again\";\n\n if (typeof error === \"string\") {\n message = error;\n }\n\n if (error instanceof Error) {\n message = error.message;\n }\n\n 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 === \"Invalid passcode\") {\n message = \"Invalid passcode, please try again\";\n }\n\n return message;\n}\n\nfunction hasQrCode(\n response?: CreateTotpFactorResponse,\n): response is CreateTotpFactorResponse & {\n authenticationFactor: {\n totp: NonNullable<CreateTotpFactorResponseAuthenticationFactorAllOfTotpAnyOf>;\n };\n} {\n const totp = response?.authenticationFactor.totp;\n return totp != null && \"qr_code\" in totp;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAsEI;AApEJ,oBAUO;AACP,YAAuB;AAEvB,UAAqB;AACrB,sBAA8D;AAC9D,sBAKO;AACP,0BAAuC;AACvC,WAAsB;AACtB,oBAAuB;AACvB,yBAA2B;AAC3B,mCAAoC;AACpC,6BAA+B;AAC/B,yBAA2B;AAC3B,8BAA+B;AAOxB,SAAS,aAAa;AAAA,EAC3B;AAAA,EACA;AAAA,EACA,GAAG;AACL,GAAsB;AACpB,QAAM,CAAC,MAAM,OAAO,IAAI,MAAM,SAAS,KAAK;AAC5C,QAAM,CAAC,mBAAmB,oBAAoB,IAAI,MAAM,SAAS,KAAK;AACtE,QAAM,EAAE,eAAe,QAAI,4CAAuB;AAClD,QAAM,uBAAmB,qCAAoB;AAE7C,QAAM,iBAAiB,YAAY;AACjC,UAAM,iBAAiB,YAAY,MAAS;AAAA,EAC9C;AAEA,QAAM,iBAAiB,CAAC,UAA+C;AACrE,QAAI,kBAAkB,CAAC,iBAAiB,MAAM;AAC5C,YAAM,eAAe;AACrB,2BAAqB,IAAI;AACzB,uBAAiB,OAAO,QAAW;AAAA,QACjC,WAAW,MAAM;AACf,kBAAQ,IAAI;AAAA,QACd;AAAA,MACF,CAAC;AAAA,IACH,OAAO;AACL,2BAAqB,KAAK;AAAA,IAC5B;AAAA,EACF;AAEA,QAAM,cAAc,MAAM,YAAY,MAAM;AAC1C,YAAQ,KAAK;AAAA,EACf,GAAG,CAAC,CAAC;AAEL,SACE;AAAA,IAAC,qBAAO;AAAA,IAAP;AAAA,MACE,GAAG;AAAA,MACJ,MAAM,MAAM,QAAQ;AAAA,MACpB,cAAc,MAAM,gBAAgB;AAAA,MAEpC;AAAA;AAAA,UAAC,qBAAO;AAAA,UAAP;AAAA,YACC,SAAS;AAAA,YAET,SAAS,qBAAqB,iBAAiB;AAAA,YAE9C;AAAA;AAAA,QACH;AAAA,QAEA,4CAAC,iCAAc,UAAS,SACtB,sDAAC,yCAAe,YAAY,gBAC1B,sDAAC,WAAQ,SAAS,aAAa,YAAY,iBAAiB,MAAM,GACpE,GACF;AAAA;AAAA;AAAA,EACF;AAEJ;AAOA,SAAS,QAAQ,EAAE,SAAS,WAAW,GAAiB;AACtD,QAAM,uBAAmB,kDAAoB;AAE7C,QAAM,CAAC,aAAa,cAAc,IAAI,MAAM,SAAwB,IAAI;AACxE,QAAM,OAAO,UAAU,UAAU,IAC7B,WAAW,qBAAqB,OAChC;AAEJ,QAAM,iBAAa,qCAAoB;AAAA,IACrC,UAAU;AAAA,MACR,WAAW,CAAC,EAAE,QAAQ,MAAM;AAC1B,YAAI,CAAC,SAAS;AACZ,yBAAe,kBAAkB;AAAA,QACnC;AAAA,MACF;AAAA,IACF;AAAA,EACF,CAAC;AAED,QAAM,cAAc,WAAW,SAAS;AACxC,QAAM,YAAY,WAAW,aAAa,CAAC;AAE3C,QAAM,eAAe,OAAO,UAA4C;AACtE,UAAM,eAAe;AACrB,mBAAe,IAAI;AAEnB,UAAM,WAAW,IAAI,SAAS,MAAM,aAAa;AACjD,UAAM,UAAU,SAAS,IAAI,UAAU,GAAG,SAAS;AAEnD,eAAW,OAAO;AAAA,MAChB,MAAM;AAAA,QACJ,2BAA2B,YAAY,wBAAwB,MAAM;AAAA,QACrE,MAAM,WAAW;AAAA,MACnB;AAAA,IACF,CAAC;AAAA,EACH;AAEA,8CAAe,WAAW,MAAM;AAC9B,qBAAiB,OAAO,OAAO,IAAI;AAAA,EACrC,CAAC;AAED,SACE,4EACE;AAAA,gDAAC,qBAAO,OAAP,EAAa,IAAG,KAAI,yCAA2B;AAAA,IAEhD,6CAAC,KAAK,MAAL,EAAU,UAAU,cACnB;AAAA,mDAAC,sBAAK,SAAQ,YAAW,MAAK,mBAAkB,MAAK,KAAI,MAAK,KAC5D;AAAA;AAAA,UAAC;AAAA;AAAA,YACC,MAAK;AAAA,YACL,SAAQ;AAAA,YACR,OAAO,EAAE,YAAY,SAAS;AAAA,YAE9B;AAAA,0DAAC,wBAAO,eAAC;AAAA,cACT;AAAA,gBAAC;AAAA;AAAA,kBACC,aAAY;AAAA,kBACZ,MAAK;AAAA,kBACL,OAAO,EAAE,OAAO,MAAM;AAAA;AAAA,cACxB;AAAA,cACA,4CAAC,wBAAO,eAAC;AAAA,cACT,4CAAC,SAAI;AAAA;AAAA;AAAA,QACP;AAAA,QAEA,6CAAC,sBAAK,MAAK,WAAU,SAAQ,UAC3B;AAAA,sDAAC,sBAAK,IAAG,KAAI,MAAK,KAAI,QAAO,QAAO,8BAEpC;AAAA,UACA,6CAAC,sBAAK,WAAU,UAAS,KAAI,KAC3B;AAAA,yDAAC,sBAAK,IAAG,KAAI,MAAK,KAAI;AAAA;AAAA,cACU;AAAA,cAC9B;AAAA,gBAAC;AAAA;AAAA,kBACC,MAAK;AAAA,kBACL,KAAI;AAAA,kBACJ,QAAO;AAAA,kBACR;AAAA;AAAA,cAED;AAAA,cAAO;AAAA,cACL;AAAA,cACF;AAAA,gBAAC;AAAA;AAAA,kBACC,MAAK;AAAA,kBACL,KAAI;AAAA,kBACJ,QAAO;AAAA,kBACR;AAAA;AAAA,cAED;AAAA,cAAO;AAAA,cACL;AAAA,cACF;AAAA,gBAAC;AAAA;AAAA,kBACC,MAAK;AAAA,kBACL,KAAI;AAAA,kBACJ,QAAO;AAAA,kBACR;AAAA;AAAA,cAED;AAAA,cAAO;AAAA,cACF;AAAA,cACL;AAAA,gBAAC;AAAA;AAAA,kBACC,MAAK;AAAA,kBACL,KAAI;AAAA,kBACJ,QAAO;AAAA,kBACR;AAAA;AAAA,cAED;AAAA,cAAQ;AAAA,cAAI;AAAA,eAEd;AAAA,YACA,6CAAC,sBAAK,OAAM,UAAS,KAAI,KAAI,IAAG,KAC9B;AAAA;AAAA,gBAAC;AAAA;AAAA,kBACC,UAAS;AAAA,kBACT,OAAM;AAAA,kBACN,QAAO;AAAA,kBACP,GAAE;AAAA,kBACF,OAAO;AAAA,oBACL,QAAQ;AAAA,oBACR,cAAc;AAAA,oBACd,YAAY;AAAA,oBACZ,UAAU;AAAA,kBACZ;AAAA,kBAEC,gBAAM,WACL,4CAAC,qBAAI,SAAO,MAAC,OAAM,QAAO,QAAO,QAC/B;AAAA,oBAAC;AAAA;AAAA,sBACC,KAAI;AAAA,sBACJ,oBAAiB;AAAA,sBACjB,QAAO;AAAA,sBACP,KAAK,KAAK;AAAA,sBACV,OAAO,EAAE,YAAY,QAAQ,YAAY,QAAQ;AAAA,sBACjD,OAAM;AAAA;AAAA,kBACR,GACF;AAAA;AAAA,cAEJ;AAAA,cAEA,6CAAC,sBAAK,WAAU,UAAS,KAAI,KAAI,OAAM,SACrC;AAAA,6DAAC,sBAAK,OAAM,QAAO,IAAG,eAAc,MAAK,KAAI;AAAA;AAAA,kBACtB;AAAA,mBACvB;AAAA,gBAEA,4CAAC,gBAAa,UAAU,MAAM,UAAU,IACtC;AAAA,kBAAC;AAAA;AAAA,oBACC,MAAK;AAAA,oBACL,UAAU,WAAW,aAAa;AAAA,oBACnC;AAAA;AAAA,gBAED,GACF;AAAA,iBACF;AAAA,eACF;AAAA,aACF;AAAA,UACA,4CAAC,sBAAK,IAAG,KAAI,MAAK,KAAI,QAAO,QAAO,uCAEpC;AAAA,UACA,6CAAC,sBAAK,WAAU,UAAS,KAAI,KAC3B;AAAA,wDAAC,sBAAK,IAAG,KAAI,MAAK,KAAI,qEAEtB;AAAA,YAEA,6CAAC,sBAAK,WAAU,UAAS,KAAI,KAC3B;AAAA;AAAA,gBAAC,IAAI;AAAA,gBAAJ;AAAA,kBACC,YAAU;AAAA,kBACV,KAAI;AAAA,kBACJ,SAAQ;AAAA,kBACR,MAAK;AAAA,kBACL,MAAK;AAAA,kBACL,SAAQ;AAAA,kBACR,UAAU,WAAW,aAAa;AAAA,kBAElC;AAAA,gEAAC,IAAI,OAAJ,EAAU,UAAQ,MAAC,WAAS,MAAC,cAAa,OAAM;AAAA,oBACjD,4CAAC,IAAI,OAAJ,EAAU,UAAQ,MAAC;AAAA,oBACpB,4CAAC,IAAI,OAAJ,EAAU,UAAQ,MAAC;AAAA,oBACpB,4CAAC,IAAI,OAAJ,EAAU,UAAQ,MAAC;AAAA,oBACpB,4CAAC,IAAI,OAAJ,EAAU,UAAQ,MAAC;AAAA,oBACpB,4CAAC,IAAI,OAAJ,EAAU,UAAQ,MAAC;AAAA;AAAA;AAAA,cACtB;AAAA,cAEC,eACC,4CAAC,sBAAK,MAAK,KAAI,OAAM,OAClB,kCAAwB,WAAW,GACtC;AAAA,eAEJ;AAAA,aACF;AAAA,WACF;AAAA,SACF;AAAA,MAEA,6CAAC,sBAAK,IAAG,KAAI,KAAI,KAAI,SAAQ,OAC3B;AAAA,oDAAC,qBAAO,OAAP,EACC,sDAAC,mCAAgB,UAAU,WAAW,aAAa,WAAW,oBAE9D,GACF;AAAA,QAEA;AAAA,UAAC;AAAA;AAAA,YACC,SAAO;AAAA,YACP,SAAS,WAAW;AAAA,YACpB,MAAM;AAAA,YACN,QAAQ;AAAA,YAER,sDAAC,iCAAc,MAAK,UAAS,qBAAO;AAAA;AAAA,QACtC;AAAA,SACF;AAAA,OACF;AAAA,IAGA,4CAAC,gCAAe,SAAO,MACrB,sDAAC,aAAQ,aAAU,UAChB,kCAAwB,WAAW,GACtC,GACF;AAAA,KACF;AAEJ;AAMA,SAAS,aAAa,EAAE,UAAU,SAAS,GAAsB;AAC/D,SACE,6CAAC,qBAAO,MAAP,EACC;AAAA,gDAAC,qBAAO,SAAP,EAAgB,UAAS;AAAA,IAC1B;AAAA,MAAC;AAAA;AAAA,QACC,UAAS;AAAA,QACT,MAAM,EAAE,SAAS,KAAK,IAAI,IAAI;AAAA,QAC9B,UAAS;AAAA,QACT,OAAM;AAAA,QAEN;AAAA,sDAAC,qBAAO,OAAP,EAAa,MAAK,KAAI,QAAO,WAAU,4BAExC;AAAA,UACA,4CAAC,qBAAO,aAAP,EACC,sDAAC,sBAAK,MAAK,KACT,sDAAC,sBAAK,SAAQ,SAAQ,OAAO,EAAE,eAAe,UAAU,GACrD,oBACH,GACF,GACF;AAAA,UAEA,4CAAC,sBAAK,OAAM,UAAS,KAAI,KAAI,SAAQ,OAAM,IAAG,KAC5C,sDAAC,qBAAO,OAAP,EACC,sDAAC,iCAAW,SAAO,MAAC,OAAO,UACzB,sDAAC,iCAAc,4BAAc,GAC/B,GACF,GACF;AAAA;AAAA;AAAA,IACF;AAAA,KACF;AAEJ;AAEA,SAAS,wBAAwB,OAAgB;AAC/C,MAAI,UAAU;AAEd,MAAI,OAAO,UAAU,UAAU;AAC7B,cAAU;AAAA,EACZ;AAEA,MAAI,iBAAiB,OAAO;AAC1B,cAAU,MAAM;AAAA,EAClB;AAEA,MACE,OAAO,UAAU,YACjB,UAAU,QACV,aAAa,SACb,OAAO,MAAM,YAAY,UACzB;AACA,cAAU,MAAM;AAAA,EAClB;AAEA,MAAI,YAAY,oBAAoB;AAClC,cAAU;AAAA,EACZ;AAEA,SAAO;AACT;AAEA,SAAS,UACP,UAKA;AACA,QAAM,OAAO,UAAU,qBAAqB;AAC5C,SAAO,QAAQ,QAAQ,aAAa;AACtC;","names":[]}
|
|
@@ -40,7 +40,7 @@ var import_elements = require("./elements.js");
|
|
|
40
40
|
var import_icon_panel = require("./icon-panel.js");
|
|
41
41
|
var import_generic_error = require("./generic-error.js");
|
|
42
42
|
var import_react_icons = require("@radix-ui/react-icons");
|
|
43
|
-
var CardList = __toESM(require("
|
|
43
|
+
var CardList = __toESM(require("./card-list.js"), 1);
|
|
44
44
|
var import_domain_item = require("./domain-item.js");
|
|
45
45
|
var import_clsx = __toESM(require("clsx"), 1);
|
|
46
46
|
const AdminPortalDomainVerification = ({
|
|
@@ -51,23 +51,30 @@ const AdminPortalDomainVerification = ({
|
|
|
51
51
|
isPending = false
|
|
52
52
|
}) => {
|
|
53
53
|
if (organizationDomains.length === 0) {
|
|
54
|
-
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
color: "gray",
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
54
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
55
|
+
import_themes.Card,
|
|
56
|
+
{
|
|
57
|
+
size: "2",
|
|
58
|
+
"data-woswidgets-widget-id": "admin-portal-domain-verification",
|
|
59
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_themes.Flex, { direction: "row", justify: "between", align: "center", children: [
|
|
60
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_themes.Text, { size: "2", color: "gray", children: "You haven't added any verified domains yet." }),
|
|
61
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
62
|
+
import_themes.Button,
|
|
63
|
+
{
|
|
64
|
+
variant: "outline",
|
|
65
|
+
color: "gray",
|
|
66
|
+
loading: isPending,
|
|
67
|
+
disabled: isPending,
|
|
68
|
+
onClick: onAddDomain,
|
|
69
|
+
children: [
|
|
70
|
+
"Add domain ",
|
|
71
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_icons.ExternalLinkIcon, {})
|
|
72
|
+
]
|
|
73
|
+
}
|
|
74
|
+
)
|
|
75
|
+
] })
|
|
76
|
+
}
|
|
77
|
+
);
|
|
71
78
|
}
|
|
72
79
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
73
80
|
import_themes.Flex,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/lib/admin-portal-domain-verification.tsx"],"sourcesContent":["\"use client\";\n\nimport * as React from \"react\";\nimport { Box, Button, Card, Flex, Text } from \"@radix-ui/themes\";\nimport { Skeleton } from \"./elements.js\";\nimport { IconPanel } from \"./icon-panel.js\";\nimport { GenericError } from \"./generic-error.js\";\nimport { ExternalLinkIcon } from \"@radix-ui/react-icons\";\nimport * as CardList from \"
|
|
1
|
+
{"version":3,"sources":["../../../src/lib/admin-portal-domain-verification.tsx"],"sourcesContent":["\"use client\";\n\nimport * as React from \"react\";\nimport { Box, Button, Card, Flex, Text } from \"@radix-ui/themes\";\nimport { Skeleton } from \"./elements.js\";\nimport { IconPanel } from \"./icon-panel.js\";\nimport { GenericError } from \"./generic-error.js\";\nimport { ExternalLinkIcon } from \"@radix-ui/react-icons\";\nimport * as CardList from \"./card-list.js\";\nimport { OrganizationDomain } from \"../api/endpoint.js\";\nimport { DomainItem } from \"./domain-item.js\";\n\nimport clsx from \"clsx\";\n\ninterface AdminPortalDomainVerificationProps {\n organizationDomains: OrganizationDomain[];\n onAddDomain: () => void;\n onDeleteDomain: (domainId: string) => void;\n onReverifyDomain: (domainId: string) => void;\n isPending?: boolean;\n}\n\nexport const AdminPortalDomainVerification = ({\n organizationDomains,\n onAddDomain,\n onDeleteDomain,\n onReverifyDomain,\n isPending = false,\n}: AdminPortalDomainVerificationProps) => {\n if (organizationDomains.length === 0) {\n return (\n <Card\n size=\"2\"\n data-woswidgets-widget-id=\"admin-portal-domain-verification\"\n >\n <Flex direction=\"row\" justify=\"between\" align=\"center\">\n <Text size=\"2\" color=\"gray\">\n You haven't added any verified domains yet.\n </Text>\n <Button\n variant=\"outline\"\n color=\"gray\"\n loading={isPending}\n disabled={isPending}\n onClick={onAddDomain}\n >\n Add domain <ExternalLinkIcon />\n </Button>\n </Flex>\n </Card>\n );\n }\n\n return (\n <Flex\n direction=\"column\"\n gap=\"4\"\n className={clsx(\"woswidgets-widget\")}\n data-woswidgets-widget-id=\"admin-portal-domain-verification\"\n >\n <CardList.Root>\n {organizationDomains.map((domain) => (\n <CardList.Item key={domain.id}>\n <DomainItem\n domain={domain}\n onDeleteDomain={onDeleteDomain}\n onReverifyDomain={onReverifyDomain}\n />\n </CardList.Item>\n ))}\n </CardList.Root>\n\n <Box>\n <Button\n loading={isPending}\n disabled={isPending}\n color=\"gray\"\n variant=\"outline\"\n onClick={onAddDomain}\n >\n Add domain <ExternalLinkIcon />\n </Button>\n </Box>\n </Flex>\n );\n};\n\nexport const AdminPortalDomainVerificationLoading: React.FC = () => {\n return (\n <Card size=\"2\">\n <Flex gap=\"4\" align=\"center\">\n <Skeleton>\n <IconPanel />\n </Skeleton>\n\n <Flex direction=\"column\">\n <Text size=\"2\" highContrast weight=\"bold\" as=\"p\" mb=\"-2px\">\n <Skeleton>Domain name</Skeleton>\n </Text>\n\n <Text size=\"2\" color=\"gray\" as=\"p\">\n <Skeleton>Added recently</Skeleton>\n </Text>\n </Flex>\n </Flex>\n </Card>\n );\n};\n\nexport function AdminPortalDomainVerificationError({\n error,\n}: {\n error: unknown;\n}) {\n return (\n <Card size=\"2\">\n <GenericError error={error} />\n </Card>\n );\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAoCU;AAjCV,oBAA8C;AAC9C,sBAAyB;AACzB,wBAA0B;AAC1B,2BAA6B;AAC7B,yBAAiC;AACjC,eAA0B;AAE1B,yBAA2B;AAE3B,kBAAiB;AAUV,MAAM,gCAAgC,CAAC;AAAA,EAC5C;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,YAAY;AACd,MAA0C;AACxC,MAAI,oBAAoB,WAAW,GAAG;AACpC,WACE;AAAA,MAAC;AAAA;AAAA,QACC,MAAK;AAAA,QACL,6BAA0B;AAAA,QAE1B,uDAAC,sBAAK,WAAU,OAAM,SAAQ,WAAU,OAAM,UAC5C;AAAA,sDAAC,sBAAK,MAAK,KAAI,OAAM,QAAO,yDAE5B;AAAA,UACA;AAAA,YAAC;AAAA;AAAA,cACC,SAAQ;AAAA,cACR,OAAM;AAAA,cACN,SAAS;AAAA,cACT,UAAU;AAAA,cACV,SAAS;AAAA,cACV;AAAA;AAAA,gBACY,4CAAC,uCAAiB;AAAA;AAAA;AAAA,UAC/B;AAAA,WACF;AAAA;AAAA,IACF;AAAA,EAEJ;AAEA,SACE;AAAA,IAAC;AAAA;AAAA,MACC,WAAU;AAAA,MACV,KAAI;AAAA,MACJ,eAAW,YAAAA,SAAK,mBAAmB;AAAA,MACnC,6BAA0B;AAAA,MAE1B;AAAA,oDAAC,SAAS,MAAT,EACE,8BAAoB,IAAI,CAAC,WACxB,4CAAC,SAAS,MAAT,EACC;AAAA,UAAC;AAAA;AAAA,YACC;AAAA,YACA;AAAA,YACA;AAAA;AAAA,QACF,KALkB,OAAO,EAM3B,CACD,GACH;AAAA,QAEA,4CAAC,qBACC;AAAA,UAAC;AAAA;AAAA,YACC,SAAS;AAAA,YACT,UAAU;AAAA,YACV,OAAM;AAAA,YACN,SAAQ;AAAA,YACR,SAAS;AAAA,YACV;AAAA;AAAA,cACY,4CAAC,uCAAiB;AAAA;AAAA;AAAA,QAC/B,GACF;AAAA;AAAA;AAAA,EACF;AAEJ;AAEO,MAAM,uCAAiD,MAAM;AAClE,SACE,4CAAC,sBAAK,MAAK,KACT,uDAAC,sBAAK,KAAI,KAAI,OAAM,UAClB;AAAA,gDAAC,4BACC,sDAAC,+BAAU,GACb;AAAA,IAEA,6CAAC,sBAAK,WAAU,UACd;AAAA,kDAAC,sBAAK,MAAK,KAAI,cAAY,MAAC,QAAO,QAAO,IAAG,KAAI,IAAG,QAClD,sDAAC,4BAAS,yBAAW,GACvB;AAAA,MAEA,4CAAC,sBAAK,MAAK,KAAI,OAAM,QAAO,IAAG,KAC7B,sDAAC,4BAAS,4BAAc,GAC1B;AAAA,OACF;AAAA,KACF,GACF;AAEJ;AAEO,SAAS,mCAAmC;AAAA,EACjD;AACF,GAEG;AACD,SACE,4CAAC,sBAAK,MAAK,KACT,sDAAC,qCAAa,OAAc,GAC9B;AAEJ;","names":["clsx"]}
|
|
@@ -41,13 +41,13 @@ var import_themes = require("@radix-ui/themes");
|
|
|
41
41
|
var import_elements = require("./elements.js");
|
|
42
42
|
var import_icon_panel = require("./icon-panel.js");
|
|
43
43
|
var import_react_icons = require("@radix-ui/react-icons");
|
|
44
|
-
var CardList = __toESM(require("
|
|
44
|
+
var CardList = __toESM(require("./card-list.js"), 1);
|
|
45
45
|
var import_provider_icon = require("./provider-icon.js");
|
|
46
46
|
var import_identity_providers = require("./identity-providers.js");
|
|
47
47
|
var import_status = require("./status.js");
|
|
48
48
|
var import_utils = require("./utils.js");
|
|
49
49
|
var import_clsx = __toESM(require("clsx"), 1);
|
|
50
|
-
var
|
|
50
|
+
var import_generic_error = require("./generic-error.js");
|
|
51
51
|
const AdminPortalSsoConnectionContext = React.createContext(null);
|
|
52
52
|
AdminPortalSsoConnectionContext.displayName = "AdminPortalSsoConnectionContext";
|
|
53
53
|
function useAdminPortalSsoConnectionContext() {
|
|
@@ -249,30 +249,7 @@ function AdminPortalSsoConnectionError({ error }) {
|
|
|
249
249
|
React.useEffect(() => {
|
|
250
250
|
console.error(error);
|
|
251
251
|
}, [error]);
|
|
252
|
-
const { heading, message } = (()
|
|
253
|
-
if (error instanceof import_errors.FetchError) {
|
|
254
|
-
return {
|
|
255
|
-
heading: "Error fetching data",
|
|
256
|
-
message: "An error occurred. You may need to configure CORS in the WorkOS Dashboard. Contact your organization admin for support."
|
|
257
|
-
};
|
|
258
|
-
}
|
|
259
|
-
if (error instanceof import_errors.NoAuthTokenError) {
|
|
260
|
-
return {
|
|
261
|
-
heading: "Error fetching data",
|
|
262
|
-
message: "Authorization error. You likely forgot to provide an authorization token to the Users Management Widget."
|
|
263
|
-
};
|
|
264
|
-
}
|
|
265
|
-
if (error instanceof import_errors.ApiError && error.status === 404) {
|
|
266
|
-
return {
|
|
267
|
-
heading: "Error fetching data",
|
|
268
|
-
message: "Authorization error. Contact your organization admin for support."
|
|
269
|
-
};
|
|
270
|
-
}
|
|
271
|
-
return {
|
|
272
|
-
heading: "Unknown error",
|
|
273
|
-
message: "An unexpected error occurred. Please try refreshing the page, or contact your organization admin for support."
|
|
274
|
-
};
|
|
275
|
-
})();
|
|
252
|
+
const { heading, message } = (0, import_generic_error.getErrorMessage)(error);
|
|
276
253
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_themes.Card, { size: "2", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_themes.Flex, { direction: "row", justify: "between", align: "center", gap: "2", children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_themes.Flex, { gap: "4", align: "center", children: [
|
|
277
254
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
278
255
|
import_themes.Flex,
|
|
@@ -284,7 +261,8 @@ function AdminPortalSsoConnectionError({ error }) {
|
|
|
284
261
|
style: {
|
|
285
262
|
borderRadius: "9999px",
|
|
286
263
|
backgroundColor: "var(--red-a4)",
|
|
287
|
-
color: "var(--red-a11)"
|
|
264
|
+
color: "var(--red-a11)",
|
|
265
|
+
flexShrink: 0
|
|
288
266
|
},
|
|
289
267
|
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_icons.Cross2Icon, { width: "18px", height: "18px" })
|
|
290
268
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/lib/admin-portal-sso-connection.tsx"],"sourcesContent":["\"use client\";\n\nimport * as React from \"react\";\nimport { Box, Button, Card, Flex, Text } from \"@radix-ui/themes\";\nimport { Skeleton } from \"./elements.js\";\nimport { IconPanel } from \"./icon-panel.js\";\nimport {\n ExternalLinkIcon,\n InfoCircledIcon,\n Cross2Icon,\n} from \"@radix-ui/react-icons\";\nimport * as CardList from \"../card-list.js\";\nimport { ProviderIcon } from \"./provider-icon.js\";\nimport {\n getIdentityProviderName,\n type IdentityProvider,\n} from \"./identity-providers.js\";\nimport { Status } from \"./status.js\";\nimport { unreachable } from \"./utils.js\";\nimport clsx from \"clsx\";\n\nimport { ApiError, FetchError, NoAuthTokenError } from \"./errors.js\";\n\ninterface NotConfiguredProps {\n connectionStatus: \"NotConfigured\";\n identityProvider?: never;\n expiryDate?: never;\n}\n\ninterface InactiveProps {\n connectionStatus: \"Inactive\";\n identityProvider: IdentityProvider;\n expiryDate?: never;\n}\n\ninterface ActiveProps {\n connectionStatus: \"Active\";\n identityProvider: IdentityProvider;\n expiryDate?: never;\n}\n\ninterface RequiresActionProps {\n connectionStatus: \"Expired\" | \"Expiring\";\n identityProvider: IdentityProvider;\n expiryDate: Date | null;\n}\n\nexport type AdminPortalSsoConnectionStatusProps =\n | NotConfiguredProps\n | InactiveProps\n | ActiveProps\n | RequiresActionProps;\n\nexport type AdminPortalSsoConnectionProps =\n AdminPortalSsoConnectionStatusProps & {\n currentDate: Date | null;\n\n lastSession: Date | null;\n adminPortalOpenButton: React.ReactNode;\n };\n\ninterface AdminPortalSsoConnectionContextValue {\n connectionStatus: AdminPortalSsoConnectionStatusProps[\"connectionStatus\"];\n}\n\nconst AdminPortalSsoConnectionContext =\n React.createContext<AdminPortalSsoConnectionContextValue | null>(null);\nAdminPortalSsoConnectionContext.displayName = \"AdminPortalSsoConnectionContext\";\n\nfunction useAdminPortalSsoConnectionContext() {\n const context = React.useContext(AdminPortalSsoConnectionContext);\n if (!context) {\n throw new Error(\n \"useAdminPortalSsoConnectionContext must be used within a AdminPortalSsoConnectionContext provider\",\n );\n }\n return context;\n}\n\nexport const AdminPortalSsoConnection = ({\n currentDate,\n connectionStatus,\n identityProvider,\n expiryDate,\n lastSession,\n adminPortalOpenButton,\n}: AdminPortalSsoConnectionProps) => {\n return (\n <CardList.Root\n size=\"2\"\n className={clsx(\"woswidgets-widget\")}\n data-woswidgets-widget-id=\"admin-portal-sso-connection\"\n >\n <AdminPortalSsoConnectionContext.Provider value={{ connectionStatus }}>\n <CardList.Item>\n <Flex direction=\"row\" justify=\"between\" align=\"center\" gap=\"2\">\n {(() => {\n if (connectionStatus === \"NotConfigured\") {\n return (\n <>\n <Text size=\"2\" color=\"gray\" ml=\"2\">\n You haven’t set up Single Sign-On yet.\n </Text>\n {adminPortalOpenButton}\n </>\n );\n }\n\n return (\n <>\n <SessionInfo\n connectionStatus={connectionStatus}\n identityProvider={identityProvider}\n lastSession={lastSession}\n currentDate={currentDate}\n />\n <Flex gap=\"5\" align=\"center\">\n <SsoStatus status={connectionStatus} />\n {adminPortalOpenButton}\n </Flex>\n </>\n );\n })()}\n </Flex>\n </CardList.Item>\n {connectionStatus === \"Expired\" && (\n <CardList.Item>\n <Flex align=\"start\" gap=\"2\">\n <Box asChild mt=\"2px\" flexShrink=\"0\">\n <InfoCircledIcon color=\"gray\" />\n </Box>\n {(() => {\n if (connectionStatus === \"Expired\") {\n return (\n <Text size=\"2\" color=\"gray\">\n {(() => {\n if (!expiryDate) {\n return \"The SAML response signing certificate has expired\";\n }\n\n return (\n <>\n The SAML response signing certificate expired on{\" \"}\n <Text weight=\"bold\" as=\"span\">\n {expiryDate?.toLocaleString(\"en-US\", {\n month: \"long\",\n day: \"numeric\",\n year: \"numeric\",\n })}\n </Text>\n </>\n );\n })()}\n . Users won’t be able to sign-in to the application until\n the certificate is renewed.\n </Text>\n );\n }\n\n if (connectionStatus === \"Expiring\") {\n return (\n <Text size=\"2\" color=\"gray\">\n {(() => {\n if (!expiryDate) {\n return \"The SAML response signing certificate is expiring soon\";\n }\n\n return (\n <>\n The SAML response signing certificate will expire on{\" \"}\n <Text weight=\"bold\" as=\"span\">\n {expiryDate?.toLocaleString(\"en-US\", {\n month: \"long\",\n day: \"numeric\",\n year: \"numeric\",\n })}\n </Text>\n </>\n );\n })()}\n . When expired, users won’t be able to sign-in.\n </Text>\n );\n }\n })()}\n </Flex>\n </CardList.Item>\n )}\n </AdminPortalSsoConnectionContext.Provider>\n </CardList.Root>\n );\n};\n\nfunction SsoStatus({\n status,\n}: {\n status: AdminPortalSsoConnectionStatusProps[\"connectionStatus\"];\n}) {\n if (status === \"NotConfigured\") {\n return null;\n }\n\n if (status === \"Inactive\") {\n return <Status state=\"waiting\">Setup in progress</Status>;\n }\n\n if (status === \"Expired\") {\n return <Status state=\"error\">Requires action</Status>;\n }\n\n if (status === \"Active\" || status === \"Expiring\") {\n return <Status state=\"success\">Connected</Status>;\n }\n\n return unreachable(status);\n}\n\nfunction SessionInfo({\n currentDate,\n identityProvider,\n lastSession,\n connectionStatus,\n}: {\n identityProvider: IdentityProvider;\n lastSession: Date | null;\n currentDate: Date | null;\n connectionStatus: AdminPortalSsoConnectionStatusProps[\"connectionStatus\"];\n}) {\n const relativeTimeString = React.useMemo(() => {\n if (\n !lastSession ||\n !currentDate ||\n connectionStatus === \"NotConfigured\" ||\n connectionStatus === \"Inactive\"\n ) {\n return null;\n }\n\n return getRelativeTimeString(currentDate, lastSession);\n }, [lastSession, currentDate, connectionStatus]);\n\n return (\n <Flex gap=\"4\" align=\"center\">\n <IconPanel color=\"panel\">\n <ProviderIcon provider={identityProvider} size=\"2\" />\n </IconPanel>\n {lastSession ? (\n <Flex direction=\"column\">\n <Text size=\"2\" weight=\"bold\">\n {getIdentityProviderName(identityProvider)}\n </Text>\n {relativeTimeString ? (\n <Text color=\"gray\" size=\"2\">\n Last session {relativeTimeString}\n </Text>\n ) : null}\n </Flex>\n ) : (\n <Text size=\"2\" weight=\"bold\">\n {getIdentityProviderName(identityProvider)}\n </Text>\n )}\n </Flex>\n );\n}\n\nexport function AdminPortalOpenButton({\n isPending,\n href,\n initConfig,\n}: {\n isPending: boolean;\n href: string | null;\n initConfig: () => void;\n}) {\n const { connectionStatus } = useAdminPortalSsoConnectionContext();\n const label = (() => {\n switch (connectionStatus) {\n case \"NotConfigured\":\n return \"Set up SSO\";\n case \"Inactive\":\n return \"Continue setup\";\n case \"Active\":\n case \"Expiring\":\n case \"Expired\":\n return \"Manage\";\n default:\n return unreachable(connectionStatus);\n }\n })();\n\n if (href) {\n return (\n <Button variant=\"outline\" color=\"gray\" asChild>\n <a href={href} target=\"_blank\" rel=\"noopener noreferrer\">\n {label} <ExternalLinkIcon />\n </a>\n </Button>\n );\n }\n\n return (\n <Button\n variant=\"outline\"\n color=\"gray\"\n loading={isPending}\n disabled={isPending}\n onClick={initConfig}\n >\n {label} <ExternalLinkIcon />\n </Button>\n );\n}\n\nexport const AdminPortalSsoConnectionLoading: React.FC = () => {\n return (\n <Card size=\"2\">\n <Flex direction=\"row\" justify=\"between\" align=\"center\" gap=\"2\">\n <Flex gap=\"4\" align=\"center\">\n <Skeleton>\n <IconPanel color=\"panel\">\n <ProviderIcon provider=\"okta\" size=\"2\" />\n </IconPanel>\n </Skeleton>\n <Flex direction=\"column\" gap=\"1\" my=\"-4px\">\n <Skeleton>\n <Text size=\"1\">Okta</Text>\n </Skeleton>\n <Skeleton>\n <Text size=\"1\">Last session 10 minutes ago</Text>\n </Skeleton>\n </Flex>\n </Flex>\n <Flex gap=\"5\" align=\"center\">\n <Skeleton>\n <Status state=\"error\">Requires action</Status>\n </Skeleton>\n <Skeleton>\n <Button variant=\"outline\" color=\"gray\">\n Manage <ExternalLinkIcon />\n </Button>\n </Skeleton>\n </Flex>\n </Flex>\n </Card>\n );\n};\n\nexport function AdminPortalSsoConnectionError({ error }: { error: unknown }) {\n React.useEffect(() => {\n console.error(error);\n }, [error]);\n\n const { heading, message } = (() => {\n if (error instanceof FetchError) {\n return {\n heading: \"Error fetching data\",\n message:\n \"An error occurred. You may need to configure CORS in the WorkOS Dashboard. \" +\n \"Contact your organization admin for support.\",\n };\n }\n\n if (error instanceof NoAuthTokenError) {\n return {\n heading: \"Error fetching data\",\n message:\n \"Authorization error. You likely forgot to provide an authorization \" +\n \"token to the Users Management Widget.\",\n };\n }\n\n if (error instanceof ApiError && error.status === 404) {\n // The widgets API treats all authorization errors as 404s. If there is a\n // legitimate 404, it's a bug on our end but there's currently no way to\n // distinguish between the two.\n return {\n heading: \"Error fetching data\",\n message:\n \"Authorization error. Contact your organization admin for support.\",\n };\n }\n\n return {\n heading: \"Unknown error\",\n message:\n \"An unexpected error occurred. Please try refreshing the page, or contact your organization admin for support.\",\n };\n })();\n\n return (\n <Card size=\"2\">\n <Flex direction=\"row\" justify=\"between\" align=\"center\" gap=\"2\">\n <Flex gap=\"4\" align=\"center\">\n <Flex\n align=\"center\"\n justify=\"center\"\n width=\"24px\"\n height=\"24px\"\n style={{\n borderRadius: \"9999px\",\n backgroundColor: \"var(--red-a4)\",\n color: \"var(--red-a11)\",\n }}\n >\n <Cross2Icon width=\"18px\" height=\"18px\" />\n </Flex>\n <Flex direction=\"column\">\n <Text size=\"2\" weight=\"bold\">\n {heading}\n </Text>\n <Text size=\"2\" color=\"gray\">\n {message}\n </Text>\n </Flex>\n </Flex>\n </Flex>\n </Card>\n );\n}\n\nfunction getRelativeTimeString(\n currentDate: Date | null,\n lastSession: Date | null,\n) {\n if (!currentDate || !lastSession) {\n return null;\n }\n\n const rtf = new Intl.RelativeTimeFormat(\"en\", { numeric: \"auto\" });\n const diff = lastSession.getTime() - currentDate.getTime();\n\n const diffSeconds = Math.round(diff / 1000);\n const diffMinutes = Math.round(diffSeconds / 60);\n const diffHours = Math.round(diffMinutes / 60);\n const diffDays = Math.round(diffHours / 24);\n const diffMonths = Math.round(diffDays / 30);\n const diffYears = Math.round(diffMonths / 12);\n\n if (Math.abs(diffSeconds) < 60) {\n return \"now\";\n }\n\n if (Math.abs(diffMinutes) < 60) {\n return rtf.format(diffMinutes, \"minute\");\n }\n\n if (Math.abs(diffHours) < 24) {\n return rtf.format(diffHours, \"hour\");\n }\n\n if (Math.abs(diffDays) < 30) {\n return rtf.format(diffDays, \"day\");\n }\n\n if (Math.abs(diffMonths) < 12) {\n return rtf.format(diffMonths, \"month\");\n }\n\n return rtf.format(diffYears, \"year\");\n}\n"],"mappings":"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","names":["clsx"]}
|
|
1
|
+
{"version":3,"sources":["../../../src/lib/admin-portal-sso-connection.tsx"],"sourcesContent":["\"use client\";\n\nimport * as React from \"react\";\nimport { Box, Button, Card, Flex, Text } from \"@radix-ui/themes\";\nimport { Skeleton } from \"./elements.js\";\nimport { IconPanel } from \"./icon-panel.js\";\nimport {\n ExternalLinkIcon,\n InfoCircledIcon,\n Cross2Icon,\n} from \"@radix-ui/react-icons\";\nimport * as CardList from \"./card-list.js\";\nimport { ProviderIcon } from \"./provider-icon.js\";\nimport {\n getIdentityProviderName,\n type IdentityProvider,\n} from \"./identity-providers.js\";\nimport { Status } from \"./status.js\";\nimport { unreachable } from \"./utils.js\";\nimport clsx from \"clsx\";\nimport { getErrorMessage } from \"./generic-error.js\";\n\ninterface NotConfiguredProps {\n connectionStatus: \"NotConfigured\";\n identityProvider?: never;\n expiryDate?: never;\n}\n\ninterface InactiveProps {\n connectionStatus: \"Inactive\";\n identityProvider: IdentityProvider;\n expiryDate?: never;\n}\n\ninterface ActiveProps {\n connectionStatus: \"Active\";\n identityProvider: IdentityProvider;\n expiryDate?: never;\n}\n\ninterface RequiresActionProps {\n connectionStatus: \"Expired\" | \"Expiring\";\n identityProvider: IdentityProvider;\n expiryDate: Date | null;\n}\n\nexport type AdminPortalSsoConnectionStatusProps =\n | NotConfiguredProps\n | InactiveProps\n | ActiveProps\n | RequiresActionProps;\n\nexport type AdminPortalSsoConnectionProps =\n AdminPortalSsoConnectionStatusProps & {\n currentDate: Date | null;\n\n lastSession: Date | null;\n adminPortalOpenButton: React.ReactNode;\n };\n\ninterface AdminPortalSsoConnectionContextValue {\n connectionStatus: AdminPortalSsoConnectionStatusProps[\"connectionStatus\"];\n}\n\nconst AdminPortalSsoConnectionContext =\n React.createContext<AdminPortalSsoConnectionContextValue | null>(null);\nAdminPortalSsoConnectionContext.displayName = \"AdminPortalSsoConnectionContext\";\n\nfunction useAdminPortalSsoConnectionContext() {\n const context = React.useContext(AdminPortalSsoConnectionContext);\n if (!context) {\n throw new Error(\n \"useAdminPortalSsoConnectionContext must be used within a AdminPortalSsoConnectionContext provider\",\n );\n }\n return context;\n}\n\nexport const AdminPortalSsoConnection = ({\n currentDate,\n connectionStatus,\n identityProvider,\n expiryDate,\n lastSession,\n adminPortalOpenButton,\n}: AdminPortalSsoConnectionProps) => {\n return (\n <CardList.Root\n size=\"2\"\n className={clsx(\"woswidgets-widget\")}\n data-woswidgets-widget-id=\"admin-portal-sso-connection\"\n >\n <AdminPortalSsoConnectionContext.Provider value={{ connectionStatus }}>\n <CardList.Item>\n <Flex direction=\"row\" justify=\"between\" align=\"center\" gap=\"2\">\n {(() => {\n if (connectionStatus === \"NotConfigured\") {\n return (\n <>\n <Text size=\"2\" color=\"gray\" ml=\"2\">\n You haven’t set up Single Sign-On yet.\n </Text>\n {adminPortalOpenButton}\n </>\n );\n }\n\n return (\n <>\n <SessionInfo\n connectionStatus={connectionStatus}\n identityProvider={identityProvider}\n lastSession={lastSession}\n currentDate={currentDate}\n />\n <Flex gap=\"5\" align=\"center\">\n <SsoStatus status={connectionStatus} />\n {adminPortalOpenButton}\n </Flex>\n </>\n );\n })()}\n </Flex>\n </CardList.Item>\n {connectionStatus === \"Expired\" && (\n <CardList.Item>\n <Flex align=\"start\" gap=\"2\">\n <Box asChild mt=\"2px\" flexShrink=\"0\">\n <InfoCircledIcon color=\"gray\" />\n </Box>\n {(() => {\n if (connectionStatus === \"Expired\") {\n return (\n <Text size=\"2\" color=\"gray\">\n {(() => {\n if (!expiryDate) {\n return \"The SAML response signing certificate has expired\";\n }\n\n return (\n <>\n The SAML response signing certificate expired on{\" \"}\n <Text weight=\"bold\" as=\"span\">\n {expiryDate?.toLocaleString(\"en-US\", {\n month: \"long\",\n day: \"numeric\",\n year: \"numeric\",\n })}\n </Text>\n </>\n );\n })()}\n . Users won’t be able to sign-in to the application until\n the certificate is renewed.\n </Text>\n );\n }\n\n if (connectionStatus === \"Expiring\") {\n return (\n <Text size=\"2\" color=\"gray\">\n {(() => {\n if (!expiryDate) {\n return \"The SAML response signing certificate is expiring soon\";\n }\n\n return (\n <>\n The SAML response signing certificate will expire on{\" \"}\n <Text weight=\"bold\" as=\"span\">\n {expiryDate?.toLocaleString(\"en-US\", {\n month: \"long\",\n day: \"numeric\",\n year: \"numeric\",\n })}\n </Text>\n </>\n );\n })()}\n . When expired, users won’t be able to sign-in.\n </Text>\n );\n }\n })()}\n </Flex>\n </CardList.Item>\n )}\n </AdminPortalSsoConnectionContext.Provider>\n </CardList.Root>\n );\n};\n\nfunction SsoStatus({\n status,\n}: {\n status: AdminPortalSsoConnectionStatusProps[\"connectionStatus\"];\n}) {\n if (status === \"NotConfigured\") {\n return null;\n }\n\n if (status === \"Inactive\") {\n return <Status state=\"waiting\">Setup in progress</Status>;\n }\n\n if (status === \"Expired\") {\n return <Status state=\"error\">Requires action</Status>;\n }\n\n if (status === \"Active\" || status === \"Expiring\") {\n return <Status state=\"success\">Connected</Status>;\n }\n\n return unreachable(status);\n}\n\nfunction SessionInfo({\n currentDate,\n identityProvider,\n lastSession,\n connectionStatus,\n}: {\n identityProvider: IdentityProvider;\n lastSession: Date | null;\n currentDate: Date | null;\n connectionStatus: AdminPortalSsoConnectionStatusProps[\"connectionStatus\"];\n}) {\n const relativeTimeString = React.useMemo(() => {\n if (\n !lastSession ||\n !currentDate ||\n connectionStatus === \"NotConfigured\" ||\n connectionStatus === \"Inactive\"\n ) {\n return null;\n }\n\n return getRelativeTimeString(currentDate, lastSession);\n }, [lastSession, currentDate, connectionStatus]);\n\n return (\n <Flex gap=\"4\" align=\"center\">\n <IconPanel color=\"panel\">\n <ProviderIcon provider={identityProvider} size=\"2\" />\n </IconPanel>\n {lastSession ? (\n <Flex direction=\"column\">\n <Text size=\"2\" weight=\"bold\">\n {getIdentityProviderName(identityProvider)}\n </Text>\n {relativeTimeString ? (\n <Text color=\"gray\" size=\"2\">\n Last session {relativeTimeString}\n </Text>\n ) : null}\n </Flex>\n ) : (\n <Text size=\"2\" weight=\"bold\">\n {getIdentityProviderName(identityProvider)}\n </Text>\n )}\n </Flex>\n );\n}\n\nexport function AdminPortalOpenButton({\n isPending,\n href,\n initConfig,\n}: {\n isPending: boolean;\n href: string | null;\n initConfig: () => void;\n}) {\n const { connectionStatus } = useAdminPortalSsoConnectionContext();\n const label = (() => {\n switch (connectionStatus) {\n case \"NotConfigured\":\n return \"Set up SSO\";\n case \"Inactive\":\n return \"Continue setup\";\n case \"Active\":\n case \"Expiring\":\n case \"Expired\":\n return \"Manage\";\n default:\n return unreachable(connectionStatus);\n }\n })();\n\n if (href) {\n return (\n <Button variant=\"outline\" color=\"gray\" asChild>\n <a href={href} target=\"_blank\" rel=\"noopener noreferrer\">\n {label} <ExternalLinkIcon />\n </a>\n </Button>\n );\n }\n\n return (\n <Button\n variant=\"outline\"\n color=\"gray\"\n loading={isPending}\n disabled={isPending}\n onClick={initConfig}\n >\n {label} <ExternalLinkIcon />\n </Button>\n );\n}\n\nexport const AdminPortalSsoConnectionLoading: React.FC = () => {\n return (\n <Card size=\"2\">\n <Flex direction=\"row\" justify=\"between\" align=\"center\" gap=\"2\">\n <Flex gap=\"4\" align=\"center\">\n <Skeleton>\n <IconPanel color=\"panel\">\n <ProviderIcon provider=\"okta\" size=\"2\" />\n </IconPanel>\n </Skeleton>\n <Flex direction=\"column\" gap=\"1\" my=\"-4px\">\n <Skeleton>\n <Text size=\"1\">Okta</Text>\n </Skeleton>\n <Skeleton>\n <Text size=\"1\">Last session 10 minutes ago</Text>\n </Skeleton>\n </Flex>\n </Flex>\n <Flex gap=\"5\" align=\"center\">\n <Skeleton>\n <Status state=\"error\">Requires action</Status>\n </Skeleton>\n <Skeleton>\n <Button variant=\"outline\" color=\"gray\">\n Manage <ExternalLinkIcon />\n </Button>\n </Skeleton>\n </Flex>\n </Flex>\n </Card>\n );\n};\n\nexport function AdminPortalSsoConnectionError({ error }: { error: unknown }) {\n React.useEffect(() => {\n console.error(error);\n }, [error]);\n\n const { heading, message } = getErrorMessage(error);\n\n return (\n <Card size=\"2\">\n <Flex direction=\"row\" justify=\"between\" align=\"center\" gap=\"2\">\n <Flex gap=\"4\" align=\"center\">\n <Flex\n align=\"center\"\n justify=\"center\"\n width=\"24px\"\n height=\"24px\"\n style={{\n borderRadius: \"9999px\",\n backgroundColor: \"var(--red-a4)\",\n color: \"var(--red-a11)\",\n flexShrink: 0,\n }}\n >\n <Cross2Icon width=\"18px\" height=\"18px\" />\n </Flex>\n <Flex direction=\"column\">\n <Text size=\"2\" weight=\"bold\">\n {heading}\n </Text>\n <Text size=\"2\" color=\"gray\">\n {message}\n </Text>\n </Flex>\n </Flex>\n </Flex>\n </Card>\n );\n}\n\nfunction getRelativeTimeString(\n currentDate: Date | null,\n lastSession: Date | null,\n) {\n if (!currentDate || !lastSession) {\n return null;\n }\n\n const rtf = new Intl.RelativeTimeFormat(\"en\", { numeric: \"auto\" });\n const diff = lastSession.getTime() - currentDate.getTime();\n\n const diffSeconds = Math.round(diff / 1000);\n const diffMinutes = Math.round(diffSeconds / 60);\n const diffHours = Math.round(diffMinutes / 60);\n const diffDays = Math.round(diffHours / 24);\n const diffMonths = Math.round(diffDays / 30);\n const diffYears = Math.round(diffMonths / 12);\n\n if (Math.abs(diffSeconds) < 60) {\n return \"now\";\n }\n\n if (Math.abs(diffMinutes) < 60) {\n return rtf.format(diffMinutes, \"minute\");\n }\n\n if (Math.abs(diffHours) < 24) {\n return rtf.format(diffHours, \"hour\");\n }\n\n if (Math.abs(diffDays) < 30) {\n return rtf.format(diffDays, \"day\");\n }\n\n if (Math.abs(diffMonths) < 12) {\n return rtf.format(diffMonths, \"month\");\n }\n\n return rtf.format(diffYears, \"year\");\n}\n"],"mappings":"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","names":["clsx"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/lib/card-list.tsx"],"sourcesContent":["import { Box, Card, CardProps, Inset } from \"@radix-ui/themes\";\n\nexport function Root({ children, ...props }: CardProps) {\n return (\n <Card size=\"2\" {...props} className=\"woswidgets-card-list\">\n <Inset side=\"all\" clip=\"padding-box\">\n {children}\n </Inset>\n </Card>\n );\n}\n\nexport function Item({ children }: { children: React.ReactNode }) {\n return (\n <Inset\n side=\"x\"\n px=\"current\"\n className=\"woswidgets-card-list-item\"\n clip=\"padding-box\"\n >\n <Box px=\"4\" py=\"4\">\n {children}\n </Box>\n </Inset>\n );\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAKM;AALN,oBAA4C;AAErC,SAAS,KAAK,EAAE,UAAU,GAAG,MAAM,GAAc;AACtD,SACE,4CAAC,sBAAK,MAAK,KAAK,GAAG,OAAO,WAAU,wBAClC,sDAAC,uBAAM,MAAK,OAAM,MAAK,eACpB,UACH,GACF;AAEJ;AAEO,SAAS,KAAK,EAAE,SAAS,GAAkC;AAChE,SACE;AAAA,IAAC;AAAA;AAAA,MACC,MAAK;AAAA,MACL,IAAG;AAAA,MACH,WAAU;AAAA,MACV,MAAK;AAAA,MAEL,sDAAC,qBAAI,IAAG,KAAI,IAAG,KACZ,UACH;AAAA;AAAA,EACF;AAEJ;","names":[]}
|
package/dist/cjs/lib/errors.cjs
CHANGED
|
@@ -52,7 +52,7 @@ class NoAuthTokenError extends Error {
|
|
|
52
52
|
class IncorrectPermissionsError extends Error {
|
|
53
53
|
constructor(args) {
|
|
54
54
|
super("Incorrect permissions");
|
|
55
|
-
this.name = "
|
|
55
|
+
this.name = "IncorrectPermissionsError";
|
|
56
56
|
this.context = args?.context;
|
|
57
57
|
}
|
|
58
58
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/lib/errors.ts"],"sourcesContent":["type QueryType = \"query\" | \"mutation\";\ntype RecordType = \"users\" | \"roles\";\n\nexport class FetchError extends Error {\n queryType: QueryType;\n recordType: RecordType;\n context: unknown;\n constructor(args: {\n message: string;\n queryType: QueryType;\n recordType: RecordType;\n context?: unknown;\n }) {\n super(args.message);\n this.name = \"FetchError\";\n this.queryType = args.queryType;\n this.recordType = args.recordType;\n this.context = args.context;\n }\n}\n\nexport class ApiError extends Error {\n status: number;\n queryType: QueryType;\n recordType: RecordType;\n context: unknown;\n constructor(args: {\n message: string;\n queryType: QueryType;\n recordType: RecordType;\n status: number;\n context?: unknown;\n }) {\n super(args.message);\n this.name = \"ApiError\";\n this.status = args.status;\n this.queryType = args.queryType;\n this.recordType = args.recordType;\n }\n}\n\nexport class NoAuthTokenError extends Error {\n context: unknown;\n constructor(args?: { context?: unknown }) {\n super(\"No auth token provided\");\n this.name = \"NoAuthTokenError\";\n this.context = args?.context;\n }\n}\n\nexport class IncorrectPermissionsError extends Error {\n context: unknown;\n constructor(args?: { context?: unknown }) {\n super(\"Incorrect permissions\");\n this.name = \"
|
|
1
|
+
{"version":3,"sources":["../../../src/lib/errors.ts"],"sourcesContent":["type QueryType = \"query\" | \"mutation\";\ntype RecordType = \"users\" | \"roles\";\n\nexport class FetchError extends Error {\n queryType: QueryType;\n recordType: RecordType;\n context: unknown;\n constructor(args: {\n message: string;\n queryType: QueryType;\n recordType: RecordType;\n context?: unknown;\n }) {\n super(args.message);\n this.name = \"FetchError\";\n this.queryType = args.queryType;\n this.recordType = args.recordType;\n this.context = args.context;\n }\n}\n\nexport class ApiError extends Error {\n status: number;\n queryType: QueryType;\n recordType: RecordType;\n context: unknown;\n constructor(args: {\n message: string;\n queryType: QueryType;\n recordType: RecordType;\n status: number;\n context?: unknown;\n }) {\n super(args.message);\n this.name = \"ApiError\";\n this.status = args.status;\n this.queryType = args.queryType;\n this.recordType = args.recordType;\n }\n}\n\nexport class NoAuthTokenError extends Error {\n context: unknown;\n constructor(args?: { context?: unknown }) {\n super(\"No auth token provided\");\n this.name = \"NoAuthTokenError\";\n this.context = args?.context;\n }\n}\n\nexport class IncorrectPermissionsError extends Error {\n context: unknown;\n constructor(args?: { context?: unknown }) {\n super(\"Incorrect permissions\");\n this.name = \"IncorrectPermissionsError\";\n this.context = args?.context;\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGO,MAAM,mBAAmB,MAAM;AAAA,EAIpC,YAAY,MAKT;AACD,UAAM,KAAK,OAAO;AAClB,SAAK,OAAO;AACZ,SAAK,YAAY,KAAK;AACtB,SAAK,aAAa,KAAK;AACvB,SAAK,UAAU,KAAK;AAAA,EACtB;AACF;AAEO,MAAM,iBAAiB,MAAM;AAAA,EAKlC,YAAY,MAMT;AACD,UAAM,KAAK,OAAO;AAClB,SAAK,OAAO;AACZ,SAAK,SAAS,KAAK;AACnB,SAAK,YAAY,KAAK;AACtB,SAAK,aAAa,KAAK;AAAA,EACzB;AACF;AAEO,MAAM,yBAAyB,MAAM;AAAA,EAE1C,YAAY,MAA8B;AACxC,UAAM,wBAAwB;AAC9B,SAAK,OAAO;AACZ,SAAK,UAAU,MAAM;AAAA,EACvB;AACF;AAEO,MAAM,kCAAkC,MAAM;AAAA,EAEnD,YAAY,MAA8B;AACxC,UAAM,uBAAuB;AAC7B,SAAK,OAAO;AACZ,SAAK,UAAU,MAAM;AAAA,EACvB;AACF;","names":[]}
|
|
@@ -28,7 +28,8 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
28
28
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
29
29
|
var generic_error_exports = {};
|
|
30
30
|
__export(generic_error_exports, {
|
|
31
|
-
GenericError: () => GenericError
|
|
31
|
+
GenericError: () => GenericError,
|
|
32
|
+
getErrorMessage: () => getErrorMessage
|
|
32
33
|
});
|
|
33
34
|
module.exports = __toCommonJS(generic_error_exports);
|
|
34
35
|
var import_jsx_runtime = require("react/jsx-runtime");
|
|
@@ -40,7 +41,7 @@ function GenericError({ error }) {
|
|
|
40
41
|
React.useEffect(() => {
|
|
41
42
|
console.error(error);
|
|
42
43
|
}, [error]);
|
|
43
|
-
const render = (
|
|
44
|
+
const render = (heading2, message2) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_themes.Flex, { p: "6", justify: "center", align: "center", direction: "column", children: [
|
|
44
45
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
45
46
|
import_themes.Flex,
|
|
46
47
|
{
|
|
@@ -58,52 +59,40 @@ function GenericError({ error }) {
|
|
|
58
59
|
}
|
|
59
60
|
),
|
|
60
61
|
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_themes.Flex, { direction: "column", gap: "1", maxWidth: "420px", children: [
|
|
61
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_themes.Heading, { size: "5", align: "center", mb: "1", wrap: "balance", as: "h3", children:
|
|
62
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_themes.Text, { as: "p", align: "center", wrap: "balance", color: "gray", children:
|
|
62
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_themes.Heading, { size: "5", align: "center", mb: "1", wrap: "balance", as: "h3", children: heading2 }),
|
|
63
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_themes.Text, { as: "p", align: "center", wrap: "balance", color: "gray", children: message2 })
|
|
63
64
|
] })
|
|
64
65
|
] });
|
|
66
|
+
const { heading, message } = getErrorMessage(error);
|
|
67
|
+
return render(heading, message);
|
|
68
|
+
}
|
|
69
|
+
function getErrorMessage(error) {
|
|
65
70
|
if (error instanceof import_errors.FetchError) {
|
|
66
|
-
return
|
|
67
|
-
"Error fetching data",
|
|
68
|
-
"An error occurred. You may need to configure CORS in the WorkOS Dashboard.
|
|
69
|
-
|
|
71
|
+
return {
|
|
72
|
+
heading: "Error fetching data",
|
|
73
|
+
message: "An error occurred. You may need to configure CORS in the WorkOS Dashboard."
|
|
74
|
+
};
|
|
70
75
|
}
|
|
71
76
|
if (error instanceof import_errors.NoAuthTokenError) {
|
|
72
|
-
return
|
|
73
|
-
"
|
|
74
|
-
"
|
|
75
|
-
|
|
76
|
-
}
|
|
77
|
-
if (error instanceof import_errors.ApiError && error.status === 404) {
|
|
78
|
-
return render(
|
|
79
|
-
"Error fetching data",
|
|
80
|
-
"Authorization error. Contact your organization admin for support."
|
|
81
|
-
);
|
|
77
|
+
return {
|
|
78
|
+
heading: "Authorization error",
|
|
79
|
+
message: "You likely forgot to provide an authorization token to the widget."
|
|
80
|
+
};
|
|
82
81
|
}
|
|
83
82
|
if (error instanceof import_errors.IncorrectPermissionsError) {
|
|
84
|
-
return
|
|
85
|
-
"
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
" ",
|
|
89
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
90
|
-
import_themes.Link,
|
|
91
|
-
{
|
|
92
|
-
href: "https://workos.com/docs/user-management/widgets/user-management",
|
|
93
|
-
target: "_blank",
|
|
94
|
-
children: "Check that the correct permissions have been assigned."
|
|
95
|
-
}
|
|
96
|
-
)
|
|
97
|
-
] })
|
|
98
|
-
);
|
|
83
|
+
return {
|
|
84
|
+
heading: "Incorrect permissions",
|
|
85
|
+
message: "Check that the correct permissions have been assigned."
|
|
86
|
+
};
|
|
99
87
|
}
|
|
100
|
-
return
|
|
101
|
-
"Error fetching data",
|
|
102
|
-
"An
|
|
103
|
-
|
|
88
|
+
return {
|
|
89
|
+
heading: "Error fetching data",
|
|
90
|
+
message: "An unexpected error occurred. Check your network connection or try refreshing the page."
|
|
91
|
+
};
|
|
104
92
|
}
|
|
105
93
|
// Annotate the CommonJS export names for ESM import in node:
|
|
106
94
|
0 && (module.exports = {
|
|
107
|
-
GenericError
|
|
95
|
+
GenericError,
|
|
96
|
+
getErrorMessage
|
|
108
97
|
});
|
|
109
98
|
//# sourceMappingURL=generic-error.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/lib/generic-error.tsx"],"sourcesContent":["import * as React from \"react\";\nimport { Flex, Heading,
|
|
1
|
+
{"version":3,"sources":["../../../src/lib/generic-error.tsx"],"sourcesContent":["import * as React from \"react\";\nimport { Flex, Heading, Text } from \"@radix-ui/themes\";\nimport {\n FetchError,\n IncorrectPermissionsError,\n NoAuthTokenError,\n} from \"./errors.js\";\nimport { Cross2Icon } from \"@radix-ui/react-icons\";\n\nexport function GenericError({ error }: { error: unknown }) {\n React.useEffect(() => {\n console.error(error);\n }, [error]);\n\n const render = (heading: string, message: React.ReactNode) => (\n <Flex p=\"6\" justify=\"center\" align=\"center\" direction=\"column\">\n <Flex\n align=\"center\"\n justify=\"center\"\n width=\"32px\"\n height=\"32px\"\n mb=\"2\"\n style={{\n borderRadius: \"9999px\",\n backgroundColor: \"var(--red-a4)\",\n color: \"var(--red-a11)\",\n }}\n >\n <Cross2Icon width=\"24px\" height=\"24px\" />\n </Flex>\n\n <Flex direction=\"column\" gap=\"1\" maxWidth=\"420px\">\n <Heading size=\"5\" align=\"center\" mb=\"1\" wrap=\"balance\" as=\"h3\">\n {heading}\n </Heading>\n\n <Text as=\"p\" align=\"center\" wrap=\"balance\" color=\"gray\">\n {message}\n </Text>\n </Flex>\n </Flex>\n );\n\n const { heading, message } = getErrorMessage(error);\n return render(heading, message);\n}\n\nexport function getErrorMessage(error: unknown) {\n if (error instanceof FetchError) {\n return {\n heading: \"Error fetching data\",\n message:\n \"An error occurred. You may need to configure CORS in the WorkOS Dashboard.\",\n };\n }\n\n if (error instanceof NoAuthTokenError) {\n return {\n heading: \"Authorization error\",\n message:\n \"You likely forgot to provide an authorization token to the widget.\",\n };\n }\n\n if (error instanceof IncorrectPermissionsError) {\n return {\n heading: \"Incorrect permissions\",\n message: \"Check that the correct permissions have been assigned.\",\n };\n }\n\n return {\n heading: \"Error fetching data\",\n message:\n \"An unexpected error occurred. Check your network connection or try refreshing the page.\",\n };\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AA4BQ;AA5BR,YAAuB;AACvB,oBAAoC;AACpC,oBAIO;AACP,yBAA2B;AAEpB,SAAS,aAAa,EAAE,MAAM,GAAuB;AAC1D,QAAM,UAAU,MAAM;AACpB,YAAQ,MAAM,KAAK;AAAA,EACrB,GAAG,CAAC,KAAK,CAAC;AAEV,QAAM,SAAS,CAACA,UAAiBC,aAC/B,6CAAC,sBAAK,GAAE,KAAI,SAAQ,UAAS,OAAM,UAAS,WAAU,UACpD;AAAA;AAAA,MAAC;AAAA;AAAA,QACC,OAAM;AAAA,QACN,SAAQ;AAAA,QACR,OAAM;AAAA,QACN,QAAO;AAAA,QACP,IAAG;AAAA,QACH,OAAO;AAAA,UACL,cAAc;AAAA,UACd,iBAAiB;AAAA,UACjB,OAAO;AAAA,QACT;AAAA,QAEA,sDAAC,iCAAW,OAAM,QAAO,QAAO,QAAO;AAAA;AAAA,IACzC;AAAA,IAEA,6CAAC,sBAAK,WAAU,UAAS,KAAI,KAAI,UAAS,SACxC;AAAA,kDAAC,yBAAQ,MAAK,KAAI,OAAM,UAAS,IAAG,KAAI,MAAK,WAAU,IAAG,MACvD,UAAAD,UACH;AAAA,MAEA,4CAAC,sBAAK,IAAG,KAAI,OAAM,UAAS,MAAK,WAAU,OAAM,QAC9C,UAAAC,UACH;AAAA,OACF;AAAA,KACF;AAGF,QAAM,EAAE,SAAS,QAAQ,IAAI,gBAAgB,KAAK;AAClD,SAAO,OAAO,SAAS,OAAO;AAChC;AAEO,SAAS,gBAAgB,OAAgB;AAC9C,MAAI,iBAAiB,0BAAY;AAC/B,WAAO;AAAA,MACL,SAAS;AAAA,MACT,SACE;AAAA,IACJ;AAAA,EACF;AAEA,MAAI,iBAAiB,gCAAkB;AACrC,WAAO;AAAA,MACL,SAAS;AAAA,MACT,SACE;AAAA,IACJ;AAAA,EACF;AAEA,MAAI,iBAAiB,yCAA2B;AAC9C,WAAO;AAAA,MACL,SAAS;AAAA,MACT,SAAS;AAAA,IACX;AAAA,EACF;AAEA,SAAO;AAAA,IACL,SAAS;AAAA,IACT,SACE;AAAA,EACJ;AACF;","names":["heading","message"]}
|
|
@@ -3,5 +3,9 @@ import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
|
3
3
|
declare function GenericError({ error }: {
|
|
4
4
|
error: unknown;
|
|
5
5
|
}): react_jsx_runtime.JSX.Element;
|
|
6
|
+
declare function getErrorMessage(error: unknown): {
|
|
7
|
+
heading: string;
|
|
8
|
+
message: string;
|
|
9
|
+
};
|
|
6
10
|
|
|
7
|
-
export { GenericError };
|
|
11
|
+
export { GenericError, getErrorMessage };
|
|
@@ -22,15 +22,15 @@ __export(use_permissions_exports, {
|
|
|
22
22
|
});
|
|
23
23
|
module.exports = __toCommonJS(use_permissions_exports);
|
|
24
24
|
var import_react_query = require("@tanstack/react-query");
|
|
25
|
+
var import_utils = require("../api/utils.js");
|
|
25
26
|
var import_errors = require("./errors.js");
|
|
26
|
-
|
|
27
|
+
var import_api_provider = require("../api/api-provider.js");
|
|
28
|
+
function usePermissions(scope) {
|
|
29
|
+
const { authToken } = (0, import_api_provider.useApi)();
|
|
27
30
|
return (0, import_react_query.useQuery)({
|
|
28
31
|
queryKey: ["permission", scope, authToken],
|
|
29
|
-
queryFn: async () => {
|
|
30
|
-
|
|
31
|
-
throw new import_errors.NoAuthTokenError();
|
|
32
|
-
}
|
|
33
|
-
const { permissions } = parseJwt(await authToken);
|
|
32
|
+
queryFn: authToken ? async () => {
|
|
33
|
+
const { permissions } = (0, import_utils.getClaims)(authToken);
|
|
34
34
|
if (!permissions || !Array.isArray(permissions)) {
|
|
35
35
|
throw new import_errors.NoAuthTokenError();
|
|
36
36
|
}
|
|
@@ -38,16 +38,9 @@ function usePermissions(scope, authToken) {
|
|
|
38
38
|
throw new import_errors.IncorrectPermissionsError();
|
|
39
39
|
}
|
|
40
40
|
return true;
|
|
41
|
-
}
|
|
41
|
+
} : import_react_query.skipToken
|
|
42
42
|
});
|
|
43
43
|
}
|
|
44
|
-
function parseJwt(token) {
|
|
45
|
-
try {
|
|
46
|
-
return JSON.parse(atob(token.split(".")[1]));
|
|
47
|
-
} catch {
|
|
48
|
-
return {};
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
44
|
// Annotate the CommonJS export names for ESM import in node:
|
|
52
45
|
0 && (module.exports = {
|
|
53
46
|
usePermissions
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/lib/use-permissions.ts"],"sourcesContent":["import { useQuery } from \"@tanstack/react-query\";\nimport { IncorrectPermissionsError, NoAuthTokenError } from \"./errors.js\";\n\n// TODO find a way to reuse the same type in the @workos-inc/node package\ntype WidgetScope = \"widgets:users-table:manage\" | \"widgets:api-keys:manage\";\n\nexport function usePermissions(
|
|
1
|
+
{"version":3,"sources":["../../../src/lib/use-permissions.ts"],"sourcesContent":["import { skipToken, useQuery } from \"@tanstack/react-query\";\nimport { getClaims } from \"../api/utils.js\";\nimport { IncorrectPermissionsError, NoAuthTokenError } from \"./errors.js\";\nimport { useApi } from \"../api/api-provider.js\";\n\n// TODO find a way to reuse the same type in the @workos-inc/node package\ntype WidgetScope = \"widgets:users-table:manage\" | \"widgets:api-keys:manage\";\n\nexport function usePermissions(scope: WidgetScope) {\n const { authToken } = useApi();\n\n return useQuery({\n queryKey: [\"permission\", scope, authToken],\n queryFn: authToken\n ? async () => {\n const { permissions } = getClaims(authToken);\n\n // When the permissions is not present in the token\n if (!permissions || !Array.isArray(permissions)) {\n throw new NoAuthTokenError();\n }\n\n // When the scope is not present in the permissions\n if (!permissions.includes(scope)) {\n throw new IncorrectPermissionsError();\n }\n\n return true;\n }\n : skipToken,\n });\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,yBAAoC;AACpC,mBAA0B;AAC1B,oBAA4D;AAC5D,0BAAuB;AAKhB,SAAS,eAAe,OAAoB;AACjD,QAAM,EAAE,UAAU,QAAI,4BAAO;AAE7B,aAAO,6BAAS;AAAA,IACd,UAAU,CAAC,cAAc,OAAO,SAAS;AAAA,IACzC,SAAS,YACL,YAAY;AACV,YAAM,EAAE,YAAY,QAAI,wBAAU,SAAS;AAG3C,UAAI,CAAC,eAAe,CAAC,MAAM,QAAQ,WAAW,GAAG;AAC/C,cAAM,IAAI,+BAAiB;AAAA,MAC7B;AAGA,UAAI,CAAC,YAAY,SAAS,KAAK,GAAG;AAChC,cAAM,IAAI,wCAA0B;AAAA,MACtC;AAEA,aAAO;AAAA,IACT,IACA;AAAA,EACN,CAAC;AACH;","names":[]}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as _tanstack_react_query from '@tanstack/react-query';
|
|
2
2
|
|
|
3
3
|
type WidgetScope = "widgets:users-table:manage" | "widgets:api-keys:manage";
|
|
4
|
-
declare function usePermissions(scope: WidgetScope
|
|
4
|
+
declare function usePermissions(scope: WidgetScope): _tanstack_react_query.UseQueryResult<boolean, Error>;
|
|
5
5
|
|
|
6
6
|
export { usePermissions };
|
|
@@ -44,7 +44,7 @@ var import_set_password_dialog = require("./set-password-dialog.js");
|
|
|
44
44
|
var import_change_password_dialog = require("./change-password-dialog.js");
|
|
45
45
|
var import_add_mfa_dialog = require("./add-mfa-dialog.js");
|
|
46
46
|
var import_reset_mfa_dialog = require("./reset-mfa-dialog.js");
|
|
47
|
-
var CardList = __toESM(require("
|
|
47
|
+
var CardList = __toESM(require("./card-list.js"), 1);
|
|
48
48
|
var import_generic_error = require("./generic-error.js");
|
|
49
49
|
var import_utils = require("./utils.js");
|
|
50
50
|
const UserSecurity = ({ settings }) => {
|