import { useEffect, useState } from "react"; import { useToast, useTranslation } from "@termix/plugin-sdk/frontend"; import { FakeSwitch, Input, SettingRow } from "@termix/plugin-sdk/ui"; import { getAiGloballyEnabled, getAiPrivateEndpoints, setAiGloballyEnabled, setAiPrivateEndpoints, } from "../ai-api"; import { notifyAiStatusChanged } from "../use-ai-availability"; /** * The instance-wide switch and the private address allowlist. Stored in the * assistant's own backend rather than plugin settings, so this saves on * change instead of through the page's Save. */ export function AiAccessSettings() { const { t } = useTranslation(); const toast = useToast(); const [enabled, setEnabled] = useState(false); const [endpoints, setEndpoints] = useState(null); useEffect(() => { let cancelled = false; void Promise.allSettled([ getAiGloballyEnabled(), getAiPrivateEndpoints(), ]).then(([enabledResult, endpointsResult]) => { if (cancelled) return; if (enabledResult.status === "fulfilled") setEnabled(enabledResult.value); setEndpoints( endpointsResult.status === "fulfilled" ? endpointsResult.value : [], ); }); return () => { cancelled = true; }; }, []); const toggle = async (next: boolean) => { setEnabled(next); try { await setAiGloballyEnabled(next); notifyAiStatusChanged(); } catch { setEnabled(!next); toast.error(t("admin.updateAiEnabledFailed")); } }; const saveEndpoints = async (hosts: string[]) => { const previous = endpoints ?? []; setEndpoints(hosts); try { setEndpoints(await setAiPrivateEndpoints(hosts)); } catch { setEndpoints(previous); toast.error(t("admin.updateAiEndpointsFailed")); } }; return (
void toggle(next)} /> {enabled && endpoints !== null && (
{t("admin.aiPrivateEndpoints")} {t("admin.aiPrivateEndpointsDesc")} void saveEndpoints( event.target.value .split(",") .map((entry) => entry.trim()) .filter(Boolean), ) } />
)}
); }