mirror of
https://github.com/BerriAI/litellm.git
synced 2026-10-08 03:08:45 +00:00
fix(ui): keep Lens investigation preview rows in place while matches reload
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
fbb6facc0f
commit
3cd22643cc
3 changed files with 37 additions and 3 deletions
|
|
@ -430,6 +430,30 @@ it("fetches one preview for two keystrokes inside the debounce window", async ()
|
|||
}
|
||||
});
|
||||
|
||||
it("shows skeleton rows on first load and keeps the previous rows while a new search loads", async () => {
|
||||
const pending = new Map<string, (page: unknown) => void>();
|
||||
proxy.post.mockImplementation(
|
||||
(_path, options) =>
|
||||
new Promise((resolve) => {
|
||||
pending.set((options?.body as { selection: Settings }).selection.q, resolve);
|
||||
}),
|
||||
);
|
||||
const user = userEvent.setup();
|
||||
renderWithProviders(<InvestigationSetup mode="new" onClose={vi.fn()} onSave={vi.fn()} />);
|
||||
const preview = within(screen.getByRole("region", { name: "Matching activity" }));
|
||||
expect((await preview.findAllByTestId("runs-placeholder")).length).toBeGreaterThan(0);
|
||||
act(() => pending.get("")?.({ eligible: 1, selected: 1, executions: [run("Old run", 1)] }));
|
||||
expect(await preview.findByText("Old run")).toBeVisible();
|
||||
expect(preview.queryByTestId("runs-placeholder")).not.toBeInTheDocument();
|
||||
await user.type(screen.getByRole("combobox", { name: "Search runs" }), "new");
|
||||
await waitFor(() => expect(pending.has("new")).toBe(true));
|
||||
expect(preview.getByText("Old run")).toBeVisible();
|
||||
expect(preview.queryByTestId("runs-placeholder")).not.toBeInTheDocument();
|
||||
act(() => pending.get("new")?.({ eligible: 1, selected: 1, executions: [run("New run", 2)] }));
|
||||
expect(await preview.findByText("New run")).toBeVisible();
|
||||
expect(preview.queryByText("Old run")).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
it.each(["empty", "error"])("blocks a new investigation when its preview is %s", async (state) => {
|
||||
if (state === "error") proxy.post.mockRejectedValue(new Error("Storage unavailable"));
|
||||
else proxy.post.mockResolvedValue({ eligible: 0, selected: 0, executions: [] });
|
||||
|
|
|
|||
|
|
@ -60,6 +60,7 @@ export function MatchingActivityPreview({
|
|||
...props
|
||||
}: MatchingActivityPreviewProps) {
|
||||
const runs = page.executions.flatMap((run) => (run.summary ? [run.summary] : []));
|
||||
const shown = status.ready || status.stale;
|
||||
return (
|
||||
<section
|
||||
aria-label="Matching activity"
|
||||
|
|
@ -97,21 +98,22 @@ export function MatchingActivityPreview({
|
|||
No matches. Try removing a filter from the search. Recent trace updates need two minutes to settle.
|
||||
</p>
|
||||
)}
|
||||
{status.ready && runs.length > 0 && (
|
||||
{(status.loading || (shown && !status.error && runs.length > 0)) && (
|
||||
<div className="max-h-[60dvh] min-h-0 overflow-auto">
|
||||
<AgentTracesTable
|
||||
traces={runs}
|
||||
isLoading={false}
|
||||
isLoading={status.loading}
|
||||
error={null}
|
||||
hasMore={page.hasMore}
|
||||
isFetching={page.loadingMore}
|
||||
isPlaceholder={status.stale}
|
||||
onLoadMore={page.loadMore}
|
||||
onSetUpTracing={() => {}}
|
||||
picks={selection ? runPicks(selection) : undefined}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
{status.ready && <PreviewFooter page={page} selection={selection} />}
|
||||
{shown && <PreviewFooter page={page} selection={selection} />}
|
||||
</section>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -29,6 +29,10 @@ export interface PreviewStatus {
|
|||
readonly title: string;
|
||||
readonly windowLabel: string;
|
||||
readonly ready: boolean;
|
||||
/** No results yet for any search: the table shows skeleton rows. */
|
||||
readonly loading: boolean;
|
||||
/** The rows belong to the previous search while this one loads. */
|
||||
readonly stale: boolean;
|
||||
readonly error: Error | null;
|
||||
readonly refresh: () => void;
|
||||
}
|
||||
|
|
@ -144,6 +148,8 @@ export function useMatchingActivity(): MatchingActivity {
|
|||
}, [empty, valid, asOf, refresh]);
|
||||
const pending = settling || preview.isLoading || preview.isPlaceholderData;
|
||||
const ready = !pending && valid;
|
||||
const loading = valid && pending && !firstPage;
|
||||
const stale = valid && pending && !!firstPage;
|
||||
const setExecutionIds = (next: readonly string[]) =>
|
||||
setValue("selection.execution_ids", [...next], { shouldValidate: true });
|
||||
const picked = manualSelection ? manualPicks(selection, setExecutionIds) : null;
|
||||
|
|
@ -156,6 +162,8 @@ export function useMatchingActivity(): MatchingActivity {
|
|||
title: previewTitle({ pending, validWindow: windowValid, valid }, firstPage),
|
||||
windowLabel: windowLabel(selection),
|
||||
ready,
|
||||
loading,
|
||||
stale,
|
||||
error: preview.error,
|
||||
refresh,
|
||||
},
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue