From 37f98fbe40b45d931e8189161f22fb9c6b90c6b3 Mon Sep 17 00:00:00 2001 From: Varun Singh Date: Thu, 11 Jun 2026 17:47:17 +0530 Subject: [PATCH] =?UTF-8?q?ui:=20consistent=20minimal=20palette=20?= =?UTF-8?q?=E2=80=94=20shared=20level=20tones,=20neutral=20JSON=20blocks?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - lib/log-levels.ts: single levelTone() used by Timeline AND CitedChunks (they previously disagreed — Timeline coloured levels, CitedChunks didn't) - palette reduced to signal-only: ERROR/FATAL -> theme destructive, WARN -> one amber accent, INFO and everything else neutral (INFO is most rows; colouring it was noise) - investigation steps: replace hardcoded vscDarkPlus rainbow JSON (dark theme regardless of mode) with a neutral
 matching CitedChunks'
  raw-text styling; align tool/observation containers to rounded-lg
---
 web/components/chat/CitedChunks.tsx   |  4 +++-
 web/components/chat/Timeline.tsx      | 17 +-------------
 web/components/investigation-step.tsx | 34 +++++++++++++--------------
 web/lib/log-levels.ts                 | 19 +++++++++++++++
 4 files changed, 39 insertions(+), 35 deletions(-)
 create mode 100644 web/lib/log-levels.ts

diff --git a/web/components/chat/CitedChunks.tsx b/web/components/chat/CitedChunks.tsx
index df57ac7..25333ad 100644
--- a/web/components/chat/CitedChunks.tsx
+++ b/web/components/chat/CitedChunks.tsx
@@ -3,6 +3,8 @@
 import { useState } from "react"
 import { Badge } from "@/components/ui/badge"
 import { ChevronDown, ChevronRight, FileText } from "lucide-react"
+import { cn } from "@/lib/utils"
+import { levelTone } from "@/lib/log-levels"
 
 export type CitedChunk = {
   chunk_id: string
@@ -62,7 +64,7 @@ export function CitedChunks({
                   
                 )}
                 {c.level && (
-                  
+                  
                     {c.level}
                   
                 )}
diff --git a/web/components/chat/Timeline.tsx b/web/components/chat/Timeline.tsx
index 1414d0d..eb5505d 100644
--- a/web/components/chat/Timeline.tsx
+++ b/web/components/chat/Timeline.tsx
@@ -4,6 +4,7 @@ import { useState } from "react"
 import { Badge } from "@/components/ui/badge"
 import { ChevronDown, ChevronRight, Clock } from "lucide-react"
 import { cn } from "@/lib/utils"
+import { levelTone } from "@/lib/log-levels"
 
 export type TimelineEntry = {
   service: string | null
@@ -24,22 +25,6 @@ function formatRange(first: string, last: string): string {
   return `${formatTs(first)}–${formatTs(last)}`
 }
 
-function levelTone(level: string | null): string {
-  switch ((level || "").toUpperCase()) {
-    case "ERROR":
-    case "CRITICAL":
-    case "FATAL":
-      return "text-red-500 border-red-500/30"
-    case "WARNING":
-    case "WARN":
-      return "text-amber-500 border-amber-500/30"
-    case "INFO":
-      return "text-blue-500 border-blue-500/30"
-    default:
-      return "text-muted-foreground border-border"
-  }
-}
-
 // Optional controlled `open` so a parent (e.g. a quick-action button on the
 // assistant turn) can force the panel open. Falls back to uncontrolled
 // internal state when omitted.
diff --git a/web/components/investigation-step.tsx b/web/components/investigation-step.tsx
index 3973128..7fffae1 100644
--- a/web/components/investigation-step.tsx
+++ b/web/components/investigation-step.tsx
@@ -7,8 +7,18 @@ import { Spinner } from "@/components/ui/spinner"
 import { Terminal, Brain, Search, ChevronDown, ChevronRight, Sparkles, Lightbulb, Flag } from "lucide-react"
 import { useState } from "react"
 import ReactMarkdown from "react-markdown"
-import { Prism as SyntaxHighlighter } from "react-syntax-highlighter"
-import { vscDarkPlus } from "react-syntax-highlighter/dist/esm/styles/prism"
+
+// Neutral JSON rendering — matches CitedChunks' raw-text styling so every
+// monospace panel in the app reads the same. Syntax-highlighting themes
+// (vscDarkPlus etc.) brought a full colour scheme into an otherwise
+// two-tone UI and ignored light/dark mode.
+function JsonBlock({ value }: { value: unknown }) {
+  return (
+    
+      {JSON.stringify(value, null, 2)}
+    
+ ) +} export function InvestigationStepCard({ step }: { step: Step }) { const [showTool, setShowTool] = useState(false) @@ -79,7 +89,7 @@ export function InvestigationStepCard({ step }: { step: Step }) { {/* Action/Tool Call */} {step.action && ( -
+
{showTool && (
- - {JSON.stringify(step.action.args, null, 2)} - +
)}
@@ -107,7 +111,7 @@ export function InvestigationStepCard({ step }: { step: Step }) { {/* Observation */} {step.observation && ( -
+
{showObservation && (
- - {JSON.stringify(step.observation, null, 2)} - +
)}
diff --git a/web/lib/log-levels.ts b/web/lib/log-levels.ts new file mode 100644 index 0000000..15c97ed --- /dev/null +++ b/web/lib/log-levels.ts @@ -0,0 +1,19 @@ +// Single source of truth for log-level badge styling, shared by every panel +// that renders a level (Timeline, CitedChunks, …) so they can't drift apart. +// +// Deliberately minimal palette: theme `destructive` for error-class levels, +// one amber accent for warnings, neutral for INFO and everything else — +// INFO is the overwhelming majority of rows, so colouring it is pure noise. +export function levelTone(level: string | null | undefined): string { + switch ((level || "").toUpperCase()) { + case "ERROR": + case "CRITICAL": + case "FATAL": + return "text-destructive border-destructive/30" + case "WARNING": + case "WARN": + return "text-amber-600 dark:text-amber-500 border-amber-500/30" + default: + return "text-muted-foreground border-border" + } +}