mirror of
https://github.com/diegosouzapw/OmniRoute.git
synced 2026-07-31 04:12:10 +03:00
fix(dashboard): switch to visible filter after auto-hiding failed models in test-all (#4887) (#4991)
* fix(dashboard): switch to visible filter after auto-hiding failed models in OAuth provider test-all (#4887) * test(dashboard): move #4887 test into tests/unit/ui so a CI runner collects it --------- Co-authored-by: Diego Rodrigues de Sa e Souza <souzamiriamrodrigues790@gmail.com>
This commit is contained in:
committed by
GitHub
parent
0412b128c0
commit
af32e0041c
@@ -12,8 +12,8 @@ _In development — bullets added per PR; finalized at release._
|
||||
|
||||
### 🔧 Bug Fixes
|
||||
|
||||
- **fix(sse):** auto-combo now soft-penalizes exhausted provider connections so dead providers stop winning. A connection in a terminal/transient status (`credits_exhausted` / `rate_limited` / `banned` / `expired` / future-dated `unavailable`) with no numeric quota fetcher used to keep `quotaRemaining=100` and score identically to a healthy provider — routing kept picking it. With the quota-preflight HARD cutoff OFF (the default), such a candidate is no longer hard-blocked (which would surface a misleading "below quota cutoff" 429); instead its auto-combo score is multiplied by `STATUS_SOFT_DEPRIORITIZE_FACTOR` (default 0.5) so it ranks strictly below an otherwise-identical healthy candidate. The existing opt-in hard-cutoff path is unchanged. (#4540)
|
||||
- **fix(dashboard):** show custom provider given-name instead of internal id across dashboard pages — cache, combo health, compression analytics, cost overview, health/autopilot, provider stats, route explainability, provider utilization, runtime. Adds shared `resolveProviderName` resolver and `useProviderNodeMap` hook. (#4603)
|
||||
- **fix(dashboard):** on OAuth providers (e.g. GLM Coding), "Test all models" with auto-hide-failed now switches the model list to the "visible" filter after the run, so just-hidden failed models actually disappear on-screen — parity with the passthrough-provider path (#3610). Previously they were hidden in the DB but stayed visible under the "All" filter, so it looked like nothing was hidden. (#4887)
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -26,6 +26,7 @@ import {
|
||||
providerText,
|
||||
testAllResultsText,
|
||||
evaluateTestAllEntry,
|
||||
shouldSwitchToVisibleFilter,
|
||||
type ProviderMessageTranslator,
|
||||
type CompatByProtocolMap,
|
||||
} from "../providerPageHelpers";
|
||||
@@ -391,6 +392,14 @@ export function useModelVisibilityHandlers({
|
||||
notify.info(testAllResultsText(t, ok, ok + error));
|
||||
if (hiddenCount > 0) {
|
||||
notify.info(providerText(t, "testAllFailedHidden", "{count} hidden", { count: hiddenCount }));
|
||||
// Bug #4887: switch to "visible" so the models we just auto-hid disappear
|
||||
// on-screen — parity with PassthroughModelsSection (#3610). Without this,
|
||||
// failed models were hidden in the DB but stayed visible under the "All"
|
||||
// filter, so on GLM (and other OAuth providers using this hook's handleTestAll)
|
||||
// it looked like nothing was hidden.
|
||||
if (shouldSwitchToVisibleFilter({ autoHideFailed, hiddenCount })) {
|
||||
setVisibilityFilter("visible");
|
||||
}
|
||||
}
|
||||
setTestingAll(false);
|
||||
setTestProgress(null);
|
||||
|
||||
142
tests/unit/ui/use-model-visibility-handlers-test-all.test.tsx
Normal file
142
tests/unit/ui/use-model-visibility-handlers-test-all.test.tsx
Normal file
@@ -0,0 +1,142 @@
|
||||
// @vitest-environment jsdom
|
||||
//
|
||||
// Regression for #4887: on OAuth providers (e.g. GLM Coding), "Test all models"
|
||||
// with auto-hide-failed enabled hid failed models in the DB but they STAYED on
|
||||
// screen, so it looked like nothing happened. The passthrough path (#3610,
|
||||
// PassthroughModelsSection) already switches the filter to "visible" after a run
|
||||
// that hid models, via shouldSwitchToVisibleFilter(...) → setVisibilityFilter.
|
||||
// The OAuth path (useModelVisibilityHandlers.handleTestAll — consumed by
|
||||
// ProviderModelsSection, which GLM renders) DID NOT, so just-hidden models stayed
|
||||
// visible under the "All" filter.
|
||||
//
|
||||
// This drives the real hook: a failing model + autoHideFailed on must leave the
|
||||
// hook's visibilityFilter === "visible" so the just-hidden model disappears.
|
||||
import React from "react";
|
||||
import { act } from "react";
|
||||
import { createRoot } from "react-dom/client";
|
||||
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
||||
|
||||
const mockFetch = vi.fn();
|
||||
vi.stubGlobal("fetch", mockFetch);
|
||||
|
||||
const {
|
||||
useModelVisibilityHandlers,
|
||||
} = await import(
|
||||
"../../../src/app/(dashboard)/dashboard/providers/[id]/hooks/useModelVisibilityHandlers"
|
||||
);
|
||||
|
||||
type Hook = ReturnType<typeof useModelVisibilityHandlers>;
|
||||
|
||||
const t = ((key: string) => key) as any;
|
||||
const notify = { error: vi.fn(), success: vi.fn(), info: vi.fn() } as any;
|
||||
|
||||
const baseParams = {
|
||||
providerId: "glm",
|
||||
modelAliases: {},
|
||||
customMap: new Map(),
|
||||
providerStorageAlias: "glm",
|
||||
fetchProviderModelMeta: async () => {},
|
||||
fetchAliases: async () => {},
|
||||
notify,
|
||||
t,
|
||||
selectedConnection: { id: "conn-1", provider: "glm" },
|
||||
providerNode: { id: "glm" },
|
||||
} as any;
|
||||
|
||||
let container: HTMLDivElement | null = null;
|
||||
let root: ReturnType<typeof createRoot> | null = null;
|
||||
let captured: Hook | null = null;
|
||||
|
||||
function TestComponent({ onHook }: { onHook: (h: Hook) => void }) {
|
||||
const hook = useModelVisibilityHandlers(baseParams);
|
||||
const { useEffect } = React;
|
||||
useEffect(() => {
|
||||
onHook(hook);
|
||||
});
|
||||
return null;
|
||||
}
|
||||
|
||||
async function renderHook() {
|
||||
(globalThis as any).IS_REACT_ACT_ENVIRONMENT = true;
|
||||
container = document.createElement("div");
|
||||
document.body.appendChild(container);
|
||||
captured = null;
|
||||
await act(async () => {
|
||||
root = createRoot(container!);
|
||||
root.render(<TestComponent onHook={(h) => (captured = h)} />);
|
||||
});
|
||||
}
|
||||
|
||||
/** Mock fetch: test-all returns the configured per-model status; the hide PATCH succeeds. */
|
||||
function setFetch(perModel: Record<string, "ok" | "error">) {
|
||||
mockFetch.mockImplementation(async (url: string, init?: RequestInit) => {
|
||||
if (typeof url === "string" && url.startsWith("/api/models/test-all")) {
|
||||
const body = JSON.parse((init?.body as string) || "{}");
|
||||
const full = body.modelIds?.[0] as string;
|
||||
return {
|
||||
ok: true,
|
||||
json: async () => ({ results: { [full]: { status: perModel[full] ?? "error" } } }),
|
||||
};
|
||||
}
|
||||
return { ok: true, text: async () => "", json: async () => ({}) };
|
||||
});
|
||||
}
|
||||
|
||||
describe("useModelVisibilityHandlers.handleTestAll — #4887 visible-filter parity", () => {
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks();
|
||||
captured = null;
|
||||
});
|
||||
afterEach(() => {
|
||||
if (root && container) act(() => root!.unmount());
|
||||
container?.remove();
|
||||
container = null;
|
||||
root = null;
|
||||
captured = null;
|
||||
});
|
||||
|
||||
it("switches visibilityFilter to 'visible' when autoHideFailed is on and a model was hidden", async () => {
|
||||
setFetch({ "glm/model-ok": "ok", "glm/model-bad": "error" });
|
||||
await renderHook();
|
||||
|
||||
expect(captured!.visibilityFilter).toBe("all");
|
||||
|
||||
act(() => captured!.setAutoHideFailed(true));
|
||||
expect(captured!.autoHideFailed).toBe(true);
|
||||
|
||||
await act(async () => {
|
||||
await captured!.handleTestAll([
|
||||
{ modelId: "model-ok", fullModel: "glm/model-ok" },
|
||||
{ modelId: "model-bad", fullModel: "glm/model-bad" },
|
||||
]);
|
||||
});
|
||||
|
||||
// The failed model was hidden — the filter must flip so it disappears on-screen.
|
||||
expect(captured!.visibilityFilter).toBe("visible");
|
||||
});
|
||||
|
||||
it("does NOT switch the filter when autoHideFailed is off (nothing hidden)", async () => {
|
||||
setFetch({ "glm/model-bad": "error" });
|
||||
await renderHook();
|
||||
expect(captured!.autoHideFailed).toBe(false);
|
||||
|
||||
await act(async () => {
|
||||
await captured!.handleTestAll([{ modelId: "model-bad", fullModel: "glm/model-bad" }]);
|
||||
});
|
||||
|
||||
expect(captured!.visibilityFilter).toBe("all");
|
||||
});
|
||||
|
||||
it("does NOT switch the filter when all models pass (nothing hidden)", async () => {
|
||||
setFetch({ "glm/model-ok": "ok" });
|
||||
await renderHook();
|
||||
|
||||
act(() => captured!.setAutoHideFailed(true));
|
||||
|
||||
await act(async () => {
|
||||
await captured!.handleTestAll([{ modelId: "model-ok", fullModel: "glm/model-ok" }]);
|
||||
});
|
||||
|
||||
expect(captured!.visibilityFilter).toBe("all");
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user