mirror of
https://github.com/BerriAI/litellm.git
synced 2026-10-04 02:31:27 +00:00
fix(lens): default to traces and restore closed span details (#44260)
This commit is contained in:
parent
04bc354525
commit
aef0a53837
5 changed files with 35 additions and 5 deletions
|
|
@ -18,12 +18,11 @@ vi.mock("./_components/LensView", () => ({
|
|||
describe("Lens navigation", () => {
|
||||
beforeEach(() => auth.mockReturnValue({ accessToken: "test-token", userRole: "Admin", isViewOnly: false }));
|
||||
|
||||
it("opens investigations and pauses trace polling when returning from traces", async () => {
|
||||
it("opens traces by default and pauses polling while viewing investigations", async () => {
|
||||
const user = userEvent.setup();
|
||||
const onUrlUpdate = vi.fn();
|
||||
renderWithProviders(<LensPage />, { onUrlUpdate });
|
||||
expect(screen.getByRole("tab", { name: "Investigations" })).toHaveAttribute("aria-selected", "true");
|
||||
await user.click(screen.getByRole("tab", { name: "Traces" }));
|
||||
expect(screen.getByRole("tab", { name: "Traces" })).toHaveAttribute("aria-selected", "true");
|
||||
expect(screen.getByText("Trace polling active")).toBeVisible();
|
||||
await user.click(screen.getByRole("tab", { name: "Investigations" }));
|
||||
expect(screen.getByText("Manage investigations")).toBeVisible();
|
||||
|
|
@ -39,6 +38,12 @@ describe("Lens navigation", () => {
|
|||
expect(screen.getByText("Manage investigations")).toBeVisible();
|
||||
});
|
||||
|
||||
it("honors an explicit traces tab even when a saved investigation is in the URL", () => {
|
||||
renderWithProviders(<LensPage />, { searchParams: "?tab=traces&lens=saved-lens" });
|
||||
expect(screen.getByRole("tab", { name: "Traces" })).toHaveAttribute("aria-selected", "true");
|
||||
expect(screen.getByText("Trace polling active")).toBeVisible();
|
||||
});
|
||||
|
||||
it.each(["Internal User", "Internal Viewer", "Org Admin"])(
|
||||
"preserves trace access without granting investigations to %s",
|
||||
async (userRole) => {
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ export default function LensPage() {
|
|||
parseAsStringLiteral(["traces", "investigations"]).withOptions({ history: "push" }),
|
||||
);
|
||||
const [lensId] = useQueryState("lens", parseAsString);
|
||||
const defaultTab = isProxyAdminTierRole(userRole ?? "") || lensId ? "investigations" : "traces";
|
||||
const defaultTab = lensId ? "investigations" : "traces";
|
||||
const activeTab = tab ?? defaultTab;
|
||||
if (!accessToken) return null;
|
||||
return (
|
||||
|
|
|
|||
|
|
@ -1,8 +1,9 @@
|
|||
"use client";
|
||||
|
||||
import { BarChart3, Clock, Coins, ListTree, MoreHorizontal, Timer } from "lucide-react";
|
||||
import { BarChart3, Clock, Coins, ListTree, MoreHorizontal, PanelRightOpen, Timer } from "lucide-react";
|
||||
import { useEffect, useMemo, useRef } from "react";
|
||||
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Switch } from "@/components/ui/switch";
|
||||
import { cn } from "@/lib/cva.config";
|
||||
|
||||
|
|
@ -24,6 +25,7 @@ interface SpanTreeProps {
|
|||
onToggleSpan: (id: string) => void;
|
||||
onToggleGroup: (id: string) => void;
|
||||
onLoadMore: (groupId: string) => void;
|
||||
onOpenDetails?: () => void;
|
||||
/** Inside the side drawer J/K switch runs, so spans move with the arrow keys. */
|
||||
embedded?: boolean;
|
||||
}
|
||||
|
|
@ -308,6 +310,7 @@ export function SpanTree({
|
|||
onToggleSpan,
|
||||
onToggleGroup,
|
||||
onLoadMore,
|
||||
onOpenDetails,
|
||||
embedded = false,
|
||||
}: SpanTreeProps) {
|
||||
const scrollRef = useRef<HTMLDivElement>(null);
|
||||
|
|
@ -333,6 +336,12 @@ export function SpanTree({
|
|||
aria-label="Hide framework spans"
|
||||
/>
|
||||
</label>
|
||||
{onOpenDetails && (
|
||||
<Button variant="ghost" size="sm" onClick={onOpenDetails} className="ml-3 shrink-0 text-xs text-trace-text-2">
|
||||
<PanelRightOpen className="size-4" />
|
||||
Show details
|
||||
</Button>
|
||||
)}
|
||||
</div>
|
||||
<div ref={scrollRef} className="min-h-0 flex-1 overflow-auto pb-4">
|
||||
<Summary summary={summary} />
|
||||
|
|
|
|||
|
|
@ -135,6 +135,21 @@ describe("RunView", () => {
|
|||
expect(screen.queryByTestId("detail-pane")).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
it.each(["button", "Escape"])("reopens the selected step after closing details with %s", async (method) => {
|
||||
const user = userEvent.setup();
|
||||
renderRun(research);
|
||||
await screen.findByTestId("detail-pane");
|
||||
await user.keyboard("j");
|
||||
const selectedId = screen.getByTestId("detail-pane").getAttribute("data-row-id");
|
||||
expect(selectedId).not.toBe(rootSpanId(research));
|
||||
if (method === "button") await user.click(screen.getByRole("button", { name: "close detail" }));
|
||||
else await user.keyboard("{Escape}");
|
||||
expect(screen.queryByTestId("detail-pane")).not.toBeInTheDocument();
|
||||
await user.click(screen.getByRole("button", { name: "Show details" }));
|
||||
expect(screen.getByTestId("detail-pane")).toHaveAttribute("data-row-id", selectedId);
|
||||
expect(screen.queryByRole("button", { name: "Show details" })).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("keeps a way back to the runs table when a run fails to load", async () => {
|
||||
const user = userEvent.setup();
|
||||
const onBack = vi.fn();
|
||||
|
|
|
|||
|
|
@ -253,6 +253,7 @@ function RunBody({ trace, accessToken, initialSpanId, embedded }: RunBodyProps)
|
|||
onToggleSpan={toggleSpan}
|
||||
onToggleGroup={toggleGroup}
|
||||
onLoadMore={loadMore}
|
||||
onOpenDetails={detailOpen ? undefined : () => setDetailOpen(true)}
|
||||
embedded={embedded}
|
||||
/>
|
||||
{detailOpen && (
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue