Spaces:
Build error
Build error
| import React, { useState } from "react"; | |
| import { useTranslation, Trans } from "react-i18next"; | |
| import { I18nKey } from "#/i18n/declaration"; | |
| import { BrandButton } from "#/components/features/settings/brand-button"; | |
| import { LoadingSpinner } from "#/components/shared/loading-spinner"; | |
| import { ApiKey, CreateApiKeyResponse } from "#/api/api-keys"; | |
| import { displayErrorToast } from "#/utils/custom-toast-handlers"; | |
| import { CreateApiKeyModal } from "./create-api-key-modal"; | |
| import { DeleteApiKeyModal } from "./delete-api-key-modal"; | |
| import { NewApiKeyModal } from "./new-api-key-modal"; | |
| import { useApiKeys } from "#/hooks/query/use-api-keys"; | |
| export function ApiKeysManager() { | |
| const { t } = useTranslation(); | |
| const { data: apiKeys = [], isLoading, error } = useApiKeys(); | |
| const [createModalOpen, setCreateModalOpen] = useState(false); | |
| const [deleteModalOpen, setDeleteModalOpen] = useState(false); | |
| const [keyToDelete, setKeyToDelete] = useState<ApiKey | null>(null); | |
| const [newlyCreatedKey, setNewlyCreatedKey] = | |
| useState<CreateApiKeyResponse | null>(null); | |
| const [showNewKeyModal, setShowNewKeyModal] = useState(false); | |
| // Display error toast if the query fails | |
| if (error) { | |
| displayErrorToast(t(I18nKey.ERROR$GENERIC)); | |
| } | |
| const handleKeyCreated = (newKey: CreateApiKeyResponse) => { | |
| setNewlyCreatedKey(newKey); | |
| setCreateModalOpen(false); | |
| setShowNewKeyModal(true); | |
| }; | |
| const handleCloseCreateModal = () => { | |
| setCreateModalOpen(false); | |
| }; | |
| const handleCloseDeleteModal = () => { | |
| setDeleteModalOpen(false); | |
| setKeyToDelete(null); | |
| }; | |
| const handleCloseNewKeyModal = () => { | |
| setShowNewKeyModal(false); | |
| setNewlyCreatedKey(null); | |
| }; | |
| const formatDate = (dateString: string | null) => { | |
| if (!dateString) return "Never"; | |
| return new Date(dateString).toLocaleString(); | |
| }; | |
| return ( | |
| <> | |
| <div className="flex flex-col gap-6"> | |
| <div className="flex items-center justify-between"> | |
| <BrandButton | |
| type="button" | |
| variant="primary" | |
| onClick={() => setCreateModalOpen(true)} | |
| > | |
| {t(I18nKey.SETTINGS$CREATE_API_KEY)} | |
| </BrandButton> | |
| </div> | |
| <p className="text-sm text-gray-300"> | |
| <Trans | |
| i18nKey={I18nKey.SETTINGS$API_KEYS_DESCRIPTION} | |
| components={{ | |
| a: ( | |
| <a | |
| href="https://docs.all-hands.dev/usage/cloud/cloud-api" | |
| target="_blank" | |
| rel="noopener noreferrer" | |
| className="text-blue-400 hover:underline" | |
| > | |
| API documentation | |
| </a> | |
| ), | |
| }} | |
| /> | |
| </p> | |
| {isLoading && ( | |
| <div className="flex justify-center p-4"> | |
| <LoadingSpinner size="large" /> | |
| </div> | |
| )} | |
| {!isLoading && Array.isArray(apiKeys) && apiKeys.length > 0 && ( | |
| <div className="border border-tertiary rounded-md overflow-hidden"> | |
| <table className="w-full"> | |
| <thead className="bg-base-tertiary"> | |
| <tr> | |
| <th className="text-left p-3 text-sm font-medium"> | |
| {t(I18nKey.SETTINGS$NAME)} | |
| </th> | |
| <th className="text-left p-3 text-sm font-medium"> | |
| {t(I18nKey.SETTINGS$CREATED_AT)} | |
| </th> | |
| <th className="text-left p-3 text-sm font-medium"> | |
| {t(I18nKey.SETTINGS$LAST_USED)} | |
| </th> | |
| <th className="text-right p-3 text-sm font-medium"> | |
| {t(I18nKey.SETTINGS$ACTIONS)} | |
| </th> | |
| </tr> | |
| </thead> | |
| <tbody> | |
| {apiKeys.map((key) => ( | |
| <tr key={key.id} className="border-t border-tertiary"> | |
| <td className="p-3 text-sm">{key.name}</td> | |
| <td className="p-3 text-sm"> | |
| {formatDate(key.created_at)} | |
| </td> | |
| <td className="p-3 text-sm"> | |
| {formatDate(key.last_used_at)} | |
| </td> | |
| <td className="p-3 text-right"> | |
| <button | |
| type="button" | |
| className="underline" | |
| onClick={() => { | |
| setKeyToDelete(key); | |
| setDeleteModalOpen(true); | |
| }} | |
| > | |
| {t(I18nKey.BUTTON$DELETE)} | |
| </button> | |
| </td> | |
| </tr> | |
| ))} | |
| </tbody> | |
| </table> | |
| </div> | |
| )} | |
| </div> | |
| {/* Create API Key Modal */} | |
| <CreateApiKeyModal | |
| isOpen={createModalOpen} | |
| onClose={handleCloseCreateModal} | |
| onKeyCreated={handleKeyCreated} | |
| /> | |
| {/* Delete API Key Modal */} | |
| <DeleteApiKeyModal | |
| isOpen={deleteModalOpen} | |
| keyToDelete={keyToDelete} | |
| onClose={handleCloseDeleteModal} | |
| /> | |
| {/* Show New API Key Modal */} | |
| <NewApiKeyModal | |
| isOpen={showNewKeyModal} | |
| newlyCreatedKey={newlyCreatedKey} | |
| onClose={handleCloseNewKeyModal} | |
| /> | |
| </> | |
| ); | |
| } | |