"use client"; import { useState, useEffect, type SyntheticEvent } from "react"; import { Plus, History, Key, RotateCw, Trash2, Eye, EyeOff } from "lucide-react"; import Link from "next/link"; import { Button } from "@/components/ui/button"; import { Card, CardContent, CardHeader, CardTitle, CardDescription } from "@/components/ui/card"; import { Input } from "@/components/ui/input"; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from "@/components/ui/select"; import { fetchCredentials, createCredential, deleteCredential, rotateCredential, CredentialType, CredentialScope, type Credential, type CreateCredentialDto, } from "@/lib/api/credentials"; import { useWorkspaceId } from "@/lib/hooks"; /* --------------------------------------------------------------------------- Constants --------------------------------------------------------------------------- */ const CREDENTIAL_TYPE_LABELS: Record = { [CredentialType.API_KEY]: "API Key", [CredentialType.OAUTH_TOKEN]: "OAuth Token", [CredentialType.ACCESS_TOKEN]: "Access Token", [CredentialType.SECRET]: "Secret", [CredentialType.PASSWORD]: "Password", [CredentialType.CUSTOM]: "Custom", }; const CREDENTIAL_SCOPE_LABELS: Record = { [CredentialScope.USER]: "User", [CredentialScope.WORKSPACE]: "Workspace", [CredentialScope.SYSTEM]: "System", }; /* --------------------------------------------------------------------------- Add Credential Dialog --------------------------------------------------------------------------- */ interface AddCredentialDialogProps { open: boolean; onOpenChange: (open: boolean) => void; onSubmit: (data: CreateCredentialDto) => Promise; isSubmitting: boolean; } function AddCredentialDialog({ open, onOpenChange, onSubmit, isSubmitting, }: AddCredentialDialogProps): React.ReactElement | null { const [name, setName] = useState(""); const [provider, setProvider] = useState(""); const [type, setType] = useState(CredentialType.API_KEY); const [scope, setScope] = useState(CredentialScope.WORKSPACE); const [value, setValue] = useState(""); const [description, setDescription] = useState(""); const [showValue, setShowValue] = useState(false); const [formError, setFormError] = useState(null); function resetForm(): void { setName(""); setProvider(""); setType(CredentialType.API_KEY); setScope(CredentialScope.WORKSPACE); setValue(""); setDescription(""); setShowValue(false); setFormError(null); } async function handleSubmit(e: SyntheticEvent): Promise { e.preventDefault(); setFormError(null); const trimmedName = name.trim(); if (!trimmedName) { setFormError("Name is required."); return; } const trimmedProvider = provider.trim(); if (!trimmedProvider) { setFormError("Provider is required."); return; } const trimmedValue = value.trim(); if (!trimmedValue) { setFormError("Credential value is required."); return; } try { const payload: CreateCredentialDto = { name: trimmedName, provider: trimmedProvider, type, scope, value: trimmedValue, }; const trimmedDesc = description.trim(); if (trimmedDesc) { payload.description = trimmedDesc; } await onSubmit(payload); resetForm(); } catch (err: unknown) { setFormError(err instanceof Error ? err.message : "Failed to create credential."); } } if (!open) return null; return (
{/* Backdrop */}
{ if (!isSubmitting) { resetForm(); onOpenChange(false); } }} /> {/* Dialog */}

Add Credential

Securely store an API key, token, or secret.

{ void handleSubmit(e); }} > {/* Name */}
) => { setName(e.target.value); }} placeholder="e.g. GitHub Personal Access Token" maxLength={255} autoFocus />
{/* Provider */}
) => { setProvider(e.target.value); }} placeholder="e.g. github, openai, custom" maxLength={100} />

The service or system this credential belongs to.

{/* Type */}
{/* Scope */}
{/* Value */}
) => { setValue(e.target.value); }} placeholder="Paste your secret value here" style={{ paddingRight: "40px" }} />

The value is encrypted at rest and never returned in plaintext.

{/* Description */}