fix(web): prevent auto-fetch when API key is missing in fetch models dialog

When a provider requires an API key but none is set, the dialog now shows
the warning without triggering a doomed fetch attempt. Fetch is deferred
until the user provides a key.
This commit is contained in:
SiYue-ZO 2026-05-06 18:07:54 +08:00
parent ee5cf2b88a
commit b4746b9b44

View file

@ -2,7 +2,7 @@ import { IconDownload, IconLoader2 } from "@tabler/icons-react"
import { useCallback, useEffect, useState } from "react" import { useCallback, useEffect, useState } from "react"
import { useTranslation } from "react-i18next" import { useTranslation } from "react-i18next"
import { fetchUpstreamModels, type UpstreamModel } from "@/api/models" import { type UpstreamModel, fetchUpstreamModels } from "@/api/models"
import { Button } from "@/components/ui/button" import { Button } from "@/components/ui/button"
import { import {
Dialog, Dialog,
@ -64,12 +64,12 @@ export function FetchModelsDialog({
} }
}, [provider, apiKey, apiBase, t]) }, [provider, apiKey, apiBase, t])
// Auto-fetch when dialog opens // Auto-fetch when dialog opens (skip if provider requires API key but none is set)
useEffect(() => { useEffect(() => {
if (open && provider) { if (open && provider && !(needsKey && !apiKey)) {
handleFetch() handleFetch()
} }
}, [open, provider, handleFetch]) }, [open, provider, apiKey, needsKey, handleFetch])
const handleFill = () => { const handleFill = () => {
onFill(Array.from(selected)) onFill(Array.from(selected))
@ -137,7 +137,7 @@ export function FetchModelsDialog({
)} )}
{fetching && ( {fetching && (
<div className="flex items-center justify-center gap-2 py-8 text-muted-foreground"> <div className="text-muted-foreground flex items-center justify-center gap-2 py-8">
<IconLoader2 className="size-5 animate-spin" /> <IconLoader2 className="size-5 animate-spin" />
<span>{t("models.fetch.fetching")}</span> <span>{t("models.fetch.fetching")}</span>
</div> </div>
@ -167,10 +167,11 @@ export function FetchModelsDialog({
onChange={(e) => setFilter(e.target.value)} onChange={(e) => setFilter(e.target.value)}
className="h-8" className="h-8"
/> />
<div className="flex items-center justify-between text-xs text-muted-foreground"> <div className="text-muted-foreground flex items-center justify-between text-xs">
<span> <span>
{t("models.fetch.found", { count: models.length })} {t("models.fetch.found", { count: models.length })}
{filter && ` ${t("models.fetch.shown", { count: filteredModels.length })}`} {filter &&
` ${t("models.fetch.shown", { count: filteredModels.length })}`}
</span> </span>
<button <button
type="button" type="button"
@ -186,7 +187,7 @@ export function FetchModelsDialog({
{filteredModels.map((m) => ( {filteredModels.map((m) => (
<label <label
key={m.id} key={m.id}
className="flex cursor-pointer items-center gap-2 rounded-sm px-2 py-1.5 text-sm hover:bg-accent" className="hover:bg-accent flex cursor-pointer items-center gap-2 rounded-sm px-2 py-1.5 text-sm"
> >
<input <input
type="checkbox" type="checkbox"