@workos-inc/widgets 1.19.0 → 1.19.1-next.1790792916241

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.
Files changed (73) hide show
  1. package/CHANGELOG.md +8 -0
  2. package/dist/cjs/admin-portal-sso-connection.client.cjs +72 -75
  3. package/dist/cjs/admin-portal-sso-connection.client.cjs.map +1 -1
  4. package/dist/cjs/lib/admin-portal-audit-log-streaming.cjs +5 -22
  5. package/dist/cjs/lib/admin-portal-audit-log-streaming.cjs.map +1 -1
  6. package/dist/cjs/lib/admin-portal-sso-connection.cjs +7 -41
  7. package/dist/cjs/lib/admin-portal-sso-connection.cjs.map +1 -1
  8. package/dist/cjs/lib/admin-portal-sso-connection.d.cts +0 -1
  9. package/dist/cjs/lib/api-keys/api-key-expiration.cjs +5 -3
  10. package/dist/cjs/lib/api-keys/api-key-expiration.cjs.map +1 -1
  11. package/dist/cjs/lib/api-keys/api-key-expiration.d.cts +1 -1
  12. package/dist/cjs/lib/api-keys/create-api-key.cjs +4 -1
  13. package/dist/cjs/lib/api-keys/create-api-key.cjs.map +1 -1
  14. package/dist/cjs/lib/api-keys/relative-time.cjs +7 -12
  15. package/dist/cjs/lib/api-keys/relative-time.cjs.map +1 -1
  16. package/dist/cjs/lib/directory-sync.cjs +5 -30
  17. package/dist/cjs/lib/directory-sync.cjs.map +1 -1
  18. package/dist/cjs/lib/domain-item.cjs +5 -10
  19. package/dist/cjs/lib/domain-item.cjs.map +1 -1
  20. package/dist/cjs/lib/user-api-keys/create-user-api-key.cjs +4 -1
  21. package/dist/cjs/lib/user-api-keys/create-user-api-key.cjs.map +1 -1
  22. package/dist/cjs/lib/user-security.cjs +9 -17
  23. package/dist/cjs/lib/user-security.cjs.map +1 -1
  24. package/dist/cjs/lib/user-sessions.cjs +9 -13
  25. package/dist/cjs/lib/user-sessions.cjs.map +1 -1
  26. package/dist/cjs/lib/user-sessions.d.cts +2 -2
  27. package/dist/cjs/lib/users-management.cjs +14 -24
  28. package/dist/cjs/lib/users-management.cjs.map +1 -1
  29. package/dist/cjs/lib/utils.cjs +49 -13
  30. package/dist/cjs/lib/utils.cjs.map +1 -1
  31. package/dist/cjs/use-comparative-readable-date.cjs +70 -0
  32. package/dist/cjs/use-comparative-readable-date.cjs.map +1 -0
  33. package/dist/cjs/use-comparative-readable-date.d.cts +8 -0
  34. package/dist/cjs/use-now.cjs +101 -0
  35. package/dist/cjs/use-now.cjs.map +1 -0
  36. package/dist/cjs/use-now.d.cts +3 -0
  37. package/dist/esm/admin-portal-sso-connection.client.js +73 -66
  38. package/dist/esm/admin-portal-sso-connection.client.js.map +1 -1
  39. package/dist/esm/lib/admin-portal-audit-log-streaming.js +5 -22
  40. package/dist/esm/lib/admin-portal-audit-log-streaming.js.map +1 -1
  41. package/dist/esm/lib/admin-portal-sso-connection.d.ts +0 -1
  42. package/dist/esm/lib/admin-portal-sso-connection.js +7 -41
  43. package/dist/esm/lib/admin-portal-sso-connection.js.map +1 -1
  44. package/dist/esm/lib/api-keys/api-key-expiration.d.ts +1 -1
  45. package/dist/esm/lib/api-keys/api-key-expiration.js +5 -3
  46. package/dist/esm/lib/api-keys/api-key-expiration.js.map +1 -1
  47. package/dist/esm/lib/api-keys/create-api-key.js +4 -1
  48. package/dist/esm/lib/api-keys/create-api-key.js.map +1 -1
  49. package/dist/esm/lib/api-keys/relative-time.js +7 -12
  50. package/dist/esm/lib/api-keys/relative-time.js.map +1 -1
  51. package/dist/esm/lib/directory-sync.js +5 -30
  52. package/dist/esm/lib/directory-sync.js.map +1 -1
  53. package/dist/esm/lib/domain-item.js +5 -10
  54. package/dist/esm/lib/domain-item.js.map +1 -1
  55. package/dist/esm/lib/identity-providers.d.ts +2 -2
  56. package/dist/esm/lib/user-api-keys/create-user-api-key.js +4 -1
  57. package/dist/esm/lib/user-api-keys/create-user-api-key.js.map +1 -1
  58. package/dist/esm/lib/user-security.js +9 -18
  59. package/dist/esm/lib/user-security.js.map +1 -1
  60. package/dist/esm/lib/user-sessions.d.ts +2 -2
  61. package/dist/esm/lib/user-sessions.js +9 -14
  62. package/dist/esm/lib/user-sessions.js.map +1 -1
  63. package/dist/esm/lib/users-management.js +14 -25
  64. package/dist/esm/lib/users-management.js.map +1 -1
  65. package/dist/esm/lib/utils.js +49 -13
  66. package/dist/esm/lib/utils.js.map +1 -1
  67. package/dist/esm/use-comparative-readable-date.d.ts +8 -0
  68. package/dist/esm/use-comparative-readable-date.js +36 -0
  69. package/dist/esm/use-comparative-readable-date.js.map +1 -0
  70. package/dist/esm/use-now.d.ts +3 -0
  71. package/dist/esm/use-now.js +67 -0
  72. package/dist/esm/use-now.js.map +1 -0
  73. package/package.json +1 -1
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/lib/directory-sync.tsx"],"sourcesContent":["\"use client\";\n\nimport * as React from \"react\";\nimport { Box, Card, Flex, Spinner, Text } from \"@radix-ui/themes\";\nimport { ExternalLinkIcon, InfoCircledIcon } from \"@radix-ui/react-icons\";\nimport { Button, Skeleton } from \"./elements.js\";\nimport { GenericError } from \"./generic-error.js\";\nimport * as CardList from \"./card-list.js\";\nimport { IconPanel } from \"./icon-panel.js\";\nimport { ProviderIcon } from \"./provider-icon.js\";\nimport {\n getDirectoryTypeIcon,\n getDirectoryTypeName,\n} from \"./identity-providers.js\";\nimport { Status } from \"./status.js\";\nimport { Translation } from \"./i18n/translation.js\";\nimport {\n getDomProps,\n type WidgetRootState,\n type WidgetRootDomProps,\n} from \"./utils.js\";\n\nconst DirectoryState = {\n requires_type: \"requires_type\",\n linked: \"linked\",\n validating: \"validating\",\n invalid_credentials: \"invalid_credentials\",\n unlinked: \"unlinked\",\n deleting: \"deleting\",\n} as const;\ntype DirectoryState = (typeof DirectoryState)[keyof typeof DirectoryState];\n\nfunction isDirectoryState(state: string): state is DirectoryState {\n return Object.values(DirectoryState).some((known) => known === state);\n}\n\ntype DirectoryType = string;\n\ninterface DirectoryMetadata {\n users: { active: number };\n groups: number;\n}\n\ninterface BaseDirectorySyncProps {\n type?: DirectoryType;\n metadata?: DirectoryMetadata;\n lastSyncAt?: string | null;\n onOpenAdminPortal?: () => void;\n isOpeningAdminPortal?: boolean;\n errorMessage?: never;\n userCount?: never;\n groupCount?: never;\n currentDate?: never;\n state: DirectoryState;\n}\n\ninterface NotConfiguredProps extends BaseDirectorySyncProps {\n state: (typeof DirectoryState)[\"unlinked\"];\n}\n\ninterface SetupInProgressProps extends Omit<BaseDirectorySyncProps, \"type\"> {\n state: (typeof DirectoryState)[\"validating\"];\n type: DirectoryType;\n}\n\ninterface ErrorBeforeConfigProps extends Omit<\n BaseDirectorySyncProps,\n \"type\" | \"errorMessage\"\n> {\n state: DirectoryState;\n type: DirectoryType;\n errorMessage: React.ReactNode;\n}\n\ninterface ValidatingProps extends Omit<BaseDirectorySyncProps, \"type\"> {\n state: (typeof DirectoryState)[\"validating\"];\n type: DirectoryType;\n}\n\ninterface ActiveProps extends Omit<\n BaseDirectorySyncProps,\n \"type\" | \"lastSyncAt\" | \"currentDate\" | \"errorMessage\"\n> {\n state: (typeof DirectoryState)[\"linked\"];\n type: DirectoryType;\n lastSyncAt: string | null;\n currentDate?: Date | null;\n errorMessage?: React.ReactNode;\n}\n\ninterface InvalidCredentialsProps extends Omit<\n BaseDirectorySyncProps,\n \"type\" | \"errorMessage\"\n> {\n state: (typeof DirectoryState)[\"invalid_credentials\"];\n type: DirectoryType;\n errorMessage: React.ReactNode;\n}\n\ninterface DeletingProps extends Omit<BaseDirectorySyncProps, \"type\"> {\n state: (typeof DirectoryState)[\"deleting\"];\n type: DirectoryType;\n}\n\ntype DirectorySyncStatusProps =\n | NotConfiguredProps\n | SetupInProgressProps\n | ErrorBeforeConfigProps\n | ValidatingProps\n | ActiveProps\n | InvalidCredentialsProps\n | DeletingProps;\n\ntype DirectorySyncProps = WidgetRootDomProps & DirectorySyncStatusProps;\n\ninterface DirectorySyncContextValue {\n state: DirectorySyncStatusProps[\"state\"];\n type?: DirectoryType;\n}\n\nconst DirectorySyncContext =\n React.createContext<DirectorySyncContextValue | null>(null);\nDirectorySyncContext.displayName = \"DirectorySyncContext\";\n\nfunction useDirectorySyncContext() {\n const context = React.useContext(DirectorySyncContext);\n if (!context) {\n throw new Error(\n \"useDirectorySyncContext must be used within a DirectorySyncContext provider\",\n );\n }\n return context;\n}\n\nfunction DirectoryProviderInfo({\n type,\n subtitle,\n}: {\n type: DirectoryType;\n subtitle?: React.ReactNode;\n}) {\n return (\n <Flex gap=\"4\" align=\"center\">\n <IconPanel color=\"panel\">\n <ProviderIcon\n provider={getDirectoryTypeIcon(type) ?? \"workos\"}\n size=\"2\"\n />\n </IconPanel>\n {subtitle ? (\n <Flex direction=\"column\">\n <Text size=\"2\" weight=\"bold\">\n {getDirectoryTypeName(type)}\n </Text>\n {subtitle}\n </Flex>\n ) : (\n <Text size=\"2\" weight=\"bold\">\n {getDirectoryTypeName(type)}\n </Text>\n )}\n </Flex>\n );\n}\n\nfunction SpinnerMessage({ children }: { children: React.ReactNode }) {\n return (\n <Flex gap=\"2\" align=\"center\">\n <Spinner />\n <Text size=\"2\" color=\"gray\">\n {children}\n </Text>\n </Flex>\n );\n}\n\nfunction getStatusBadge(state: DirectoryState) {\n switch (state) {\n case DirectoryState.requires_type:\n case DirectoryState.invalid_credentials:\n return (\n <Status state=\"error\">\n <Translation\n defaultMessage=\"Requires action\"\n id=\"uuuXIF\"\n description=\"Status badge when directory requires user action\"\n />\n </Status>\n );\n case DirectoryState.linked:\n return (\n <Status state=\"success\">\n <Translation\n defaultMessage=\"Connected\"\n id=\"H/dAHq\"\n description=\"Status badge when directory is active\"\n />\n </Status>\n );\n default:\n return null;\n }\n}\n\nfunction getSpinnerMessage(\n state: DirectoryState,\n hasType: boolean,\n): string | null {\n if (state === DirectoryState.unlinked && hasType)\n return \"Setup in progress...\";\n if (state === DirectoryState.validating)\n return \"Waiting for users and groups...\";\n if (state === DirectoryState.deleting) return \"Deleting directory...\";\n return null;\n}\n\nconst DirectorySync: React.FC<DirectorySyncProps> = ({\n state,\n className,\n ...rest\n}) => {\n const type =\n \"type\" in rest ? (rest as { type: DirectoryType }).type : undefined;\n const errorMessage =\n \"errorMessage\" in rest\n ? (rest as { errorMessage: React.ReactNode }).errorMessage\n : undefined;\n const metadata =\n \"metadata\" in rest\n ? (rest as { metadata: DirectoryMetadata }).metadata\n : undefined;\n const { onOpenAdminPortal, isOpeningAdminPortal } = rest;\n const userCount = metadata?.users.active ?? 0;\n const groupCount = metadata?.groups ?? 0;\n const lastSyncAt = rest.lastSyncAt ? new Date(rest.lastSyncAt) : null;\n\n const currentDate =\n \"currentDate\" in rest && rest.currentDate instanceof Date\n ? rest.currentDate\n : undefined;\n\n const lastSyncString = lastSyncAt\n ? getRelativeTimeString(currentDate ?? new Date(), lastSyncAt)\n : null;\n\n const showCounts =\n state === DirectoryState.linked ||\n state === DirectoryState.invalid_credentials ||\n state === DirectoryState.deleting;\n const statusBadge = getStatusBadge(state);\n const spinnerMessage = getSpinnerMessage(state, !!type);\n const showButton = state !== DirectoryState.deleting;\n const domProps: WidgetRootDomProps = { className };\n\n const countsSubtitle = showCounts ? (\n <Text size=\"2\" color=\"gray\">\n <Translation\n defaultMessage=\"{userCount} {userLabel}\"\n id=\"aZxx55\"\n description=\"Directory sync user and group counts\"\n values={{\n userCount,\n userLabel: userCount !== 1 ? \"users\" : \"user\",\n }}\n />\n {/* eslint-disable-next-line formatjs/no-literal-string-in-jsx */}\n <span aria-hidden> ∙ </span>\n <Translation\n defaultMessage=\"{groupCount} {groupLabel}\"\n id=\"SgiDio\"\n description=\"Directory sync group count\"\n values={{\n groupCount,\n groupLabel: groupCount !== 1 ? \"groups\" : \"group\",\n }}\n />\n {lastSyncString && (\n <>\n {/* eslint-disable-next-line formatjs/no-literal-string-in-jsx */}\n <span aria-hidden> ∙ </span>\n <Translation\n defaultMessage=\"Last sync {lastSync}\"\n id=\"UUqjnE\"\n description=\"Last sync timestamp for directory\"\n values={{ lastSync: lastSyncString }}\n />\n </>\n )}\n </Text>\n ) : null;\n\n return (\n <CardList.Root {...getWidgetRootDomProps(\"resolved\", domProps)}>\n <DirectorySyncContext.Provider value={{ state, type }}>\n <CardList.Item>\n <Flex direction=\"row\" justify=\"between\" align=\"center\" gap=\"2\">\n {!type ? (\n <>\n <Text size=\"2\" color=\"gray\">\n <Translation\n defaultMessage=\"You haven't set up a directory yet.\"\n id=\"+ywYVl\"\n description=\"Empty state message when no directory is configured\"\n />\n </Text>\n <AdminPortalOpenButton\n onOpen={onOpenAdminPortal}\n isPending={isOpeningAdminPortal ?? false}\n />\n </>\n ) : (\n <>\n <DirectoryProviderInfo type={type} subtitle={countsSubtitle} />\n <Flex gap=\"5\" align=\"center\">\n {statusBadge}\n {spinnerMessage && (\n <SpinnerMessage>{spinnerMessage}</SpinnerMessage>\n )}\n {showButton && (\n <AdminPortalOpenButton\n onOpen={onOpenAdminPortal}\n isPending={isOpeningAdminPortal ?? false}\n />\n )}\n </Flex>\n </>\n )}\n </Flex>\n </CardList.Item>\n\n {errorMessage && (\n <CardList.Item>\n <Flex align=\"start\" gap=\"2\">\n <Box asChild mt=\"2px\" flexShrink=\"0\">\n <InfoCircledIcon color=\"var(--gray-11)\" />\n </Box>\n <Text size=\"2\" color=\"gray\">\n {errorMessage}\n </Text>\n </Flex>\n </CardList.Item>\n )}\n </DirectorySyncContext.Provider>\n </CardList.Root>\n );\n};\n\nfunction AdminPortalOpenButton({\n onOpen,\n isPending,\n children,\n}: {\n onOpen: (() => void) | undefined;\n isPending: boolean;\n children?: React.ReactNode;\n}) {\n const { state, type } = useDirectorySyncContext();\n\n const label = (() => {\n switch (state) {\n case DirectoryState.unlinked:\n return type ? \"Continue setup\" : \"Set up directory\";\n case DirectoryState.validating:\n return \"Manage\";\n default:\n return \"Manage\";\n }\n })();\n\n if (onOpen) {\n return (\n <Button\n variant=\"secondary\"\n onClick={() => onOpen()}\n loading={isPending}\n disabled={isPending}\n >\n {children ?? label} <ExternalLinkIcon aria-hidden />\n </Button>\n );\n }\n\n return (\n <Button variant=\"secondary\" disabled>\n {children ?? label} <ExternalLinkIcon aria-hidden />\n </Button>\n );\n}\n\ninterface DirectorySyncLoadingProps extends WidgetRootDomProps {}\n\nconst DirectorySyncLoading: React.FC<DirectorySyncLoadingProps> = (props) => {\n return (\n <Card size=\"2\" {...getWidgetRootDomProps(\"loading\", props)}>\n <Flex direction=\"row\" justify=\"between\" align=\"center\" gap=\"2\">\n <Skeleton>\n {/* eslint-disable-next-line formatjs/no-literal-string-in-jsx */}\n <Text size=\"2\" color=\"gray\">\n You haven't set up a directory yet.\n </Text>\n </Skeleton>\n <Skeleton>\n {/* eslint-disable-next-line formatjs/no-literal-string-in-jsx */}\n <Button variant=\"secondary\">\n Set up directory <ExternalLinkIcon aria-hidden />\n </Button>\n </Skeleton>\n </Flex>\n </Card>\n );\n};\n\ninterface DirectorySyncErrorProps extends WidgetRootDomProps {\n error: unknown;\n}\n\nconst DirectorySyncError: React.FC<DirectorySyncErrorProps> = ({\n error,\n ...domProps\n}) => {\n return (\n <Card size=\"2\" {...getWidgetRootDomProps(\"error\", domProps)}>\n <GenericError error={error} />\n </Card>\n );\n};\n\nfunction getWidgetRootDomProps(\n state: WidgetRootState,\n domProps: WidgetRootDomProps,\n) {\n return getDomProps({\n ...domProps,\n isWidgetRoot: true,\n widgetId: \"directory-sync\",\n widgetState: state,\n });\n}\n\nfunction getRelativeTimeString(\n currentDate: Date | null,\n lastSync: Date | null,\n) {\n if (!currentDate || !lastSync) {\n return null;\n }\n\n const rtf = new Intl.RelativeTimeFormat(\"en\", { numeric: \"auto\" });\n const diff = lastSync.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\nexport type {\n DirectorySyncProps,\n DirectorySyncLoadingProps,\n DirectorySyncErrorProps,\n DirectorySyncStatusProps,\n DirectoryMetadata,\n};\nexport {\n DirectorySync,\n DirectorySyncLoading,\n DirectorySyncError,\n DirectoryState,\n isDirectoryState,\n};\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../../src/lib/directory-sync.tsx"],"sourcesContent":["\"use client\";\n\nimport * as React from \"react\";\nimport { Box, Card, Flex, Spinner, Text } from \"@radix-ui/themes\";\nimport { ExternalLinkIcon, InfoCircledIcon } from \"@radix-ui/react-icons\";\nimport { Button, Skeleton } from \"./elements.js\";\nimport { GenericError } from \"./generic-error.js\";\nimport * as CardList from \"./card-list.js\";\nimport { IconPanel } from \"./icon-panel.js\";\nimport { ProviderIcon } from \"./provider-icon.js\";\nimport {\n getDirectoryTypeIcon,\n getDirectoryTypeName,\n} from \"./identity-providers.js\";\nimport { Status } from \"./status.js\";\nimport { Translation } from \"./i18n/translation.js\";\nimport {\n getDomProps,\n type WidgetRootState,\n type WidgetRootDomProps,\n} from \"./utils.js\";\nimport { useComparativeReadableDate } from \"../use-comparative-readable-date.js\";\n\nconst DirectoryState = {\n requires_type: \"requires_type\",\n linked: \"linked\",\n validating: \"validating\",\n invalid_credentials: \"invalid_credentials\",\n unlinked: \"unlinked\",\n deleting: \"deleting\",\n} as const;\ntype DirectoryState = (typeof DirectoryState)[keyof typeof DirectoryState];\n\nfunction isDirectoryState(state: string): state is DirectoryState {\n return Object.values(DirectoryState).some((known) => known === state);\n}\n\ntype DirectoryType = string;\n\ninterface DirectoryMetadata {\n users: { active: number };\n groups: number;\n}\n\ninterface BaseDirectorySyncProps {\n type?: DirectoryType;\n metadata?: DirectoryMetadata;\n lastSyncAt?: string | null;\n onOpenAdminPortal?: () => void;\n isOpeningAdminPortal?: boolean;\n errorMessage?: never;\n userCount?: never;\n groupCount?: never;\n currentDate?: never;\n state: DirectoryState;\n}\n\ninterface NotConfiguredProps extends BaseDirectorySyncProps {\n state: (typeof DirectoryState)[\"unlinked\"];\n}\n\ninterface SetupInProgressProps extends Omit<BaseDirectorySyncProps, \"type\"> {\n state: (typeof DirectoryState)[\"validating\"];\n type: DirectoryType;\n}\n\ninterface ErrorBeforeConfigProps extends Omit<\n BaseDirectorySyncProps,\n \"type\" | \"errorMessage\"\n> {\n state: DirectoryState;\n type: DirectoryType;\n errorMessage: React.ReactNode;\n}\n\ninterface ValidatingProps extends Omit<BaseDirectorySyncProps, \"type\"> {\n state: (typeof DirectoryState)[\"validating\"];\n type: DirectoryType;\n}\n\ninterface ActiveProps extends Omit<\n BaseDirectorySyncProps,\n \"type\" | \"lastSyncAt\" | \"currentDate\" | \"errorMessage\"\n> {\n state: (typeof DirectoryState)[\"linked\"];\n type: DirectoryType;\n lastSyncAt: string | null;\n currentDate?: Date | null;\n errorMessage?: React.ReactNode;\n}\n\ninterface InvalidCredentialsProps extends Omit<\n BaseDirectorySyncProps,\n \"type\" | \"errorMessage\"\n> {\n state: (typeof DirectoryState)[\"invalid_credentials\"];\n type: DirectoryType;\n errorMessage: React.ReactNode;\n}\n\ninterface DeletingProps extends Omit<BaseDirectorySyncProps, \"type\"> {\n state: (typeof DirectoryState)[\"deleting\"];\n type: DirectoryType;\n}\n\ntype DirectorySyncStatusProps =\n | NotConfiguredProps\n | SetupInProgressProps\n | ErrorBeforeConfigProps\n | ValidatingProps\n | ActiveProps\n | InvalidCredentialsProps\n | DeletingProps;\n\ntype DirectorySyncProps = WidgetRootDomProps & DirectorySyncStatusProps;\n\ninterface DirectorySyncContextValue {\n state: DirectorySyncStatusProps[\"state\"];\n type?: DirectoryType;\n}\n\nconst DirectorySyncContext =\n React.createContext<DirectorySyncContextValue | null>(null);\nDirectorySyncContext.displayName = \"DirectorySyncContext\";\n\nfunction useDirectorySyncContext() {\n const context = React.useContext(DirectorySyncContext);\n if (!context) {\n throw new Error(\n \"useDirectorySyncContext must be used within a DirectorySyncContext provider\",\n );\n }\n return context;\n}\n\nfunction DirectoryProviderInfo({\n type,\n subtitle,\n}: {\n type: DirectoryType;\n subtitle?: React.ReactNode;\n}) {\n return (\n <Flex gap=\"4\" align=\"center\">\n <IconPanel color=\"panel\">\n <ProviderIcon\n provider={getDirectoryTypeIcon(type) ?? \"workos\"}\n size=\"2\"\n />\n </IconPanel>\n {subtitle ? (\n <Flex direction=\"column\">\n <Text size=\"2\" weight=\"bold\">\n {getDirectoryTypeName(type)}\n </Text>\n {subtitle}\n </Flex>\n ) : (\n <Text size=\"2\" weight=\"bold\">\n {getDirectoryTypeName(type)}\n </Text>\n )}\n </Flex>\n );\n}\n\nfunction SpinnerMessage({ children }: { children: React.ReactNode }) {\n return (\n <Flex gap=\"2\" align=\"center\">\n <Spinner />\n <Text size=\"2\" color=\"gray\">\n {children}\n </Text>\n </Flex>\n );\n}\n\nfunction getStatusBadge(state: DirectoryState) {\n switch (state) {\n case DirectoryState.requires_type:\n case DirectoryState.invalid_credentials:\n return (\n <Status state=\"error\">\n <Translation\n defaultMessage=\"Requires action\"\n id=\"uuuXIF\"\n description=\"Status badge when directory requires user action\"\n />\n </Status>\n );\n case DirectoryState.linked:\n return (\n <Status state=\"success\">\n <Translation\n defaultMessage=\"Connected\"\n id=\"H/dAHq\"\n description=\"Status badge when directory is active\"\n />\n </Status>\n );\n default:\n return null;\n }\n}\n\nfunction getSpinnerMessage(\n state: DirectoryState,\n hasType: boolean,\n): string | null {\n if (state === DirectoryState.unlinked && hasType)\n return \"Setup in progress...\";\n if (state === DirectoryState.validating)\n return \"Waiting for users and groups...\";\n if (state === DirectoryState.deleting) return \"Deleting directory...\";\n return null;\n}\n\nconst DirectorySync: React.FC<DirectorySyncProps> = ({\n state,\n className,\n ...rest\n}) => {\n const type =\n \"type\" in rest ? (rest as { type: DirectoryType }).type : undefined;\n const errorMessage =\n \"errorMessage\" in rest\n ? (rest as { errorMessage: React.ReactNode }).errorMessage\n : undefined;\n const metadata =\n \"metadata\" in rest\n ? (rest as { metadata: DirectoryMetadata }).metadata\n : undefined;\n const { onOpenAdminPortal, isOpeningAdminPortal } = rest;\n const userCount = metadata?.users.active ?? 0;\n const groupCount = metadata?.groups ?? 0;\n const lastSyncAt = rest.lastSyncAt ? new Date(rest.lastSyncAt) : null;\n\n const currentDate =\n \"currentDate\" in rest && rest.currentDate instanceof Date\n ? rest.currentDate\n : undefined;\n\n const lastSyncString = useComparativeReadableDate({\n date: lastSyncAt,\n currentDate,\n });\n\n const showCounts =\n state === DirectoryState.linked ||\n state === DirectoryState.invalid_credentials ||\n state === DirectoryState.deleting;\n const statusBadge = getStatusBadge(state);\n const spinnerMessage = getSpinnerMessage(state, !!type);\n const showButton = state !== DirectoryState.deleting;\n const domProps: WidgetRootDomProps = { className };\n\n const countsSubtitle = showCounts ? (\n <Text size=\"2\" color=\"gray\">\n <Translation\n defaultMessage=\"{userCount} {userLabel}\"\n id=\"aZxx55\"\n description=\"Directory sync user and group counts\"\n values={{\n userCount,\n userLabel: userCount !== 1 ? \"users\" : \"user\",\n }}\n />\n {/* eslint-disable-next-line formatjs/no-literal-string-in-jsx */}\n <span aria-hidden> ∙ </span>\n <Translation\n defaultMessage=\"{groupCount} {groupLabel}\"\n id=\"SgiDio\"\n description=\"Directory sync group count\"\n values={{\n groupCount,\n groupLabel: groupCount !== 1 ? \"groups\" : \"group\",\n }}\n />\n {lastSyncString && (\n <>\n {/* eslint-disable-next-line formatjs/no-literal-string-in-jsx */}\n <span aria-hidden> ∙ </span>\n <Translation\n defaultMessage=\"Last sync {lastSync}\"\n id=\"UUqjnE\"\n description=\"Last sync timestamp for directory\"\n values={{ lastSync: lastSyncString }}\n />\n </>\n )}\n </Text>\n ) : null;\n\n return (\n <CardList.Root {...getWidgetRootDomProps(\"resolved\", domProps)}>\n <DirectorySyncContext.Provider value={{ state, type }}>\n <CardList.Item>\n <Flex direction=\"row\" justify=\"between\" align=\"center\" gap=\"2\">\n {!type ? (\n <>\n <Text size=\"2\" color=\"gray\">\n <Translation\n defaultMessage=\"You haven't set up a directory yet.\"\n id=\"+ywYVl\"\n description=\"Empty state message when no directory is configured\"\n />\n </Text>\n <AdminPortalOpenButton\n onOpen={onOpenAdminPortal}\n isPending={isOpeningAdminPortal ?? false}\n />\n </>\n ) : (\n <>\n <DirectoryProviderInfo type={type} subtitle={countsSubtitle} />\n <Flex gap=\"5\" align=\"center\">\n {statusBadge}\n {spinnerMessage && (\n <SpinnerMessage>{spinnerMessage}</SpinnerMessage>\n )}\n {showButton && (\n <AdminPortalOpenButton\n onOpen={onOpenAdminPortal}\n isPending={isOpeningAdminPortal ?? false}\n />\n )}\n </Flex>\n </>\n )}\n </Flex>\n </CardList.Item>\n\n {errorMessage && (\n <CardList.Item>\n <Flex align=\"start\" gap=\"2\">\n <Box asChild mt=\"2px\" flexShrink=\"0\">\n <InfoCircledIcon color=\"var(--gray-11)\" />\n </Box>\n <Text size=\"2\" color=\"gray\">\n {errorMessage}\n </Text>\n </Flex>\n </CardList.Item>\n )}\n </DirectorySyncContext.Provider>\n </CardList.Root>\n );\n};\n\nfunction AdminPortalOpenButton({\n onOpen,\n isPending,\n children,\n}: {\n onOpen: (() => void) | undefined;\n isPending: boolean;\n children?: React.ReactNode;\n}) {\n const { state, type } = useDirectorySyncContext();\n\n const label = (() => {\n switch (state) {\n case DirectoryState.unlinked:\n return type ? \"Continue setup\" : \"Set up directory\";\n case DirectoryState.validating:\n return \"Manage\";\n default:\n return \"Manage\";\n }\n })();\n\n if (onOpen) {\n return (\n <Button\n variant=\"secondary\"\n onClick={() => onOpen()}\n loading={isPending}\n disabled={isPending}\n >\n {children ?? label} <ExternalLinkIcon aria-hidden />\n </Button>\n );\n }\n\n return (\n <Button variant=\"secondary\" disabled>\n {children ?? label} <ExternalLinkIcon aria-hidden />\n </Button>\n );\n}\n\ninterface DirectorySyncLoadingProps extends WidgetRootDomProps {}\n\nconst DirectorySyncLoading: React.FC<DirectorySyncLoadingProps> = (props) => {\n return (\n <Card size=\"2\" {...getWidgetRootDomProps(\"loading\", props)}>\n <Flex direction=\"row\" justify=\"between\" align=\"center\" gap=\"2\">\n <Skeleton>\n {/* eslint-disable-next-line formatjs/no-literal-string-in-jsx */}\n <Text size=\"2\" color=\"gray\">\n You haven't set up a directory yet.\n </Text>\n </Skeleton>\n <Skeleton>\n {/* eslint-disable-next-line formatjs/no-literal-string-in-jsx */}\n <Button variant=\"secondary\">\n Set up directory <ExternalLinkIcon aria-hidden />\n </Button>\n </Skeleton>\n </Flex>\n </Card>\n );\n};\n\ninterface DirectorySyncErrorProps extends WidgetRootDomProps {\n error: unknown;\n}\n\nconst DirectorySyncError: React.FC<DirectorySyncErrorProps> = ({\n error,\n ...domProps\n}) => {\n return (\n <Card size=\"2\" {...getWidgetRootDomProps(\"error\", domProps)}>\n <GenericError error={error} />\n </Card>\n );\n};\n\nfunction getWidgetRootDomProps(\n state: WidgetRootState,\n domProps: WidgetRootDomProps,\n) {\n return getDomProps({\n ...domProps,\n isWidgetRoot: true,\n widgetId: \"directory-sync\",\n widgetState: state,\n });\n}\n\nexport type {\n DirectorySyncProps,\n DirectorySyncLoadingProps,\n DirectorySyncErrorProps,\n DirectorySyncStatusProps,\n DirectoryMetadata,\n};\nexport {\n DirectorySync,\n DirectorySyncLoading,\n DirectorySyncError,\n DirectoryState,\n isDirectoryState,\n};\n"],"mappings":"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","names":[]}
@@ -25,18 +25,19 @@ module.exports = __toCommonJS(domain_item_exports);
25
25
  var import_jsx_runtime = require("react/jsx-runtime");
