diff --git a/ui/litellm-dashboard/src/components/view_logs/LogDetailsDrawer/JsonViewer.test.tsx b/ui/litellm-dashboard/src/components/view_logs/LogDetailsDrawer/JsonViewer.test.tsx
index 055e400167b..a0ccb7f5323 100644
--- a/ui/litellm-dashboard/src/components/view_logs/LogDetailsDrawer/JsonViewer.test.tsx
+++ b/ui/litellm-dashboard/src/components/view_logs/LogDetailsDrawer/JsonViewer.test.tsx
@@ -1,17 +1,26 @@
import { render, screen } from "@testing-library/react";
+import { ThemeProvider } from "next-themes";
+import { darkStyles, defaultStyles } from "react-json-view-lite";
import { describe, expect, it } from "vitest";
import { JsonViewer } from "./JsonViewer";
+const renderWithTheme = (theme: "light" | "dark", data: unknown) =>
+ render(
+
+
+ ,
+ );
+
describe("JsonViewer", () => {
it("should render a placeholder and no tree when the log entry carries no payload", () => {
- render();
+ renderWithTheme("light", null);
expect(screen.getByText("No data")).toBeInTheDocument();
expect(screen.queryByRole("tree")).not.toBeInTheDocument();
});
it("should render the payload as a tree exposing its keys", () => {
- render();
+ renderWithTheme("light", { model: "claude-opus-4-5", stream: true });
expect(screen.getByRole("tree")).toBeInTheDocument();
expect(screen.getByText(/model/)).toBeInTheDocument();
@@ -20,9 +29,26 @@ describe("JsonViewer", () => {
});
it("should treat an empty payload as data rather than showing the placeholder", () => {
- render();
+ renderWithTheme("light", {});
expect(screen.getByRole("tree")).toBeInTheDocument();
expect(screen.queryByText("No data")).not.toBeInTheDocument();
});
+
+ it("should style the tree with the light palette when the dashboard theme is light", () => {
+ renderWithTheme("light", { model: "claude-opus-4-5" });
+
+ expect(screen.getByRole("tree")).toHaveClass(...defaultStyles.container.split(" "));
+ });
+
+ it("should style the tree with the dark palette when the dashboard theme is dark", () => {
+ renderWithTheme("dark", { model: "claude-opus-4-5" });
+
+ const tree = screen.getByRole("tree");
+ expect(tree).toHaveClass(...darkStyles.container.split(" "));
+ defaultStyles.container
+ .split(" ")
+ .filter((className) => !darkStyles.container.split(" ").includes(className))
+ .forEach((lightOnlyClassName) => expect(tree).not.toHaveClass(lightOnlyClassName));
+ });
});
diff --git a/ui/litellm-dashboard/src/components/view_logs/LogDetailsDrawer/JsonViewer.tsx b/ui/litellm-dashboard/src/components/view_logs/LogDetailsDrawer/JsonViewer.tsx
index 86b897f526f..980573a65cc 100644
--- a/ui/litellm-dashboard/src/components/view_logs/LogDetailsDrawer/JsonViewer.tsx
+++ b/ui/litellm-dashboard/src/components/view_logs/LogDetailsDrawer/JsonViewer.tsx
@@ -1,4 +1,5 @@
-import { JsonView, defaultStyles } from "react-json-view-lite";
+import { useTheme } from "next-themes";
+import { JsonView, darkStyles, defaultStyles } from "react-json-view-lite";
import "react-json-view-lite/dist/index.css";
import { JSON_MAX_HEIGHT, SPACING_LARGE } from "./constants";
@@ -12,6 +13,8 @@ interface JsonViewerProps {
* Uses an interactive tree component for easy navigation.
*/
export function JsonViewer({ data }: JsonViewerProps) {
+ const { resolvedTheme } = useTheme();
+
if (!data) return No data;
return (
@@ -24,8 +27,8 @@ export function JsonViewer({ data }: JsonViewerProps) {
borderRadius: 4,
}}
>
-
);