Add Cloudflare AI provider support and enhance connection management

- Introduced Cloudflare AI as a new provider with specific configurations in providerModels.js and providers.js.
- Updated DefaultExecutor to handle account ID resolution for Cloudflare AI connections.
- Enhanced AddApiKeyModal and EditConnectionModal to include account ID input for Cloudflare AI.
- Implemented validation for Cloudflare AI API key connections in testUtils.js and route.js.
- Updated UI components to reflect changes in provider management and connection handling.
This commit is contained in:
decolua 2026-04-28 11:07:39 +07:00
parent 111e78940a
commit 1bb621317d
18 changed files with 325 additions and 71 deletions

View file

@ -0,0 +1,86 @@
"use client";
import { useEffect, useState } from "react";
import PropTypes from "prop-types";
import Card from "./Card";
import Select from "./Select";
import Badge from "./Badge";
const NONE_PROXY_POOL_VALUE = "__none__";
export default function NoAuthProxyCard({ providerId }) {
const [proxyPools, setProxyPools] = useState([]);
const [proxyPoolId, setProxyPoolId] = useState(NONE_PROXY_POOL_VALUE);
const [saving, setSaving] = useState(false);
const [savedFlash, setSavedFlash] = useState(false);
useEffect(() => {
let cancelled = false;
Promise.all([
fetch("/api/proxy-pools?isActive=true", { cache: "no-store" }).then((r) => r.ok ? r.json() : { proxyPools: [] }),
fetch("/api/settings", { cache: "no-store" }).then((r) => r.ok ? r.json() : {}),
]).then(([poolData, settingsData]) => {
if (cancelled) return;
setProxyPools(poolData.proxyPools || []);
const override = (settingsData.providerStrategies || {})[providerId] || {};
setProxyPoolId(override.proxyPoolId || NONE_PROXY_POOL_VALUE);
}).catch(() => {});
return () => { cancelled = true; };
}, [providerId]);
const handleChange = async (newValue) => {
setProxyPoolId(newValue);
setSaving(true);
try {
const res = await fetch("/api/settings", { cache: "no-store" });
const data = res.ok ? await res.json() : {};
const current = data.providerStrategies || {};
const override = { ...(current[providerId] || {}) };
if (newValue === NONE_PROXY_POOL_VALUE) delete override.proxyPoolId;
else override.proxyPoolId = newValue;
const updated = { ...current };
if (Object.keys(override).length === 0) delete updated[providerId];
else updated[providerId] = override;
await fetch("/api/settings", {
method: "PATCH",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ providerStrategies: updated }),
});
setSavedFlash(true);
setTimeout(() => setSavedFlash(false), 1500);
} catch (e) {
console.log("Save proxyPoolId error:", e);
} finally {
setSaving(false);
}
};
return (
<Card>
<div className="flex items-center gap-3 mb-4">
<div className="inline-flex items-center justify-center w-10 h-10 rounded-full bg-green-500/10 text-green-500">
<span className="material-symbols-outlined text-[20px]">lock_open</span>
</div>
<div className="flex-1">
<p className="text-sm font-medium">No authentication required</p>
<p className="text-xs text-text-muted">This provider is ready to use. Optionally route requests through a proxy pool to bypass IP-based limits.</p>
</div>
{savedFlash && <Badge variant="success" size="sm">Saved</Badge>}
</div>
<Select
label="Proxy Pool"
value={proxyPoolId}
onChange={(e) => handleChange(e.target.value)}
disabled={saving}
options={[
{ value: NONE_PROXY_POOL_VALUE, label: "None (direct)" },
...proxyPools.map((pool) => ({ value: pool.id, label: pool.name })),
]}
/>
</Card>
);
}
NoAuthProxyCard.propTypes = {
providerId: PropTypes.string.isRequired,
};