{"version":3,"sources":["../../../../src/lib/api-keys/api-keys-table.tsx"],"sourcesContent":["import { Flex, Text, Table, Code, Heading } from \"@radix-ui/themes\";\nimport { Button, DropdownMenu, IconButton } from \"../elements.js\";\nimport { DotsHorizontalIcon, MagnifyingGlassIcon } from \"@radix-ui/react-icons\";\nimport { useState } from \"react\";\nimport { RevokeApiKeyDialog } from \"./revoke-api-key-dialog.js\";\nimport { CreateApiKeyButton } from \"./create-api-key.js\";\nimport { ApiKeyDetailsDialog } from \"./api-key-details-dialog.js\";\nimport { useIsHydrated } from \"../use-is-hydrated.js\";\nimport { RelativeTime } from \"./relative-time.js\";\nimport {\n  ListOrganizationApiKeysResponse,\n  ListOrganizationApiKeysResponseData,\n} from \"../../api/endpoint.js\";\nimport { useApiKeysContext } from \"./api-keys-context.js\";\nimport { useApiKeysSearchContext } from \"./api-keys-search-provider.js\";\nimport { ApiKeysSearch } from \"./api-keys-search.js\";\nimport { Translation } from \"../i18n/translation.js\";\nimport { useTranslation } from \"../i18n/use-translation.js\";\nimport { useLocale } from \"../i18n/use-locale.js\";\nimport { getListMetadata } from \"../utils.js\";\n\nfunction NoApiKeys() {\n  const { clearSearch } = useApiKeysSearchContext();\n  return (\n    <Flex p=\"6\" gap=\"4\" justify=\"center\" align=\"center\" direction=\"column\">\n      <Flex direction=\"column\" gap=\"1\" maxWidth=\"420px\" align=\"center\">\n        <MagnifyingGlassIcon\n          style={{ color: \"var(--gray-9)\" }}\n          width=\"32px\"\n          height=\"32px\"\n        />\n        <Heading size=\"5\" mb=\"1\" wrap=\"balance\" as=\"h3\">\n          <Translation\n            defaultMessage=\"No API keys match your search\"\n            id=\"cKitHb\"\n            description=\"Empty state message when no API keys match search\"\n          />\n        </Heading>\n      </Flex>\n\n      <Button variant=\"secondary\" onClick={clearSearch}>\n        <Translation\n          defaultMessage=\"Clear search\"\n          id=\"jTupOW\"\n          description=\"Button to clear API key search filters\"\n        />\n      </Button>\n    </Flex>\n  );\n}\n\nfunction ApiKeysTableHeader() {\n  return (\n    <Flex justify=\"between\" align=\"center\">\n      <ApiKeysSearch name=\"api-keys-widget-search\" style={{ width: \"390px\" }} />\n      <CreateApiKeyButton />\n    </Flex>\n  );\n}\n\nfunction CreatedOn({ createdOn }: { createdOn: Date }) {\n  const isHydrated = useIsHydrated();\n  const locale = useLocale();\n  return (\n    <>\n      {createdOn.toLocaleDateString(locale, {\n        timeZone: isHydrated ? undefined : \"UTC\",\n        month: \"short\",\n        day: \"numeric\",\n        year: \"numeric\",\n      })}\n    </>\n  );\n}\n\ninterface ApiKeyRowProps {\n  apiKey: ListOrganizationApiKeysResponseData;\n}\n\nfunction ApiKeyRow({ apiKey }: ApiKeyRowProps) {\n  const [revokeDialogOpen, setRevokeDialogOpen] = useState(false);\n  const [detailsOpen, setDetailsOpen] = useState(false);\n  const translate = useTranslation();\n  return (\n    <>\n      <RevokeApiKeyDialog\n        // always remount the form when the dialog is opened to reset the validation errors\n        key={`${revokeDialogOpen}`}\n        open={revokeDialogOpen}\n        onOpenChange={setRevokeDialogOpen}\n        apiKey={apiKey}\n      />\n      <ApiKeyDetailsDialog\n        open={detailsOpen}\n        onOpenChange={setDetailsOpen}\n        apiKey={apiKey}\n        permissions={apiKey.permissions}\n      />\n      <Table.Row align=\"center\">\n        <Table.Cell>\n          <Text>{apiKey.name}</Text>\n        </Table.Cell>\n        <Table.Cell>\n          <Code color=\"gray\">{apiKey.obfuscatedValue}</Code>\n        </Table.Cell>\n        <Table.Cell>\n          <Text\n            style={apiKey.lastUsedAt ? undefined : { color: \"var(--gray-10)\" }}\n          >\n            <RelativeTime\n              date={apiKey.lastUsedAt ? new Date(apiKey.lastUsedAt) : undefined}\n            />\n          </Text>\n        </Table.Cell>\n        <Table.Cell>\n          <Text>\n            <CreatedOn createdOn={new Date(apiKey.createdAt)} />\n          </Text>\n        </Table.Cell>\n        <Table.Cell justify=\"end\">\n          <DropdownMenu.Root>\n            <DropdownMenu.Trigger>\n              {(() => {\n                const title = translate({\n                  defaultMessage: \"API key actions\",\n                  id: \"RIBfYe\",\n                  description: \"Tooltip for API key actions menu button\",\n                });\n                return (\n                  <IconButton title={title}>\n                    <DotsHorizontalIcon />\n                  </IconButton>\n                );\n              })()}\n            </DropdownMenu.Trigger>\n            <DropdownMenu.Content size=\"2\" align=\"end\">\n              <DropdownMenu.Item onSelect={() => setDetailsOpen(true)}>\n                <Translation\n                  defaultMessage=\"View details\"\n                  id=\"VGKbbj\"\n                  description=\"Menu item to view API key details\"\n                />\n              </DropdownMenu.Item>\n              <DropdownMenu.Item\n                variant=\"destructive\"\n                onSelect={() => setRevokeDialogOpen(true)}\n              >\n                <Translation\n                  defaultMessage=\"Revoke key\"\n                  id=\"KZIJPP\"\n                  description=\"Menu item to revoke an API key\"\n                />\n              </DropdownMenu.Item>\n            </DropdownMenu.Content>\n          </DropdownMenu.Root>\n        </Table.Cell>\n      </Table.Row>\n    </>\n  );\n}\n\nexport function ApiKeysTable({\n  apiKeys,\n}: {\n  apiKeys: ListOrganizationApiKeysResponse;\n}) {\n  const { dispatch } = useApiKeysContext();\n\n  // The API response previously returned an object with the `listMetadata`\n  // property. We might not need this, but it's a defensive check until we\n  // verify the API response changes are correct.\n  const pagination = getListMetadata(apiKeys);\n\n  const hasPagination = !!(pagination.before || pagination.after);\n  const hasPreviousPage = !!pagination.after;\n  const hasNextPage = !!pagination.before;\n\n  return (\n    <Flex direction=\"column\" align=\"stretch\" gap=\"3\">\n      <ApiKeysTableHeader />\n      {apiKeys.data.length === 0 ? (\n        <NoApiKeys />\n      ) : (\n        <>\n          <Table.Root variant=\"ghost\" size=\"2\">\n            <Table.Header>\n              <Table.Row>\n                <Table.ColumnHeaderCell width=\"25%\">\n                  <Translation\n                    defaultMessage=\"Name\"\n                    id=\"VYbVXN\"\n                    description=\"Table column header for API key name\"\n                  />\n                </Table.ColumnHeaderCell>\n                <Table.ColumnHeaderCell width=\"25%\">\n                  <Translation\n                    defaultMessage=\"Secret key\"\n                    id=\"H5k7GB\"\n                    description=\"Table column header for API key secret value\"\n                  />\n                </Table.ColumnHeaderCell>\n                <Table.ColumnHeaderCell width=\"25%\">\n                  <Translation\n                    defaultMessage=\"Last used\"\n                    id=\"E46t3O\"\n                    description=\"Table column header for API key last used timestamp\"\n                  />\n                </Table.ColumnHeaderCell>\n                <Table.ColumnHeaderCell width=\"25%\">\n                  <Translation\n                    defaultMessage=\"Created\"\n                    id=\"CXHhXd\"\n                    description=\"Table column header for API key creation date\"\n                  />\n                </Table.ColumnHeaderCell>\n                <Table.ColumnHeaderCell width=\"28px\" />\n              </Table.Row>\n            </Table.Header>\n            <Table.Body>\n              {apiKeys.data.map((apiKey) => (\n                <ApiKeyRow key={apiKey.id} apiKey={apiKey} />\n              ))}\n            </Table.Body>\n          </Table.Root>\n          {hasPagination && (\n            <Flex gap=\"2\" justify=\"end\">\n              <Button\n                variant=\"secondary\"\n                disabled={!hasPreviousPage}\n                size=\"1\"\n                onClick={() =>\n                  dispatch({\n                    type: \"SET_PAGINATION\",\n                    pagination: { before: null, after: pagination.after },\n                  })\n                }\n              >\n                <Translation\n                  defaultMessage=\"Previous\"\n                  id=\"f7TUj0\"\n                  description=\"Button to navigate to previous page of API keys\"\n                />\n              </Button>\n              <Button\n                variant=\"secondary\"\n                disabled={!hasNextPage}\n                size=\"1\"\n                onClick={() =>\n                  dispatch({\n                    type: \"SET_PAGINATION\",\n                    pagination: { before: pagination.before, after: null },\n                  })\n                }\n              >\n                <Translation\n                  defaultMessage=\"Next\"\n                  id=\"L2EBxV\"\n                  description=\"Button to navigate to next page of API keys\"\n                />\n              </Button>\n            </Flex>\n          )}\n        </>\n      )}\n    </Flex>\n  );\n}\n"],"mappings":"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","names":[]}