@@ -65,6 +65,7 @@ import {
6565 Timer ,
6666 CheckCircle ,
6767 XCircle ,
68+ Gauge ,
6869} from 'lucide-react' ;
6970import { clsx } from 'clsx' ;
7071import { useNavigate } from 'react-router-dom' ;
@@ -167,6 +168,13 @@ export const Logs = () => {
167168 // progressTick is incremented to trigger re-renders when progress data changes.
168169 // The value itself is intentionally unused; only the setter is called.
169170 const [ , setProgressTick ] = useState ( 0 ) ;
171+ // liveTick triggers re-renders every 100ms so pending-request durations update live.
172+ const [ , setLiveTick ] = useState ( 0 ) ;
173+
174+ useEffect ( ( ) => {
175+ const interval = setInterval ( ( ) => setLiveTick ( ( t ) => t + 1 ) , 100 ) ;
176+ return ( ) => clearInterval ( interval ) ;
177+ } , [ ] ) ;
170178
171179 const loadLogs = async ( ) => {
172180 setLoading ( true ) ;
@@ -645,31 +653,45 @@ export const Logs = () => {
645653 log . responseStatus === 'pending'
646654 ? progressMapRef . current . get ( log . requestId )
647655 : undefined ;
656+ const liveDuration = formatMs (
657+ log . durationMs != null ? log . durationMs : Date . now ( ) - log . startTime
658+ ) ;
648659 if ( progress ) {
649660 return (
650661 < div
651662 style = { { display : 'flex' , flexDirection : 'column' , gap : '2px' } }
652663 >
653- < div
654- style = { { display : 'flex' , alignItems : 'center' , gap : '4px' } }
664+ < span > Duration: { liveDuration } </ span >
665+ < span
666+ style = { {
667+ color : 'var(--color-text-secondary)' ,
668+ fontSize : '0.85em' ,
669+ display : 'flex' ,
670+ alignItems : 'center' ,
671+ gap : '4px' ,
672+ } }
655673 >
656674 < CloudDownload size = { 11 } className = "text-yellow-400" />
657675 < span > { formatBytes ( progress . bytesReceived ) } </ span >
658- </ div >
676+ </ span >
659677 { progress . bytesPerSec != null && (
660678 < span
661679 style = { {
662680 color : 'var(--color-text-secondary)' ,
663681 fontSize : '0.85em' ,
682+ display : 'flex' ,
683+ alignItems : 'center' ,
684+ gap : '4px' ,
664685 } }
665686 >
687+ < Gauge size = { 11 } className = "text-text-secondary" />
666688 { formatBytes ( progress . bytesPerSec ) } /s
667689 </ span >
668690 ) }
669691 </ div >
670692 ) ;
671693 }
672- return formatMs ( log . durationMs ) ;
694+ return liveDuration ;
673695 } ) ( ) }
674696 </ div >
675697 </ div >
@@ -678,7 +700,8 @@ export const Logs = () => {
678700 Meta
679701 </ div >
680702 < div className = "text-text" >
681- { log . messageCount || 0 } msg / { log . toolCallsCount || 0 } tools
703+ { ( log . messageCount || 0 ) === 0 ? '-' : log . messageCount } msg /{ ' ' }
704+ { ( log . toolCallsCount || 0 ) === 0 ? '-' : log . toolCallsCount } tools
682705 </ div >
683706 </ div >
684707 </ div >
@@ -754,7 +777,7 @@ export const Logs = () => {
754777 </ th >
755778 < th
756779 className = "px-2 py-1.5 text-center border-b border-border-glass border-r border-r-border-glass bg-bg-hover font-semibold text-text-secondary text-[11px] uppercase tracking-wider whitespace-nowrap"
757- style = { { minWidth : '70px ' } }
780+ style = { { minWidth : '130px ' } }
758781 >
759782 { renderSortableHeader ( 'Cost' , 'costTotal' ) }
760783 </ th >
@@ -1135,81 +1158,78 @@ export const Logs = () => {
11351158 </ td >
11361159 < td className = "px-2 py-1.5 border-b border-border-glass text-text align-middle" >
11371160 { log . costTotal !== undefined && log . costTotal !== null ? (
1138- < div style = { { display : 'flex' , gap : '12px ' , alignItems : 'center ' } } >
1139- { /* Left side : Total cost */ }
1140- < div style = { { minWidth : '50px' } } >
1161+ < div style = { { display : 'flex' , flexDirection : 'column ' , gap : '2px ' } } >
1162+ { /* Row 1 : Total cost */ }
1163+ < div >
11411164 { log . costSource ? (
11421165 < CostToolTip
11431166 source = { log . costSource }
11441167 costMetadata = { log . costMetadata }
11451168 >
11461169 < span style = { { fontWeight : '500' , cursor : 'help' } } >
1147- { log . costTotal === 0 ? '∅ ' : formatCost ( log . costTotal ) }
1170+ { log . costTotal === 0 ? '- ' : formatCost ( log . costTotal , 6 ) }
11481171 </ span >
11491172 </ CostToolTip >
11501173 ) : (
11511174 < span style = { { fontWeight : '500' } } >
1152- { log . costTotal === 0 ? '∅ ' : formatCost ( log . costTotal ) }
1175+ { log . costTotal === 0 ? '- ' : formatCost ( log . costTotal , 6 ) }
11531176 </ span >
11541177 ) }
11551178 </ div >
1156- { /* Right side: Breakdown */ }
1157- < div style = { { display : 'flex' , flexDirection : 'column' , gap : '2px' } } >
1158- < div style = { { display : 'flex' , alignItems : 'center' , gap : '4px' } } >
1159- < CloudUpload size = { 10 } className = "text-blue-400" />
1160- < span
1161- style = { {
1162- color : 'var(--color-text-secondary)' ,
1163- fontSize : '0.85em' ,
1164- minWidth : '35px' ,
1165- } }
1166- >
1167- { log . costInput === 0 ? '∅' : formatCost ( log . costInput || 0 ) }
1168- </ span >
1169- </ div >
1170- < div style = { { display : 'flex' , alignItems : 'center' , gap : '4px' } } >
1171- < CloudDownload size = { 10 } className = "text-green-400" />
1172- < span
1173- style = { {
1174- color : 'var(--color-text-secondary)' ,
1175- fontSize : '0.85em' ,
1176- minWidth : '35px' ,
1177- } }
1178- >
1179- { log . costOutput === 0 ? '∅' : formatCost ( log . costOutput || 0 ) }
1180- </ span >
1181- </ div >
1182- < div style = { { display : 'flex' , alignItems : 'center' , gap : '4px' } } >
1183- < PackageOpen size = { 10 } className = "text-orange-400" />
1184- < span
1185- style = { {
1186- color : 'var(--color-text-secondary)' ,
1187- fontSize : '0.85em' ,
1188- minWidth : '35px' ,
1189- } }
1190- >
1191- { log . costCached === 0 ? '∅' : formatCost ( log . costCached || 0 ) }
1192- </ span >
1193- </ div >
1194- < div style = { { display : 'flex' , alignItems : 'center' , gap : '4px' } } >
1195- < PencilLine size = { 10 } className = "text-fuchsia-400" />
1196- < span
1197- style = { {
1198- color : 'var(--color-text-secondary)' ,
1199- fontSize : '0.85em' ,
1200- minWidth : '35px' ,
1201- } }
1202- >
1203- { log . costCacheWrite === 0
1204- ? '∅'
1205- : formatCost ( log . costCacheWrite || 0 ) }
1206- </ span >
1207- </ div >
1179+ { /* Separator */ }
1180+ < div
1181+ style = { {
1182+ borderTop : '1px solid var(--color-border-glass)' ,
1183+ margin : '1px 2px' ,
1184+ } }
1185+ />
1186+ { /* Breakdown grid: 2 rows x 4 columns (icon, value, icon, value) */ }
1187+ < div
1188+ style = { {
1189+ display : 'grid' ,
1190+ gridTemplateColumns : 'auto 1fr auto 1fr' ,
1191+ gap : '2px 4px' ,
1192+ alignItems : 'center' ,
1193+ } }
1194+ >
1195+ < CloudUpload size = { 10 } className = "text-blue-400" />
1196+ < span
1197+ style = { { color : 'var(--color-text-secondary)' , fontSize : '0.85em' } }
1198+ >
1199+ { log . costInput === 0 ? '$-.----' : formatCost ( log . costInput || 0 ) }
1200+ </ span >
1201+ < CloudDownload size = { 10 } className = "text-green-400" />
1202+ < span
1203+ style = { { color : 'var(--color-text-secondary)' , fontSize : '0.85em' } }
1204+ >
1205+ { log . costOutput === 0 ? '$-.----' : formatCost ( log . costOutput || 0 ) }
1206+ </ span >
1207+ < PackageOpen size = { 10 } className = "text-orange-400" />
1208+ < span
1209+ style = { { color : 'var(--color-text-secondary)' , fontSize : '0.85em' } }
1210+ >
1211+ { log . costCached === 0 ? '$-.----' : formatCost ( log . costCached || 0 ) }
1212+ </ span >
1213+ < PencilLine size = { 10 } className = "text-fuchsia-400" />
1214+ < span
1215+ style = { { color : 'var(--color-text-secondary)' , fontSize : '0.85em' } }
1216+ >
1217+ { log . costCacheWrite === 0
1218+ ? '$-.----'
1219+ : formatCost ( log . costCacheWrite || 0 ) }
1220+ </ span >
12081221 </ div >
12091222 </ div >
12101223 ) : (
1211- < span style = { { color : 'var(--color-text-secondary)' , fontSize : '1.2em' } } >
1212- ∅
1224+ < span
1225+ style = { {
1226+ color : 'var(--color-text-secondary)' ,
1227+ fontSize : '1.2em' ,
1228+ display : 'block' ,
1229+ textAlign : 'center' ,
1230+ } }
1231+ >
1232+ -
12131233 </ span >
12141234 ) }
12151235 </ td >
@@ -1219,22 +1239,36 @@ export const Logs = () => {
12191239 log . responseStatus === 'pending'
12201240 ? progressMapRef . current . get ( log . requestId )
12211241 : undefined ;
1242+ const liveDuration = formatMs (
1243+ log . durationMs != null ? log . durationMs : Date . now ( ) - log . startTime
1244+ ) ;
12221245 if ( progress ) {
12231246 return (
1224- < div style = { { display : 'flex' , flexDirection : 'column' , gap : '2px' } } >
1225- < div style = { { display : 'flex' , alignItems : 'center' , gap : '4px' } } >
1247+ < div style = { { display : 'flex' , flexDirection : 'column' } } >
1248+ < span > Duration: { liveDuration } </ span >
1249+ < span
1250+ style = { {
1251+ color : 'var(--color-text-secondary)' ,
1252+ fontSize : '0.85em' ,
1253+ display : 'flex' ,
1254+ alignItems : 'center' ,
1255+ gap : '4px' ,
1256+ } }
1257+ >
12261258 < CloudDownload size = { 12 } className = "text-yellow-400" />
1227- < span style = { { fontSize : '0.9em' } } >
1228- { formatBytes ( progress . bytesReceived ) }
1229- </ span >
1230- </ div >
1259+ < span > { formatBytes ( progress . bytesReceived ) } </ span >
1260+ </ span >
12311261 { progress . bytesPerSec != null && (
12321262 < span
12331263 style = { {
12341264 color : 'var(--color-text-secondary)' ,
12351265 fontSize : '0.85em' ,
1266+ display : 'flex' ,
1267+ alignItems : 'center' ,
1268+ gap : '4px' ,
12361269 } }
12371270 >
1271+ < Gauge size = { 12 } className = "text-text-secondary" />
12381272 { formatBytes ( progress . bytesPerSec ) } /s
12391273 </ span >
12401274 ) }
@@ -1243,7 +1277,7 @@ export const Logs = () => {
12431277 }
12441278 return (
12451279 < div style = { { display : 'flex' , flexDirection : 'column' } } >
1246- < span > Duration: { formatMs ( log . durationMs ) } </ span >
1280+ < span > Duration: { liveDuration } </ span >
12471281 < span
12481282 style = { {
12491283 color : 'var(--color-text-secondary)' ,
@@ -1292,7 +1326,7 @@ export const Logs = () => {
12921326 < span
12931327 style = { { fontWeight : '500' , fontSize : '0.9em' , minWidth : '20px' } }
12941328 >
1295- { log . messageCount || 0 }
1329+ { ( log . messageCount || 0 ) === 0 ? '-' : log . messageCount }
12961330 </ span >
12971331 </ div >
12981332 < div
@@ -1307,7 +1341,7 @@ export const Logs = () => {
13071341 minWidth : '20px' ,
13081342 } }
13091343 >
1310- { log . toolCallsCount || 0 }
1344+ { ( log . toolCallsCount || 0 ) === 0 ? '-' : log . toolCallsCount }
13111345 </ span >
13121346 </ div >
13131347 </ div >
@@ -1321,7 +1355,7 @@ export const Logs = () => {
13211355 < span
13221356 style = { { fontWeight : '500' , fontSize : '0.9em' , minWidth : '20px' } }
13231357 >
1324- { log . toolsDefined || 0 }
1358+ { ( log . toolsDefined || 0 ) === 0 ? '-' : log . toolsDefined }
13251359 </ span >
13261360 </ div >
13271361 < div style = { { display : 'flex' , alignItems : 'center' , gap : '4px' } } >
0 commit comments