From 26612790fe23dd43dd801bec6a37df74a8bda83d Mon Sep 17 00:00:00 2001 From: lc6464 <64722907+lc6464@users.noreply.github.com> Date: Tue, 31 Mar 2026 09:46:17 +0800 Subject: [PATCH] fix(web): clarify unreachable model status and wording - Show unreachable status in model cards instead of API key preview when service is down - Keep API key placeholder preview in model settings whenever an API key is already saved - Rename model status wording from configured to available across backend, frontend, and i18n - Update backend model status tests to match renamed status semantics --- web/backend/api/model_status.go | 6 +++--- web/backend/api/models_test.go | 16 ++++++++-------- web/frontend/src/api/models.ts | 2 +- .../src/components/models/edit-model-sheet.tsx | 7 ++++--- .../src/components/models/model-card.tsx | 6 +++--- web/frontend/src/i18n/locales/en.json | 2 +- web/frontend/src/i18n/locales/zh.json | 2 +- 7 files changed, 21 insertions(+), 20 deletions(-) diff --git a/web/backend/api/model_status.go b/web/backend/api/model_status.go index 5a1588d32..160c4d257 100644 --- a/web/backend/api/model_status.go +++ b/web/backend/api/model_status.go @@ -16,7 +16,7 @@ import ( const modelProbeTimeout = 800 * time.Millisecond const ( - modelStatusConfigured = "configured" + modelStatusAvailable = "available" modelStatusUnconfigured = "unconfigured" modelStatusUnreachable = "unreachable" ) @@ -60,11 +60,11 @@ func modelConfigurationStatus(m *config.ModelConfig) modelConfigurationSummary { } if requiresRuntimeProbe(m) { if probeLocalModelAvailability(m) { - return modelConfigurationSummary{Available: true, Status: modelStatusConfigured} + return modelConfigurationSummary{Available: true, Status: modelStatusAvailable} } return modelConfigurationSummary{Available: false, Status: modelStatusUnreachable} } - return modelConfigurationSummary{Available: true, Status: modelStatusConfigured} + return modelConfigurationSummary{Available: true, Status: modelStatusAvailable} } func requiresRuntimeProbe(m *config.ModelConfig) bool { diff --git a/web/backend/api/models_test.go b/web/backend/api/models_test.go index cf276a259..e78de1606 100644 --- a/web/backend/api/models_test.go +++ b/web/backend/api/models_test.go @@ -138,17 +138,17 @@ func TestHandleListModels_AvailabilityUsesRuntimeProbesForLocalModels(t *testing if gotStatus["openai-oauth"] != modelStatusUnconfigured { t.Fatalf("openai oauth model status = %q, want %q", gotStatus["openai-oauth"], modelStatusUnconfigured) } - if gotStatus["vllm-local"] != modelStatusConfigured { - t.Fatalf("vllm local model status = %q, want %q", gotStatus["vllm-local"], modelStatusConfigured) + if gotStatus["vllm-local"] != modelStatusAvailable { + t.Fatalf("vllm local model status = %q, want %q", gotStatus["vllm-local"], modelStatusAvailable) } - if gotStatus["ollama-default"] != modelStatusConfigured { - t.Fatalf("ollama default model status = %q, want %q", gotStatus["ollama-default"], modelStatusConfigured) + if gotStatus["ollama-default"] != modelStatusAvailable { + t.Fatalf("ollama default model status = %q, want %q", gotStatus["ollama-default"], modelStatusAvailable) } - if gotStatus["vllm-remote"] != modelStatusConfigured { - t.Fatalf("remote vllm model status = %q, want %q", gotStatus["vllm-remote"], modelStatusConfigured) + if gotStatus["vllm-remote"] != modelStatusAvailable { + t.Fatalf("remote vllm model status = %q, want %q", gotStatus["vllm-remote"], modelStatusAvailable) } - if gotStatus["copilot-gpt-5.4"] != modelStatusConfigured { - t.Fatalf("copilot model status = %q, want %q", gotStatus["copilot-gpt-5.4"], modelStatusConfigured) + if gotStatus["copilot-gpt-5.4"] != modelStatusAvailable { + t.Fatalf("copilot model status = %q, want %q", gotStatus["copilot-gpt-5.4"], modelStatusAvailable) } if len(openAIProbes) != 1 || openAIProbes[0] != "http://127.0.0.1:8000/v1|custom-model|" { t.Fatalf("openAI probes = %#v, want only local vllm probe", openAIProbes) diff --git a/web/frontend/src/api/models.ts b/web/frontend/src/api/models.ts index 7dfbbb863..6fd388656 100644 --- a/web/frontend/src/api/models.ts +++ b/web/frontend/src/api/models.ts @@ -21,7 +21,7 @@ export interface ModelInfo { extra_body?: Record // Meta available: boolean - status?: "configured" | "unconfigured" | "unreachable" + status?: "available" | "unconfigured" | "unreachable" is_default: boolean is_virtual: boolean } diff --git a/web/frontend/src/components/models/edit-model-sheet.tsx b/web/frontend/src/components/models/edit-model-sheet.tsx index 8865f4cdf..52e2d8d9d 100644 --- a/web/frontend/src/components/models/edit-model-sheet.tsx +++ b/web/frontend/src/components/models/edit-model-sheet.tsx @@ -133,9 +133,10 @@ export function EditModelSheet({ } const isOAuth = model?.auth_method === "oauth" - const apiKeyPlaceholder = model?.available + const hasSavedAPIKey = Boolean(model?.api_key) + const apiKeyPlaceholder = hasSavedAPIKey ? maskedSecretPlaceholder( - model.api_key, + model?.api_key ?? "", t("models.field.apiKeyPlaceholderSet"), ) : t("models.field.apiKeyPlaceholder") @@ -161,7 +162,7 @@ export function EditModelSheet({ OAuth - ) : model.api_key ? ( + ) : status === "available" && model.api_key ? ( {model.api_key} diff --git a/web/frontend/src/i18n/locales/en.json b/web/frontend/src/i18n/locales/en.json index 29e9751a1..8a464639e 100644 --- a/web/frontend/src/i18n/locales/en.json +++ b/web/frontend/src/i18n/locales/en.json @@ -170,7 +170,7 @@ "noDefaultHintPrefix": "No default model set yet. Click", "noDefaultHintSuffix": "to set one.", "status": { - "configured": "Configured", + "available": "Available", "unconfigured": "Not configured", "unreachable": "Service unreachable" }, diff --git a/web/frontend/src/i18n/locales/zh.json b/web/frontend/src/i18n/locales/zh.json index d494e5872..9fc6db9e5 100644 --- a/web/frontend/src/i18n/locales/zh.json +++ b/web/frontend/src/i18n/locales/zh.json @@ -170,7 +170,7 @@ "noDefaultHintPrefix": "尚未设置默认模型,点击", "noDefaultHintSuffix": "设为默认。", "status": { - "configured": "已配置", + "available": "可用", "unconfigured": "未配置", "unreachable": "服务不可达" },