26
26
  var import_themes = require("@radix-ui/themes");
27
27
  var import_icon_panel = require("./icon-panel.js");
28
- var import_utils = require("./utils.js");
29
28
  var import_status = require("./status.js");
30
29
  var import_name_server_icon = require("./name-server-icon.js");
31
30
  var import_domain_actions = require("./domain-actions.js");
32
31
  var import_translation = require("./i18n/translation.js");
33
- var import_use_locale = require("./i18n/use-locale.js");
32
+ var import_use_comparative_readable_date = require("../use-comparative-readable-date.js");
34
33
  const DomainItem = ({
35
34
  domain,
36
35
  onDeleteDomain,
37
36
  onReverifyDomain
38
37
  }) => {
39
- const locale = (0, import_use_locale.useLocale)();
38
+ const timeAgo = (0, import_use_comparative_readable_date.useComparativeReadableDate)({
39
+ date: new Date(domain.createdAt)
40
+ });
40
41
  return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_themes.Flex, { gap: "4", align: "center", children: [
41
42
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_icon_panel.IconPanel, { color: domain.nameServer === "Other" ? "gray" : "panel", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_name_server_icon.NameServerIcon, { provider: domain.nameServer }) }),
42
43
  /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_themes.Flex, { direction: "column", children: [
@@ -47,13 +48,7 @@ const DomainItem = ({
47
48
  defaultMessage: "Added {timeAgo}",
48
49
  id: "DtZ2fb",
49
50
  description: "Label showing when the domain was added",
50
- values: {
51
- timeAgo: (0, import_utils.getComparativeReadableDate)(
52
- /* @__PURE__ */ new Date(),
53
- new Date(domain.createdAt),
54
- { locale }
55
- )
56
- }
51
+ values: { timeAgo }
57
52
  }
58
53
  ) })
59
54
  ] }),
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/lib/domain-item.tsx"],"sourcesContent":["\"use client\";\n\nimport { Flex, Text } from \"@radix-ui/themes\";\nimport type { OrganizationDomainFieldsFragment } from \"../api/client-graphql/generated.js\";\nimport { IconPanel } from \"./icon-panel.js\";\nimport { getComparativeReadableDate } from \"./utils.js\";\nimport { Status } from \"./status.js\";\nimport { NameServerIcon } from \"./name-server-icon.js\";\nimport { DomainActions } from \"./domain-actions.js\";\nimport { Translation } from \"./i18n/translation.js\";\nimport { useLocale } from \"./i18n/use-locale.js\";\n\ninterface DomainItemProps {\n domain: OrganizationDomainFieldsFragment;\n onDeleteDomain: (domainId: string) => void;\n onReverifyDomain: (domainId: string) => void;\n}\n\nexport const DomainItem = ({\n domain,\n onDeleteDomain,\n onReverifyDomain,\n}: DomainItemProps) => {\n const locale = useLocale();\n\n return (\n <Flex gap=\"4\" align=\"center\">\n <IconPanel color={domain.nameServer === \"Other\" ? \"gray\" : \"panel\"}>\n <NameServerIcon provider={domain.nameServer} />\n </IconPanel>\n\n <Flex direction=\"column\">\n <Text size=\"2\" highContrast weight=\"bold\" as=\"p\">\n {domain.domain}\n </Text>\n\n <Text size=\"2\" color=\"gray\" as=\"p\">\n <Translation\n defaultMessage=\"Added {timeAgo}\"\n id=\"DtZ2fb\"\n description=\"Label showing when the domain was added\"\n values={{\n timeAgo: getComparativeReadableDate(\n new Date(),\n new Date(domain.createdAt),\n { locale },\n ),\n }}\n />\n </Text>\n </Flex>\n\n <Flex ml=\"auto\" mr=\"2\" gap=\"4\" align=\"center\">\n <Flex gap=\"1\" align=\"center\">\n <Status state={getDomainStatus(domain)}>\n {domainStateToLabel(domain)}\n </Status>\n </Flex>\n\n <DomainActions\n domain={domain}\n onDeleteDomain={onDeleteDomain}\n onReverifyDomain={onReverifyDomain}\n />\n </Flex>\n </Flex>\n );\n};\n\nconst domainStateToLabel = (domain: OrganizationDomainFieldsFragment) => {\n switch (domain.state) {\n case \"Verified\":\n case \"LegacyVerified\":\n return (\n <Translation\n defaultMessage=\"Verified\"\n id=\"T7rpHw\"\n description=\"Domain verification status indicating the domain is verified\"\n />\n );\n case \"Pending\":\n return (\n <Translation\n defaultMessage=\"Verification pending\"\n id=\"gc1yge\"\n description=\"Domain verification status indicating verification is in progress\"\n />\n );\n case \"Failed\":\n return (\n <Translation\n defaultMessage=\"Verification failed\"\n id=\"cbbwqK\"\n description=\"Domain verification status indicating verification has failed\"\n />\n );\n }\n};\n\nconst getDomainStatus = (domain: OrganizationDomainFieldsFragment) => {\n switch (domain.state) {\n case \"Verified\":\n case \"LegacyVerified\":\n return \"success\";\n case \"Pending\":\n return \"waiting\";\n case \"Failed\":\n return \"error\";\n }\n};\n"],"mappings":";;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AA4BQ;AA1BR,oBAA2B;AAE3B,wBAA0B;AAC1B,mBAA2C;AAC3C,oBAAuB;AACvB,8BAA+B;AAC/B,4BAA8B;AAC9B,yBAA4B;AAC5B,wBAA0B;AAQnB,MAAM,aAAa,CAAC;AAAA,EACzB;AAAA,EACA;AAAA,EACA;AACF,MAAuB;AACrB,QAAM,aAAS,6BAAU;AAEzB,SACE,6CAAC,sBAAK,KAAI,KAAI,OAAM,UAClB;AAAA,gDAAC,+BAAU,OAAO,OAAO,eAAe,UAAU,SAAS,SACzD,sDAAC,0CAAe,UAAU,OAAO,YAAY,GAC/C;AAAA,IAEA,6CAAC,sBAAK,WAAU,UACd;AAAA,kDAAC,sBAAK,MAAK,KAAI,cAAY,MAAC,QAAO,QAAO,IAAG,KAC1C,iBAAO,QACV;AAAA,MAEA,4CAAC,sBAAK,MAAK,KAAI,OAAM,QAAO,IAAG,KAC7B;AAAA,QAAC;AAAA;AAAA,UACC,gBAAe;AAAA,UACf,IAAG;AAAA,UACH,aAAY;AAAA,UACZ,QAAQ;AAAA,YACN,aAAS;AAAA,cACP,oBAAI,KAAK;AAAA,cACT,IAAI,KAAK,OAAO,SAAS;AAAA,cACzB,EAAE,OAAO;AAAA,YACX;AAAA,UACF;AAAA;AAAA,MACF,GACF;AAAA,OACF;AAAA,IAEA,6CAAC,sBAAK,IAAG,QAAO,IAAG,KAAI,KAAI,KAAI,OAAM,UACnC;AAAA,kDAAC,sBAAK,KAAI,KAAI,OAAM,UAClB,sDAAC,wBAAO,OAAO,gBAAgB,MAAM,GAClC,6BAAmB,MAAM,GAC5B,GACF;AAAA,MAEA;AAAA,QAAC;AAAA;AAAA,UACC;AAAA,UACA;AAAA,UACA;AAAA;AAAA,MACF;AAAA,OACF;AAAA,KACF;AAEJ;AAEA,MAAM,qBAAqB,CAAC,WAA6C;AACvE,UAAQ,OAAO,OAAO;AAAA,IACpB,KAAK;AAAA,IACL,KAAK;AACH,aACE;AAAA,QAAC;AAAA;AAAA,UACC,gBAAe;AAAA,UACf,IAAG;AAAA,UACH,aAAY;AAAA;AAAA,MACd;AAAA,IAEJ,KAAK;AACH,aACE;AAAA,QAAC;AAAA;AAAA,UACC,gBAAe;AAAA,UACf,IAAG;AAAA,UACH,aAAY;AAAA;AAAA,MACd;AAAA,IAEJ,KAAK;AACH,aACE;AAAA,QAAC;AAAA;AAAA,UACC,gBAAe;AAAA,UACf,IAAG;AAAA,UACH,aAAY;AAAA;AAAA,MACd;AAAA,EAEN;AACF;AAEA,MAAM,kBAAkB,CAAC,WAA6C;AACpE,UAAQ,OAAO,OAAO;AAAA,IACpB,KAAK;AAAA,IACL,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,EACX;AACF;","names":[]}
1
+ {"version":3,"sources":["../../../src/lib/domain-item.tsx"],"sourcesContent":["\"use client\";\n\nimport { Flex, Text } from \"@radix-ui/themes\";\nimport type { OrganizationDomainFieldsFragment } from \"../api/client-graphql/generated.js\";\nimport { IconPanel } from \"./icon-panel.js\";\nimport { Status } from \"./status.js\";\nimport { NameServerIcon } from \"./name-server-icon.js\";\nimport { DomainActions } from \"./domain-actions.js\";\nimport { Translation } from \"./i18n/translation.js\";\nimport { useComparativeReadableDate } from \"../use-comparative-readable-date.js\";\n\ninterface DomainItemProps {\n domain: OrganizationDomainFieldsFragment;\n onDeleteDomain: (domainId: string) => void;\n onReverifyDomain: (domainId: string) => void;\n}\n\nexport const DomainItem = ({\n domain,\n onDeleteDomain,\n onReverifyDomain,\n}: DomainItemProps) => {\n const timeAgo = useComparativeReadableDate({\n date: new Date(domain.createdAt),\n });\n\n return (\n <Flex gap=\"4\" align=\"center\">\n <IconPanel color={domain.nameServer === \"Other\" ? \"gray\" : \"panel\"}>\n <NameServerIcon provider={domain.nameServer} />\n </IconPanel>\n\n <Flex direction=\"column\">\n <Text size=\"2\" highContrast weight=\"bold\" as=\"p\">\n {domain.domain}\n </Text>\n\n <Text size=\"2\" color=\"gray\" as=\"p\">\n <Translation\n defaultMessage=\"Added {timeAgo}\"\n id=\"DtZ2fb\"\n description=\"Label showing when the domain was added\"\n values={{ timeAgo }}\n />\n </Text>\n </Flex>\n\n <Flex ml=\"auto\" mr=\"2\" gap=\"4\" align=\"center\">\n <Flex gap=\"1\" align=\"center\">\n <Status state={getDomainStatus(domain)}>\n {domainStateToLabel(domain)}\n </Status>\n </Flex>\n\n <DomainActions\n domain={domain}\n onDeleteDomain={onDeleteDomain}\n onReverifyDomain={onReverifyDomain}\n />\n </Flex>\n </Flex>\n );\n};\n\nconst domainStateToLabel = (domain: OrganizationDomainFieldsFragment) => {\n switch (domain.state) {\n case \"Verified\":\n case \"LegacyVerified\":\n return (\n <Translation\n defaultMessage=\"Verified\"\n id=\"T7rpHw\"\n description=\"Domain verification status indicating the domain is verified\"\n />\n );\n case \"Pending\":\n return (\n <Translation\n defaultMessage=\"Verification pending\"\n id=\"gc1yge\"\n description=\"Domain verification status indicating verification is in progress\"\n />\n );\n case \"Failed\":\n return (\n <Translation\n defaultMessage=\"Verification failed\"\n id=\"cbbwqK\"\n description=\"Domain verification status indicating verification has failed\"\n />\n );\n }\n};\n\nconst getDomainStatus = (domain: OrganizationDomainFieldsFragment) => {\n switch (domain.state) {\n case \"Verified\":\n case \"LegacyVerified\":\n return \"success\";\n case \"Pending\":\n return \"waiting\";\n case \"Failed\":\n return \"error\";\n }\n};\n"],"mappings":";;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AA6BQ;AA3BR,oBAA2B;AAE3B,wBAA0B;AAC1B,oBAAuB;AACvB,8BAA+B;AAC/B,4BAA8B;AAC9B,yBAA4B;AAC5B,2CAA2C;AAQpC,MAAM,aAAa,CAAC;AAAA,EACzB;AAAA,EACA;AAAA,EACA;AACF,MAAuB;AACrB,QAAM,cAAU,iEAA2B;AAAA,IACzC,MAAM,IAAI,KAAK,OAAO,SAAS;AAAA,EACjC,CAAC;AAED,SACE,6CAAC,sBAAK,KAAI,KAAI,OAAM,UAClB;AAAA,gDAAC,+BAAU,OAAO,OAAO,eAAe,UAAU,SAAS,SACzD,sDAAC,0CAAe,UAAU,OAAO,YAAY,GAC/C;AAAA,IAEA,6CAAC,sBAAK,WAAU,UACd;AAAA,kDAAC,sBAAK,MAAK,KAAI,cAAY,MAAC,QAAO,QAAO,IAAG,KAC1C,iBAAO,QACV;AAAA,MAEA,4CAAC,sBAAK,MAAK,KAAI,OAAM,QAAO,IAAG,KAC7B;AAAA,QAAC;AAAA;AAAA,UACC,gBAAe;AAAA,UACf,IAAG;AAAA,UACH,aAAY;AAAA,UACZ,QAAQ,EAAE,QAAQ;AAAA;AAAA,MACpB,GACF;AAAA,OACF;AAAA,IAEA,6CAAC,sBAAK,IAAG,QAAO,IAAG,KAAI,KAAI,KAAI,OAAM,UACnC;AAAA,kDAAC,sBAAK,KAAI,KAAI,OAAM,UAClB,sDAAC,wBAAO,OAAO,gBAAgB,MAAM,GAClC,6BAAmB,MAAM,GAC5B,GACF;AAAA,MAEA;AAAA,QAAC;AAAA;AAAA,UACC;AAAA,UACA;AAAA,UACA;AAAA;AAAA,MACF;AAAA,OACF;AAAA,KACF;AAEJ;AAEA,MAAM,qBAAqB,CAAC,WAA6C;AACvE,UAAQ,OAAO,OAAO;AAAA,IACpB,KAAK;AAAA,IACL,KAAK;AACH,aACE;AAAA,QAAC;AAAA;AAAA,UACC,gBAAe;AAAA,UACf,IAAG;AAAA,UACH,aAAY;AAAA;AAAA,MACd;AAAA,IAEJ,KAAK;AACH,aACE;AAAA,QAAC;AAAA;AAAA,UACC,gBAAe;AAAA,UACf,IAAG;AAAA,UACH,aAAY;AAAA;AAAA,MACd;AAAA,IAEJ,KAAK;AACH,aACE;AAAA,QAAC;AAAA;AAAA,UACC,gBAAe;AAAA,UACf,IAAG;AAAA,UACH,aAAY;AAAA;AAAA,MACd;AAAA,EAEN;AACF;AAEA,MAAM,kBAAkB,CAAC,WAA6C;AACpE,UAAQ,OAAO,OAAO;AAAA,IACpB,KAAK;AAAA,IACL,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,EACX;AACF;","names":[]}
@@ -97,7 +97,9 @@ function CreateUserApiKeyForm() {
97
97
  {
98
98
  onSubmit: (e) => {
99
99
  e.preventDefault();
100
- if (isPending) return;
100
+ if (isPending) {
101
+ return;
102
+ }
101
103
  const data = new FormData(e.currentTarget);
102
104
  const isValid = validate(data);
103
105
  if (!isValid) {
@@ -109,6 +111,7 @@ function CreateUserApiKeyForm() {
109
111
  name: data.get("name")?.toString() ?? "",
110
112
  permissions: selectedPermissions.map((p) => p.slug),
111
113
  expiresAt: (0, import_api_key_expiration.getApiKeyExpiresAt)(
114
+ /* @__PURE__ */ new Date(),
112
115
  data.get("expiration")?.toString() ?? "never"
113
116
  ) ?? null
114
117
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../src/lib/user-api-keys/create-user-api-key.tsx"],"sourcesContent":["import {\n Box,\n Checkbox,\n Flex,\n ScrollArea,\n Text,\n Callout,\n} from \"@radix-ui/themes\";\nimport {\n Dialog,\n Label,\n Button,\n TextField,\n TextFieldSlot,\n} from \"../elements.js\";\nimport * as Form from \"../form.js\";\nimport {\n ExclamationTriangleIcon,\n InfoCircledIcon,\n MagnifyingGlassIcon,\n} from \"@radix-ui/react-icons\";\nimport { CopyButton, CopyIconButton } from \"../copy-button.js\";\nimport * as React from \"react\";\nimport {\n type ListUserApiKeyPermission,\n useCreateUserApiKeyWithInvalidation,\n useListUserApiKeyPermissions,\n} from \"../api/user-api-key.js\";\nimport { useUserApiKeysContext } from \"./user-api-keys-context.js\";\nimport { Translation } from \"../i18n/translation.js\";\nimport { useTranslation } from \"../i18n/use-translation.js\";\nimport {\n ApiKeyExpirationSelectField,\n getApiKeyExpiresAt,\n type ApiKeyExpirationOption,\n} from \"../api-keys/api-key-expiration.js\";\n\nexport function CreateUserApiKeyDialog({ canCreate }: { canCreate: boolean }) {\n const {\n state: { createDialogOpen, createdApiKey },\n dispatch,\n } = useUserApiKeysContext();\n\n if (!canCreate) {\n return null;\n }\n\n return (\n <Dialog.Root\n open={createDialogOpen}\n onOpenChange={(open) => {\n if (!open) {\n dispatch({ type: \"CLOSE_CREATE_DIALOG\" });\n }\n }}\n >\n {createdApiKey ? (\n <SaveApiKeyContent apiKey={createdApiKey.value} />\n ) : (\n <CreateUserApiKeyForm key={`${createDialogOpen}`} />\n )}\n </Dialog.Root>\n );\n}\n\nfunction CreateUserApiKeyForm() {\n const { dispatch } = useUserApiKeysContext();\n const translate = useTranslation();\n const [errors, setErrors] = React.useState<{\n name: boolean;\n }>({ name: false });\n const [selectedPermissions, setSelectedPermissions] = React.useState<\n ListUserApiKeyPermission[]\n >([]);\n\n const validate = (formData: FormData) => {\n const name = formData.get(\"name\")?.toString() ?? \"\";\n const nextErrors = { name: !name.trim().length };\n setErrors(nextErrors);\n return Object.values(nextErrors).every((error) => error === false);\n };\n\n const {\n mutate: createUserApiKey,\n error,\n isPending,\n isSuccess,\n } = useCreateUserApiKeyWithInvalidation();\n const permissions = useListUserApiKeyPermissions({ limit: 100 });\n\n return (\n <Dialog.Content maxWidth=\"529px\">\n <Dialog.Title size=\"4\" weight=\"bold\">\n <Translation\n defaultMessage=\"Create API key\"\n id=\"eUFRNS\"\n description=\"Dialog title for creating a new API key\"\n />\n </Dialog.Title>\n <Form.Root\n onSubmit={(e) => {\n e.preventDefault();\n if (isPending) return;\n const data = new FormData(e.currentTarget);\n const isValid = validate(data);\n if (!isValid) {\n return;\n }\n\n createUserApiKey(\n {\n data: {\n name: data.get(\"name\")?.toString() ?? \"\",\n permissions: selectedPermissions.map((p) => p.slug),\n expiresAt:\n getApiKeyExpiresAt(\n (data.get(\"expiration\")?.toString() ??\n \"never\") as ApiKeyExpirationOption,\n ) ?? null,\n },\n },\n {\n onSuccess: (data) => {\n dispatch({ type: \"RESET_PAGINATION\" });\n dispatch({ type: \"SET_CREATED_API_KEY\", apiKey: data });\n },\n },\n );\n }}\n >\n <Flex direction=\"column\" align=\"stretch\" gap=\"4\">\n {error ? (\n <Callout.Root color=\"red\" role=\"alert\">\n <Callout.Icon>\n <ExclamationTriangleIcon />\n </Callout.Icon>\n <Callout.Text>\n <Translation\n defaultMessage=\"An error occurred while creating the API key.\"\n id=\"0LyBVd\"\n description=\"Error message when API key creation fails\"\n />\n </Callout.Text>\n </Callout.Root>\n ) : null}\n <Form.Field name=\"name\" asChild>\n <Flex direction=\"column\" align=\"stretch\" gap=\"2\">\n <Form.Label asChild>\n <Label>\n <Translation\n defaultMessage=\"Name\"\n id=\"v0VmRy\"\n description=\"Label for API key name input field\"\n />\n </Label>\n </Form.Label>\n <Form.Control asChild>\n <TextField\n data-1p-ignore\n autoComplete=\"off\"\n placeholder={translate({\n defaultMessage: \"A descriptive name for the API key\",\n id: \"moyvr4\",\n description: \"Placeholder for API key name input\",\n })}\n />\n </Form.Control>\n {errors.name && (\n <Form.Message asChild>\n <Text size=\"2\" color=\"red\">\n <Translation\n defaultMessage=\"The name is required\"\n id=\"oF9d2V\"\n description=\"Validation error when API key name is empty\"\n />\n </Text>\n </Form.Message>\n )}\n </Flex>\n </Form.Field>\n <ApiKeyExpirationSelectField />\n {permissions.isError ? (\n <Callout.Root color=\"amber\" role=\"status\">\n <Callout.Icon>\n <ExclamationTriangleIcon />\n </Callout.Icon>\n <Callout.Text>\n <Translation\n defaultMessage=\"Permissions are unavailable right now. You can still create an API key without selecting permissions.\"\n id=\"Pw7VUu\"\n description=\"Warning message when API key permissions fail to load\"\n />\n </Callout.Text>\n </Callout.Root>\n ) : null}\n {permissions.isSuccess && permissions.data.data.length > 0 && (\n <PermissionsField\n permissions={permissions.data.data}\n selectedPermissions={selectedPermissions}\n setSelectedPermissions={setSelectedPermissions}\n />\n )}\n </Flex>\n\n <Flex align=\"center\" gap=\"3\" justify=\"end\" mt=\"5\">\n <Dialog.Close>\n <Button variant=\"secondary\" disabled={isPending || isSuccess}>\n <Translation\n defaultMessage=\"Cancel\"\n id=\"AyVAAW\"\n description=\"Button to cancel API key creation\"\n />\n </Button>\n </Dialog.Close>\n <Button type=\"submit\" loading={isPending || isSuccess}>\n <Translation\n defaultMessage=\"Create API key\"\n id=\"d4BNWL\"\n description=\"Button to submit and create the API key\"\n />\n </Button>\n </Flex>\n </Form.Root>\n </Dialog.Content>\n );\n}\n\nfunction SaveApiKeyContent({ apiKey }: { apiKey: string }) {\n return (\n <Dialog.Content\n maxWidth=\"529px\"\n onEscapeKeyDown={(event) => event.preventDefault()}\n onPointerDownOutside={(event) => event.preventDefault()}\n >\n <Dialog.Title size=\"4\" weight=\"bold\">\n <Translation\n defaultMessage=\"Save your key\"\n id=\"wFFCij\"\n description=\"Dialog title prompting user to save their API key\"\n />\n </Dialog.Title>\n <Dialog.Description>\n <Translation\n defaultMessage=\"Please save this API key in a secure location. If you lose it, you'll need to generate a new one.\"\n id=\"sy+2x7\"\n description=\"Warning message about saving the API key\"\n />\n </Dialog.Description>\n <Callout.Root mt=\"5\" mb=\"4\">\n <Callout.Icon>\n <InfoCircledIcon />\n </Callout.Icon>\n <Callout.Text>\n <Translation\n defaultMessage=\"You won't be able to access the key again. Please copy it now.\"\n id=\"EFAK/K\"\n description=\"Callout warning that the key won't be accessible again\"\n />\n </Callout.Text>\n </Callout.Root>\n <TextField value={apiKey} readOnly>\n <TextFieldSlot side=\"right\">\n <CopyIconButton value={apiKey} />\n </TextFieldSlot>\n </TextField>\n <Flex align=\"center\" gap=\"3\" justify=\"end\" mt=\"5\">\n <Dialog.Close>\n <CopyButton value={apiKey}>\n <Translation\n defaultMessage=\"Copy and close\"\n id=\"ViYtvQ\"\n description=\"Button to copy API key and close dialog\"\n />\n </CopyButton>\n </Dialog.Close>\n </Flex>\n </Dialog.Content>\n );\n}\n\nfunction Permission({\n checked,\n permission,\n onChange,\n}: {\n checked: boolean;\n permission: ListUserApiKeyPermission;\n onChange: (isChecked: boolean) => void;\n}) {\n return (\n <label\n htmlFor={permission.slug}\n style={{\n display: \"flex\",\n alignItems: \"center\",\n padding: \"var(--space-2) var(--space-4)\",\n gap: \"var(--space-3)\",\n borderBottom: \"1px solid var(--gray-6)\",\n cursor: \"pointer\",\n }}\n >\n <Checkbox\n checked={checked}\n id={permission.slug}\n name=\"permission\"\n value={permission.slug}\n onCheckedChange={(e) => onChange(e === \"indeterminate\" ? false : e)}\n />\n <Flex direction=\"column\">\n <Text size=\"2\" weight=\"bold\">\n {permission.name}\n </Text>\n <Text size=\"2\" color=\"gray\">\n {permission.description}\n </Text>\n </Flex>\n </label>\n );\n}\n\nfunction PermissionsField({\n permissions = [],\n selectedPermissions,\n setSelectedPermissions,\n}: {\n permissions: ListUserApiKeyPermission[];\n selectedPermissions: ListUserApiKeyPermission[];\n setSelectedPermissions: React.Dispatch<\n React.SetStateAction<ListUserApiKeyPermission[]>\n >;\n}) {\n const [filter, setFilter] = React.useState(\"\");\n const fieldRef = React.useRef<HTMLDivElement | null>(null);\n const translate = useTranslation();\n const filteredPermissions = React.useMemo(() => {\n const query = filter.trim().toLowerCase();\n return permissions.filter((p) => {\n return (\n !query.length ||\n p.description?.toLowerCase().includes(query) ||\n p.name.toLowerCase().includes(query) ||\n p.slug.toLowerCase().includes(query)\n );\n });\n }, [permissions, filter]);\n const filteredSelectedPermissions = React.useMemo(() => {\n return filteredPermissions.filter((permission) =>\n selectedPermissions.some((sp) => sp.slug === permission.slug),\n );\n }, [filteredPermissions, selectedPermissions]);\n\n React.useEffect(() => {\n const onResize = () => {\n if (fieldRef.current && filteredPermissions.length !== 0) {\n fieldRef.current.style.minHeight = \"unset\";\n }\n };\n window.addEventListener(\"resize\", onResize);\n return () => {\n window.removeEventListener(\"resize\", onResize);\n };\n }, [filteredPermissions.length]);\n\n return (\n <Form.Field name=\"permissions\" asChild>\n <Flex direction=\"column\" align=\"stretch\" gap=\"1\">\n <Form.Label asChild>\n <Label>\n <Translation\n defaultMessage=\"Permissions\"\n id=\"6YN1wO\"\n description=\"Label for API key permissions field\"\n />\n </Label>\n </Form.Label>\n <Text size=\"2\" mb=\"2\" color=\"gray\">\n <Translation\n defaultMessage=\"Only enable the minimum permissions required for your use case.\"\n id=\"q2VEtG\"\n description=\"Help text for API key permissions selection\"\n />\n </Text>\n <Flex\n ref={fieldRef}\n style={{\n borderRadius: \"var(--radius-3)\",\n borderColor: \"var(--gray-6)\",\n borderWidth: \"1px\",\n borderStyle: \"solid\",\n }}\n direction=\"column\"\n align=\"stretch\"\n >\n <TextField\n name=\"search\"\n value={filter}\n size=\"2\"\n aria-label={translate({\n defaultMessage: \"Search permissions\",\n id: \"jQfPuI\",\n description: \"Accessible label for permissions search input\",\n })}\n onKeyDown={(e) => {\n if (e.key === \"Enter\") {\n e.preventDefault();\n }\n }}\n onChange={(e) => {\n if (fieldRef.current) {\n fieldRef.current.style.minHeight =\n fieldRef.current.clientHeight + 2 + \"px\";\n }\n setFilter(e.target.value);\n }}\n style={{\n height: \"40px\",\n borderRadius: \"var(--radius-3) var(--radius-3) 0 0\",\n boxShadow: \"none\",\n }}\n placeholder={translate({\n defaultMessage: \"Search\",\n id: \"iyNcly\",\n description: \"Placeholder for permissions search input\",\n })}\n >\n <TextFieldSlot side=\"left\" px=\"3\">\n <MagnifyingGlassIcon aria-hidden=\"true\" height=\"16\" width=\"16\" />\n </TextFieldSlot>\n </TextField>\n {filteredPermissions.length > 0 ? (\n <>\n <ScrollArea\n scrollbars=\"vertical\"\n style={{\n flex: 1,\n maxHeight: \"calc(50vh - 150px)\",\n border: \"1px solid var(--gray-6)\",\n borderWidth: \"1px 0 0\",\n }}\n >\n {filteredPermissions.map((permission) => (\n <Permission\n checked={selectedPermissions.some(\n (sp) => sp.slug === permission.slug,\n )}\n key={permission.slug}\n permission={permission}\n onChange={(isChecked) =>\n setSelectedPermissions((prev) =>\n isChecked\n ? [...prev, permission]\n : prev.filter((sp) => sp.slug !== permission.slug),\n )\n }\n />\n ))}\n </ScrollArea>\n <Box\n px=\"4\"\n py=\"3\"\n mt={\"-1px\"}\n flexGrow=\"0\"\n style={{\n borderTop: \"0 solid var(--gray-6)\",\n borderWidth: \"1px 0 0\",\n }}\n >\n <SelectedPermissions\n selected={selectedPermissions.length}\n allFilteredSelected={\n filteredPermissions.length > 0 &&\n filteredSelectedPermissions.length ===\n filteredPermissions.length\n }\n onToggle={() => {\n setSelectedPermissions((prev) => {\n const filteredPermissionSlugs = new Set(\n filteredPermissions.map(\n (permission) => permission.slug,\n ),\n );\n const selectedPermissionSlugs = new Set(\n prev.map((permission) => permission.slug),\n );\n const allFilteredPermissionsSelected =\n filteredPermissions.every((permission) =>\n selectedPermissionSlugs.has(permission.slug),\n );\n\n if (allFilteredPermissionsSelected) {\n return prev.filter(\n (permission) =>\n !filteredPermissionSlugs.has(permission.slug),\n );\n }\n\n return [\n ...prev,\n ...filteredPermissions.filter(\n (permission) =>\n !selectedPermissionSlugs.has(permission.slug),\n ),\n ];\n });\n }}\n />\n </Box>\n </>\n ) : (\n <Flex\n gap=\"4\"\n pt=\"6\"\n pb=\"6\"\n style={{ borderTop: \"1px solid var(--gray-6)\" }}\n flexGrow=\"1\"\n justify=\"center\"\n align=\"center\"\n direction=\"column\"\n >\n <MagnifyingGlassIcon\n style={{\n color: \"var(--gray-9)\",\n width: \"var(--space-5)\",\n height: \"var(--space-5)\",\n }}\n />\n <Text size=\"2\" align=\"center\" mb=\"2\" wrap=\"balance\" weight=\"bold\">\n <Translation\n defaultMessage=\"No permissions match your search\"\n id=\"xjqT9f\"\n description=\"Empty state message when no permissions match search\"\n />\n </Text>\n <Button\n type=\"button\"\n variant=\"secondary\"\n size=\"1\"\n onClick={() => setFilter(\"\")}\n >\n <Translation\n defaultMessage=\"Clear search\"\n id=\"YrMs63\"\n description=\"Button to clear permissions search\"\n />\n </Button>\n </Flex>\n )}\n </Flex>\n </Flex>\n </Form.Field>\n );\n}\n\nfunction SelectedPermissions({\n selected,\n allFilteredSelected,\n onToggle,\n}: {\n selected: number;\n allFilteredSelected: boolean;\n onToggle: () => void;\n}) {\n return (\n <Flex align=\"baseline\" gap=\"2\">\n <Text size=\"1\" style={{ color: \"var(--gray-11)\" }}>\n {selected === 0 ? (\n <Translation\n defaultMessage=\"No permissions selected\"\n id=\"FqU9hv\"\n description=\"Message when no permissions are selected\"\n />\n ) : selected === 1 ? (\n <Translation\n defaultMessage=\"1 permission selected\"\n id=\"VouLgT\"\n description=\"Message showing count of selected permissions\"\n />\n ) : (\n <Translation\n defaultMessage=\"{count} permissions selected\"\n id=\"ZL90DI\"\n description=\"Message showing count of selected permissions\"\n values={{ count: selected }}\n />\n )}\n </Text>\n <button\n type=\"button\"\n onClick={onToggle}\n aria-pressed={allFilteredSelected}\n style={{\n background: \"none\",\n border: 0,\n padding: 0,\n font: \"inherit\",\n cursor: \"pointer\",\n color: \"var(--accent-10)\",\n }}\n >\n <Text size=\"1\">\n {allFilteredSelected ? (\n <Translation\n defaultMessage=\"Deselect all\"\n id=\"63f7SY\"\n description=\"Button to deselect all permissions\"\n />\n ) : (\n <Translation\n defaultMessage=\"Select all\"\n id=\"onTqlA\"\n description=\"Button to select all permissions\"\n />\n )}\n </Text>\n </button>\n </Flex>\n );\n}\n\nexport function CreateUserApiKeyButton({ canCreate }: { canCreate: boolean }) {\n const { dispatch } = useUserApiKeysContext();\n\n if (!canCreate) {\n return null;\n }\n\n return (\n <Button onClick={() => dispatch({ type: \"OPEN_CREATE_DIALOG\" })}>\n <Translation\n defaultMessage=\"Create API key\"\n id=\"vq5724\"\n description=\"Button to open create API key dialog\"\n />\n </Button>\n );\n}\n"],"mappings":"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","names":["error","data"]}
1
+ {"version":3,"sources":["../../../../src/lib/user-api-keys/create-user-api-key.tsx"],"sourcesContent":["import {\n Box,\n Checkbox,\n Flex,\n ScrollArea,\n Text,\n Callout,\n} from \"@radix-ui/themes\";\nimport {\n Dialog,\n Label,\n Button,\n TextField,\n TextFieldSlot,\n} from \"../elements.js\";\nimport * as Form from \"../form.js\";\nimport {\n ExclamationTriangleIcon,\n InfoCircledIcon,\n MagnifyingGlassIcon,\n} from \"@radix-ui/react-icons\";\nimport { CopyButton, CopyIconButton } from \"../copy-button.js\";\nimport * as React from \"react\";\nimport {\n type ListUserApiKeyPermission,\n useCreateUserApiKeyWithInvalidation,\n useListUserApiKeyPermissions,\n} from \"../api/user-api-key.js\";\nimport { useUserApiKeysContext } from \"./user-api-keys-context.js\";\nimport { Translation } from \"../i18n/translation.js\";\nimport { useTranslation } from \"../i18n/use-translation.js\";\nimport {\n ApiKeyExpirationSelectField,\n getApiKeyExpiresAt,\n type ApiKeyExpirationOption,\n} from \"../api-keys/api-key-expiration.js\";\n\nexport function CreateUserApiKeyDialog({ canCreate }: { canCreate: boolean }) {\n const {\n state: { createDialogOpen, createdApiKey },\n dispatch,\n } = useUserApiKeysContext();\n\n if (!canCreate) {\n return null;\n }\n\n return (\n <Dialog.Root\n open={createDialogOpen}\n onOpenChange={(open) => {\n if (!open) {\n dispatch({ type: \"CLOSE_CREATE_DIALOG\" });\n }\n }}\n >\n {createdApiKey ? (\n <SaveApiKeyContent apiKey={createdApiKey.value} />\n ) : (\n <CreateUserApiKeyForm key={`${createDialogOpen}`} />\n )}\n </Dialog.Root>\n );\n}\n\nfunction CreateUserApiKeyForm() {\n const { dispatch } = useUserApiKeysContext();\n const translate = useTranslation();\n const [errors, setErrors] = React.useState<{\n name: boolean;\n }>({ name: false });\n const [selectedPermissions, setSelectedPermissions] = React.useState<\n ListUserApiKeyPermission[]\n >([]);\n\n const validate = (formData: FormData) => {\n const name = formData.get(\"name\")?.toString() ?? \"\";\n const nextErrors = { name: !name.trim().length };\n setErrors(nextErrors);\n return Object.values(nextErrors).every((error) => error === false);\n };\n\n const {\n mutate: createUserApiKey,\n error,\n isPending,\n isSuccess,\n } = useCreateUserApiKeyWithInvalidation();\n const permissions = useListUserApiKeyPermissions({ limit: 100 });\n\n return (\n <Dialog.Content maxWidth=\"529px\">\n <Dialog.Title size=\"4\" weight=\"bold\">\n <Translation\n defaultMessage=\"Create API key\"\n id=\"eUFRNS\"\n description=\"Dialog title for creating a new API key\"\n />\n </Dialog.Title>\n <Form.Root\n onSubmit={(e) => {\n e.preventDefault();\n if (isPending) {\n return;\n }\n const data = new FormData(e.currentTarget);\n const isValid = validate(data);\n if (!isValid) {\n return;\n }\n\n createUserApiKey(\n {\n data: {\n name: data.get(\"name\")?.toString() ?? \"\",\n permissions: selectedPermissions.map((p) => p.slug),\n expiresAt:\n getApiKeyExpiresAt(\n new Date(),\n (data.get(\"expiration\")?.toString() ??\n \"never\") as ApiKeyExpirationOption,\n ) ?? null,\n },\n },\n {\n onSuccess: (data) => {\n dispatch({ type: \"RESET_PAGINATION\" });\n dispatch({ type: \"SET_CREATED_API_KEY\", apiKey: data });\n },\n },\n );\n }}\n >\n <Flex direction=\"column\" align=\"stretch\" gap=\"4\">\n {error ? (\n <Callout.Root color=\"red\" role=\"alert\">\n <Callout.Icon>\n <ExclamationTriangleIcon />\n </Callout.Icon>\n <Callout.Text>\n <Translation\n defaultMessage=\"An error occurred while creating the API key.\"\n id=\"0LyBVd\"\n description=\"Error message when API key creation fails\"\n />\n </Callout.Text>\n </Callout.Root>\n ) : null}\n <Form.Field name=\"name\" asChild>\n <Flex direction=\"column\" align=\"stretch\" gap=\"2\">\n <Form.Label asChild>\n <Label>\n <Translation\n defaultMessage=\"Name\"\n id=\"v0VmRy\"\n description=\"Label for API key name input field\"\n />\n </Label>\n </Form.Label>\n <Form.Control asChild>\n <TextField\n data-1p-ignore\n autoComplete=\"off\"\n placeholder={translate({\n defaultMessage: \"A descriptive name for the API key\",\n id: \"moyvr4\",\n description: \"Placeholder for API key name input\",\n })}\n />\n </Form.Control>\n {errors.name && (\n <Form.Message asChild>\n <Text size=\"2\" color=\"red\">\n <Translation\n defaultMessage=\"The name is required\"\n id=\"oF9d2V\"\n description=\"Validation error when API key name is empty\"\n />\n </Text>\n </Form.Message>\n )}\n </Flex>\n </Form.Field>\n <ApiKeyExpirationSelectField />\n {permissions.isError ? (\n <Callout.Root color=\"amber\" role=\"status\">\n <Callout.Icon>\n <ExclamationTriangleIcon />\n </Callout.Icon>\n <Callout.Text>\n <Translation\n defaultMessage=\"Permissions are unavailable right now. You can still create an API key without selecting permissions.\"\n id=\"Pw7VUu\"\n description=\"Warning message when API key permissions fail to load\"\n />\n </Callout.Text>\n </Callout.Root>\n ) : null}\n {permissions.isSuccess && permissions.data.data.length > 0 && (\n <PermissionsField\n permissions={permissions.data.data}\n selectedPermissions={selectedPermissions}\n setSelectedPermissions={setSelectedPermissions}\n />\n )}\n </Flex>\n\n <Flex align=\"center\" gap=\"3\" justify=\"end\" mt=\"5\">\n <Dialog.Close>\n <Button variant=\"secondary\" disabled={isPending || isSuccess}>\n <Translation\n defaultMessage=\"Cancel\"\n id=\"AyVAAW\"\n description=\"Button to cancel API key creation\"\n />\n </Button>\n </Dialog.Close>\n <Button type=\"submit\" loading={isPending || isSuccess}>\n <Translation\n defaultMessage=\"Create API key\"\n id=\"d4BNWL\"\n description=\"Button to submit and create the API key\"\n />\n </Button>\n </Flex>\n </Form.Root>\n </Dialog.Content>\n );\n}\n\nfunction SaveApiKeyContent({ apiKey }: { apiKey: string }) {\n return (\n <Dialog.Content\n maxWidth=\"529px\"\n onEscapeKeyDown={(event) => event.preventDefault()}\n onPointerDownOutside={(event) => event.preventDefault()}\n >\n <Dialog.Title size=\"4\" weight=\"bold\">\n <Translation\n defaultMessage=\"Save your key\"\n id=\"wFFCij\"\n description=\"Dialog title prompting user to save their API key\"\n />\n </Dialog.Title>\n <Dialog.Description>\n <Translation\n defaultMessage=\"Please save this API key in a secure location. If you lose it, you'll need to generate a new one.\"\n id=\"sy+2x7\"\n description=\"Warning message about saving the API key\"\n />\n </Dialog.Description>\n <Callout.Root mt=\"5\" mb=\"4\">\n <Callout.Icon>\n <InfoCircledIcon />\n </Callout.Icon>\n <Callout.Text>\n <Translation\n defaultMessage=\"You won't be able to access the key again. Please copy it now.\"\n id=\"EFAK/K\"\n description=\"Callout warning that the key won't be accessible again\"\n />\n </Callout.Text>\n </Callout.Root>\n <TextField value={apiKey} readOnly>\n <TextFieldSlot side=\"right\">\n <CopyIconButton value={apiKey} />\n </TextFieldSlot>\n </TextField>\n <Flex align=\"center\" gap=\"3\" justify=\"end\" mt=\"5\">\n <Dialog.Close>\n <CopyButton value={apiKey}>\n <Translation\n defaultMessage=\"Copy and close\"\n id=\"ViYtvQ\"\n description=\"Button to copy API key and close dialog\"\n />\n </CopyButton>\n </Dialog.Close>\n </Flex>\n </Dialog.Content>\n );\n}\n\nfunction Permission({\n checked,\n permission,\n onChange,\n}: {\n checked: boolean;\n permission: ListUserApiKeyPermission;\n onChange: (isChecked: boolean) => void;\n}) {\n return (\n <label\n htmlFor={permission.slug}\n style={{\n display: \"flex\",\n alignItems: \"center\",\n padding: \"var(--space-2) var(--space-4)\",\n gap: \"var(--space-3)\",\n borderBottom: \"1px solid var(--gray-6)\",\n cursor: \"pointer\",\n }}\n >\n <Checkbox\n checked={checked}\n id={permission.slug}\n name=\"permission\"\n value={permission.slug}\n onCheckedChange={(e) => onChange(e === \"indeterminate\" ? false : e)}\n />\n <Flex direction=\"column\">\n <Text size=\"2\" weight=\"bold\">\n {permission.name}\n </Text>\n <Text size=\"2\" color=\"gray\">\n {permission.description}\n </Text>\n </Flex>\n </label>\n );\n}\n\nfunction PermissionsField({\n permissions = [],\n selectedPermissions,\n setSelectedPermissions,\n}: {\n permissions: ListUserApiKeyPermission[];\n selectedPermissions: ListUserApiKeyPermission[];\n setSelectedPermissions: React.Dispatch<\n React.SetStateAction<ListUserApiKeyPermission[]>\n >;\n}) {\n const [filter, setFilter] = React.useState(\"\");\n const fieldRef = React.useRef<HTMLDivElement | null>(null);\n const translate = useTranslation();\n const filteredPermissions = React.useMemo(() => {\n const query = filter.trim().toLowerCase();\n return permissions.filter((p) => {\n return (\n !query.length ||\n p.description?.toLowerCase().includes(query) ||\n p.name.toLowerCase().includes(query) ||\n p.slug.toLowerCase().includes(query)\n );\n });\n }, [permissions, filter]);\n const filteredSelectedPermissions = React.useMemo(() => {\n return filteredPermissions.filter((permission) =>\n selectedPermissions.some((sp) => sp.slug === permission.slug),\n );\n }, [filteredPermissions, selectedPermissions]);\n\n React.useEffect(() => {\n const onResize = () => {\n if (fieldRef.current && filteredPermissions.length !== 0) {\n fieldRef.current.style.minHeight = \"unset\";\n }\n };\n window.addEventListener(\"resize\", onResize);\n return () => {\n window.removeEventListener(\"resize\", onResize);\n };\n }, [filteredPermissions.length]);\n\n return (\n <Form.Field name=\"permissions\" asChild>\n <Flex direction=\"column\" align=\"stretch\" gap=\"1\">\n <Form.Label asChild>\n <Label>\n <Translation\n defaultMessage=\"Permissions\"\n id=\"6YN1wO\"\n description=\"Label for API key permissions field\"\n />\n </Label>\n </Form.Label>\n <Text size=\"2\" mb=\"2\" color=\"gray\">\n <Translation\n defaultMessage=\"Only enable the minimum permissions required for your use case.\"\n id=\"q2VEtG\"\n description=\"Help text for API key permissions selection\"\n />\n </Text>\n <Flex\n ref={fieldRef}\n style={{\n borderRadius: \"var(--radius-3)\",\n borderColor: \"var(--gray-6)\",\n borderWidth: \"1px\",\n borderStyle: \"solid\",\n }}\n direction=\"column\"\n align=\"stretch\"\n >\n <TextField\n name=\"search\"\n value={filter}\n size=\"2\"\n aria-label={translate({\n defaultMessage: \"Search permissions\",\n id: \"jQfPuI\",\n description: \"Accessible label for permissions search input\",\n })}\n onKeyDown={(e) => {\n if (e.key === \"Enter\") {\n e.preventDefault();\n }\n }}\n onChange={(e) => {\n if (fieldRef.current) {\n fieldRef.current.style.minHeight =\n fieldRef.current.clientHeight + 2 + \"px\";\n }\n setFilter(e.target.value);\n }}\n style={{\n height: \"40px\",\n borderRadius: \"var(--radius-3) var(--radius-3) 0 0\",\n boxShadow: \"none\",\n }}\n placeholder={translate({\n defaultMessage: \"Search\",\n id: \"iyNcly\",\n description: \"Placeholder for permissions search input\",\n })}\n >\n <TextFieldSlot side=\"left\" px=\"3\">\n <MagnifyingGlassIcon aria-hidden=\"true\" height=\"16\" width=\"16\" />\n </TextFieldSlot>\n </TextField>\n {filteredPermissions.length > 0 ? (\n <>\n <ScrollArea\n scrollbars=\"vertical\"\n style={{\n flex: 1,\n maxHeight: \"calc(50vh - 150px)\",\n border: \"1px solid var(--gray-6)\",\n borderWidth: \"1px 0 0\",\n }}\n >\n {filteredPermissions.map((permission) => (\n <Permission\n checked={selectedPermissions.some(\n (sp) => sp.slug === permission.slug,\n )}\n key={permission.slug}\n permission={permission}\n onChange={(isChecked) =>\n setSelectedPermissions((prev) =>\n isChecked\n ? [...prev, permission]\n : prev.filter((sp) => sp.slug !== permission.slug),\n )\n }\n />\n ))}\n </ScrollArea>\n <Box\n px=\"4\"\n py=\"3\"\n mt={\"-1px\"}\n flexGrow=\"0\"\n style={{\n borderTop: \"0 solid var(--gray-6)\",\n borderWidth: \"1px 0 0\",\n }}\n >\n <SelectedPermissions\n selected={selectedPermissions.length}\n allFilteredSelected={\n filteredPermissions.length > 0 &&\n filteredSelectedPermissions.length ===\n filteredPermissions.length\n }\n onToggle={() => {\n setSelectedPermissions((prev) => {\n const filteredPermissionSlugs = new Set(\n filteredPermissions.map(\n (permission) => permission.slug,\n ),\n );\n const selectedPermissionSlugs = new Set(\n prev.map((permission) => permission.slug),\n );\n const allFilteredPermissionsSelected =\n filteredPermissions.every((permission) =>\n selectedPermissionSlugs.has(permission.slug),\n );\n\n if (allFilteredPermissionsSelected) {\n return prev.filter(\n (permission) =>\n !filteredPermissionSlugs.has(permission.slug),\n );\n }\n\n return [\n ...prev,\n ...filteredPermissions.filter(\n (permission) =>\n !selectedPermissionSlugs.has(permission.slug),\n ),\n ];\n });\n }}\n />\n </Box>\n </>\n ) : (\n <Flex\n gap=\"4\"\n pt=\"6\"\n pb=\"6\"\n style={{ borderTop: \"1px solid var(--gray-6)\" }}\n flexGrow=\"1\"\n justify=\"center\"\n align=\"center\"\n direction=\"column\"\n >\n <MagnifyingGlassIcon\n style={{\n color: \"var(--gray-9)\",\n width: \"var(--space-5)\",\n height: \"var(--space-5)\",\n }}\n />\n <Text size=\"2\" align=\"center\" mb=\"2\" wrap=\"balance\" weight=\"bold\">\n <Translation\n defaultMessage=\"No permissions match your search\"\n id=\"xjqT9f\"\n description=\"Empty state message when no permissions match search\"\n />\n </Text>\n <Button\n type=\"button\"\n variant=\"secondary\"\n size=\"1\"\n onClick={() => setFilter(\"\")}\n >\n <Translation\n defaultMessage=\"Clear search\"\n id=\"YrMs63\"\n description=\"Button to clear permissions search\"\n />\n </Button>\n </Flex>\n )}\n </Flex>\n </Flex>\n </Form.Field>\n );\n}\n\nfunction SelectedPermissions({\n selected,\n allFilteredSelected,\n onToggle,\n}: {\n selected: number;\n allFilteredSelected: boolean;\n onToggle: () => void;\n}) {\n return (\n <Flex align=\"baseline\" gap=\"2\">\n <Text size=\"1\" style={{ color: \"var(--gray-11)\" }}>\n {selected === 0 ? (\n <Translation\n defaultMessage=\"No permissions selected\"\n id=\"FqU9hv\"\n description=\"Message when no permissions are selected\"\n />\n ) : selected === 1 ? (\n <Translation\n defaultMessage=\"1 permission selected\"\n id=\"VouLgT\"\n description=\"Message showing count of selected permissions\"\n />\n ) : (\n <Translation\n defaultMessage=\"{count} permissions selected\"\n id=\"ZL90DI\"\n description=\"Message showing count of selected permissions\"\n values={{ count: selected }}\n />\n )}\n </Text>\n <button\n type=\"button\"\n onClick={onToggle}\n aria-pressed={allFilteredSelected}\n style={{\n background: \"none\",\n border: 0,\n padding: 0,\n font: \"inherit\",\n cursor: \"pointer\",\n color: \"var(--accent-10)\",\n }}\n >\n <Text size=\"1\">\n {allFilteredSelected ? (\n <Translation\n defaultMessage=\"Deselect all\"\n id=\"63f7SY\"\n description=\"Button to deselect all permissions\"\n />\n ) : (\n <Translation\n defaultMessage=\"Select all\"\n id=\"onTqlA\"\n description=\"Button to select all permissions\"\n />\n )}\n </Text>\n </button>\n </Flex>\n );\n}\n\nexport function CreateUserApiKeyButton({ canCreate }: { canCreate: boolean }) {\n const { dispatch } = useUserApiKeysContext();\n\n if (!canCreate) {\n return null;\n }\n\n return (\n <Button onClick={() => dispatch({ type: \"OPEN_CREATE_DIALOG\" })}>\n <Translation\n defaultMessage=\"Create API key\"\n id=\"vq5724\"\n description=\"Button to open create API key dialog\"\n />\n </Button>\n );\n}\n"],"mappings":"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","names":["error","data"]}
@@ -47,7 +47,7 @@ var CardList = __toESM(require("./card-list.js"), 1);
47
47
  var import_generic_error = require("./generic-error.js");
48
48
  var import_utils = require("./utils.js");
49
49
  var import_translation = require("./i18n/translation.js");
50
- var import_use_locale = require("./i18n/use-locale.js");
50
+ var import_use_comparative_readable_date = require("../use-comparative-readable-date.js");
51
51
  const UserSecurity = ({
52
52
  user,
53
53
  settings,
@@ -104,7 +104,9 @@ const UserSecurityLoading = (props) => {
104
104
  ] }) });
105
105
  };
