11import React , { useEffect , useRef } from 'react' ;
2- import clsx from 'clsx ' ;
2+ import { Flex , Box , Heading , Text } from '@radix-ui/themes ' ;
33import { LogEntry , formatTime } from '../types/log' ;
44import { ToolCallView } from './log/ToolCallView' ;
55import { DiffView } from './log/DiffView' ;
@@ -12,117 +12,153 @@ interface LogViewProps {
1212
1313export function LogView ( { logs, isRunning } : LogViewProps ) {
1414 const scrollRef = useRef < HTMLDivElement > ( null ) ;
15-
15+
1616 // Auto-scroll to bottom when new logs arrive
1717 useEffect ( ( ) => {
1818 if ( scrollRef . current ) {
1919 scrollRef . current . scrollTop = scrollRef . current . scrollHeight ;
2020 }
2121 } , [ logs ] ) ;
22-
22+
2323 if ( logs . length === 0 && ! isRunning ) {
2424 return (
25- < div className = "flex flex-col items- center justify- center h-full p- 8">
26- < div className = "text-dark-text-muted text- center">
27- < p className = "mb-2 "> No activity yet</ p >
28- < p className = "text-sm" > Run the task to see logs here</ p >
29- </ div >
30- </ div >
25+ < Flex direction = "column" align = " center" justify = " center" height = "100%" p = " 8">
26+ < Flex direction = "column" align = " center" gap = "2 ">
27+ < Text color = "gray "> No activity yet</ Text >
28+ < Text size = "2" color = "gray" > Run the task to see logs here</ Text >
29+ </ Flex >
30+ </ Flex >
3131 ) ;
3232 }
33-
33+
3434 return (
35- < div className = "flex flex-col h-full" >
36- < div className = "p-4 border-b border-dark-border flex items-center justify-between" >
37- < h2 className = "font-medium text-dark-text" > Activity Log</ h2 >
38- { isRunning && (
39- < div className = "flex items-center gap-2" >
40- < div className = "w-2 h-2 bg-green-500 rounded-full animate-pulse" />
41- < span className = "text-sm text-dark-text-muted" > Running</ span >
42- </ div >
43- ) }
44- </ div >
45-
46- < div ref = { scrollRef } className = "flex-1 overflow-y-auto p-4 font-mono text-sm whitespace-pre-wrap" >
35+ < Flex direction = "column" height = "100%" >
36+ < Box p = "4" className = "border-b border-gray-6" >
37+ < Flex align = "center" justify = "between" >
38+ < Heading size = "3" > Activity Log</ Heading >
39+ { isRunning && (
40+ < Flex align = "center" gap = "2" >
41+ < Box
42+ width = "8px"
43+ height = "8px"
44+ className = "bg-green-9 rounded-full animate-pulse"
45+ />
46+ < Text size = "2" color = "gray" > Running</ Text >
47+ </ Flex >
48+ ) }
49+ </ Flex >
50+ </ Box >
51+
52+ < Box
53+ ref = { scrollRef }
54+ flexGrow = "1"
55+ overflowY = "auto"
56+ p = "4"
57+ className = "font-mono text-sm whitespace-pre-wrap"
58+ >
4759 { logs . map ( ( log , index ) => {
4860 // Backward compat for plain strings
4961 if ( typeof log === 'string' ) {
5062 return (
51- < div key = { index } className = { clsx ( 'mb-2 leading-relaxed text-dark-text' ) } >
52- < span className = "text-dark-text-muted mr-2" > { new Date ( ) . toLocaleTimeString ( ) } </ span >
53- { log }
54- </ div >
63+ < Box key = { index } >
64+ < Text color = "gray" >
65+ { new Date ( ) . toLocaleTimeString ( ) }
66+ </ Text >
67+ < Text > { log } </ Text >
68+ </ Box >
5569 ) ;
5670 }
5771 // Structured entries
5872 switch ( log . type ) {
5973 case 'text' :
6074 return (
61- < div key = { index } className = { clsx ( 'mb-2 leading-relaxed' , log . level === 'error' ? 'text-red-400' : 'text-dark-text' ) } >
62- < span className = "text-dark-text-muted mr-2" > { formatTime ( log . ts ) } </ span >
63- { log . content }
64- </ div >
75+ < Box key = { index } mb = "2" >
76+ < Text color = "gray" mr = "2" >
77+ { formatTime ( log . ts ) }
78+ </ Text >
79+ < Text color = { log . level === 'error' ? 'red' : undefined } >
80+ { log . content }
81+ </ Text >
82+ </ Box >
6583 ) ;
6684 case 'status' :
6785 return (
68- < div key = { index } className = "mb-2 leading-relaxed text-dark-text" >
69- < span className = "text-dark-text-muted mr-2" > { formatTime ( log . ts ) } </ span >
70- status: { log . phase }
71- </ div >
86+ < Box key = { index } mb = "2" >
87+ < Text color = "gray" mr = "2" >
88+ { formatTime ( log . ts ) }
89+ </ Text >
90+ < Text > status: { log . phase } </ Text >
91+ </ Box >
7292 ) ;
7393 case 'tool_call' :
7494 return (
75- < div key = { index } className = "mb-4" >
76- < div className = "text-xs text-dark-text-muted mb-1" > { formatTime ( log . ts ) } tool_call</ div >
95+ < Box key = { index } mb = "2" >
96+ < Text size = "1" color = "gray" >
97+ { formatTime ( log . ts ) } tool_call
98+ </ Text >
7799 < ToolCallView toolName = { log . toolName } callId = { log . callId } args = { log . args } />
78- </ div >
100+ </ Box >
79101 ) ;
80102 case 'tool_result' :
81103 return (
82- < div key = { index } className = "mb-4" >
83- < div className = "text-xs text-dark-text-muted mb-1" > { formatTime ( log . ts ) } tool_result</ div >
104+ < Box key = { index } mb = "2" >
105+ < Text size = "1" color = "gray" >
106+ { formatTime ( log . ts ) } tool_result
107+ </ Text >
84108 < ToolCallView toolName = { log . toolName } callId = { log . callId } args = { log . result } />
85- </ div >
109+ </ Box >
86110 ) ;
87111 case 'diff' :
88112 return (
89- < div key = { index } className = "mb-4" >
90- < div className = "text-xs text-dark-text-muted mb-1" > { formatTime ( log . ts ) } diff</ div >
113+ < Box key = { index } mb = "2" >
114+ < Text size = "1" color = "gray" >
115+ { formatTime ( log . ts ) } diff
116+ </ Text >
91117 < DiffView file = { log . file } patch = { log . patch } added = { log . summary ?. added } removed = { log . summary ?. removed } />
92- </ div >
118+ </ Box >
93119 ) ;
94120 case 'file_write' :
95121 return (
96- < div key = { index } className = "mb-2 leading-relaxed text-dark-text" >
97- < span className = "text-dark-text-muted mr-2" > { formatTime ( log . ts ) } </ span >
98- file_write: { log . path }
99- { typeof log . bytes === 'number' ? < span className = "text-dark-text-muted" > ({ log . bytes } bytes)</ span > : null }
100- </ div >
122+ < Box key = { index } mb = "2" >
123+ < Text color = "gray" mr = "2" >
124+ { formatTime ( log . ts ) }
125+ </ Text >
126+ < Text > file_write: { log . path } </ Text >
127+ { typeof log . bytes === 'number' && (
128+ < Text color = "gray" > ({ log . bytes } bytes)</ Text >
129+ ) }
130+ </ Box >
101131 ) ;
102132 case 'metric' :
103133 return (
104- < div key = { index } className = "mb-2" >
105- < div className = "text-xs text-dark-text-muted mb-1" > { formatTime ( log . ts ) } metric</ div >
134+ < Box key = { index } mb = "2" >
135+ < Text size = "1" color = "gray" >
136+ { formatTime ( log . ts ) } metric
137+ </ Text >
106138 < MetricView keyName = { log . key } value = { log . value } unit = { log . unit } />
107- </ div >
139+ </ Box >
108140 ) ;
109141 case 'artifact' :
110142 return (
111- < div key = { index } className = "mb-2 leading-relaxed text-dark-text" >
112- < span className = "text-dark-text-muted mr-2" > { formatTime ( log . ts ) } </ span >
113- artifact: { /* simple preview */ }
114- </ div >
143+ < Box key = { index } mb = "2" >
144+ < Text color = "gray" mr = "2" >
145+ { formatTime ( log . ts ) }
146+ </ Text >
147+ < Text > artifact: { /* simple preview */ } </ Text >
148+ </ Box >
115149 ) ;
116150 default :
117151 return (
118- < div key = { index } className = "mb-2 leading-relaxed text-dark-text" >
119- < span className = "text-dark-text-muted mr-2" > { new Date ( ) . toLocaleTimeString ( ) } </ span >
120- { JSON . stringify ( log ) }
121- </ div >
152+ < Box key = { index } mb = "2" >
153+ < Text color = "gray" mr = "2" >
154+ { new Date ( ) . toLocaleTimeString ( ) }
155+ </ Text >
156+ < Text > { JSON . stringify ( log ) } </ Text >
157+ </ Box >
122158 ) ;
123159 }
124160 } ) }
125- </ div >
126- </ div >
161+ </ Box >
162+ </ Flex >
127163 ) ;
128164}
0 commit comments