mirror of
https://github.com/BerriAI/litellm.git
synced 2026-10-04 02:31:27 +00:00
fix(ui): make the Lens traces refresh button always clickable (#44252)
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Co-authored-by: Ishaan Jaffer <155045088+ishaan-berri@users.noreply.github.com>
This commit is contained in:
parent
a292fd409f
commit
22bd49e231
3 changed files with 50 additions and 15 deletions
|
|
@ -7,7 +7,7 @@ import { ApiError } from "@/lib/http/client";
|
|||
import { chooseSelectOption, renderWithProviders, testQueryClient } from "../../../../tests/test-utils";
|
||||
import traceList from "./__fixtures__/trace_list.json";
|
||||
import AgentTracesPage from "./AgentTracesPage";
|
||||
import { AgentTracesSection, filterRuns } from "./AgentTracesSection";
|
||||
import { AgentTracesSection, filterRuns, type TimeControls } from "./AgentTracesSection";
|
||||
import type { TracePage, TraceSummary } from "./traceTypes";
|
||||
|
||||
vi.mock("../../networking", () => ({
|
||||
|
|
@ -45,7 +45,7 @@ const renderSection = () =>
|
|||
);
|
||||
|
||||
// A UTC-pinned day around the fixture runs (2026-09-30 ~06:43 UTC), so they land in the same bucket in any timezone.
|
||||
const renderWindowed = () =>
|
||||
const renderWindowed = (timeControls?: TimeControls) =>
|
||||
renderWithProviders(
|
||||
<AgentTracesSection
|
||||
accessToken="sk-test"
|
||||
|
|
@ -54,6 +54,7 @@ const renderWindowed = () =>
|
|||
endTime="2026-10-01T00:00Z"
|
||||
isCustomDate
|
||||
isLiveTail={false}
|
||||
timeControls={timeControls}
|
||||
/>,
|
||||
);
|
||||
|
||||
|
|
@ -425,6 +426,25 @@ describe("AgentTracesSection", () => {
|
|||
expect(screen.queryByTestId("timeline-selection")).not.toBeInTheDocument();
|
||||
expect(rowCount()).toBe(runs.length);
|
||||
});
|
||||
|
||||
it("clears timeline zoom when refreshed", async () => {
|
||||
vi.mocked(agentTraceListCall).mockResolvedValue(traceList as TracePage);
|
||||
renderWindowed({ rangeHours: 24, onRangeHoursChange: () => {}, onLiveChange: () => {} });
|
||||
await screen.findAllByTestId("agent-trace-row");
|
||||
const area = screen.getByTestId("timeline-area");
|
||||
const x = (bucket: number) => bucket * 10 + 5;
|
||||
|
||||
fireEvent.pointerDown(area, { clientX: x(0), pointerId: 1 });
|
||||
fireEvent.pointerMove(area, { clientX: x(1), pointerId: 1 });
|
||||
fireEvent.pointerUp(area, { clientX: x(1), pointerId: 1 });
|
||||
expect(screen.getByTestId("timeline-selection")).toBeInTheDocument();
|
||||
expect(screen.queryAllByTestId("agent-trace-row")).toHaveLength(0);
|
||||
|
||||
fireEvent.click(screen.getByRole("button", { name: "Refresh" }));
|
||||
|
||||
expect(screen.queryByTestId("timeline-selection")).not.toBeInTheDocument();
|
||||
expect(screen.getAllByTestId("agent-trace-row")).toHaveLength(runs.length);
|
||||
});
|
||||
});
|
||||
|
||||
describe("AgentTracesPage", () => {
|
||||
|
|
@ -453,7 +473,18 @@ describe("AgentTracesPage", () => {
|
|||
expect(live).toHaveAttribute("aria-pressed", "true");
|
||||
fireEvent.click(live);
|
||||
expect(live).toHaveAttribute("aria-pressed", "false");
|
||||
expect(screen.getByRole("button", { name: "Reset zoom" })).toBeDisabled();
|
||||
expect(screen.getByRole("button", { name: "Refresh" })).toBeEnabled();
|
||||
});
|
||||
|
||||
it("refreshes the trace list", async () => {
|
||||
vi.mocked(agentTraceListCall).mockResolvedValue(traceList as TracePage);
|
||||
renderWithProviders(<AgentTracesPage accessToken="sk-test" />);
|
||||
await screen.findByTestId("runs-table");
|
||||
|
||||
const callsBeforeRefresh = vi.mocked(agentTraceListCall).mock.calls.length;
|
||||
fireEvent.click(screen.getByRole("button", { name: "Refresh" }));
|
||||
|
||||
await waitFor(() => expect(vi.mocked(agentTraceListCall).mock.calls.length).toBeGreaterThan(callsBeforeRefresh));
|
||||
});
|
||||
|
||||
it("keeps the time controls on an empty range the user picked, instead of showing onboarding", async () => {
|
||||
|
|
|
|||
|
|
@ -211,8 +211,11 @@ export function AgentTracesSection({
|
|||
onRangeHoursChange={(hours) => changeRange(hours, timeControls.onRangeHoursChange)}
|
||||
live={isLiveTail}
|
||||
onLiveChange={timeControls.onLiveChange}
|
||||
zoomed={zoom !== null}
|
||||
onResetZoom={() => setZoom(null)}
|
||||
onRefresh={() => {
|
||||
setZoom(null);
|
||||
checkTraces();
|
||||
}}
|
||||
refreshing={traces.isFetching}
|
||||
/>
|
||||
)}
|
||||
</RunsToolbar>
|
||||
|
|
|
|||
|
|
@ -35,30 +35,31 @@ interface TimeRangeControlsProps {
|
|||
onRangeHoursChange: (hours: number) => void;
|
||||
live: boolean;
|
||||
onLiveChange: (live: boolean) => void;
|
||||
zoomed: boolean;
|
||||
onResetZoom: () => void;
|
||||
onRefresh: () => void;
|
||||
refreshing: boolean;
|
||||
}
|
||||
|
||||
/** Joined control group: reset zoom, the actual time range (opens presets), and Live. */
|
||||
/** Joined control group: refresh, the actual time range (opens presets), and Live. */
|
||||
export function TimeRangeControls({
|
||||
range,
|
||||
rangeHours,
|
||||
onRangeHoursChange,
|
||||
live,
|
||||
onLiveChange,
|
||||
zoomed,
|
||||
onResetZoom,
|
||||
onRefresh,
|
||||
refreshing,
|
||||
}: TimeRangeControlsProps) {
|
||||
return (
|
||||
<div className="flex items-center gap-1.5">
|
||||
<button
|
||||
type="button"
|
||||
onClick={onResetZoom}
|
||||
disabled={!zoomed}
|
||||
aria-label="Reset zoom"
|
||||
className="inline-flex size-7 items-center justify-center rounded-md border border-border text-info hover:bg-info/10 disabled:text-muted-foreground disabled:opacity-40 disabled:hover:bg-transparent"
|
||||
onClick={onRefresh}
|
||||
aria-label="Refresh"
|
||||
title="Refresh"
|
||||
aria-busy={refreshing}
|
||||
className="inline-flex size-7 items-center justify-center rounded-md border border-border text-muted-foreground hover:text-foreground hover:bg-muted/60"
|
||||
>
|
||||
<RotateCcw className="size-3.5" />
|
||||
<RotateCcw className={cn("size-3.5", refreshing && "animate-spin")} />
|
||||
</button>
|
||||
<div className="flex items-center divide-x divide-border overflow-hidden rounded-md border border-border bg-card">
|
||||
<DropdownMenu>
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue