fix(alerts): align filters and monitoring guidance

This commit is contained in:
moe-berri 2026-11-08 16:35:54 +08:00
parent 0b668b9c6a
commit 6e05cdc3e2
6 changed files with 25 additions and 16 deletions

View file

@ -224,8 +224,8 @@ export default function IssueFamilySettings({ accessToken }: { accessToken: stri
) : (
<>
<p className="text-xs text-muted-foreground">
Daily monitoring is enabled by default. Checks wait for a usable baseline and complete usage data. Model
retirement alerts appear automatically for used models.
Daily checks wait for a usable baseline and complete usage data. Model retirement alerts appear
automatically for used models.
</p>
{delayedChecks > 0 && (
<p role="status" className="text-xs text-muted-foreground">

View file

@ -282,8 +282,8 @@ describe("unified issue investigations", () => {
).toBe("0");
});
it("keeps old performance list links usable", async () => {
renderWithProviders(<IssuesInbox />, { searchParams: "type=usage&usage_status=resolved" });
it("uses the same kind and status filters in the URL and API", async () => {
renderWithProviders(<IssuesInbox />, { searchParams: "kind=performance&status=resolved" });
await screen.findByRole("link", { name: "Spend on Checkout key rose to 20× normal" });
const request = calls.find((call) => call.path === "/alerts");
expect(request?.query.get("kind")).toBe("performance");
@ -555,7 +555,7 @@ describe("unified issue investigations", () => {
);
expect(screen.getByRole("link", { name: "Migration details" })).toHaveAttribute(
"href",
"/ui/alerts?type=model-deprecations&model=provider%2Fretiring-model",
"/ui/alerts?kind=model_deprecation&model=provider%2Fretiring-model",
);
expect(screen.getByRole("link", { name: "View model activity" })).toHaveAttribute(
"href",

View file

@ -54,9 +54,9 @@ export default function IssuesInbox() {
const { accessToken, userRole, isViewOnly } = useAuthorized();
const [params, setParams] = useQueryStates(issueRouteParsers);
const table = useUrlTableState(TABLE_STATE);
const status = params.status ?? params.state ?? params.usage_status ?? "open";
const family = params.family ?? (params.type === "model-deprecations" ? "retirement" : undefined);
const kind = params.type === "usage" && !family ? ("performance" as const) : undefined;
const status = params.status ?? "open";
const family = params.family ?? undefined;
const kind = family ? undefined : params.kind ?? undefined;
const queryOptions = {
status,
family,
@ -79,13 +79,13 @@ export default function IssuesInbox() {
} else if (query.data && pageIndex > lastPage) onPaginationChange({ pageIndex: lastPage, pageSize });
}, [query.data, pageIndex, pageSize, lastPage, onPaginationChange]);
const changeStatus = (next: IssueStatus) => {
void setParams({ status: next, state: null, usage_status: null });
void setParams({ status: next });
table.onPaginationChange({ ...table.pagination, pageIndex: 0 });
};
const changeFamily = (next: string) => {
void setParams({
family: next === "all" || next === "performance" ? null : (next as AlertFamily),
type: next === "performance" ? "usage" : null,
kind: next === "performance" ? "performance" : null,
});
table.onPaginationChange({ ...table.pagination, pageIndex: 0 });
};
@ -118,12 +118,12 @@ export default function IssuesInbox() {
<div className="flex shrink-0 flex-wrap items-center justify-end gap-2 border-b px-4 py-3">
<select
aria-label="Alert type"
value={family ?? kind ?? "all"}
value={family ?? (kind === "model_deprecation" ? "retirement" : kind) ?? "all"}
onChange={(event) => changeFamily(event.target.value)}
className="h-8 rounded-md border border-input bg-background px-2 text-xs"
>
<option value="all">All alert types</option>
{kind && <option value="performance">All performance types</option>}
<option value="performance">All performance types</option>
{ISSUE_FAMILIES.map((value) => (
<option key={value} value={value}>
{FAMILY_LABELS[value]}

View file

@ -5,8 +5,6 @@ export const issueRouteParsers = {
alert: parseAsString.withOptions({ history: "push" }),
family: parseAsStringLiteral(ISSUE_FAMILIES),
status: parseAsStringLiteral(ISSUE_STATUSES),
type: parseAsStringLiteral(["usage", "model-deprecations"] as const),
kind: parseAsStringLiteral(["performance", "model_deprecation"] as const),
model: parseAsString,
state: parseAsStringLiteral(ISSUE_STATUSES),
usage_status: parseAsStringLiteral(ISSUE_STATUSES),
};

View file

@ -9,6 +9,6 @@ export const migrationUrlParsers = {
};
export function migrationHref(model?: string) {
const base = `${uiHref("alerts")}?type=model-deprecations`;
const base = `${uiHref("alerts")}?kind=model_deprecation`;
return model ? `${base}&model=${encodeURIComponent(model)}` : base;
}

View file

@ -210,6 +210,17 @@ describe("issue notifications", () => {
expect(screen.getByLabelText("Notification content")).toContainElement(update);
});
it("lets the reader retry a failed alerts request", async () => {
const user = userEvent.setup();
const retry = vi.fn();
renderWithProviders(
<NotificationsBellView currentVersion={null} latestRelease={null} issuesFailed onRetryAlerts={retry} />,
);
await user.click(screen.getByRole("button", { name: /^notifications/i }));
await user.click(screen.getByRole("button", { name: "Retry" }));
expect(retry).toHaveBeenCalledTimes(1);
});
it("opens issue-owned investigations and keeps resources outside the scrolling content", async () => {
const user = userEvent.setup();
renderWithProviders(<NotificationsBellView currentVersion={null} latestRelease={null} issues={ISSUES} />);