@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/admin-portal-sso-connection.tsx"],"sourcesContent":["\"use client\";\n\nimport * as React from \"react\";\nimport { Box, Card, Flex, Text } from \"@radix-ui/themes\";\nimport { Button, 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 {\n getDomProps,\n unreachable,\n type WidgetRootState,\n type WidgetRootDomProps,\n} from \"./utils.js\";\nimport { Translation } from \"./i18n/translation.js\";\nimport { useTranslation } from \"./i18n/use-translation.js\";\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\ntype AdminPortalSsoConnectionProps = WidgetRootDomProps &\n AdminPortalSsoConnectionStatusProps & {\n currentDate: Date | null;\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\nconst AdminPortalSsoConnection: React.FC<AdminPortalSsoConnectionProps> = ({\n currentDate,\n connectionStatus,\n identityProvider,\n expiryDate,\n lastSession,\n adminPortalOpenButton,\n ...domProps\n}) => {\n return (\n <CardList.Root size=\"2\" {...getWidgetRootDomProps(\"resolved\", domProps)}>\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\">\n <Translation\n defaultMessage=\"You haven't set up Single Sign-On yet.\"\n id=\"KDs1Ib\"\n description=\"Empty state message when SSO is not configured\"\n />\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 (\n <Translation\n defaultMessage=\"The SAML response signing certificate has expired. Users won't be able to sign-in to the application until the certificate is renewed.\"\n id=\"5tX19v\"\n description=\"Error message when SAML certificate has expired (no date)\"\n />\n );\n }\n\n return (\n <Translation\n defaultMessage=\"The SAML response signing certificate expired on {expiryDate}. Users won't be able to sign-in to the application until the certificate is renewed.\"\n id=\"vmTW/h\"\n description=\"Error message when SAML certificate has expired with date\"\n values={{\n expiryDate: (\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 );\n })()}\n </Text>\n );\n }\n\n if (connectionStatus === \"Expiring\") {\n return (\n <Text size=\"2\" color=\"gray\">\n {(() => {\n if (!expiryDate) {\n return (\n <Translation\n defaultMessage=\"The SAML response signing certificate is expiring soon. When expired, users won't be able to sign-in.\"\n id=\"3dgA5f\"\n description=\"Warning message when SAML certificate is expiring soon (no date)\"\n />\n );\n }\n\n return (\n <Translation\n defaultMessage=\"The SAML response signing certificate will expire on {expiryDate}. When expired, users won't be able to sign-in.\"\n id=\"xT9Exy\"\n description=\"Warning message when SAML certificate is expiring with date\"\n values={{\n expiryDate: (\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 );\n })()}\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 (\n <Status state=\"waiting\">\n <Translation\n defaultMessage=\"Setup in progress\"\n id=\"MQR5mR\"\n description=\"Status label when SSO setup is incomplete\"\n />\n </Status>\n );\n }\n\n if (status === \"Expired\") {\n return (\n <Status state=\"error\">\n <Translation\n defaultMessage=\"Requires action\"\n id=\"Yo2vHC\"\n description=\"Status label when SSO requires attention\"\n />\n </Status>\n );\n }\n\n if (status === \"Active\" || status === \"Expiring\") {\n return (\n <Status state=\"success\">\n <Translation\n defaultMessage=\"Connected\"\n id=\"8S+Cyw\"\n description=\"Status label when SSO is active\"\n />\n </Status>\n );\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 <Translation\n defaultMessage=\"Last session {relativeTime}\"\n id=\"yN72Gc\"\n description=\"Label showing when the last SSO session occurred\"\n values={{ relativeTime: relativeTimeString }}\n />\n </Text>\n ) : null}\n </Flex>\n ) : (\n <Text size=\"2\" weight=\"bold\">\n {getIdentityProviderName(identityProvider)}\n </Text>\n )}\n </Flex>\n );\n}\n\nfunction AdminPortalOpenButton({\n isPending,\n initConfig,\n}: {\n isPending: boolean;\n initConfig: () => void;\n}) {\n const { connectionStatus } = useAdminPortalSsoConnectionContext();\n const label = (() => {\n switch (connectionStatus) {\n case \"NotConfigured\":\n return (\n <Translation\n defaultMessage=\"Set up SSO\"\n id=\"MtkNQO\"\n description=\"Button label to start SSO setup\"\n />\n );\n case \"Inactive\":\n return (\n <Translation\n defaultMessage=\"Continue setup\"\n id=\"HFxrbY\"\n description=\"Button label to continue incomplete SSO setup\"\n />\n );\n case \"Active\":\n case \"Expiring\":\n case \"Expired\":\n return (\n <Translation\n defaultMessage=\"Manage\"\n id=\"T1VKzP\"\n description=\"Button label to manage SSO settings\"\n />\n );\n default:\n return unreachable(connectionStatus);\n }\n })();\n\n return (\n <Button\n variant=\"secondary\"\n loading={isPending}\n disabled={isPending}\n onClick={initConfig}\n >\n {label} <ExternalLinkIcon aria-hidden />\n </Button>\n );\n}\n\ninterface AdminPortalSsoConnectionLoadingProps extends WidgetRootDomProps {}\n\nconst AdminPortalSsoConnectionLoading: React.FC<\n AdminPortalSsoConnectionLoadingProps\n> = (props) => {\n return (\n <Card size=\"2\" {...getWidgetRootDomProps(\"loading\", props)}>\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 {/* eslint-disable-next-line formatjs/no-literal-string-in-jsx */}\n <Text size=\"1\">Okta</Text>\n </Skeleton>\n <Skeleton>\n {/* eslint-disable-next-line formatjs/no-literal-string-in-jsx */}\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 {/* eslint-disable-next-line formatjs/no-literal-string-in-jsx */}\n <Status state=\"error\">Requires action</Status>\n </Skeleton>\n <Skeleton>\n {/* eslint-disable-next-line formatjs/no-literal-string-in-jsx */}\n <Button variant=\"secondary\">\n Manage <ExternalLinkIcon aria-hidden />\n </Button>\n </Skeleton>\n </Flex>\n </Flex>\n </Card>\n );\n};\n\ninterface AdminPortalSsoConnectionErrorProps extends WidgetRootDomProps {\n error: unknown;\n}\n\nconst AdminPortalSsoConnectionError: React.FC<\n AdminPortalSsoConnectionErrorProps\n> = ({ error, ...domProps }) => {\n const translate = useTranslation();\n React.useEffect(() => {\n console.error(error);\n }, [error]);\n\n const { heading, message } = getErrorMessage(error, translate);\n\n return (\n <Card size=\"2\" {...getWidgetRootDomProps(\"error\", domProps)}>\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\nfunction getWidgetRootDomProps(\n state: WidgetRootState,\n domProps: WidgetRootDomProps,\n) {\n return getDomProps({\n ...domProps,\n isWidgetRoot: true,\n widgetId: \"admin-portal-sso-connection\",\n widgetState: state,\n });\n}\n\nexport type {\n AdminPortalSsoConnectionProps,\n AdminPortalSsoConnectionLoadingProps,\n AdminPortalSsoConnectionErrorProps,\n};\nexport {\n AdminPortalSsoConnection,\n AdminPortalSsoConnectionLoading,\n AdminPortalSsoConnectionError,\n /** @internal */\n AdminPortalOpenButton,\n};\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../../src/lib/admin-portal-sso-connection.tsx"],"sourcesContent":["\"use client\";\n\nimport * as React from \"react\";\nimport { Box, Card, Flex, Text } from \"@radix-ui/themes\";\nimport { Button, 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 {\n getDomProps,\n unreachable,\n type WidgetRootState,\n type WidgetRootDomProps,\n} from \"./utils.js\";\nimport { Translation } from \"./i18n/translation.js\";\nimport { useTranslation } from \"./i18n/use-translation.js\";\nimport { getErrorMessage } from \"./generic-error.js\";\nimport { useComparativeReadableDate } from \"../use-comparative-readable-date.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\ntype AdminPortalSsoConnectionProps = WidgetRootDomProps &\n AdminPortalSsoConnectionStatusProps & {\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\nconst AdminPortalSsoConnection: React.FC<AdminPortalSsoConnectionProps> = ({\n connectionStatus,\n identityProvider,\n expiryDate,\n lastSession,\n adminPortalOpenButton,\n ...domProps\n}) => {\n return (\n <CardList.Root size=\"2\" {...getWidgetRootDomProps(\"resolved\", domProps)}>\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\">\n <Translation\n defaultMessage=\"You haven't set up Single Sign-On yet.\"\n id=\"KDs1Ib\"\n description=\"Empty state message when SSO is not configured\"\n />\n </Text>\n {adminPortalOpenButton}\n </>\n );\n }\n\n return (\n <>\n <SessionInfo\n connectionStatus={connectionStatus}\n identityProvider={identityProvider}\n lastSession={lastSession}\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 (\n <Translation\n defaultMessage=\"The SAML response signing certificate has expired. Users won't be able to sign-in to the application until the certificate is renewed.\"\n id=\"5tX19v\"\n description=\"Error message when SAML certificate has expired (no date)\"\n />\n );\n }\n\n return (\n <Translation\n defaultMessage=\"The SAML response signing certificate expired on {expiryDate}. Users won't be able to sign-in to the application until the certificate is renewed.\"\n id=\"vmTW/h\"\n description=\"Error message when SAML certificate has expired with date\"\n values={{\n expiryDate: (\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 );\n })()}\n </Text>\n );\n }\n\n if (connectionStatus === \"Expiring\") {\n return (\n <Text size=\"2\" color=\"gray\">\n {(() => {\n if (!expiryDate) {\n return (\n <Translation\n defaultMessage=\"The SAML response signing certificate is expiring soon. When expired, users won't be able to sign-in.\"\n id=\"3dgA5f\"\n description=\"Warning message when SAML certificate is expiring soon (no date)\"\n />\n );\n }\n\n return (\n <Translation\n defaultMessage=\"The SAML response signing certificate will expire on {expiryDate}. When expired, users won't be able to sign-in.\"\n id=\"xT9Exy\"\n description=\"Warning message when SAML certificate is expiring with date\"\n values={{\n expiryDate: (\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 );\n })()}\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 (\n <Status state=\"waiting\">\n <Translation\n defaultMessage=\"Setup in progress\"\n id=\"MQR5mR\"\n description=\"Status label when SSO setup is incomplete\"\n />\n </Status>\n );\n }\n\n if (status === \"Expired\") {\n return (\n <Status state=\"error\">\n <Translation\n defaultMessage=\"Requires action\"\n id=\"Yo2vHC\"\n description=\"Status label when SSO requires attention\"\n />\n </Status>\n );\n }\n\n if (status === \"Active\" || status === \"Expiring\") {\n return (\n <Status state=\"success\">\n <Translation\n defaultMessage=\"Connected\"\n id=\"8S+Cyw\"\n description=\"Status label when SSO is active\"\n />\n </Status>\n );\n }\n\n return unreachable(status);\n}\n\nfunction SessionInfo({\n identityProvider,\n lastSession,\n connectionStatus,\n}: {\n identityProvider: IdentityProvider;\n lastSession: Date | null;\n connectionStatus: AdminPortalSsoConnectionStatusProps[\"connectionStatus\"];\n}) {\n const relativeTime = useComparativeReadableDate({\n date:\n connectionStatus === \"NotConfigured\" || connectionStatus === \"Inactive\"\n ? null\n : lastSession,\n });\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 {relativeTime ? (\n <Text color=\"gray\" size=\"2\">\n <Translation\n defaultMessage=\"Last session {relativeTime}\"\n id=\"yN72Gc\"\n description=\"Label showing when the last SSO session occurred\"\n values={{ relativeTime }}\n />\n </Text>\n ) : null}\n </Flex>\n ) : (\n <Text size=\"2\" weight=\"bold\">\n {getIdentityProviderName(identityProvider)}\n </Text>\n )}\n </Flex>\n );\n}\n\nfunction AdminPortalOpenButton({\n isPending,\n initConfig,\n}: {\n isPending: boolean;\n initConfig: () => void;\n}) {\n const { connectionStatus } = useAdminPortalSsoConnectionContext();\n const label = (() => {\n switch (connectionStatus) {\n case \"NotConfigured\":\n return (\n <Translation\n defaultMessage=\"Set up SSO\"\n id=\"MtkNQO\"\n description=\"Button label to start SSO setup\"\n />\n );\n case \"Inactive\":\n return (\n <Translation\n defaultMessage=\"Continue setup\"\n id=\"HFxrbY\"\n description=\"Button label to continue incomplete SSO setup\"\n />\n );\n case \"Active\":\n case \"Expiring\":\n case \"Expired\":\n return (\n <Translation\n defaultMessage=\"Manage\"\n id=\"T1VKzP\"\n description=\"Button label to manage SSO settings\"\n />\n );\n default:\n return unreachable(connectionStatus);\n }\n })();\n\n return (\n <Button\n variant=\"secondary\"\n loading={isPending}\n disabled={isPending}\n onClick={initConfig}\n >\n {label} <ExternalLinkIcon aria-hidden />\n </Button>\n );\n}\n\ninterface AdminPortalSsoConnectionLoadingProps extends WidgetRootDomProps {}\n\nconst AdminPortalSsoConnectionLoading: React.FC<\n AdminPortalSsoConnectionLoadingProps\n> = (props) => {\n return (\n <Card size=\"2\" {...getWidgetRootDomProps(\"loading\", props)}>\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 {/* eslint-disable-next-line formatjs/no-literal-string-in-jsx */}\n <Text size=\"1\">Okta</Text>\n </Skeleton>\n <Skeleton>\n {/* eslint-disable-next-line formatjs/no-literal-string-in-jsx */}\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 {/* eslint-disable-next-line formatjs/no-literal-string-in-jsx */}\n <Status state=\"error\">Requires action</Status>\n </Skeleton>\n <Skeleton>\n {/* eslint-disable-next-line formatjs/no-literal-string-in-jsx */}\n <Button variant=\"secondary\">\n Manage <ExternalLinkIcon aria-hidden />\n </Button>\n </Skeleton>\n </Flex>\n </Flex>\n </Card>\n );\n};\n\ninterface AdminPortalSsoConnectionErrorProps extends WidgetRootDomProps {\n error: unknown;\n}\n\nconst AdminPortalSsoConnectionError: React.FC<\n AdminPortalSsoConnectionErrorProps\n> = ({ error, ...domProps }) => {\n const translate = useTranslation();\n React.useEffect(() => {\n console.error(error);\n }, [error]);\n\n const { heading, message } = getErrorMessage(error, translate);\n\n return (\n <Card size=\"2\" {...getWidgetRootDomProps(\"error\", domProps)}>\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 getWidgetRootDomProps(\n state: WidgetRootState,\n domProps: WidgetRootDomProps,\n) {\n return getDomProps({\n ...domProps,\n isWidgetRoot: true,\n widgetId: \"admin-portal-sso-connection\",\n widgetState: state,\n });\n}\n\nexport type {\n AdminPortalSsoConnectionProps,\n AdminPortalSsoConnectionLoadingProps,\n AdminPortalSsoConnectionErrorProps,\n};\nexport {\n AdminPortalSsoConnection,\n AdminPortalSsoConnectionLoading,\n AdminPortalSsoConnectionError,\n /** @internal */\n AdminPortalOpenButton,\n};\n"],"mappings":"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","names":[]}
@@ -36,7 +36,6 @@ interface RequiresActionProps {
36
36
  }
