fix: resolve v3.7.0 stabilization issues (#1566, #1560, #1559)

This commit is contained in:
diegosouzapw
2026-04-24 15:23:43 -03:00
parent 7ed15c742f
commit 5b5e21a99e
3 changed files with 54 additions and 29 deletions

View File

@@ -1051,7 +1051,7 @@ export default function ProviderDetailPage() {
name: cm.name || cm.id, name: cm.name || cm.id,
source: cm.source === "api-sync" ? "api-sync" : "custom", source: cm.source === "api-sync" ? "api-sync" : "custom",
})); }));
return [...builtInModels, ...syncedExtras, ...customExtras]; return [...builtInModels, ...syncedExtras];
}, [providerId, registryModels, syncedAvailableModels, modelMeta.customModels]); }, [providerId, registryModels, syncedAvailableModels, modelMeta.customModels]);
const providerAlias = getProviderAlias(providerId); const providerAlias = getProviderAlias(providerId);
const isManagedAvailableModelsProvider = isCompatible || providerId === "openrouter"; const isManagedAvailableModelsProvider = isCompatible || providerId === "openrouter";
@@ -2680,11 +2680,7 @@ export default function ProviderDetailPage() {
</p> </p>
</div> </div>
<div className="flex items-center gap-2"> <div className="flex items-center gap-2">
<Button <Button size="sm" icon="add" onClick={() => setShowAddApiKeyModal(true)}>
size="sm"
icon="add"
onClick={() => setShowAddApiKeyModal(true)}
>
{t("add")} {t("add")}
</Button> </Button>
<Button <Button
@@ -3076,15 +3072,13 @@ export default function ProviderDetailPage() {
{renderModelsSection()} {renderModelsSection()}
{/* Custom Models — available for all providers */} {/* Custom Models — available for all providers */}
{!isManagedAvailableModelsProvider && ( <CustomModelsSection
<CustomModelsSection providerId={providerId}
providerId={providerId} providerAlias={providerDisplayAlias}
providerAlias={providerDisplayAlias} copied={copied}
copied={copied} onCopy={copy}
onCopy={copy} onModelsChanged={fetchProviderModelMeta}
onModelsChanged={fetchProviderModelMeta} />
/>
)}
</Card> </Card>
)} )}
@@ -3875,6 +3869,7 @@ function CustomModelsSection({
const [editingApiFormat, setEditingApiFormat] = useState("chat-completions"); const [editingApiFormat, setEditingApiFormat] = useState("chat-completions");
const [editingEndpoints, setEditingEndpoints] = useState<string[]>(["chat"]); const [editingEndpoints, setEditingEndpoints] = useState<string[]>(["chat"]);
const [savingModelId, setSavingModelId] = useState<string | null>(null); const [savingModelId, setSavingModelId] = useState<string | null>(null);
const [togglingModelId, setTogglingModelId] = useState<string | null>(null);
const customMap = useMemo(() => buildCompatMap(customModels), [customModels]); const customMap = useMemo(() => buildCompatMap(customModels), [customModels]);
const overrideMap = useMemo(() => buildCompatMap(modelCompatOverrides), [modelCompatOverrides]); const overrideMap = useMemo(() => buildCompatMap(modelCompatOverrides), [modelCompatOverrides]);
@@ -3943,6 +3938,28 @@ function CustomModelsSection({
} }
}; };
const handleToggleHidden = async (modelId: string, hidden: boolean) => {
setTogglingModelId(modelId);
try {
const res = await fetch(
`/api/provider-models?provider=${encodeURIComponent(providerId)}&modelId=${encodeURIComponent(modelId)}`,
{
method: "PATCH",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ isHidden: hidden }),
}
);
if (res.ok) {
await fetchCustomModels();
onModelsChanged?.();
}
} catch (e) {
console.error("Failed to toggle model visibility:", e);
} finally {
setTogglingModelId(null);
}
};
const beginEdit = (model) => { const beginEdit = (model) => {
setEditingModelId(model.id); setEditingModelId(model.id);
setEditingApiFormat(model.apiFormat || "chat-completions"); setEditingApiFormat(model.apiFormat || "chat-completions");
@@ -4311,6 +4328,16 @@ function CustomModelsSection({
showDeveloperToggle showDeveloperToggle
disabled={savingModelId === model.id} disabled={savingModelId === model.id}
/> />
<button
onClick={() => handleToggleHidden(model.id, !model.isHidden)}
disabled={togglingModelId === model.id}
className="rounded p-1 text-text-muted hover:bg-sidebar hover:text-primary disabled:opacity-50"
title={model.isHidden ? t("unhideModel") : t("hideModel")}
>
<span className="material-symbols-outlined text-sm">
{model.isHidden ? "visibility_off" : "visibility"}
</span>
</button>
<button <button
onClick={() => handleRemove(model.id)} onClick={() => handleRemove(model.id)}
className="rounded p-1 text-red-500 hover:bg-red-50" className="rounded p-1 text-red-500 hover:bg-red-50"

View File

@@ -545,7 +545,15 @@ export default function ProxyRegistryManager() {
title={editingId ? t("modalEditTitle") : t("modalCreateTitle")} title={editingId ? t("modalEditTitle") : t("modalCreateTitle")}
maxWidth="lg" maxWidth="lg"
> >
<div className="flex flex-col gap-3"> <form
className="flex flex-col gap-3"
onSubmit={(e) => {
e.preventDefault();
handleSave();
}}
autoComplete="off"
data-1p-ignore="true"
>
<div className="grid grid-cols-2 gap-3"> <div className="grid grid-cols-2 gap-3">
<div> <div>
<label className="text-xs text-text-muted mb-1 block">{t("labelName")}</label> <label className="text-xs text-text-muted mb-1 block">{t("labelName")}</label>
@@ -643,7 +651,7 @@ export default function ProxyRegistryManager() {
Save Save
</Button> </Button>
</div> </div>
</div> </form>
</Modal> </Modal>
<Modal <Modal

View File

@@ -105,12 +105,7 @@ export async function POST(request: Request) {
} }
const existingConnections = await getProviderConnections({ provider }); const existingConnections = await getProviderConnections({ provider });
if (!allowMultipleCompatibleConnections && existingConnections.length > 0) { // Allow multiple connections for compatible nodes exactly like first-party providers
return NextResponse.json(
{ error: "Only one connection is allowed for this OpenAI Compatible node" },
{ status: 400 }
);
}
providerSpecificData = { providerSpecificData = {
...(providerSpecificData || {}), ...(providerSpecificData || {}),
@@ -135,12 +130,7 @@ export async function POST(request: Request) {
} }
const existingConnections = await getProviderConnections({ provider }); const existingConnections = await getProviderConnections({ provider });
if (!allowMultipleCompatibleConnections && existingConnections.length > 0) { // Allow multiple connections for compatible nodes exactly like first-party providers
return NextResponse.json(
{ error: "Only one connection is allowed for this Anthropic Compatible node" },
{ status: 400 }
);
}
providerSpecificData = { providerSpecificData = {
...(providerSpecificData || {}), ...(providerSpecificData || {}),