-
+
+ setTab(value as LensTab)} className="min-h-0 flex-1 gap-0">
+
+
-
+
+
-
-
-
-
-
-
-
- {isProxyAdminTierRole(userRole) ? (
-
+
+
+
- ) : (
-
- Investigations require proxy administrator access. You can still view your traces.
-
- )}
-
-
+
+
+
+
+ {canInvestigate ? (
+
+ ) : (
+
+ Investigations require proxy administrator access. You can still view your traces.
+
+ )}
+
+
+
);
diff --git a/ui/litellm-dashboard/src/components/lens/model/status.test.ts b/ui/litellm-dashboard/src/components/lens/model/status.test.ts
index b77490e981e..c6b9eabf70e 100644
--- a/ui/litellm-dashboard/src/components/lens/model/status.test.ts
+++ b/ui/litellm-dashboard/src/components/lens/model/status.test.ts
@@ -1,4 +1,4 @@
-import { nextCheckStatus, workerConnected } from "./status";
+import { investigationActivity, nextCheckStatus, workerConnected } from "./status";
import { describe, expect, it } from "vitest";
import type { Job, Lens, LensList } from "./types";
@@ -102,3 +102,12 @@ it("shows the actual next schedule and avoids a stale countdown during active sc
);
expect(nextCheckStatus(lens, now)).toBeNull();
});
+
+it("summarizes activity across investigations, preferring a running scan over a queued one", () => {
+ const withStatus = (status: Job["status"]): Lens => ({ ...lens, jobs: [{ ...job, status }] });
+ expect(investigationActivity([])).toBe("idle");
+ expect(investigationActivity([lens, withStatus("failed")])).toBe("idle");
+ expect(investigationActivity([lens, withStatus("queued")])).toBe("queued");
+ expect(investigationActivity([withStatus("queued"), withStatus("running")])).toBe("running");
+ expect(investigationActivity([{ ...lens, jobs: [lens.jobs[0], { ...job, status: "running" }] }])).toBe("running");
+});
diff --git a/ui/litellm-dashboard/src/components/lens/model/status.ts b/ui/litellm-dashboard/src/components/lens/model/status.ts
index daed4c9060b..75a345c6ea5 100644
--- a/ui/litellm-dashboard/src/components/lens/model/status.ts
+++ b/ui/litellm-dashboard/src/components/lens/model/status.ts
@@ -43,3 +43,12 @@ export function readiness(
const ready = activityReady && connected && !listError;
return { tracesReady, requestsReady, activityReady, ready };
}
+
+export type InvestigationActivity = "running" | "queued" | "idle";
+
+export function investigationActivity(lenses: readonly Lens[]): InvestigationActivity {
+ const statuses = new Set(lenses.flatMap((lens) => lens.jobs.map((job) => job.status)));
+ if (statuses.has("running")) return "running";
+ if (statuses.has("queued")) return "queued";
+ return "idle";
+}
- Investigations require proxy administrator access. You can still view your traces. -
- )} -+ Investigations require proxy administrator access. You can still view your traces. +
+ )} +