import { useState } from "react"; import { useTranslation } from "react-i18next"; import { Plus, RotateCcw, Trash2, Pencil, Zap } from "lucide-react"; import type { Provider } from "@/lib/types"; import { useProviders, useProviderMutations, useRestore, useStatus } from "@/lib/queries"; import { useToast } from "@/components/toast"; import { Badge } from "@/components/ui/badge"; import { Button } from "@/components/ui/button"; import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; import { ProviderForm, type ProviderSubmitInput } from "@/components/ProviderForm"; import { formatProtocolBadge } from "@/lib/utils"; export default function Codex() { const { t } = useTranslation(); const status = useStatus(); const { data, isLoading, isError } = useProviders("codex"); const mutations = useProviderMutations(); const restore = useRestore(); const { show } = useToast(); const [injection, setInjection] = useState | null>(null); const [editing, setEditing] = useState<{ provider: Provider | null } | null>(null); const providers = data?.items ?? []; const active = status.data?.active_codex_provider ?? null; const submitForm = (input: ProviderSubmitInput) => { const target = editing?.provider ?? null; const onSuccess = () => { show(target ? t("providers.updated") : t("providers.created")); setEditing(null); }; const onError = (err: Error) => show(err.message, "error"); if (target) { mutations.update.mutate({ id: target.id, input }, { onSuccess, onError }); } else { mutations.create.mutate(input, { onSuccess, onError }); } }; const apply = (provider: Provider) => { mutations.apply.mutate( { id: provider.id, target: "codex" }, { onSuccess: (result) => { setInjection(result.injection?.table ?? null); show(`${t("codex.activated")}: ${provider.name}`); }, onError: (err: Error) => show(err.message, "error"), }, ); }; const restoreConfig = () => { restore.mutate( { target: "codex" }, { onSuccess: () => { setInjection(null); show(t("codex.restoreDone")); }, onError: (err: Error) => show(err.message, "error"), }, ); }; if (isLoading) return
{t("common.loading")}
; if (isError) return
{t("common.error")}
; return (

{t("codex.title")}

{editing && ( setEditing(null)} /> )} {t("codex.status")}
{active ? t("codex.injected") : t("codex.notInjected")} {active && {active.name}}
{t("codex.configPath")}: ~/.codex/config.toml
{t("codex.portHint")}
{injection && ( {t("codex.preview")}
  • model_provider = crossrelay
  • {Object.entries(injection) .sort(([a], [b]) => a.localeCompare(b)) .map(([key, value]) => (
  • {key} = {value}
  • ))}
)} {providers.length === 0 ? ( {t("codex.empty")} ) : (
{providers.map((provider) => (
{provider.name} {provider.enabled_for_codex && {t("codex.activated")}} {provider.preset && {provider.preset}} {provider.protocol && ( {formatProtocolBadge(provider.protocol)} )}
{provider.base_url}
))}
)}
); }