import { Button } from "@/src/components/ui/button"; import { api } from "@/src/utils/api"; import { useState } from "react"; import { PlusIcon } from "lucide-react"; import { Dialog, DialogBody, DialogContent, DialogFooter, DialogHeader, DialogTitle, DialogTrigger, } from "@/src/components/ui/dialog"; import { CodeView } from "@/src/components/ui/CodeJsonViewer"; import { useHasProjectAccess } from "@/src/features/rbac/utils/checkProjectAccess"; import { useHasOrganizationAccess } from "@/src/features/rbac/utils/checkOrganizationAccess"; import { usePostHogClientCapture } from "@/src/features/posthog-analytics/usePostHogClientCapture"; import { Input } from "@/src/components/ui/input"; import { useLangfuseEnvCode } from "@/src/features/public-api/hooks/useLangfuseEnvCode"; import { Label } from "@/src/components/ui/label"; import { cn } from "@/src/utils/tailwind"; import { SubHeader } from "@/src/components/layouts/header"; type ApiKeyScope = "project" | "organization"; export function CreateApiKeyButton(props: { entityId: string; scope: ApiKeyScope; }) { const utils = api.useUtils(); const capture = usePostHogClientCapture(); const hasProjectAccess = useHasProjectAccess({ projectId: props.entityId, scope: "apiKeys:CUD", }); const hasOrganizationAccess = useHasOrganizationAccess({ organizationId: props.entityId, scope: "organization:CRUD_apiKeys", }); const hasAccess = props.scope === "project" ? hasProjectAccess : hasOrganizationAccess; const mutCreateProjectApiKey = api.projectApiKeys.create.useMutation({ onSuccess: () => utils.projectApiKeys.invalidate(), }); const mutCreateOrgApiKey = api.organizationApiKeys.create.useMutation({ onSuccess: () => utils.organizationApiKeys.invalidate(), }); const [open, setOpen] = useState(false); const [note, setNote] = useState(""); const [generatedKeys, setGeneratedKeys] = useState<{ secretKey: string; publicKey: string; } | null>(null); const handleOpenChange = (newOpen: boolean) => { setOpen(newOpen); if (!newOpen) { // Reset state when closing setGeneratedKeys(null); setNote(""); } }; const createApiKey = () => { if (props.scope === "project") { mutCreateProjectApiKey .mutateAsync({ projectId: props.entityId, note: note || undefined, }) .then(({ secretKey, publicKey }) => { setGeneratedKeys({ secretKey, publicKey, }); capture(`${props.scope}_settings:api_key_create`); }) .catch((error) => { console.error(error); }); } else { mutCreateOrgApiKey .mutateAsync({ orgId: props.entityId, note: note || undefined, }) .then(({ secretKey, publicKey }) => { setGeneratedKeys({ secretKey, publicKey, }); capture(`${props.scope}_settings:api_key_create`); }) .catch((error) => { console.error(error); }); } }; if (!hasAccess) return null; return ( e.preventDefault()}> {generatedKeys ? "API Keys" : "Create API Keys"} {generatedKeys ? ( ) : (
setNote(e.target.value)} onKeyDown={(e) => { if (e.key === "Enter") { createApiKey(); } }} className="mt-1.5" />
)}
{!generatedKeys && ( )}
); } export const ApiKeyRender = ({ scope, generatedKeys, className, }: { scope: ApiKeyScope; generatedKeys?: { secretKey: string; publicKey: string }; className?: string; }) => { const envCode = useLangfuseEnvCode(generatedKeys); return (
This key can only be viewed once. You can always create new keys in the {scope} settings.
); };