fix(cloudflare-ai): support accountId in bulk key import (#2449)

Bulk import now parses name|apiKey|accountId lines for Cloudflare AI and
forwards accountId via providerSpecificData, with a provider-specific
placeholder and format hint.
This commit is contained in:
Rizkal 2026-07-10 12:05:51 +07:00 committed by decolua
parent b25e10160d
commit 5cdcf67484

View file

@ -41,6 +41,10 @@ export default function AddApiKeyModal({ isOpen, provider, providerName, isCompa
const [validating, setValidating] = useState(false); const [validating, setValidating] = useState(false);
const [validationResult, setValidationResult] = useState(null); const [validationResult, setValidationResult] = useState(null);
const [saving, setSaving] = useState(false); const [saving, setSaving] = useState(false);
const bulkPlaceholder = isCloudflareAi
? `name1|sk-key1|acc123456\nname2|sk-key2|def789012\nsk-key-only-auto-named`
: BULK_PLACEHOLDER;
const [mode, setMode] = useState("single"); // "single" | "bulk" const [mode, setMode] = useState("single"); // "single" | "bulk"
const [bulkText, setBulkText] = useState(""); const [bulkText, setBulkText] = useState("");
const [bulkResult, setBulkResult] = useState(null); // { success, failed } const [bulkResult, setBulkResult] = useState(null); // { success, failed }
@ -135,14 +139,31 @@ export default function AddApiKeyModal({ isOpen, provider, providerName, isCompa
let failed = 0; let failed = 0;
for (let i = 0; i < lines.length; i++) { for (let i = 0; i < lines.length; i++) {
const parts = lines[i].split("|"); const parts = lines[i].split("|");
const apiKey = parts.length >= 2 ? parts.slice(1).join("|").trim() : parts[0].trim();
const baseName = parts.length >= 2 ? parts[0].trim() : "Key"; const baseName = parts.length >= 2 ? parts[0].trim() : "Key";
const name = `${baseName} ${i + 1}`; const name = `${baseName} ${i + 1}`;
let apiKey;
let providerSpecificData;
if (isCloudflareAi && parts.length >= 3) {
// Format: name|apiKey|accountId
apiKey = parts.slice(1, -1).join("|").trim();
providerSpecificData = { accountId: parts[parts.length - 1].trim() };
} else {
apiKey = parts.length >= 2 ? parts.slice(1).join("|").trim() : parts[0].trim();
}
try { try {
const res = await fetch("/api/providers", { const res = await fetch("/api/providers", {
method: "POST", method: "POST",
headers: { "Content-Type": "application/json" }, headers: { "Content-Type": "application/json" },
body: JSON.stringify({ provider, apiKey, name, priority: 1, testStatus: "unknown" }), body: JSON.stringify({
provider,
apiKey,
name,
priority: 1,
testStatus: "unknown",
...(providerSpecificData ? { providerSpecificData } : {}),
}),
}); });
if (res.ok) success++; if (res.ok) success++;
else failed++; else failed++;
@ -168,10 +189,15 @@ export default function AddApiKeyModal({ isOpen, provider, providerName, isCompa
{mode === "bulk" && ( {mode === "bulk" && (
<div className="flex flex-col gap-3"> <div className="flex flex-col gap-3">
<p className="text-xs text-text-muted">One key per line. Format: <code>name|apiKey</code> or just <code>apiKey</code> (auto-named by index).</p> <p className="text-xs text-text-muted">
{isCloudflareAi
? <>One key per line. Format: <code>name|apiKey|accountId</code> or just <code>apiKey</code> (auto-named by index).</>
: <>One key per line. Format: <code>name|apiKey</code> or just <code>apiKey</code> (auto-named by index).</>
}
</p>
<textarea <textarea
className="w-full rounded border border-accent/30 bg-sidebar p-2 text-sm font-mono resize-y min-h-[140px] focus:outline-none focus:ring-1 focus:ring-primary" className="w-full rounded border border-accent/30 bg-sidebar p-2 text-sm font-mono resize-y min-h-[140px] focus:outline-none focus:ring-1 focus:ring-primary"
placeholder={BULK_PLACEHOLDER} placeholder={bulkPlaceholder}
value={bulkText} value={bulkText}
onChange={(e) => setBulkText(e.target.value)} onChange={(e) => setBulkText(e.target.value)}
/> />