"use client"; import { AiConfigBlocks } from "@app/components/ai-client-config/AiConfigBlocks"; import { Button } from "@app/components/ui/button"; import { Collapsible, CollapsibleContent, CollapsibleTrigger } from "@app/components/ui/collapsible"; import { OptionSelect } from "@app/components/OptionSelect"; import type { AiClientAuthInput, AiClientId, AiClientPresetId } from "@app/lib/aiClientConfig"; import { buildAiClientGuide } from "@app/lib/aiClientConfig"; import { cn } from "@app/lib/cn"; import { ChevronDown, Loader2 } from "lucide-react"; import { useTheme } from "next-themes"; import Image from "next/image"; import { useTranslations } from "next-intl"; import { useEffect, useMemo, useState } from "react"; type AiClientConfigCardProps = { clientId: AiClientId; name: string; endpoint: string; keyAuth: AiClientAuthInput; description: string; iconSrc: { light: string; dark: string }; resourceNiceId?: string; }; type SetupMode = "cli" | "manual"; export function AiClientConfigCard({ clientId, name, endpoint, keyAuth, description, iconSrc, resourceNiceId }: AiClientConfigCardProps) { const t = useTranslations(); const { theme } = useTheme(); const [resolvedIconSrc, setResolvedIconSrc] = useState(iconSrc.light); const [open, setOpen] = useState(false); const [presetId, setPresetId] = useState("default"); const [setupMode, setSetupMode] = useState("cli"); const [revealedKey, setRevealedKey] = useState(null); const [revealing, setRevealing] = useState(false); const [revealError, setRevealError] = useState(false); useEffect(() => { let lightOrDark = theme; if (theme === "system" || !theme) { lightOrDark = window.matchMedia("(prefers-color-scheme: dark)") .matches ? "dark" : "light"; } setResolvedIconSrc( lightOrDark === "dark" ? iconSrc.dark : iconSrc.light ); }, [theme, iconSrc]); const reveal = () => { if (keyAuth.mode !== "keyed" || revealedKey !== null || revealing) { return; } setRevealing(true); setRevealError(false); keyAuth .getKeyText() .then(setRevealedKey) .catch(() => setRevealError(true)) .finally(() => setRevealing(false)); }; const handleOpenChange = (next: boolean) => { setOpen(next); if (next) { reveal(); } }; const guide = useMemo(() => { if (keyAuth.mode === "keyless") { return buildAiClientGuide( clientId, endpoint, { mode: "keyless" }, resourceNiceId ); } if (revealedKey === null) { return null; } return buildAiClientGuide( clientId, endpoint, { mode: "keyed", key: revealedKey }, resourceNiceId ); }, [clientId, endpoint, keyAuth.mode, revealedKey, resourceNiceId]); const preset = guide?.presets.find((p) => p.id === presetId) ?? guide?.presets[0]; const manualContent = guide ? (
{guide.presets.length > 1 ? ( label={t("aiClientConfigPreset")} options={guide.presets.map((p) => ({ value: p.id, label: p.label }))} value={preset?.id ?? presetId} onChange={setPresetId} cols={2} /> ) : null} {preset ? ( ) : null}
) : null; return ( {name}

{name}

{description}

{!guide && revealing ? (
) : null} {!guide && revealError ? (

{t("aiClientConfigRevealError")}

) : null} {guide ? ( guide.cli ? (
label={t("aiClientConfigSetup")} options={[ { value: "cli", label: t("aiClientConfigTabCli") }, { value: "manual", label: t("aiClientConfigTabManual") } ]} value={setupMode} onChange={setSetupMode} cols={2} /> {setupMode === "cli" ? ( ) : ( manualContent )}
) : ( manualContent ) ) : null}
); }