From 03bec959bfebea1671188cad4030369c240356c2 Mon Sep 17 00:00:00 2001 From: Yujong Lee Date: Sun, 4 Oct 2026 17:12:42 -0700 Subject: [PATCH] fix(ui): show Lens run reloads as a search spinner and a blurred body Co-Authored-By: Claude Opus 5.5 --- ui/litellm-dashboard/src/app/globals.css | 9 --------- .../AgentTracesSection.integration.test.tsx | 4 ++-- .../lens/traces/list/AgentTracesSection.tsx | 9 ++++++++- .../lens/traces/list/AgentTracesTable.test.tsx | 1 - .../lens/traces/list/AgentTracesTable.tsx | 4 ++-- .../lens/traces/list/runSearch/RunSearch.tsx | 4 +++- .../lens/traces/list/runSearch/RunsToolbar.tsx | 6 ++++-- .../src/components/shared/InspectorTable.tsx | 17 +---------------- .../src/components/shared/search/SearchBox.tsx | 16 +++++++++++++--- 9 files changed, 33 insertions(+), 37 deletions(-) diff --git a/ui/litellm-dashboard/src/app/globals.css b/ui/litellm-dashboard/src/app/globals.css index dcd428c2565..3de122128d4 100644 --- a/ui/litellm-dashboard/src/app/globals.css +++ b/ui/litellm-dashboard/src/app/globals.css @@ -469,12 +469,3 @@ left: 100%; } } - -@keyframes rows-sweep { - from { - left: -25%; - } - to { - left: 100%; - } -} diff --git a/ui/litellm-dashboard/src/components/lens/traces/list/AgentTracesSection.integration.test.tsx b/ui/litellm-dashboard/src/components/lens/traces/list/AgentTracesSection.integration.test.tsx index 259c44a294b..c87bae8d8dd 100644 --- a/ui/litellm-dashboard/src/components/lens/traces/list/AgentTracesSection.integration.test.tsx +++ b/ui/litellm-dashboard/src/components/lens/traces/list/AgentTracesSection.integration.test.tsx @@ -671,12 +671,12 @@ describe("AgentTracesPage", () => { }), ); fireEvent.click(screen.getByTestId(`sort-header-${key}`)); - expect(await screen.findByRole("progressbar", { name: "Updating rows" })).toBeInTheDocument(); + expect(await screen.findByRole("status", { name: "Loading results" })).toBeInTheDocument(); expect(screen.getAllByTestId("agent-trace-row")).toHaveLength(rowsBefore.length); expect(listRequest(-1)).toMatchObject({ order: { key, descending: true }, page: { cursor: null } }); act(release); - await waitFor(() => expect(screen.queryByRole("progressbar")).not.toBeInTheDocument()); + await waitFor(() => expect(screen.queryByRole("status", { name: "Loading results" })).not.toBeInTheDocument()); expect(screen.getAllByTestId("agent-trace-row")[0]).toHaveTextContent(topAfter); expect(lastUrl(onUrlUpdate).get("sort_by")).toBe(key); expect(lastUrl(onUrlUpdate).has("sort_dir")).toBe(false); diff --git a/ui/litellm-dashboard/src/components/lens/traces/list/AgentTracesSection.tsx b/ui/litellm-dashboard/src/components/lens/traces/list/AgentTracesSection.tsx index 8a6331062bc..758326cd125 100644 --- a/ui/litellm-dashboard/src/components/lens/traces/list/AgentTracesSection.tsx +++ b/ui/litellm-dashboard/src/components/lens/traces/list/AgentTracesSection.tsx @@ -171,7 +171,14 @@ export function AgentTracesSection({ /> )} - + {timeControls && ( { ), ); expect(screen.getAllByTestId("agent-trace-row")).toHaveLength(runs.length); - expect(screen.getByRole("progressbar", { name: "Updating rows" })).toBeInTheDocument(); expect(screen.queryByTestId("runs-placeholder")).not.toBeInTheDocument(); expect(screen.queryByRole("status")).not.toBeInTheDocument(); expect(onLoadMore).not.toHaveBeenCalled(); diff --git a/ui/litellm-dashboard/src/components/lens/traces/list/AgentTracesTable.tsx b/ui/litellm-dashboard/src/components/lens/traces/list/AgentTracesTable.tsx index d712bbe084e..bb9ae69ca8d 100644 --- a/ui/litellm-dashboard/src/components/lens/traces/list/AgentTracesTable.tsx +++ b/ui/litellm-dashboard/src/components/lens/traces/list/AgentTracesTable.tsx @@ -287,10 +287,10 @@ export function AgentTracesTable({ - + rowHeight={() => ROW_HEIGHT} - className={cn(isPlaceholder && "opacity-60 transition-opacity motion-reduce:transition-none")} + className={cn("transition-[filter]", isPlaceholder && "blur-[1.5px]")} after={ <> {isLoading && SKELETON_ROWS.map((row) => )} diff --git a/ui/litellm-dashboard/src/components/lens/traces/list/runSearch/RunSearch.tsx b/ui/litellm-dashboard/src/components/lens/traces/list/runSearch/RunSearch.tsx index 3f713fd2cd8..7730c1871d8 100644 --- a/ui/litellm-dashboard/src/components/lens/traces/list/runSearch/RunSearch.tsx +++ b/ui/litellm-dashboard/src/components/lens/traces/list/runSearch/RunSearch.tsx @@ -21,10 +21,11 @@ interface RunSearchProps { /** The range and order the list shows; the copied query follows both. */ range?: TimeWindow; order?: RunOrder; + busy?: boolean; } /** The runs list query box: free text plus `key:value` filters over run fields, copyable as a trace query. */ -export function RunSearch({ value, onChange, runs, range, order = NEWEST }: RunSearchProps) { +export function RunSearch({ value, onChange, runs, range, order = NEWEST, busy = false }: RunSearchProps) { const command = useMemo(() => runQueryCommand(range, order), [range, order]); return ( diff --git a/ui/litellm-dashboard/src/components/lens/traces/list/runSearch/RunsToolbar.tsx b/ui/litellm-dashboard/src/components/lens/traces/list/runSearch/RunsToolbar.tsx index fc4a4a8a015..10c7989fa6b 100644 --- a/ui/litellm-dashboard/src/components/lens/traces/list/runSearch/RunsToolbar.tsx +++ b/ui/litellm-dashboard/src/components/lens/traces/list/runSearch/RunsToolbar.tsx @@ -13,14 +13,16 @@ interface RunsToolbarProps { /** The range and order the list shows, for the copied query. */ range?: TimeWindow; order?: RunOrder; + /** Shows a spinner in the search box while the list reloads for a new query or order. */ + busy?: boolean; /** Extra controls (time range, live tail) rendered on the right. */ children?: React.ReactNode; } -export function RunsToolbar({ query, onQueryChange, runs, range, order, children }: RunsToolbarProps) { +export function RunsToolbar({ query, onQueryChange, runs, range, order, busy, children }: RunsToolbarProps) { return (
- + {children &&
{children}
}
); diff --git a/ui/litellm-dashboard/src/components/shared/InspectorTable.tsx b/ui/litellm-dashboard/src/components/shared/InspectorTable.tsx index 6a4c50e535e..8cddaeb133d 100644 --- a/ui/litellm-dashboard/src/components/shared/InspectorTable.tsx +++ b/ui/litellm-dashboard/src/components/shared/InspectorTable.tsx @@ -73,11 +73,9 @@ function ariaSort(column: Column): "ascending" | "descending" | "none" | u interface HeaderProps { readonly hidden?: boolean; - /** Shows a progress line under the headings while the rows below are being replaced. */ - readonly busy?: boolean; } -function Header({ hidden = false, busy = false }: HeaderProps) { +function Header({ hidden = false }: HeaderProps) { const { table } = useInspectorTable(); return (