37
37
  type AdminPortalSsoConnectionStatusProps = NotConfiguredProps | InactiveProps | ActiveProps | RequiresActionProps;
38
38
  type AdminPortalSsoConnectionProps = WidgetRootDomProps & AdminPortalSsoConnectionStatusProps & {
39
- currentDate: Date | null;
40
39
  lastSession: Date | null;
41
40
  adminPortalOpenButton: React.ReactNode;
42
41
  };
@@ -51,8 +51,7 @@ const EXPIRATION_OPTIONS = [
51
51
  "3_days",
52
52
  "7_days"
53
53
  ];
54
- function getApiKeyExpiresAt(value) {
55
- const now = /* @__PURE__ */ new Date();
54
+ function getApiKeyExpiresAt(now, value) {
56
55
  switch (value) {
57
56
  case "never":
58
57
  return null;
@@ -253,7 +252,10 @@ function EditApiKeyExpirationDialogContent({
253
252
  disabled: !canSave,
254
253
  loading: isPending || isSuccess,
255
254
  onClick: () => {
256
- const nextExpiresAt = getApiKeyExpiresAt(selectedExpiration);
255
+ const nextExpiresAt = getApiKeyExpiresAt(
256
+ /* @__PURE__ */ new Date(),
257
+ selectedExpiration
258
+ );
257
259
  if (nextExpiresAt !== void 0 && selectedExpiration !== "current") {
258
260
  onSave(nextExpiresAt);
259
261
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../src/lib/api-keys/api-key-expiration.tsx"],"sourcesContent":["import { Callout, Flex } from \"@radix-ui/themes\";\nimport { ExclamationTriangleIcon } from \"@radix-ui/react-icons\";\nimport * as React from \"react\";\nimport { Button, Dialog, Label, Select } from \"../elements.js\";\nimport { Translation } from \"../i18n/translation.js\";\nimport { useLocale } from \"../i18n/use-locale.js\";\nimport { useIsHydrated } from \"../use-is-hydrated.js\";\n\nexport type ApiKeyExpirationOption =\n | \"never\"\n | \"1_hour\"\n | \"24_hours\"\n | \"3_days\"\n | \"7_days\"\n | \"current\";\n\nexport type ApiKeyExpirationPreset = Exclude<ApiKeyExpirationOption, \"current\">;\n\nconst EXPIRATION_OPTIONS = [\n \"never\",\n \"1_hour\",\n \"24_hours\",\n \"3_days\",\n \"7_days\",\n] satisfies ApiKeyExpirationPreset[];\n\nexport function getApiKeyExpiresAt(\n value: ApiKeyExpirationOption,\n): string | null | undefined {\n const now = new Date();\n\n switch (value) {\n case \"never\":\n return null;\n case \"1_hour\":\n return new Date(now.getTime() + 60 * 60 * 1000).toISOString();\n case \"24_hours\":\n return new Date(now.getTime() + 24 * 60 * 60 * 1000).toISOString();\n case \"3_days\":\n return new Date(now.getTime() + 3 * 24 * 60 * 60 * 1000).toISOString();\n case \"7_days\":\n return new Date(now.getTime() + 7 * 24 * 60 * 60 * 1000).toISOString();\n case \"current\":\n return undefined;\n }\n}\n\nexport function getApiKeyExpirationSelectValue(\n expiresAt?: string | null,\n): ApiKeyExpirationOption {\n if (!expiresAt) {\n return \"never\";\n }\n\n return \"current\";\n}\n\nexport function ApiKeyExpirationSelectField({\n defaultValue = \"never\",\n value,\n onValueChange,\n currentExpiresAt,\n}: {\n defaultValue?: ApiKeyExpirationOption;\n value?: ApiKeyExpirationOption;\n onValueChange?: (value: ApiKeyExpirationOption) => void;\n currentExpiresAt?: string | null;\n}) {\n return (\n <Flex direction=\"column\" align=\"stretch\" gap=\"2\">\n <Label>\n <Translation\n defaultMessage=\"Expiration\"\n id=\"pwfOwu\"\n description=\"Label for API key expiration field\"\n />\n </Label>\n <Select.Root\n name=\"expiration\"\n defaultValue={defaultValue}\n value={value}\n onValueChange={(nextValue) =>\n onValueChange?.(nextValue as ApiKeyExpirationOption)\n }\n >\n <Select.Trigger />\n <Select.Content>\n {currentExpiresAt ? (\n <Select.Item value=\"current\">\n <Translation\n defaultMessage=\"Current Expiration - {expiresAt}\"\n id=\"9HtsNU\"\n description=\"Option label for the current API key expiration\"\n values={{\n expiresAt: (\n <ApiKeyExpiresOn expiresAt={currentExpiresAt} includeTime />\n ),\n }}\n />\n </Select.Item>\n ) : null}\n {EXPIRATION_OPTIONS.map((option) => (\n <Select.Item key={option} value={option}>\n <ExpirationOptionLabel option={option} />\n </Select.Item>\n ))}\n </Select.Content>\n </Select.Root>\n </Flex>\n );\n}\n\nexport function ApiKeyExpiresOn({\n expiresAt,\n includeTime = false,\n}: {\n expiresAt?: string | null;\n includeTime?: boolean;\n}) {\n const isHydrated = useIsHydrated();\n const locale = useLocale();\n\n if (!expiresAt) {\n return <NeverApiKeyExpirationLabel />;\n }\n\n const expiresOn = new Date(expiresAt);\n const options = {\n timeZone: isHydrated ? undefined : \"UTC\",\n month: \"short\",\n day: \"numeric\",\n year: \"numeric\",\n ...(includeTime ? { hour: \"numeric\", minute: \"2-digit\" } : {}),\n } satisfies Intl.DateTimeFormatOptions;\n\n return (\n <>\n {includeTime\n ? expiresOn.toLocaleString(locale, options)\n : expiresOn.toLocaleDateString(locale, options)}\n </>\n );\n}\n\nexport function ApiKeyTimestamp({ timestamp }: { timestamp: string }) {\n const isHydrated = useIsHydrated();\n const locale = useLocale();\n const date = new Date(timestamp);\n\n return (\n <>\n {date.toLocaleString(locale, {\n timeZone: isHydrated ? undefined : \"UTC\",\n month: \"short\",\n day: \"numeric\",\n year: \"numeric\",\n hour: \"numeric\",\n minute: \"2-digit\",\n })}\n </>\n );\n}\n\nexport function EditApiKeyExpirationDialog({\n apiKeyName,\n expiresAt,\n error,\n isPending,\n isSuccess,\n open,\n onOpenChange,\n onReset,\n onSave,\n}: {\n apiKeyName: string;\n expiresAt?: string | null;\n error: unknown;\n isPending: boolean;\n isSuccess: boolean;\n open: boolean;\n onOpenChange: (open: boolean) => void;\n onReset: () => void;\n onSave: (expiresAt: string | null) => void;\n}) {\n return (\n <Dialog.Root open={open} onOpenChange={onOpenChange}>\n {open ? (\n <EditApiKeyExpirationDialogContent\n apiKeyName={apiKeyName}\n expiresAt={expiresAt}\n error={error}\n isPending={isPending}\n isSuccess={isSuccess}\n onReset={onReset}\n onSave={onSave}\n />\n ) : null}\n </Dialog.Root>\n );\n}\n\nfunction EditApiKeyExpirationDialogContent({\n apiKeyName,\n expiresAt,\n error,\n isPending,\n isSuccess,\n onReset,\n onSave,\n}: {\n apiKeyName: string;\n expiresAt?: string | null;\n error: unknown;\n isPending: boolean;\n isSuccess: boolean;\n onReset: () => void;\n onSave: (expiresAt: string | null) => void;\n}) {\n const selectedInitialValue = getApiKeyExpirationSelectValue(expiresAt);\n const [selectedExpiration, setSelectedExpiration] =\n React.useState<ApiKeyExpirationOption>(selectedInitialValue);\n\n const isCurrentExpiration = selectedExpiration === \"current\";\n const isUnchanged = selectedExpiration === selectedInitialValue;\n const canSave =\n !isCurrentExpiration && !isUnchanged && !isPending && !isSuccess;\n\n return (\n <Dialog.Content maxWidth=\"529px\">\n <Dialog.Title>\n <Translation\n defaultMessage=\"Edit secret key expiration\"\n id=\"pIxXuW\"\n description=\"Dialog title for editing API key expiration\"\n />\n </Dialog.Title>\n <Dialog.Description>\n {isCurrentExpiration ? (\n <Translation\n defaultMessage=\"Confirm API key expiration. Once this key expires, you can no longer use it.\"\n id=\"48Q0bX\"\n description=\"Description for confirming the current API key expiration\"\n />\n ) : (\n <Translation\n defaultMessage=\"Set API Key expiration for {name}. Once this key expires, you can no longer use it.\"\n id=\"aLj8zz\"\n description=\"Description for setting API key expiration\"\n values={{ name: apiKeyName }}\n />\n )}\n </Dialog.Description>\n <Flex direction=\"column\" align=\"stretch\" gap=\"4\" mt=\"5\">\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 updating the API key expiration.\"\n id=\"ge66Rv\"\n description=\"Error message when API key expiration update fails\"\n />\n </Callout.Text>\n </Callout.Root>\n ) : null}\n <ApiKeyExpirationSelectField\n currentExpiresAt={expiresAt}\n value={selectedExpiration}\n onValueChange={(nextExpiration) => {\n if (!isPending) {\n onReset();\n }\n setSelectedExpiration(nextExpiration);\n }}\n />\n </Flex>\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=\"I9XnRG\"\n description=\"Button to cancel API key expiration editing\"\n />\n </Button>\n </Dialog.Close>\n <Button\n disabled={!canSave}\n loading={isPending || isSuccess}\n onClick={() => {\n const nextExpiresAt = getApiKeyExpiresAt(selectedExpiration);\n if (\n nextExpiresAt !== undefined &&\n selectedExpiration !== \"current\"\n ) {\n onSave(nextExpiresAt);\n }\n }}\n >\n <Translation\n defaultMessage=\"Save changes\"\n id=\"ThFw5g\"\n description=\"Button to save API key expiration changes\"\n />\n </Button>\n </Flex>\n </Dialog.Content>\n );\n}\n\nfunction ExpirationOptionLabel({\n option,\n}: {\n option: Exclude<ApiKeyExpirationOption, \"current\">;\n}) {\n switch (option) {\n case \"never\":\n return <NeverApiKeyExpirationLabel />;\n case \"1_hour\":\n return (\n <Translation\n defaultMessage=\"in 1 hour\"\n id=\"+GR+6F\"\n description=\"Option to expire an API key in one hour\"\n />\n );\n case \"24_hours\":\n return (\n <Translation\n defaultMessage=\"in 24 hours\"\n id=\"UPQwj+\"\n description=\"Option to expire an API key in twenty-four hours\"\n />\n );\n case \"3_days\":\n return (\n <Translation\n defaultMessage=\"in 3 days\"\n id=\"elvZ6g\"\n description=\"Option to expire an API key in three days\"\n />\n );\n case \"7_days\":\n return (\n <Translation\n defaultMessage=\"in 7 days\"\n id=\"Dzu4Fy\"\n description=\"Option to expire an API key in seven days\"\n />\n );\n }\n}\n\nfunction NeverApiKeyExpirationLabel() {\n return (\n <Translation\n defaultMessage=\"Never\"\n id=\"T7DoYo\"\n description=\"Text indicating API key expiration is not set\"\n />\n );\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../../../src/lib/api-keys/api-key-expiration.tsx"],"sourcesContent":["import { Callout, Flex } from \"@radix-ui/themes\";\nimport { ExclamationTriangleIcon } from \"@radix-ui/react-icons\";\nimport * as React from \"react\";\nimport { Button, Dialog, Label, Select } from \"../elements.js\";\nimport { Translation } from \"../i18n/translation.js\";\nimport { useLocale } from \"../i18n/use-locale.js\";\nimport { useIsHydrated } from \"../use-is-hydrated.js\";\n\nexport type ApiKeyExpirationOption =\n | \"never\"\n | \"1_hour\"\n | \"24_hours\"\n | \"3_days\"\n | \"7_days\"\n | \"current\";\n\nexport type ApiKeyExpirationPreset = Exclude<ApiKeyExpirationOption, \"current\">;\n\nconst EXPIRATION_OPTIONS = [\n \"never\",\n \"1_hour\",\n \"24_hours\",\n \"3_days\",\n \"7_days\",\n] satisfies ApiKeyExpirationPreset[];\n\nexport function getApiKeyExpiresAt(\n now: Date,\n value: ApiKeyExpirationOption,\n): string | null | undefined {\n switch (value) {\n case \"never\":\n return null;\n case \"1_hour\":\n return new Date(now.getTime() + 60 * 60 * 1000).toISOString();\n case \"24_hours\":\n return new Date(now.getTime() + 24 * 60 * 60 * 1000).toISOString();\n case \"3_days\":\n return new Date(now.getTime() + 3 * 24 * 60 * 60 * 1000).toISOString();\n case \"7_days\":\n return new Date(now.getTime() + 7 * 24 * 60 * 60 * 1000).toISOString();\n case \"current\":\n return undefined;\n }\n}\n\nexport function getApiKeyExpirationSelectValue(\n expiresAt?: string | null,\n): ApiKeyExpirationOption {\n if (!expiresAt) {\n return \"never\";\n }\n\n return \"current\";\n}\n\nexport function ApiKeyExpirationSelectField({\n defaultValue = \"never\",\n value,\n onValueChange,\n currentExpiresAt,\n}: {\n defaultValue?: ApiKeyExpirationOption;\n value?: ApiKeyExpirationOption;\n onValueChange?: (value: ApiKeyExpirationOption) => void;\n currentExpiresAt?: string | null;\n}) {\n return (\n <Flex direction=\"column\" align=\"stretch\" gap=\"2\">\n <Label>\n <Translation\n defaultMessage=\"Expiration\"\n id=\"pwfOwu\"\n description=\"Label for API key expiration field\"\n />\n </Label>\n <Select.Root\n name=\"expiration\"\n defaultValue={defaultValue}\n value={value}\n onValueChange={(nextValue) =>\n onValueChange?.(nextValue as ApiKeyExpirationOption)\n }\n >\n <Select.Trigger />\n <Select.Content>\n {currentExpiresAt ? (\n <Select.Item value=\"current\">\n <Translation\n defaultMessage=\"Current Expiration - {expiresAt}\"\n id=\"9HtsNU\"\n description=\"Option label for the current API key expiration\"\n values={{\n expiresAt: (\n <ApiKeyExpiresOn expiresAt={currentExpiresAt} includeTime />\n ),\n }}\n />\n </Select.Item>\n ) : null}\n {EXPIRATION_OPTIONS.map((option) => (\n <Select.Item key={option} value={option}>\n <ExpirationOptionLabel option={option} />\n </Select.Item>\n ))}\n </Select.Content>\n </Select.Root>\n </Flex>\n );\n}\n\nexport function ApiKeyExpiresOn({\n expiresAt,\n includeTime = false,\n}: {\n expiresAt?: string | null;\n includeTime?: boolean;\n}) {\n const isHydrated = useIsHydrated();\n const locale = useLocale();\n\n if (!expiresAt) {\n return <NeverApiKeyExpirationLabel />;\n }\n\n const expiresOn = new Date(expiresAt);\n const options = {\n timeZone: isHydrated ? undefined : \"UTC\",\n month: \"short\",\n day: \"numeric\",\n year: \"numeric\",\n ...(includeTime ? { hour: \"numeric\", minute: \"2-digit\" } : {}),\n } satisfies Intl.DateTimeFormatOptions;\n\n return (\n <>\n {includeTime\n ? expiresOn.toLocaleString(locale, options)\n : expiresOn.toLocaleDateString(locale, options)}\n </>\n );\n}\n\nexport function ApiKeyTimestamp({ timestamp }: { timestamp: string }) {\n const isHydrated = useIsHydrated();\n const locale = useLocale();\n const date = new Date(timestamp);\n\n return (\n <>\n {date.toLocaleString(locale, {\n timeZone: isHydrated ? undefined : \"UTC\",\n month: \"short\",\n day: \"numeric\",\n year: \"numeric\",\n hour: \"numeric\",\n minute: \"2-digit\",\n })}\n </>\n );\n}\n\nexport function EditApiKeyExpirationDialog({\n apiKeyName,\n expiresAt,\n error,\n isPending,\n isSuccess,\n open,\n onOpenChange,\n onReset,\n onSave,\n}: {\n apiKeyName: string;\n expiresAt?: string | null;\n error: unknown;\n isPending: boolean;\n isSuccess: boolean;\n open: boolean;\n onOpenChange: (open: boolean) => void;\n onReset: () => void;\n onSave: (expiresAt: string | null) => void;\n}) {\n return (\n <Dialog.Root open={open} onOpenChange={onOpenChange}>\n {open ? (\n <EditApiKeyExpirationDialogContent\n apiKeyName={apiKeyName}\n expiresAt={expiresAt}\n error={error}\n isPending={isPending}\n isSuccess={isSuccess}\n onReset={onReset}\n onSave={onSave}\n />\n ) : null}\n </Dialog.Root>\n );\n}\n\nfunction EditApiKeyExpirationDialogContent({\n apiKeyName,\n expiresAt,\n error,\n isPending,\n isSuccess,\n onReset,\n onSave,\n}: {\n apiKeyName: string;\n expiresAt?: string | null;\n error: unknown;\n isPending: boolean;\n isSuccess: boolean;\n onReset: () => void;\n onSave: (expiresAt: string | null) => void;\n}) {\n const selectedInitialValue = getApiKeyExpirationSelectValue(expiresAt);\n const [selectedExpiration, setSelectedExpiration] =\n React.useState<ApiKeyExpirationOption>(selectedInitialValue);\n\n const isCurrentExpiration = selectedExpiration === \"current\";\n const isUnchanged = selectedExpiration === selectedInitialValue;\n const canSave =\n !isCurrentExpiration && !isUnchanged && !isPending && !isSuccess;\n\n return (\n <Dialog.Content maxWidth=\"529px\">\n <Dialog.Title>\n <Translation\n defaultMessage=\"Edit secret key expiration\"\n id=\"pIxXuW\"\n description=\"Dialog title for editing API key expiration\"\n />\n </Dialog.Title>\n <Dialog.Description>\n {isCurrentExpiration ? (\n <Translation\n defaultMessage=\"Confirm API key expiration. Once this key expires, you can no longer use it.\"\n id=\"48Q0bX\"\n description=\"Description for confirming the current API key expiration\"\n />\n ) : (\n <Translation\n defaultMessage=\"Set API Key expiration for {name}. Once this key expires, you can no longer use it.\"\n id=\"aLj8zz\"\n description=\"Description for setting API key expiration\"\n values={{ name: apiKeyName }}\n />\n )}\n </Dialog.Description>\n <Flex direction=\"column\" align=\"stretch\" gap=\"4\" mt=\"5\">\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 updating the API key expiration.\"\n id=\"ge66Rv\"\n description=\"Error message when API key expiration update fails\"\n />\n </Callout.Text>\n </Callout.Root>\n ) : null}\n <ApiKeyExpirationSelectField\n currentExpiresAt={expiresAt}\n value={selectedExpiration}\n onValueChange={(nextExpiration) => {\n if (!isPending) {\n onReset();\n }\n setSelectedExpiration(nextExpiration);\n }}\n />\n </Flex>\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=\"I9XnRG\"\n description=\"Button to cancel API key expiration editing\"\n />\n </Button>\n </Dialog.Close>\n <Button\n disabled={!canSave}\n loading={isPending || isSuccess}\n onClick={() => {\n const nextExpiresAt = getApiKeyExpiresAt(\n new Date(),\n selectedExpiration,\n );\n if (\n nextExpiresAt !== undefined &&\n selectedExpiration !== \"current\"\n ) {\n onSave(nextExpiresAt);\n }\n }}\n >\n <Translation\n defaultMessage=\"Save changes\"\n id=\"ThFw5g\"\n description=\"Button to save API key expiration changes\"\n />\n </Button>\n </Flex>\n </Dialog.Content>\n );\n}\n\nfunction ExpirationOptionLabel({\n option,\n}: {\n option: Exclude<ApiKeyExpirationOption, \"current\">;\n}) {\n switch (option) {\n case \"never\":\n return <NeverApiKeyExpirationLabel />;\n case \"1_hour\":\n return (\n <Translation\n defaultMessage=\"in 1 hour\"\n id=\"+GR+6F\"\n description=\"Option to expire an API key in one hour\"\n />\n );\n case \"24_hours\":\n return (\n <Translation\n defaultMessage=\"in 24 hours\"\n id=\"UPQwj+\"\n description=\"Option to expire an API key in twenty-four hours\"\n />\n );\n case \"3_days\":\n return (\n <Translation\n defaultMessage=\"in 3 days\"\n id=\"elvZ6g\"\n description=\"Option to expire an API key in three days\"\n />\n );\n case \"7_days\":\n return (\n <Translation\n defaultMessage=\"in 7 days\"\n id=\"Dzu4Fy\"\n description=\"Option to expire an API key in seven days\"\n />\n );\n }\n}\n\nfunction NeverApiKeyExpirationLabel() {\n return (\n <Translation\n defaultMessage=\"Never\"\n id=\"T7DoYo\"\n description=\"Text indicating API key expiration is not set\"\n />\n );\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAsEQ;AAtER,oBAA8B;AAC9B,yBAAwC;AACxC,YAAuB;AACvB,sBAA8C;AAC9C,yBAA4B;AAC5B,wBAA0B;AAC1B,6BAA8B;AAY9B,MAAM,qBAAqB;AAAA,EACzB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAEO,SAAS,mBACd,KACA,OAC2B;AAC3B,UAAQ,OAAO;AAAA,IACb,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO,IAAI,KAAK,IAAI,QAAQ,IAAI,KAAK,KAAK,GAAI,EAAE,YAAY;AAAA,IAC9D,KAAK;AACH,aAAO,IAAI,KAAK,IAAI,QAAQ,IAAI,KAAK,KAAK,KAAK,GAAI,EAAE,YAAY;AAAA,IACnE,KAAK;AACH,aAAO,IAAI,KAAK,IAAI,QAAQ,IAAI,IAAI,KAAK,KAAK,KAAK,GAAI,EAAE,YAAY;AAAA,IACvE,KAAK;AACH,aAAO,IAAI,KAAK,IAAI,QAAQ,IAAI,IAAI,KAAK,KAAK,KAAK,GAAI,EAAE,YAAY;AAAA,IACvE,KAAK;AACH,aAAO;AAAA,EACX;AACF;AAEO,SAAS,+BACd,WACwB;AACxB,MAAI,CAAC,WAAW;AACd,WAAO;AAAA,EACT;AAEA,SAAO;AACT;AAEO,SAAS,4BAA4B;AAAA,EAC1C,eAAe;AAAA,EACf;AAAA,EACA;AAAA,EACA;AACF,GAKG;AACD,SACE,6CAAC,sBAAK,WAAU,UAAS,OAAM,WAAU,KAAI,KAC3C;AAAA,gDAAC,yBACC;AAAA,MAAC;AAAA;AAAA,QACC,gBAAe;AAAA,QACf,IAAG;AAAA,QACH,aAAY;AAAA;AAAA,IACd,GACF;AAAA,IACA;AAAA,MAAC,uBAAO;AAAA,MAAP;AAAA,QACC,MAAK;AAAA,QACL;AAAA,QACA;AAAA,QACA,eAAe,CAAC,cACd,gBAAgB,SAAmC;AAAA,QAGrD;AAAA,sDAAC,uBAAO,SAAP,EAAe;AAAA,UAChB,6CAAC,uBAAO,SAAP,EACE;AAAA,+BACC,4CAAC,uBAAO,MAAP,EAAY,OAAM,WACjB;AAAA,cAAC;AAAA;AAAA,gBACC,gBAAe;AAAA,gBACf,IAAG;AAAA,gBACH,aAAY;AAAA,gBACZ,QAAQ;AAAA,kBACN,WACE,4CAAC,mBAAgB,WAAW,kBAAkB,aAAW,MAAC;AAAA,gBAE9D;AAAA;AAAA,YACF,GACF,IACE;AAAA,YACH,mBAAmB,IAAI,CAAC,WACvB,4CAAC,uBAAO,MAAP,EAAyB,OAAO,QAC/B,sDAAC,yBAAsB,QAAgB,KADvB,MAElB,CACD;AAAA,aACH;AAAA;AAAA;AAAA,IACF;AAAA,KACF;AAEJ;AAEO,SAAS,gBAAgB;AAAA,EAC9B;AAAA,EACA,cAAc;AAChB,GAGG;AACD,QAAM,iBAAa,sCAAc;AACjC,QAAM,aAAS,6BAAU;AAEzB,MAAI,CAAC,WAAW;AACd,WAAO,4CAAC,8BAA2B;AAAA,EACrC;AAEA,QAAM,YAAY,IAAI,KAAK,SAAS;AACpC,QAAM,UAAU;AAAA,IACd,UAAU,aAAa,SAAY;AAAA,IACnC,OAAO;AAAA,IACP,KAAK;AAAA,IACL,MAAM;AAAA,IACN,GAAI,cAAc,EAAE,MAAM,WAAW,QAAQ,UAAU,IAAI,CAAC;AAAA,EAC9D;AAEA,SACE,2EACG,wBACG,UAAU,eAAe,QAAQ,OAAO,IACxC,UAAU,mBAAmB,QAAQ,OAAO,GAClD;AAEJ;AAEO,SAAS,gBAAgB,EAAE,UAAU,GAA0B;AACpE,QAAM,iBAAa,sCAAc;AACjC,QAAM,aAAS,6BAAU;AACzB,QAAM,OAAO,IAAI,KAAK,SAAS;AAE/B,SACE,2EACG,eAAK,eAAe,QAAQ;AAAA,IAC3B,UAAU,aAAa,SAAY;AAAA,IACnC,OAAO;AAAA,IACP,KAAK;AAAA,IACL,MAAM;AAAA,IACN,MAAM;AAAA,IACN,QAAQ;AAAA,EACV,CAAC,GACH;AAEJ;AAEO,SAAS,2BAA2B;AAAA,EACzC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAUG;AACD,SACE,4CAAC,uBAAO,MAAP,EAAY,MAAY,cACtB,iBACC;AAAA,IAAC;AAAA;AAAA,MACC;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,EACF,IACE,MACN;AAEJ;AAEA,SAAS,kCAAkC;AAAA,EACzC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAQG;AACD,QAAM,uBAAuB,+BAA+B,SAAS;AACrE,QAAM,CAAC,oBAAoB,qBAAqB,IAC9C,MAAM,SAAiC,oBAAoB;AAE7D,QAAM,sBAAsB,uBAAuB;AACnD,QAAM,cAAc,uBAAuB;AAC3C,QAAM,UACJ,CAAC,uBAAuB,CAAC,eAAe,CAAC,aAAa,CAAC;AAEzD,SACE,6CAAC,uBAAO,SAAP,EAAe,UAAS,SACvB;AAAA,gDAAC,uBAAO,OAAP,EACC;AAAA,MAAC;AAAA;AAAA,QACC,gBAAe;AAAA,QACf,IAAG;AAAA,QACH,aAAY;AAAA;AAAA,IACd,GACF;AAAA,IACA,4CAAC,uBAAO,aAAP,EACE,gCACC;AAAA,MAAC;AAAA;AAAA,QACC,gBAAe;AAAA,QACf,IAAG;AAAA,QACH,aAAY;AAAA;AAAA,IACd,IAEA;AAAA,MAAC;AAAA;AAAA,QACC,gBAAe;AAAA,QACf,IAAG;AAAA,QACH,aAAY;AAAA,QACZ,QAAQ,EAAE,MAAM,WAAW;AAAA;AAAA,IAC7B,GAEJ;AAAA,IACA,6CAAC,sBAAK,WAAU,UAAS,OAAM,WAAU,KAAI,KAAI,IAAG,KACjD;AAAA,cACC,6CAAC,sBAAQ,MAAR,EAAa,OAAM,OAAM,MAAK,SAC7B;AAAA,oDAAC,sBAAQ,MAAR,EACC,sDAAC,8CAAwB,GAC3B;AAAA,QACA,4CAAC,sBAAQ,MAAR,EACC;AAAA,UAAC;AAAA;AAAA,YACC,gBAAe;AAAA,YACf,IAAG;AAAA,YACH,aAAY;AAAA;AAAA,QACd,GACF;AAAA,SACF,IACE;AAAA,MACJ;AAAA,QAAC;AAAA;AAAA,UACC,kBAAkB;AAAA,UAClB,OAAO;AAAA,UACP,eAAe,CAAC,mBAAmB;AACjC,gBAAI,CAAC,WAAW;AACd,sBAAQ;AAAA,YACV;AACA,kCAAsB,cAAc;AAAA,UACtC;AAAA;AAAA,MACF;AAAA,OACF;AAAA,IACA,6CAAC,sBAAK,OAAM,UAAS,KAAI,KAAI,SAAQ,OAAM,IAAG,KAC5C;AAAA,kDAAC,uBAAO,OAAP,EACC,sDAAC,0BAAO,SAAQ,aAAY,UAAU,aAAa,WACjD;AAAA,QAAC;AAAA;AAAA,UACC,gBAAe;AAAA,UACf,IAAG;AAAA,UACH,aAAY;AAAA;AAAA,MACd,GACF,GACF;AAAA,MACA;AAAA,QAAC;AAAA;AAAA,UACC,UAAU,CAAC;AAAA,UACX,SAAS,aAAa;AAAA,UACtB,SAAS,MAAM;AACb,kBAAM,gBAAgB;AAAA,cACpB,oBAAI,KAAK;AAAA,cACT;AAAA,YACF;AACA,gBACE,kBAAkB,UAClB,uBAAuB,WACvB;AACA,qBAAO,aAAa;AAAA,YACtB;AAAA,UACF;AAAA,UAEA;AAAA,YAAC;AAAA;AAAA,cACC,gBAAe;AAAA,cACf,IAAG;AAAA,cACH,aAAY;AAAA;AAAA,UACd;AAAA;AAAA,MACF;AAAA,OACF;AAAA,KACF;AAEJ;AAEA,SAAS,sBAAsB;AAAA,EAC7B;AACF,GAEG;AACD,UAAQ,QAAQ;AAAA,IACd,KAAK;AACH,aAAO,4CAAC,8BAA2B;AAAA,IACrC,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,IAEJ,KAAK;AACH,aACE;AAAA,QAAC;AAAA;AAAA,UACC,gBAAe;AAAA,UACf,IAAG;AAAA,UACH,aAAY;AAAA;AAAA,MACd;AAAA,EAEN;AACF;AAEA,SAAS,6BAA6B;AACpC,SACE;AAAA,IAAC;AAAA;AAAA,MACC,gBAAe;AAAA,MACf,IAAG;AAAA,MACH,aAAY;AAAA;AAAA,EACd;AAEJ;","names":[]}
@@ -2,7 +2,7 @@ import * as React from 'react';
2
2
 
3
3
  type ApiKeyExpirationOption = "never" | "1_hour" | "24_hours" | "3_days" | "7_days" | "current";
4
4
  type ApiKeyExpirationPreset = Exclude<ApiKeyExpirationOption, "current">;
5
- declare function getApiKeyExpiresAt(value: ApiKeyExpirationOption): string | null | undefined;
5
+ declare function getApiKeyExpiresAt(now: Date, value: ApiKeyExpirationOption): string | null | undefined;
6
6
  declare function getApiKeyExpirationSelectValue(expiresAt?: string | null): ApiKeyExpirationOption;
7
7
  declare function ApiKeyExpirationSelectField({ defaultValue, value, onValueChange, currentExpiresAt, }: {
8
8
  defaultValue?: ApiKeyExpirationOption;
@@ -97,8 +97,10 @@ function CreateApiKeyForm() {
97
97
  Form.Root,
98
98
  {
99
99
  onSubmit: (e) => {
100
- if (isPending) return;
101
100
  e.preventDefault();
101
+ if (isPending) {
102
+ return;
103
+ }
102
104
  const data = new FormData(e.currentTarget);
103
105
  const isValid = validate(data);
104
106
  if (!isValid) {
@@ -110,6 +112,7 @@ function CreateApiKeyForm() {
110
112
  name: data.get("name")?.toString() ?? "",
111
113
  permissions: data.getAll("permission").map(String),
112
114
  expiresAt: (0, import_api_key_expiration.getApiKeyExpiresAt)(
115
+ /* @__PURE__ */ new Date(),
113
116
  data.get("expiration")?.toString() ?? "never"
114
117
  ) ?? null
115
118
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../src/lib/api-keys/create-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 type { ListOrganizationApiKeyPermission } from \"../api/types.js\";\nimport {\n useCreateApiKey,\n useListOrganizationApiKeyPermissions,\n} from \"../api/api-key.js\";\nimport { useApiKeysContext } from \"./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-key-expiration.js\";\n\nexport function CreateApiKeyDialog() {\n const {\n state: { createDialogOpen, createdApiKey },\n dispatch,\n } = useApiKeysContext();\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 <CreateApiKeyForm\n // always remount the form when the dialog is opened to reset the validation errors\n key={`${createDialogOpen}`}\n />\n )}\n </Dialog.Root>\n );\n}\n\nfunction CreateApiKeyForm() {\n const { dispatch } = useApiKeysContext();\n const translate = useTranslation();\n const [errors, setErrors] = React.useState<{\n name: boolean;\n }>({ name: false });\n\n const validate = (formData: FormData) => {\n const name = formData.get(\"name\")?.toString() ?? \"\";\n const errors = { name: !name.trim().length };\n setErrors(errors);\n const isValid = Object.values(errors).every((error) => error === false);\n return isValid;\n };\n\n const {\n mutate: createOrganizationApiKey,\n error,\n isPending,\n isSuccess,\n } = useCreateApiKey();\n const permissions = useListOrganizationApiKeyPermissions({ 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 if (isPending) return;\n e.preventDefault();\n const data = new FormData(e.currentTarget);\n const isValid = validate(data);\n if (!isValid) {\n return;\n }\n\n createOrganizationApiKey(\n {\n data: {\n name: data.get(\"name\")?.toString() ?? \"\",\n permissions: data.getAll(\"permission\").map(String),\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 )}\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 permissions={permissions.data.data} />\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 maxWidth=\"529px\">\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: ListOrganizationApiKeyPermission;\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}: {\n permissions: ListOrganizationApiKeyPermission[];\n}) {\n const [selectedPermissions, setSelectedPermissions] = React.useState<\n ListOrganizationApiKeyPermission[]\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 return permissions.filter((p) => {\n return (\n !filter.trim().length ||\n p.description?.toLowerCase().match(filter.toLowerCase()) ||\n p.name.toLowerCase().match(filter.toLowerCase()) ||\n p.slug.toLowerCase().match(filter.toLowerCase())\n );\n });\n }, [permissions, filter]);\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 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 total={permissions.length}\n selected={selectedPermissions.length}\n onToggle={() =>\n setSelectedPermissions((prev) =>\n prev.length === permissions.length ? [] : permissions,\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 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 total,\n selected,\n onToggle,\n}: {\n total: number;\n selected: number;\n onToggle: () => void;\n}) {\n return (\n <Flex align=\"center\" gap=\"2\">\n <Text size=\"1\" style={{ lineHeight: 1, 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 <Text\n size=\"1\"\n onClick={onToggle}\n style={{ cursor: \"pointer\", color: \"var(--accent-10)\" }}\n >\n {total === selected ? (\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 </Flex>\n );\n}\n\nexport function CreateApiKeyButton() {\n const { dispatch } = useApiKeysContext();\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":["errors","error","data"]}
1
+ {"version":3,"sources":["../../../../src/lib/api-keys/create-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 type { ListOrganizationApiKeyPermission } from \"../api/types.js\";\nimport {\n useCreateApiKey,\n useListOrganizationApiKeyPermissions,\n} from \"../api/api-key.js\";\nimport { useApiKeysContext } from \"./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-key-expiration.js\";\n\nexport function CreateApiKeyDialog() {\n const {\n state: { createDialogOpen, createdApiKey },\n dispatch,\n } = useApiKeysContext();\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 <CreateApiKeyForm\n // always remount the form when the dialog is opened to reset the validation errors\n key={`${createDialogOpen}`}\n />\n )}\n </Dialog.Root>\n );\n}\n\nfunction CreateApiKeyForm() {\n const { dispatch } = useApiKeysContext();\n const translate = useTranslation();\n const [errors, setErrors] = React.useState<{\n name: boolean;\n }>({ name: false });\n\n const validate = (formData: FormData) => {\n const name = formData.get(\"name\")?.toString() ?? \"\";\n const errors = { name: !name.trim().length };\n setErrors(errors);\n const isValid = Object.values(errors).every((error) => error === false);\n return isValid;\n };\n\n const {\n mutate: createOrganizationApiKey,\n error,\n isPending,\n isSuccess,\n } = useCreateApiKey();\n const permissions = useListOrganizationApiKeyPermissions({ 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 createOrganizationApiKey(\n {\n data: {\n name: data.get(\"name\")?.toString() ?? \"\",\n permissions: data.getAll(\"permission\").map(String),\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 )}\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 permissions={permissions.data.data} />\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 maxWidth=\"529px\">\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: ListOrganizationApiKeyPermission;\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}: {\n permissions: ListOrganizationApiKeyPermission[];\n}) {\n const [selectedPermissions, setSelectedPermissions] = React.useState<\n ListOrganizationApiKeyPermission[]\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 return permissions.filter((p) => {\n return (\n !filter.trim().length ||\n p.description?.toLowerCase().match(filter.toLowerCase()) ||\n p.name.toLowerCase().match(filter.toLowerCase()) ||\n p.slug.toLowerCase().match(filter.toLowerCase())\n );\n });\n }, [permissions, filter]);\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 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 total={permissions.length}\n selected={selectedPermissions.length}\n onToggle={() =>\n setSelectedPermissions((prev) =>\n prev.length === permissions.length ? [] : permissions,\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 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 total,\n selected,\n onToggle,\n}: {\n total: number;\n selected: number;\n onToggle: () => void;\n}) {\n return (\n <Flex align=\"center\" gap=\"2\">\n <Text size=\"1\" style={{ lineHeight: 1, 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 <Text\n size=\"1\"\n onClick={onToggle}\n style={{ cursor: \"pointer\", color: \"var(--accent-10)\" }}\n >\n {total === selected ? (\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 </Flex>\n );\n}\n\nexport function CreateApiKeyButton() {\n const { dispatch } = useApiKeysContext();\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":["errors","error","data"]}
@@ -22,28 +22,23 @@ __export(relative_time_exports, {
22
22
  });
23
23
  module.exports = __toCommonJS(relative_time_exports);
24
24
  var import_jsx_runtime = require("react/jsx-runtime");
25
- var import_use_is_hydrated = require("../use-is-hydrated.js");
26
- var import_utils = require("../utils.js");
27
25
  var import_translation = require("../i18n/translation.js");
28
- var import_use_locale = require("../i18n/use-locale.js");
26
+ var import_use_comparative_readable_date = require("../../use-comparative-readable-date.js");
29
27
  function RelativeTime({ date }) {
30
- const isHydrated = (0, import_use_is_hydrated.useIsHydrated)();
31
- const locale = (0, import_use_locale.useLocale)();
32
28
  if (!date) {
33
- return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_jsx_runtime.Fragment, { children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
29
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
34
30
  import_translation.Translation,
35
31
  {
36
32
  defaultMessage: "Never",
37
33
  id: "yXCbRa",
38
34
  description: "Text indicating API key was never used"
39
35
  }
40
- ) });
36
+ );
41
37
  }
42
- return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_jsx_runtime.Fragment, { children: isHydrated ? (0, import_utils.getComparativeReadableDate)(/* @__PURE__ */ new Date(), date, { locale }) : date.toLocaleDateString(locale, {
43
- month: "short",
44
- day: "numeric",
45
- year: "numeric"
46
- }) });
38
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(RelativeTimeImpl, { date });
39
+ }
40
+ function RelativeTimeImpl({ date }) {
41
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_jsx_runtime.Fragment, { children: (0, import_use_comparative_readable_date.useComparativeReadableDate)({ date }) });
47
42
  }
48
43
  // Annotate the CommonJS export names for ESM import in node:
49
44
  0 && (module.exports = {
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../src/lib/api-keys/relative-time.tsx"],"sourcesContent":["import { useIsHydrated } from \"../use-is-hydrated.js\";\nimport { getComparativeReadableDate } from \"../utils.js\";\nimport { Translation } from \"../i18n/translation.js\";\nimport { useLocale } from \"../i18n/use-locale.js\";\n\nexport function RelativeTime({ date }: { date?: Date }) {\n const isHydrated = useIsHydrated();\n const locale = useLocale();\n\n if (!date) {\n return (\n <>\n <Translation\n defaultMessage=\"Never\"\n id=\"yXCbRa\"\n description=\"Text indicating API key was never used\"\n />\n </>\n );\n }\n\n return (\n <>\n {isHydrated\n ? getComparativeReadableDate(new Date(), date, { locale })\n : date.toLocaleDateString(locale, {\n month: \"short\",\n day: \"numeric\",\n year: \"numeric\",\n })}\n </>\n );\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAWM;AAXN,6BAA8B;AAC9B,mBAA2C;AAC3C,yBAA4B;AAC5B,wBAA0B;AAEnB,SAAS,aAAa,EAAE,KAAK,GAAoB;AACtD,QAAM,iBAAa,sCAAc;AACjC,QAAM,aAAS,6BAAU;AAEzB,MAAI,CAAC,MAAM;AACT,WACE,2EACE;AAAA,MAAC;AAAA;AAAA,QACC,gBAAe;AAAA,QACf,IAAG;AAAA,QACH,aAAY;AAAA;AAAA,IACd,GACF;AAAA,EAEJ;AAEA,SACE,2EACG,2BACG,yCAA2B,oBAAI,KAAK,GAAG,MAAM,EAAE,OAAO,CAAC,IACvD,KAAK,mBAAmB,QAAQ;AAAA,IAC9B,OAAO;AAAA,IACP,KAAK;AAAA,IACL,MAAM;AAAA,EACR,CAAC,GACP;AAEJ;","names":[]}
1
+ {"version":3,"sources":["../../../../src/lib/api-keys/relative-time.tsx"],"sourcesContent":["import * as React from \"react\";\nimport { Translation } from \"../i18n/translation.js\";\nimport { useComparativeReadableDate } from \"../../use-comparative-readable-date.js\";\n\nexport function RelativeTime({ date }: { date?: Date }) {\n if (!date) {\n return (\n <Translation\n defaultMessage=\"Never\"\n id=\"yXCbRa\"\n description=\"Text indicating API key was never used\"\n />\n );\n }\n\n return <RelativeTimeImpl date={date} />;\n}\n\nfunction RelativeTimeImpl({ date }: { date: Date }): React.ReactNode {\n return <>{useComparativeReadableDate({ date })}</>;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAOM;AANN,yBAA4B;AAC5B,2CAA2C;AAEpC,SAAS,aAAa,EAAE,KAAK,GAAoB;AACtD,MAAI,CAAC,MAAM;AACT,WACE;AAAA,MAAC;AAAA;AAAA,QACC,gBAAe;AAAA,QACf,IAAG;AAAA,QACH,aAAY;AAAA;AAAA,IACd;AAAA,EAEJ;AAEA,SAAO,4CAAC,oBAAiB,MAAY;AACvC;AAEA,SAAS,iBAAiB,EAAE,KAAK,GAAoC;AACnE,SAAO,2EAAG,+EAA2B,EAAE,KAAK,CAAC,GAAE;AACjD;","names":[]}
@@ -49,6 +49,7 @@ var import_identity_providers = require("./identity-providers.js");
49
49
  var import_status = require("./status.js");
50
50
  var import_translation = require("./i18n/translation.js");
51
51
  var import_utils = require("./utils.js");
52
+ var import_use_comparative_readable_date = require("../use-comparative-readable-date.js");
52
53
  const DirectoryState = {
53
54
  requires_type: "requires_type",
54
55
  linked: "linked",
@@ -141,7 +142,10 @@ const DirectorySync = ({
141
142
  const groupCount = metadata?.groups ?? 0;
142
143
  const lastSyncAt = rest.lastSyncAt ? new Date(rest.lastSyncAt) : null;
143
144
  const currentDate = "currentDate" in rest && rest.currentDate instanceof Date ? rest.currentDate : void 0;
144
- const lastSyncString = lastSyncAt ? getRelativeTimeString(currentDate ?? /* @__PURE__ */ new Date(), lastSyncAt) : null;
145
+ const lastSyncString = (0, import_use_comparative_readable_date.useComparativeReadableDate)({
146
+ date: lastSyncAt,
147
+ currentDate
148
+ });
145
149
  const showCounts = state === DirectoryState.linked || state === DirectoryState.invalid_credentials || state === DirectoryState.deleting;
146
150
  const statusBadge = getStatusBadge(state);
147
151
  const spinnerMessage = getSpinnerMessage(state, !!type);
@@ -284,35 +288,6 @@ function getWidgetRootDomProps(state, domProps) {
284
288
  widgetState: state
285
289
  });
286
290
  }
287
- function getRelativeTimeString(currentDate, lastSync) {
288
- if (!currentDate || !lastSync) {
289
- return null;
290
- }
291
- const rtf = new Intl.RelativeTimeFormat("en", { numeric: "auto" });
292
- const diff = lastSync.getTime() - currentDate.getTime();
293
- const diffSeconds = Math.round(diff / 1e3);
294
- const diffMinutes = Math.round(diffSeconds / 60);
295
- const diffHours = Math.round(diffMinutes / 60);
296
- const diffDays = Math.round(diffHours / 24);
297
- const diffMonths = Math.round(diffDays / 30);
298
- const diffYears = Math.round(diffMonths / 12);
299
- if (Math.abs(diffSeconds) < 60) {
300
- return "now";
301
- }
302
- if (Math.abs(diffMinutes) < 60) {
303
- return rtf.format(diffMinutes, "minute");
304
- }
305
- if (Math.abs(diffHours) < 24) {
306
- return rtf.format(diffHours, "hour");
307
- }
308
- if (Math.abs(diffDays) < 30) {
309
- return rtf.format(diffDays, "day");
310
- }
311
- if (Math.abs(diffMonths) < 12) {
312
- return rtf.format(diffMonths, "month");
313
- }
314
- return rtf.format(diffYears, "year");
315
- }
316
291
  // Annotate the CommonJS export names for ESM import in node:
317
292
  0 && (module.exports = {
318
293
  DirectoryState,