106
106
  function PasswordSettings({ settings }) {
107
- const locale = (0, import_use_locale.useLocale)();
107
+ const timeAgo = (0, import_use_comparative_readable_date.useComparativeReadableDate)({
108
+ date: settings.lastUsed ? new Date(settings.lastUsed) : null
109
+ });
108
110
  return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_themes.Grid, { columns: "auto 1fr auto", align: "center", gap: "4", children: [
109
111
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_icon_panel.IconPanel, { children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_icons.LockClosedIcon, {}) }),
110
112
  /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_themes.Flex, { direction: "column", children: [
@@ -122,13 +124,7 @@ function PasswordSettings({ settings }) {
122
124
  defaultMessage: "Last used {time}",
123
125
  id: "Jqn+r+",
124
126
  description: "Label indicating when password was last used with time",
125
- values: {
126
- time: (0, import_utils.getComparativeReadableDate)(
127
- /* @__PURE__ */ new Date(),
128
- new Date(settings.lastUsed),
129
- { locale }
130
- )
131
- }
127
+ values: { time: timeAgo }
132
128
  }
133
129
  ) }) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_themes.Text, { as: "p", size: "2", color: "gray", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
134
130
  import_translation.Translation,
@@ -160,7 +156,9 @@ function MfaSettings({
160
156
  settings,
161
157
  isPasswordSet
162
158
  }) {
163
- const locale = (0, import_use_locale.useLocale)();
159
+ const timeAgo = (0, import_use_comparative_readable_date.useComparativeReadableDate)({
160
+ date: settings.lastUsed ? new Date(settings.lastUsed) : null
161
+ });
164
162
  return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_themes.Grid, { columns: "auto 1fr auto", align: "center", gap: "4", children: [
165
163
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_icon_panel.IconPanel, { children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_icons.ButtonIcon, {}) }),
166
164
  /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_themes.Flex, { direction: "column", children: [
@@ -189,13 +187,7 @@ function MfaSettings({
189
187
  defaultMessage: "Last used {time}",
190
188
  id: "h3R6gY",
191
189
  description: "Label indicating when MFA was last used with time",
192
- values: {
193
- time: (0, import_utils.getComparativeReadableDate)(
194
- /* @__PURE__ */ new Date(),
195
- new Date(settings.lastUsed),
196
- { locale }
197
- )
198
- }
190
+ values: { time: timeAgo }
199
191
  }
200
192
  ) })
201
193
  ] })
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/lib/user-security.tsx"],"sourcesContent":["\"use client\";\n\nimport { Card, Flex, Grid, Text } from \"@radix-ui/themes\";\nimport { Button, Skeleton } from \"./elements.js\";\nimport { IconPanel } from \"./icon-panel.js\";\nimport { ButtonIcon, LockClosedIcon } from \"@radix-ui/react-icons\";\nimport { SetPasswordDialog } from \"./set-password-dialog.js\";\nimport { ChangePasswordDialog } from \"./change-password-dialog.js\";\nimport { AddMfaDialog } from \"./add-mfa-dialog.js\";\nimport type {\n AuthenticationSettingsQuery,\n UserFieldsFragment,\n} from \"../api/client-graphql/generated.js\";\nimport { ResetMfaDialog } from \"./reset-mfa-dialog.js\";\nimport * as CardList from \"./card-list.js\";\nimport { GenericError } from \"./generic-error.js\";\nimport {\n getComparativeReadableDate,\n getDomProps,\n type WidgetRootDomProps,\n type WidgetRootState,\n} from \"./utils.js\";\nimport { Translation } from \"./i18n/translation.js\";\nimport { useLocale } from \"./i18n/use-locale.js\";\n\ntype AuthenticationSettings =\n AuthenticationSettingsQuery[\"authenticationSettings\"];\n\ninterface VerificationMethod {\n isSetUp: boolean;\n lastUsed?: string | null;\n}\n\ninterface UserSecurityProps extends WidgetRootDomProps {\n user: UserFieldsFragment;\n settings: AuthenticationSettings;\n}\n\nconst UserSecurity: React.FC<UserSecurityProps> = ({\n user,\n settings,\n ...domProps\n}) => {\n const passwordSettings: VerificationMethod | null =\n settings.passwordAuthEnabled\n ? { isSetUp: user.passwordSet, lastUsed: user.passwordLastUsedAt }\n : null;\n const mfaSettings: VerificationMethod | null = settings.mfaEnabled\n ? { isSetUp: user.mfaEnabled, lastUsed: user.mfaLastUsedAt }\n : null;\n return (\n <CardList.Root {...getWidgetRootDomProps(\"resolved\", domProps)}>\n {passwordSettings && (\n <CardList.Item>\n <PasswordSettings settings={passwordSettings} />\n </CardList.Item>\n )}\n {mfaSettings && (\n <CardList.Item>\n <MfaSettings\n settings={mfaSettings}\n isPasswordSet={!!passwordSettings?.isSetUp}\n />\n </CardList.Item>\n )}\n </CardList.Root>\n );\n};\n\ninterface UserSecurityErrorProps extends WidgetRootDomProps {\n error: unknown;\n}\n\nconst UserSecurityError: React.FC<UserSecurityErrorProps> = ({\n error,\n ...domProps\n}) => {\n return (\n <Card size=\"2\" {...getWidgetRootDomProps(\"error\", domProps)}>\n <GenericError error={error} />\n </Card>\n );\n};\n\ninterface UserSecurityLoadingProps extends WidgetRootDomProps {}\n\nconst UserSecurityLoading: React.FC<UserSecurityLoadingProps> = (props) => {\n return (\n <Card size=\"2\" {...getWidgetRootDomProps(\"loading\", props)}>\n <Grid columns=\"auto 1fr auto\" align=\"center\" gap=\"4\">\n <Skeleton>\n <IconPanel />\n </Skeleton>\n\n <Flex direction=\"column\">\n <Text size=\"2\" highContrast weight=\"bold\" as=\"p\" mb=\"-2px\">\n <Skeleton>\n <Translation\n defaultMessage=\"Password\"\n id=\"z19aZa\"\n description=\"Label for password security settings section\"\n />\n </Skeleton>\n </Text>\n <Text as=\"p\" size=\"2\" color=\"gray\">\n <Skeleton>\n <Translation\n defaultMessage=\"Set a password to access your account\"\n id=\"leodiT\"\n description=\"Description for setting up a password\"\n />\n </Skeleton>\n </Text>\n </Flex>\n\n <ChangePasswordDialog>\n <Skeleton>\n <Button variant=\"secondary\">\n <Translation\n defaultMessage=\"Change\"\n id=\"/ZV6cj\"\n description=\"Button label to change password\"\n />\n </Button>\n </Skeleton>\n </ChangePasswordDialog>\n </Grid>\n </Card>\n );\n};\n\nfunction PasswordSettings({ settings }: { settings: VerificationMethod }) {\n const locale = useLocale();\n\n return (\n <Grid columns=\"auto 1fr auto\" align=\"center\" gap=\"4\">\n <IconPanel>\n <LockClosedIcon />\n </IconPanel>\n\n <Flex direction=\"column\">\n <Text size=\"2\" highContrast weight=\"bold\" as=\"p\" mb=\"-2px\">\n <Translation\n defaultMessage=\"Password\"\n id=\"z19aZa\"\n description=\"Label for password security settings section\"\n />\n </Text>\n\n {settings.isSetUp ? (\n settings.lastUsed && (\n <Text size=\"2\" color=\"gray\">\n <Translation\n defaultMessage=\"Last used {time}\"\n id=\"Jqn+r+\"\n description=\"Label indicating when password was last used with time\"\n values={{\n time: getComparativeReadableDate(\n new Date(),\n new Date(settings.lastUsed),\n { locale },\n ),\n }}\n />\n </Text>\n )\n ) : (\n <Text as=\"p\" size=\"2\" color=\"gray\">\n <Translation\n defaultMessage=\"Set a password to access your account\"\n id=\"leodiT\"\n description=\"Description for setting up a password\"\n />\n </Text>\n )}\n </Flex>\n\n {settings.isSetUp ? (\n <ChangePasswordDialog>\n <Button variant=\"secondary\">\n <Translation\n defaultMessage=\"Change\"\n id=\"/ZV6cj\"\n description=\"Button label to change password\"\n />\n </Button>\n </ChangePasswordDialog>\n ) : (\n <SetPasswordDialog>\n <Button variant=\"secondary\">\n <Translation\n defaultMessage=\"Set a password\"\n id=\"zokPvK\"\n description=\"Button label to set a new password\"\n />\n </Button>\n </SetPasswordDialog>\n )}\n </Grid>\n );\n}\n\nfunction MfaSettings({\n settings,\n isPasswordSet,\n}: {\n settings: VerificationMethod;\n isPasswordSet: boolean;\n}) {\n const locale = useLocale();\n\n return (\n <Grid columns=\"auto 1fr auto\" align=\"center\" gap=\"4\">\n <IconPanel>\n <ButtonIcon />\n </IconPanel>\n\n <Flex direction=\"column\">\n <Text size=\"2\" highContrast weight=\"bold\" as=\"p\" mb=\"-2px\">\n <Translation\n defaultMessage=\"Multi-factor authentication\"\n id=\"f3uhhm\"\n description=\"Label for multi-factor authentication settings section\"\n />\n </Text>\n\n {settings.isSetUp ? (\n <Text size=\"2\">\n <Translation\n defaultMessage=\"Authenticator app\"\n id=\"0p/a72\"\n description=\"Label indicating MFA is set up with an authenticator app\"\n />\n {settings.lastUsed && (\n <>\n {/* eslint-disable-next-line formatjs/no-literal-string-in-jsx */}\n <Text size=\"2\" color=\"gray\" mx=\"1\">\n ∙\n </Text>\n <Text size=\"2\" color=\"gray\">\n <Translation\n defaultMessage=\"Last used {time}\"\n id=\"h3R6gY\"\n description=\"Label indicating when MFA was last used with time\"\n values={{\n time: getComparativeReadableDate(\n new Date(),\n new Date(settings.lastUsed),\n { locale },\n ),\n }}\n />\n </Text>\n </>\n )}\n </Text>\n ) : (\n <Text as=\"p\" size=\"2\" color=\"gray\">\n <Translation\n defaultMessage=\"Secure your account with an extra verification step\"\n id=\"xZFdkq\"\n description=\"Description for setting up multi-factor authentication\"\n />\n </Text>\n )}\n </Flex>\n\n {settings.isSetUp ? (\n <ResetMfaDialog isPasswordSet={isPasswordSet}>\n <Button variant=\"secondary\">\n <Translation\n defaultMessage=\"Disable\"\n id=\"4flMgv\"\n description=\"Button label to disable multi-factor authentication\"\n />\n </Button>\n </ResetMfaDialog>\n ) : (\n <AddMfaDialog>\n <Button variant=\"secondary\">\n <Translation\n defaultMessage=\"Set up authenticator app\"\n id=\"oLNIQv\"\n description=\"Button label to set up multi-factor authentication with an authenticator app\"\n />\n </Button>\n </AddMfaDialog>\n )}\n </Grid>\n );\n}\n\nfunction getWidgetRootDomProps(\n state: WidgetRootState,\n domProps: WidgetRootDomProps,\n) {\n return getDomProps({\n ...domProps,\n isWidgetRoot: true,\n widgetId: \"user-security\",\n widgetState: state,\n });\n}\n\nexport type {\n UserSecurityProps,\n UserSecurityLoadingProps,\n UserSecurityErrorProps,\n};\nexport { UserSecurity, UserSecurityLoading, UserSecurityError };\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../../src/lib/user-security.tsx"],"sourcesContent":["\"use client\";\n\nimport { Card, Flex, Grid, Text } from \"@radix-ui/themes\";\nimport { Button, Skeleton } from \"./elements.js\";\nimport { IconPanel } from \"./icon-panel.js\";\nimport { ButtonIcon, LockClosedIcon } from \"@radix-ui/react-icons\";\nimport { SetPasswordDialog } from \"./set-password-dialog.js\";\nimport { ChangePasswordDialog } from \"./change-password-dialog.js\";\nimport { AddMfaDialog } from \"./add-mfa-dialog.js\";\nimport type {\n AuthenticationSettingsQuery,\n UserFieldsFragment,\n} from \"../api/client-graphql/generated.js\";\nimport { ResetMfaDialog } from \"./reset-mfa-dialog.js\";\nimport * as CardList from \"./card-list.js\";\nimport { GenericError } from \"./generic-error.js\";\nimport {\n getDomProps,\n type WidgetRootDomProps,\n type WidgetRootState,\n} from \"./utils.js\";\nimport { Translation } from \"./i18n/translation.js\";\nimport { useComparativeReadableDate } from \"../use-comparative-readable-date.js\";\n\ntype AuthenticationSettings =\n AuthenticationSettingsQuery[\"authenticationSettings\"];\n\ninterface VerificationMethod {\n isSetUp: boolean;\n lastUsed?: string | null;\n}\n\ninterface UserSecurityProps extends WidgetRootDomProps {\n user: UserFieldsFragment;\n settings: AuthenticationSettings;\n}\n\nconst UserSecurity: React.FC<UserSecurityProps> = ({\n user,\n settings,\n ...domProps\n}) => {\n const passwordSettings: VerificationMethod | null =\n settings.passwordAuthEnabled\n ? { isSetUp: user.passwordSet, lastUsed: user.passwordLastUsedAt }\n : null;\n const mfaSettings: VerificationMethod | null = settings.mfaEnabled\n ? { isSetUp: user.mfaEnabled, lastUsed: user.mfaLastUsedAt }\n : null;\n return (\n <CardList.Root {...getWidgetRootDomProps(\"resolved\", domProps)}>\n {passwordSettings && (\n <CardList.Item>\n <PasswordSettings settings={passwordSettings} />\n </CardList.Item>\n )}\n {mfaSettings && (\n <CardList.Item>\n <MfaSettings\n settings={mfaSettings}\n isPasswordSet={!!passwordSettings?.isSetUp}\n />\n </CardList.Item>\n )}\n </CardList.Root>\n );\n};\n\ninterface UserSecurityErrorProps extends WidgetRootDomProps {\n error: unknown;\n}\n\nconst UserSecurityError: React.FC<UserSecurityErrorProps> = ({\n error,\n ...domProps\n}) => {\n return (\n <Card size=\"2\" {...getWidgetRootDomProps(\"error\", domProps)}>\n <GenericError error={error} />\n </Card>\n );\n};\n\ninterface UserSecurityLoadingProps extends WidgetRootDomProps {}\n\nconst UserSecurityLoading: React.FC<UserSecurityLoadingProps> = (props) => {\n return (\n <Card size=\"2\" {...getWidgetRootDomProps(\"loading\", props)}>\n <Grid columns=\"auto 1fr auto\" align=\"center\" gap=\"4\">\n <Skeleton>\n <IconPanel />\n </Skeleton>\n\n <Flex direction=\"column\">\n <Text size=\"2\" highContrast weight=\"bold\" as=\"p\" mb=\"-2px\">\n <Skeleton>\n <Translation\n defaultMessage=\"Password\"\n id=\"z19aZa\"\n description=\"Label for password security settings section\"\n />\n </Skeleton>\n </Text>\n <Text as=\"p\" size=\"2\" color=\"gray\">\n <Skeleton>\n <Translation\n defaultMessage=\"Set a password to access your account\"\n id=\"leodiT\"\n description=\"Description for setting up a password\"\n />\n </Skeleton>\n </Text>\n </Flex>\n\n <ChangePasswordDialog>\n <Skeleton>\n <Button variant=\"secondary\">\n <Translation\n defaultMessage=\"Change\"\n id=\"/ZV6cj\"\n description=\"Button label to change password\"\n />\n </Button>\n </Skeleton>\n </ChangePasswordDialog>\n </Grid>\n </Card>\n );\n};\n\nfunction PasswordSettings({ settings }: { settings: VerificationMethod }) {\n const timeAgo = useComparativeReadableDate({\n date: settings.lastUsed ? new Date(settings.lastUsed) : null,\n });\n\n return (\n <Grid columns=\"auto 1fr auto\" align=\"center\" gap=\"4\">\n <IconPanel>\n <LockClosedIcon />\n </IconPanel>\n\n <Flex direction=\"column\">\n <Text size=\"2\" highContrast weight=\"bold\" as=\"p\" mb=\"-2px\">\n <Translation\n defaultMessage=\"Password\"\n id=\"z19aZa\"\n description=\"Label for password security settings section\"\n />\n </Text>\n\n {settings.isSetUp ? (\n settings.lastUsed && (\n <Text size=\"2\" color=\"gray\">\n <Translation\n defaultMessage=\"Last used {time}\"\n id=\"Jqn+r+\"\n description=\"Label indicating when password was last used with time\"\n values={{ time: timeAgo }}\n />\n </Text>\n )\n ) : (\n <Text as=\"p\" size=\"2\" color=\"gray\">\n <Translation\n defaultMessage=\"Set a password to access your account\"\n id=\"leodiT\"\n description=\"Description for setting up a password\"\n />\n </Text>\n )}\n </Flex>\n\n {settings.isSetUp ? (\n <ChangePasswordDialog>\n <Button variant=\"secondary\">\n <Translation\n defaultMessage=\"Change\"\n id=\"/ZV6cj\"\n description=\"Button label to change password\"\n />\n </Button>\n </ChangePasswordDialog>\n ) : (\n <SetPasswordDialog>\n <Button variant=\"secondary\">\n <Translation\n defaultMessage=\"Set a password\"\n id=\"zokPvK\"\n description=\"Button label to set a new password\"\n />\n </Button>\n </SetPasswordDialog>\n )}\n </Grid>\n );\n}\n\nfunction MfaSettings({\n settings,\n isPasswordSet,\n}: {\n settings: VerificationMethod;\n isPasswordSet: boolean;\n}) {\n const timeAgo = useComparativeReadableDate({\n date: settings.lastUsed ? new Date(settings.lastUsed) : null,\n });\n\n return (\n <Grid columns=\"auto 1fr auto\" align=\"center\" gap=\"4\">\n <IconPanel>\n <ButtonIcon />\n </IconPanel>\n\n <Flex direction=\"column\">\n <Text size=\"2\" highContrast weight=\"bold\" as=\"p\" mb=\"-2px\">\n <Translation\n defaultMessage=\"Multi-factor authentication\"\n id=\"f3uhhm\"\n description=\"Label for multi-factor authentication settings section\"\n />\n </Text>\n\n {settings.isSetUp ? (\n <Text size=\"2\">\n <Translation\n defaultMessage=\"Authenticator app\"\n id=\"0p/a72\"\n description=\"Label indicating MFA is set up with an authenticator app\"\n />\n {settings.lastUsed && (\n <>\n {/* eslint-disable-next-line formatjs/no-literal-string-in-jsx */}\n <Text size=\"2\" color=\"gray\" mx=\"1\">\n ∙\n </Text>\n <Text size=\"2\" color=\"gray\">\n <Translation\n defaultMessage=\"Last used {time}\"\n id=\"h3R6gY\"\n description=\"Label indicating when MFA was last used with time\"\n values={{ time: timeAgo }}\n />\n </Text>\n </>\n )}\n </Text>\n ) : (\n <Text as=\"p\" size=\"2\" color=\"gray\">\n <Translation\n defaultMessage=\"Secure your account with an extra verification step\"\n id=\"xZFdkq\"\n description=\"Description for setting up multi-factor authentication\"\n />\n </Text>\n )}\n </Flex>\n\n {settings.isSetUp ? (\n <ResetMfaDialog isPasswordSet={isPasswordSet}>\n <Button variant=\"secondary\">\n <Translation\n defaultMessage=\"Disable\"\n id=\"4flMgv\"\n description=\"Button label to disable multi-factor authentication\"\n />\n </Button>\n </ResetMfaDialog>\n ) : (\n <AddMfaDialog>\n <Button variant=\"secondary\">\n <Translation\n defaultMessage=\"Set up authenticator app\"\n id=\"oLNIQv\"\n description=\"Button label to set up multi-factor authentication with an authenticator app\"\n />\n </Button>\n </AddMfaDialog>\n )}\n </Grid>\n );\n}\n\nfunction getWidgetRootDomProps(\n state: WidgetRootState,\n domProps: WidgetRootDomProps,\n) {\n return getDomProps({\n ...domProps,\n isWidgetRoot: true,\n widgetId: \"user-security\",\n widgetState: state,\n });\n}\n\nexport type {\n UserSecurityProps,\n UserSecurityLoadingProps,\n UserSecurityErrorProps,\n};\nexport { UserSecurity, UserSecurityLoading, UserSecurityError };\n"],"mappings":"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","names":[]}
@@ -42,11 +42,11 @@ var import_logout_dialog = require("./logout-dialog.js");
42
42
  var import_logout_all_sessions_dialog = require("./logout-all-sessions-dialog.js");
