From a84477e8153b11ab7f28065e463494634c28ba6b Mon Sep 17 00:00:00 2001 From: decolua Date: Sat, 28 Feb 2026 16:33:18 +0700 Subject: [PATCH] chore: update version and enhance dashboard components - Add a warning message for Windows users in AntigravityToolCard to run the terminal as Administrator for MITM functionality. - Refactor model testing logic in ProviderDetailPage to improve state management and user experience. - Introduce new version notification in Sidebar for available updates. --- package.json | 2 +- .../components/AntigravityToolCard.js | 8 +++ .../dashboard/providers/[id]/page.js | 57 ++++++++++--------- src/app/api/version/route.js | 46 +++++++++++++++ src/shared/components/Sidebar.js | 21 ++++++- 5 files changed, 104 insertions(+), 30 deletions(-) create mode 100644 src/app/api/version/route.js diff --git a/package.json b/package.json index e5c082ff..11b684e0 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "9router-app", - "version": "0.3.17", + "version": "0.3.18", "description": "9Router web dashboard", "private": true, "scripts": { diff --git a/src/app/(dashboard)/dashboard/cli-tools/components/AntigravityToolCard.js b/src/app/(dashboard)/dashboard/cli-tools/components/AntigravityToolCard.js index 368b3990..c9322880 100644 --- a/src/app/(dashboard)/dashboard/cli-tools/components/AntigravityToolCard.js +++ b/src/app/(dashboard)/dashboard/cli-tools/components/AntigravityToolCard.js @@ -351,6 +351,14 @@ export default function AntigravityToolCard({ )} + {/* Windows admin warning */} + {!isRunning && isWindows && ( +
+ warning + Windows: Run terminal (9Router) as Administrator to enable MITM +
+ )} + {/* When stopped: how it works */} {!isRunning && (
diff --git a/src/app/(dashboard)/dashboard/providers/[id]/page.js b/src/app/(dashboard)/dashboard/providers/[id]/page.js index f49afa62..6a499e87 100644 --- a/src/app/(dashboard)/dashboard/providers/[id]/page.js +++ b/src/app/(dashboard)/dashboard/providers/[id]/page.js @@ -25,7 +25,7 @@ export default function ProviderDetailPage() { const [modelAliases, setModelAliases] = useState({}); const [headerImgError, setHeaderImgError] = useState(false); const [modelTestResults, setModelTestResults] = useState({}); - const [testingModels, setTestingModels] = useState(false); + const [testingModelId, setTestingModelId] = useState(null); const [showAddCustomModel, setShowAddCustomModel] = useState(false); const { copied, copy } = useCopyToClipboard(); @@ -259,24 +259,21 @@ export default function ProviderDetailPage() { } }; - const handleTestModels = async () => { - if (testingModels) return; - const conn = connections.find((c) => c.isActive !== false) || connections[0]; - if (!conn) return; - setTestingModels(true); - setModelTestResults({}); + const handleTestModel = async (modelId) => { + if (testingModelId) return; + setTestingModelId(modelId); try { - const res = await fetch(`/api/providers/${conn.id}/test-models`, { method: "POST" }); + const res = await fetch("/api/models/test", { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ model: `${providerStorageAlias}/${modelId}` }), + }); const data = await res.json(); - if (res.ok) { - const map = {}; - for (const r of data.results || []) map[r.modelId] = r.ok ? "ok" : "error"; - setModelTestResults(map); - } + setModelTestResults((prev) => ({ ...prev, [modelId]: data.ok ? "ok" : "error" })); } catch { - // silent fail + setModelTestResults((prev) => ({ ...prev, [modelId]: "error" })); } finally { - setTestingModels(false); + setTestingModelId(null); } }; @@ -342,6 +339,8 @@ export default function ProviderDetailPage() { onSetAlias={(alias) => handleSetAlias(model.id, alias, providerStorageAlias)} onDeleteAlias={() => handleDeleteAlias(existingAlias)} testStatus={modelTestResults[model.id]} + onTest={connections.length > 0 ? () => handleTestModel(model.id) : undefined} + isTesting={testingModelId === model.id} /> ); })} @@ -559,18 +558,6 @@ export default function ProviderDetailPage() {

{providerInfo.passthroughModels ? "Model Aliases" : "Available Models"}

- {connections.length > 0 && ( - - )}
{renderModelsSection()} @@ -638,7 +625,7 @@ export default function ProviderDetailPage() { ); } -function ModelRow({ model, fullModel, alias, copied, onCopy, testStatus, isCustom, onDeleteAlias }) { +function ModelRow({ model, fullModel, alias, copied, onCopy, testStatus, isCustom, onDeleteAlias, onTest, isTesting }) { const borderColor = testStatus === "ok" ? "border-green-500/40" : testStatus === "error" @@ -660,6 +647,18 @@ function ModelRow({ model, fullModel, alias, copied, onCopy, testStatus, isCusto {testStatus === "ok" ? "check_circle" : testStatus === "error" ? "cancel" : "smart_toy"} {fullModel} + {onTest && ( + + )}