fix(ui): let a caller retry a failed auto-router model fetch in-form

A failed fetchAvailableModels call disabled every preset with no way to recover short of closing and reopening the modal, even for a transient error. Surface the failure next to the template selector with a Retry action that re-runs the same useQuery.
This commit is contained in:
Tin Chi Lo 2026-08-03 16:47:34 -07:00
parent a1ff26cf13
commit b12931a84c
2 changed files with 25 additions and 0 deletions

View file

@ -184,6 +184,22 @@ describe("AddAutoRouterTab", () => {
expect(isOptionDisabled(optionByLabel("OpenAI Family")!)).toBe(true);
});
// A failed fetch must not strand the caller: Retry re-runs the same query, and a caller who
// only hit a transient error can recover without closing and reopening the whole modal.
it("recovers presets once Retry re-fetches successfully", async () => {
const user = userEvent.setup();
mockFetchAvailableModels.mockRejectedValueOnce(new Error("boom")).mockResolvedValueOnce(ALL_FAMILY_MODELS);
renderWithProviders(<Harness />);
await waitFor(() => expect(screen.getByRole("button", { name: /retry/i })).toBeInTheDocument());
await user.click(screen.getByRole("button", { name: /retry/i }));
openTemplateDropdown();
await waitFor(() => expect(isOptionDisabled(optionByLabel("Anthropic Family")!)).toBe(false));
expect(mockFetchAvailableModels).toHaveBeenCalledTimes(2);
});
// The headline behavior: selecting a preset must pre-fill the tier config so the created
// router carries the preset's models. Real tier validation runs here (getMissingTiersError is
// not stubbed), so if selection stopped pre-filling, the empty tiers would either block the

View file

@ -109,6 +109,7 @@ const AddAutoRouterTab: React.FC<AddAutoRouterTabProps> = ({
data: modelInfo = [],
isLoading: modelsLoading,
isError: modelsError,
refetch: refetchModels,
} = useQuery({
queryKey: ["availableModels", "autoRouter", accessToken],
queryFn: () => fetchAvailableModels(accessToken),
@ -357,6 +358,14 @@ const AddAutoRouterTab: React.FC<AddAutoRouterTabProps> = ({
{showValidationErrors && !selectedPreset && (
<div className="text-xs mt-1 text-red-500">Please select a template</div>
)}
{modelsError && (
<div className="text-xs mt-1 text-red-500">
Could not load available models.{" "}
<button type="button" className="underline" onClick={() => refetchModels()}>
Retry
</button>
</div>
)}
</div>
<Form.Item