43
43
  var CardList = __toESM(require("./card-list.js"), 1);
44
44
  var import_icon_panel = require("./icon-panel.js");
45
- var import_react = require("react");
45
+ var React = __toESM(require("react"), 1);
46
46
  var import_generic_error = require("./generic-error.js");
47
47
  var import_react_icons = require("@radix-ui/react-icons");
48
48
  var import_translation = require("./i18n/translation.js");
49
- var import_use_locale = require("./i18n/use-locale.js");
49
+ var import_use_comparative_readable_date = require("../use-comparative-readable-date.js");
50
50
  const UserSessions = ({
51
51
  sessionsData: sessions,
52
52
  currentSessionId,
@@ -58,9 +58,9 @@ const UserSessions = ({
58
58
  const otherSessions = sessions.filter(
59
59
  (session) => session.id !== currentSessionId
60
60
  );
61
- const [openLogoutDialog, setOpenLogoutDialog] = (0, import_react.useState)(false);
62
- const [sessionToSignOut, setSessionToSignOut] = (0, import_react.useState)(null);
63
- const [openLogoutAllSessionsDialog, setOpenLogoutAllSessionsDialog] = (0, import_react.useState)(false);
61
+ const [openLogoutDialog, setOpenLogoutDialog] = React.useState(false);
62
+ const [sessionToSignOut, setSessionToSignOut] = React.useState(null);
63
+ const [openLogoutAllSessionsDialog, setOpenLogoutAllSessionsDialog] = React.useState(false);
64
64
  return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
65
65
  import_themes.Flex,
66
66
  {
@@ -177,7 +177,9 @@ const UserSession = ({
177
177
  session.currentLocation,
178
178
  session.ipAddress
179
179
  );
180
- const locale = (0, import_use_locale.useLocale)();
180
+ const timeAgo = (0, import_use_comparative_readable_date.useComparativeReadableDate)({
181
+ date: session.lastActivityAt ? new Date(session.lastActivityAt) : null
182
+ });
181
183
  return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_themes.Flex, { gap: "4", align: "center", children: [
182
184
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_icon_panel.IconPanel, { children: userAgent?.isMobile ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_icons.MobileIcon, {}) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_icons.LaptopIcon, {}) }),
183
185
  /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_themes.Flex, { direction: "column", children: [
@@ -207,13 +209,7 @@ const UserSession = ({
207
209
  defaultMessage: "Last seen {timeAgo}",
208
210
  id: "gF+kUw",
209
211
  description: "Text showing when the session was last active",
210
- values: {
211
- timeAgo: (0, import_utils.getComparativeReadableDate)(
212
- /* @__PURE__ */ new Date(),
213
- new Date(session.lastActivityAt),
214
- { locale }
215
- )
216
- }
212
+ values: { timeAgo }
217
213
  }
218
214
  ) })
219
215
  ] })