1
1
import { useQuery } from '@tanstack/react-query' ;
2
2
import { format } from 'date-fns' ;
3
- import { useEffect , useRef , useState } from 'react' ;
3
+ import { useEffect , useRef , useState , useCallback } from 'react' ;
4
4
import { useAgents } from '../hooks/use-query-hooks' ;
5
5
import { apiClient } from '../lib/api' ;
6
6
import PageTitle from './page-title' ;
7
7
import { ScrollArea } from './ui/scroll-area' ;
8
8
import { Select , SelectContent , SelectItem , SelectTrigger , SelectValue } from './ui/select' ;
9
+ import { useQueryClient } from '@tanstack/react-query' ;
10
+ import { Button } from './ui/button' ;
9
11
10
12
interface LogEntry {
11
13
level : number ;
@@ -60,9 +62,11 @@ export function LogViewer({ agentName, level, hideTitle }: LogViewerProps = {})
60
62
const [ selectedLevel , setSelectedLevel ] = useState ( level || 'all' ) ;
61
63
const [ selectedAgentName , setSelectedAgentName ] = useState ( agentName || 'all' ) ;
62
64
const [ shouldAutoScroll , setShouldAutoScroll ] = useState ( true ) ;
65
+ const [ isClearing , setIsClearing ] = useState ( false ) ;
63
66
const scrollAreaRef = useRef < HTMLDivElement > ( null ) ;
64
67
const isUserScrolling = useRef ( false ) ;
65
68
const lastLogId = useRef < string > ( '' ) ;
69
+ const queryClient = useQueryClient ( ) ;
66
70
67
71
const { data, error, isLoading } = useQuery < LogResponse > ( {
68
72
queryKey : [ 'logs' , selectedLevel , selectedAgentName ] ,
@@ -78,7 +82,20 @@ export function LogViewer({ agentName, level, hideTitle }: LogViewerProps = {})
78
82
const { data : agents } = useAgents ( ) ;
79
83
const agentNames = agents ?. data ?. agents ?. map ( ( agent ) => agent . name ) ?? [ ] ;
80
84
81
- const scrollToBottom = ( ) => {
85
+ const handleClearLogs = async ( ) => {
86
+ try {
87
+ setIsClearing ( true ) ;
88
+ await apiClient . deleteLogs ( ) ;
89
+ // Invalidate the logs query to trigger a refetch
90
+ queryClient . invalidateQueries ( { queryKey : [ 'logs' ] } ) ;
91
+ } catch ( error ) {
92
+ console . error ( 'Failed to clear logs:' , error ) ;
93
+ } finally {
94
+ setIsClearing ( false ) ;
95
+ }
96
+ } ;
97
+
98
+ const scrollToBottom = useCallback ( ( ) => {
82
99
if ( ! scrollAreaRef . current ) return ;
83
100
84
101
const scrollArea = scrollAreaRef . current ;
@@ -89,7 +106,7 @@ export function LogViewer({ agentName, level, hideTitle }: LogViewerProps = {})
89
106
top : scrollHeight - clientHeight ,
90
107
behavior : 'instant' ,
91
108
} ) ;
92
- } ;
109
+ } , [ ] ) ;
93
110
94
111
useEffect ( ( ) => {
95
112
if ( ! data ?. logs ?. length ) return ;
@@ -101,7 +118,7 @@ export function LogViewer({ agentName, level, hideTitle }: LogViewerProps = {})
101
118
setTimeout ( scrollToBottom , 0 ) ;
102
119
lastLogId . current = currentLastLogId ;
103
120
}
104
- } , [ data ?. logs , shouldAutoScroll ] ) ;
121
+ } , [ data ?. logs , shouldAutoScroll , scrollToBottom ] ) ;
105
122
106
123
const handleScroll = ( event : React . UIEvent < HTMLDivElement > ) => {
107
124
if ( isUserScrolling . current ) return ;
@@ -125,7 +142,7 @@ export function LogViewer({ agentName, level, hideTitle }: LogViewerProps = {})
125
142
126
143
useEffect ( ( ) => {
127
144
setTimeout ( scrollToBottom , 100 ) ;
128
- } , [ data ?. logs ] ) ;
145
+ } , [ scrollToBottom ] ) ;
129
146
130
147
const getLevelName = ( level : number ) => {
131
148
return LOG_LEVEL_NUMBERS [ level as keyof typeof LOG_LEVEL_NUMBERS ] || 'UNKNOWN' ;
@@ -164,6 +181,10 @@ export function LogViewer({ agentName, level, hideTitle }: LogViewerProps = {})
164
181
< div className = "mb-4 flex items-center justify-between" >
165
182
{ ! hideTitle && < PageTitle title = { 'System Logs' } /> }
166
183
< div className = "flex items-center gap-4" >
184
+ < Button variant = "destructive" size = "sm" onClick = { handleClearLogs } disabled = { isClearing } >
185
+ { isClearing ? 'Clearing...' : 'Clear Logs' }
186
+ </ Button >
187
+
167
188
{ ! shouldAutoScroll && (
168
189
< button
169
190
type = "button"
0 commit comments