@@ -83,130 +83,141 @@ const TraceHistory: React.FC = () => {
83
83
) ;
84
84
85
85
return (
86
- < div className = "flex h-screen bg-gray-100 dark:bg-gray-900" >
86
+ < div className = "flex h-screen overflow-hidden bg-gray-100 dark:bg-gray-900" >
87
87
< Sidebar />
88
- < div className = { `flex-1 overflow-y-auto p-8 transition-all duration-300 ${ isPanelOpen ? 'mr-96' : '' } ` } >
89
- < div className = "flex justify-between items-center mb-8" >
90
- < div className = "flex items-center" >
91
- < History className = "mr-2 h-8 w-8 text-indigo-600 dark:text-indigo-400" />
92
- < h1 className = "text-3xl font-bold text-gray-800 dark:text-white" > Trace History</ h1 >
88
+ < div className = { `flex-1 flex flex-col h-screen transition-all duration-300 ${ isPanelOpen ? 'mr-96' : '' } ` } >
89
+ { /* Header Section - Fixed Height */ }
90
+ < div className = "p-8 bg-gray-100 dark:bg-gray-900" >
91
+ < div className = "flex justify-between items-center mb-8" >
92
+ < div className = "flex items-center" >
93
+ < History className = "mr-2 h-8 w-8 text-indigo-600 dark:text-indigo-400" />
94
+ < h1 className = "text-3xl font-bold text-gray-800 dark:text-white" > Trace History</ h1 >
95
+ </ div >
96
+ < Select
97
+ value = { selectedProject ?. toString ( ) }
98
+ onValueChange = { ( value ) => setSelectedProject ( Number ( value ) ) }
99
+ >
100
+ < SelectTrigger className = "w-[200px]" >
101
+ < SelectValue placeholder = "Select project" />
102
+ </ SelectTrigger >
103
+ < SelectContent >
104
+ { projects . map ( ( project ) => (
105
+ < SelectItem key = { project . id } value = { project . id . toString ( ) } >
106
+ { project . name }
107
+ </ SelectItem >
108
+ ) ) }
109
+ </ SelectContent >
110
+ </ Select >
93
111
</ div >
94
- < Select
95
- value = { selectedProject ?. toString ( ) }
96
- onValueChange = { ( value ) => setSelectedProject ( Number ( value ) ) }
97
- >
98
- < SelectTrigger className = "w-[200px]" >
99
- < SelectValue placeholder = "Select project" />
100
- </ SelectTrigger >
101
- < SelectContent >
102
- { projects . map ( ( project ) => (
103
- < SelectItem key = { project . id } value = { project . id . toString ( ) } >
104
- { project . name }
105
- </ SelectItem >
106
- ) ) }
107
- </ SelectContent >
108
- </ Select >
112
+
113
+ < Card className = "mb-8" >
114
+ < CardContent className = "p-4" >
115
+ < div className = "flex space-x-4" >
116
+ < Input
117
+ type = "text"
118
+ placeholder = "Search by Trace ID..."
119
+ value = { searchTerm }
120
+ onChange = { ( e ) => setSearchTerm ( e . target . value ) }
121
+ className = "flex-grow"
122
+ />
123
+ < Button onClick = { ( ) => setCurrentPage ( 1 ) } className = "flex items-center" >
124
+ < Search className = "w-4 h-4 mr-2" /> Search
125
+ </ Button >
126
+ </ div >
127
+ </ CardContent >
128
+ </ Card >
109
129
</ div >
110
130
111
- < Card className = "mb-8" >
112
- < CardContent className = "p-4" >
113
- < div className = "flex space-x-4" >
114
- < Input
115
- type = "text"
116
- placeholder = "Search by Trace ID..."
117
- value = { searchTerm }
118
- onChange = { ( e ) => setSearchTerm ( e . target . value ) }
119
- className = "flex-grow"
120
- />
121
- < Button onClick = { ( ) => setCurrentPage ( 1 ) } className = "flex items-center" >
122
- < Search className = "w-4 h-4 mr-2" /> Search
123
- </ Button >
131
+ { /* Table Section - Scrollable */ }
132
+ < div className = "flex-1 overflow-hidden flex flex-col px-8 pb-8" >
133
+ < div className = "flex-1 bg-white dark:bg-gray-800 rounded-lg shadow overflow-hidden flex flex-col" >
134
+ < div className = "overflow-x-auto" >
135
+ < div className = "inline-block min-w-full align-middle" >
136
+ < table className = "min-w-full divide-y divide-gray-200 dark:divide-gray-700" >
137
+ < thead className = "bg-gray-50 dark:bg-gray-700" >
138
+ < tr >
139
+ < th className = "sticky top-0 px-6 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-300 uppercase tracking-wider" > ID</ th >
140
+ < th className = "sticky top-0 px-6 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-300 uppercase tracking-wider" > Start Time</ th >
141
+ < th className = "sticky top-0 px-6 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-300 uppercase tracking-wider" > Duration</ th >
142
+ < th className = "sticky top-0 px-6 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-300 uppercase tracking-wider" > LLM Calls</ th >
143
+ < th className = "sticky top-0 px-6 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-300 uppercase tracking-wider" > Tool Calls</ th >
144
+ < th className = "sticky top-0 px-6 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-300 uppercase tracking-wider" > Agent Calls</ th >
145
+ < th className = "sticky top-0 px-6 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-300 uppercase tracking-wider" > Errors</ th >
146
+ </ tr >
147
+ </ thead >
148
+ < tbody className = "bg-white dark:bg-gray-800 divide-y divide-gray-200 dark:divide-gray-700" >
149
+ { isLoading ? (
150
+ < tr >
151
+ < td colSpan = { 7 } className = "px-6 py-4 text-center text-gray-500 dark:text-gray-300" >
152
+ Loading traces...
153
+ </ td >
154
+ </ tr >
155
+ ) : paginatedTraces . length === 0 ? (
156
+ < tr >
157
+ < td colSpan = { 7 } className = "px-6 py-4 text-center text-gray-500 dark:text-gray-300" >
158
+ No traces found. { ! selectedProject && "Please select a project." }
159
+ </ td >
160
+ </ tr >
161
+ ) : (
162
+ paginatedTraces . map ( ( trace ) => (
163
+ < tr
164
+ key = { trace . id }
165
+ onClick = { ( ) => handleTraceSelect ( trace . id ) }
166
+ className = { `hover:bg-gray-50 dark:hover:bg-gray-700 cursor-pointer transition-colors duration-150 ease-in-out ${ selectedTraceId === trace . id ? 'bg-purple-50 dark:bg-purple-900' : ''
167
+ } `}
168
+ >
169
+ < td className = "px-6 py-4 whitespace-nowrap text-sm font-medium text-indigo-600 dark:text-indigo-400" >
170
+ { trace . id }
171
+ </ td >
172
+ < td className = "px-6 py-4 whitespace-nowrap text-sm text-gray-500 dark:text-gray-300" >
173
+ { new Date ( trace . start_time ) . toLocaleString ( ) }
174
+ </ td >
175
+ < td className = "px-6 py-4 whitespace-nowrap text-sm text-gray-500 dark:text-gray-300" >
176
+ { trace . duration ? `${ trace . duration . toFixed ( 2 ) } s` : "-" }
177
+ </ td >
178
+ < td className = "px-6 py-4 whitespace-nowrap text-sm text-gray-500 dark:text-gray-300" >
179
+ { trace . total_llm_calls ?? "-" }
180
+ </ td >
181
+ < td className = "px-6 py-4 whitespace-nowrap text-sm text-gray-500 dark:text-gray-300" >
182
+ { trace . total_tool_calls ?? "-" }
183
+ </ td >
184
+ < td className = "px-6 py-4 whitespace-nowrap text-sm text-gray-500 dark:text-gray-300" >
185
+ { trace . total_agent_calls ?? "-" }
186
+ </ td >
187
+ < td className = "px-6 py-4 whitespace-nowrap text-sm text-gray-500 dark:text-gray-300" >
188
+ { trace . total_errors ?? "-" }
189
+ </ td >
190
+ </ tr >
191
+ ) )
192
+ ) }
193
+ </ tbody >
194
+ </ table >
195
+ </ div >
124
196
</ div >
125
- </ CardContent >
126
- </ Card >
127
-
128
- < div className = "bg-white dark:bg-gray-800 rounded-lg shadow overflow-hidden" >
129
- < table className = "min-w-full divide-y divide-gray-200 dark:divide-gray-700" >
130
- < thead className = "bg-gray-50 dark:bg-gray-700" >
131
- < tr >
132
- < th className = "px-6 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-300 uppercase tracking-wider" > ID</ th >
133
- < th className = "px-6 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-300 uppercase tracking-wider" > Start Time</ th >
134
- < th className = "px-6 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-300 uppercase tracking-wider" > Duration</ th >
135
- < th className = "px-6 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-300 uppercase tracking-wider" > LLM Calls</ th >
136
- < th className = "px-6 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-300 uppercase tracking-wider" > Tool Calls</ th >
137
- < th className = "px-6 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-300 uppercase tracking-wider" > Agent Calls</ th >
138
- < th className = "px-6 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-300 uppercase tracking-wider" > Errors</ th >
139
- </ tr >
140
- </ thead >
141
- < tbody className = "bg-white dark:bg-gray-800 divide-y divide-gray-200 dark:divide-gray-700" >
142
- { isLoading ? (
143
- < tr >
144
- < td colSpan = { 7 } className = "px-6 py-4 text-center text-gray-500 dark:text-gray-300" >
145
- Loading traces...
146
- </ td >
147
- </ tr >
148
- ) : paginatedTraces . length === 0 ? (
149
- < tr >
150
- < td colSpan = { 7 } className = "px-6 py-4 text-center text-gray-500 dark:text-gray-300" >
151
- No traces found. { ! selectedProject && "Please select a project." }
152
- </ td >
153
- </ tr >
154
- ) : (
155
- paginatedTraces . map ( ( trace ) => (
156
- < tr
157
- key = { trace . id }
158
- onClick = { ( ) => handleTraceSelect ( trace . id ) }
159
- className = { `hover:bg-gray-50 dark:hover:bg-gray-700 cursor-pointer transition-colors duration-150 ease-in-out ${ selectedTraceId === trace . id ? 'bg-purple-50 dark:bg-purple-900' : ''
160
- } `}
161
- >
162
- < td className = "px-6 py-4 whitespace-nowrap text-sm font-medium text-indigo-600 dark:text-indigo-400" >
163
- { trace . id }
164
- </ td >
165
- < td className = "px-6 py-4 whitespace-nowrap text-sm text-gray-500 dark:text-gray-300" >
166
- { new Date ( trace . start_time ) . toLocaleString ( ) }
167
- </ td >
168
- < td className = "px-6 py-4 whitespace-nowrap text-sm text-gray-500 dark:text-gray-300" >
169
- { trace . duration ? `${ trace . duration . toFixed ( 2 ) } s` : "-" }
170
- </ td >
171
- < td className = "px-6 py-4 whitespace-nowrap text-sm text-gray-500 dark:text-gray-300" >
172
- { trace . total_llm_calls ?? "-" }
173
- </ td >
174
- < td className = "px-6 py-4 whitespace-nowrap text-sm text-gray-500 dark:text-gray-300" >
175
- { trace . total_tool_calls ?? "-" }
176
- </ td >
177
- < td className = "px-6 py-4 whitespace-nowrap text-sm text-gray-500 dark:text-gray-300" >
178
- { trace . total_agent_calls ?? "-" }
179
- </ td >
180
- < td className = "px-6 py-4 whitespace-nowrap text-sm text-gray-500 dark:text-gray-300" >
181
- { trace . total_errors ?? "-" }
182
- </ td >
183
- </ tr >
184
- ) )
185
- ) }
186
- </ tbody >
187
- </ table >
188
- </ div >
197
+ </ div >
189
198
190
- < div className = "mt-6 flex justify-between items-center" >
191
- < Button
192
- onClick = { ( ) => setCurrentPage ( prev => Math . max ( prev - 1 , 1 ) ) }
193
- disabled = { currentPage === 1 }
194
- variant = "outline"
195
- className = "flex items-center"
196
- >
197
- < ChevronLeft className = "w-4 h-4 mr-2" /> Previous
198
- </ Button >
199
- < span className = "text-sm text-gray-600 dark:text-gray-300" >
200
- Page { currentPage } of { totalPages }
201
- </ span >
202
- < Button
203
- onClick = { ( ) => setCurrentPage ( prev => Math . min ( prev + 1 , totalPages ) ) }
204
- disabled = { currentPage === totalPages }
205
- variant = "outline"
206
- className = "flex items-center"
207
- >
208
- Next < ChevronRight className = "w-4 h-4 ml-2" />
209
- </ Button >
199
+ { /* Pagination - Fixed at Bottom */ }
200
+ < div className = "mt-6 flex justify-between items-center" >
201
+ < Button
202
+ onClick = { ( ) => setCurrentPage ( prev => Math . max ( prev - 1 , 1 ) ) }
203
+ disabled = { currentPage === 1 }
204
+ variant = "outline"
205
+ className = "flex items-center"
206
+ >
207
+ < ChevronLeft className = "w-4 h-4 mr-2" /> Previous
208
+ </ Button >
209
+ < span className = "text-sm text-gray-600 dark:text-gray-300" >
210
+ Page { currentPage } of { totalPages }
211
+ </ span >
212
+ < Button
213
+ onClick = { ( ) => setCurrentPage ( prev => Math . min ( prev + 1 , totalPages ) ) }
214
+ disabled = { currentPage === totalPages }
215
+ variant = "outline"
216
+ className = "flex items-center"
217
+ >
218
+ Next < ChevronRight className = "w-4 h-4 ml-2" />
219
+ </ Button >
220
+ </ div >
210
221
</ div >
211
222
</ div >
212
223
0 commit comments