@@ -73,6 +73,7 @@ const DeviceStatusPanel = ({ isInferenceRunning, setNotifications }: DeviceStatu
73
73
memory : { warning : 85 , error : 90 , compare : "gt" as ComparisonOperator } ,
74
74
disk : { warning : 90 , error : 95 , compare : "gt" as ComparisonOperator } ,
75
75
performance : {
76
+ latency_mean : { warning : 20.0 , error : 30.0 , compare : "gt" as ComparisonOperator } ,
76
77
latency_p95 : { warning : 1.35 , error : 1.75 , compare : "gt" as ComparisonOperator } ,
77
78
fps_mean : { warning : 1.05 , error : 1.1 , compare : "gt" as ComparisonOperator } ,
78
79
} ,
@@ -102,7 +103,7 @@ const DeviceStatusPanel = ({ isInferenceRunning, setNotifications }: DeviceStatu
102
103
) ;
103
104
104
105
const addFlashMessage = useCallback (
105
- ( id : string , content : string , type : FlashbarProps . Type ) => {
106
+ ( id : string , content : string , type : FlashbarProps . Type , header ?: string ) => {
106
107
// Check if a message with this ID already exists and update it if needed
107
108
setNotifications ( ( prev ) => {
108
109
const existingMessageIndex = prev . findIndex ( ( message ) => message . id === id ) ;
@@ -114,6 +115,7 @@ const DeviceStatusPanel = ({ isInferenceRunning, setNotifications }: DeviceStatu
114
115
type,
115
116
dismissible : type !== "in-progress" ,
116
117
onDismiss : type !== "in-progress" ? ( ) => removeFlashMessage ( id ) : undefined ,
118
+ ...( header && { header } ) ,
117
119
} ;
118
120
119
121
// If message already exists, update it
@@ -171,79 +173,146 @@ const DeviceStatusPanel = ({ isInferenceRunning, setNotifications }: DeviceStatu
171
173
172
174
const allAlerts = useMemo (
173
175
( ) => ( {
174
- "device-status-cpu-usage" : {
175
- metricValue : metrics . cpuUsage ,
176
- status : checkStatus ( metrics . cpuUsage , thresholds . cpu . usage ) ,
177
- warningMessage : "CPU Usage is high" ,
178
- errorMessage : "CPU Usage is extremely high" ,
176
+ system : {
177
+ "device-status-memory-usage" : {
178
+ metricValue : metrics . memoryUsage ,
179
+ status : checkStatus ( metrics . memoryUsage , thresholds . memory ) ,
180
+ warningMessage : "Memory Usage is high" ,
181
+ errorMessage : "Memory Usage is extremely high" ,
182
+ } ,
183
+ "device-status-disk-usage" : {
184
+ metricValue : metrics . diskUsage ,
185
+ status : checkStatus ( metrics . diskUsage , thresholds . disk ) ,
186
+ warningMessage : "Disk Usage is high" ,
187
+ errorMessage : "Disk Usage is extremely high" ,
188
+ } ,
189
+ "device-status-cpu-freq" : {
190
+ metricValue : ( metrics . cpuFreq / metrics . cpuFreqMax ) * 100.0 ,
191
+ status : checkStatusWithInference (
192
+ ( metrics . cpuFreq / metrics . cpuFreqMax ) * 100.0 ,
193
+ thresholds . cpu . frequency ,
194
+ isInferenceRunning ,
195
+ 2 ,
196
+ "info"
197
+ ) ,
198
+ warningMessage : "CPU Frequency is low" ,
199
+ errorMessage : "CPU Frequency is critically low" ,
200
+ updateDelay : 2 ,
201
+ noInferenceStatus : "info" as "info" | "stopped" | "pending" ,
202
+ } ,
179
203
} ,
180
- "device-status-cpu-temp" : {
181
- metricValue : metrics . temperature ,
182
- status : checkStatus ( metrics . temperature , thresholds . cpu . temperature ) ,
183
- warningMessage : "CPU Temperature is high" ,
184
- errorMessage : "CPU Temperature is extremely high" ,
185
- } ,
186
- "device-status-memory-usage" : {
187
- metricValue : metrics . memoryUsage ,
188
- status : checkStatus ( metrics . memoryUsage , thresholds . memory ) ,
189
- warningMessage : "Memory Usage is high" ,
190
- errorMessage : "Memory Usage is extremely high" ,
191
- } ,
192
- "device-status-disk-usage" : {
193
- metricValue : metrics . diskUsage ,
194
- status : checkStatus ( metrics . diskUsage , thresholds . disk ) ,
195
- warningMessage : "Disk Usage is high" ,
196
- errorMessage : "Disk Usage is extremely high" ,
197
- } ,
198
- "device-status-cpu-freq" : {
199
- metricValue : ( metrics . cpuFreq / metrics . cpuFreqMax ) * 100.0 ,
200
- status : checkStatusWithInference (
201
- ( metrics . cpuFreq / metrics . cpuFreqMax ) * 100.0 ,
202
- thresholds . cpu . frequency ,
203
- isInferenceRunning ,
204
- 2 ,
205
- "info"
206
- ) ,
207
- warningMessage : "CPU Frequency is low" ,
208
- errorMessage : "CPU Frequency is critically low" ,
209
- updateDelay : 2 ,
210
- noInferenceStatus : "info" as "info" | "stopped" | "pending" ,
211
- } ,
212
- "device-status-latency-p95" : {
213
- metricValue : metrics . latencyP95 / metrics . latencyMean ,
214
- status : checkStatusWithInference (
215
- metrics . latencyP95 / metrics . latencyMean ,
216
- thresholds . performance . latency_p95 ,
217
- isInferenceRunning ,
218
- 2 ,
219
- "stopped"
220
- ) ,
221
- warningMessage : "95% Latency is high" ,
222
- errorMessage : "95% Latency is critically high" ,
223
- updateDelay : 2 ,
224
- noInferenceStatus : "stopped" as "info" | "stopped" | "pending" ,
225
- } ,
226
- "device-status-fps-mean" : {
227
- metricValue : 30.0 / metrics . fpsMean ,
228
- status : checkStatusWithInference (
229
- 30.0 / metrics . fpsMean ,
230
- thresholds . performance . fps_mean ,
231
- isInferenceRunning ,
232
- 2 ,
233
- "stopped"
234
- ) ,
235
- warningMessage : "Frame Rate is low" ,
236
- errorMessage : "Frame Rate is critically low" ,
237
- updateDelay : 2 ,
238
- noInferenceStatus : "stopped" as "info" | "stopped" | "pending" ,
204
+ performance : {
205
+ "device-status-cpu-temp" : {
206
+ metricValue : metrics . temperature ,
207
+ status : checkStatus ( metrics . temperature , thresholds . cpu . temperature ) ,
208
+ warningMessage : "CPU Temperature is high" ,
209
+ errorMessage : "CPU Temperature is extremely high" ,
210
+ } ,
211
+ "device-status-cpu-usage" : {
212
+ metricValue : metrics . cpuUsage ,
213
+ status : checkStatusWithInference (
214
+ metrics . cpuUsage ,
215
+ thresholds . cpu . usage ,
216
+ isInferenceRunning ,
217
+ 2 ,
218
+ "info"
219
+ ) ,
220
+ warningMessage : "CPU Usage is high" ,
221
+ errorMessage : "CPU Usage is extremely high" ,
222
+ updateDelay : 2 ,
223
+ } ,
224
+ "device-status-latency" : {
225
+ metricValue : metrics . latencyMean ,
226
+ status : checkStatusWithInference (
227
+ metrics . latencyMean ,
228
+ thresholds . performance . latency_mean ,
229
+ isInferenceRunning ,
230
+ 2 ,
231
+ "stopped"
232
+ ) ,
233
+ warningMessage : "Latency is high" ,
234
+ errorMessage : "Latency is critically high" ,
235
+ updateDelay : 2 ,
236
+ noInferenceStatus : "stopped" as "info" | "stopped" | "pending" ,
237
+ } ,
238
+ "device-status-latency-p95" : {
239
+ metricValue : metrics . latencyP95 / metrics . latencyMean ,
240
+ status : checkStatusWithInference (
241
+ metrics . latencyP95 / metrics . latencyMean ,
242
+ thresholds . performance . latency_p95 ,
243
+ isInferenceRunning ,
244
+ 2 ,
245
+ "stopped"
246
+ ) ,
247
+ warningMessage : "95% Latency is high" ,
248
+ errorMessage : "95% Latency is critically high" ,
249
+ updateDelay : 2 ,
250
+ noInferenceStatus : "stopped" as "info" | "stopped" | "pending" ,
251
+ } ,
252
+ "device-status-fps-mean" : {
253
+ metricValue : 30.0 / metrics . fpsMean ,
254
+ status : checkStatusWithInference (
255
+ 30.0 / metrics . fpsMean ,
256
+ thresholds . performance . fps_mean ,
257
+ isInferenceRunning ,
258
+ 2 ,
259
+ "stopped"
260
+ ) ,
261
+ warningMessage : "Frame Rate is low" ,
262
+ errorMessage : "Frame Rate is critically low" ,
263
+ updateDelay : 2 ,
264
+ noInferenceStatus : "stopped" as "info" | "stopped" | "pending" ,
265
+ } ,
239
266
} ,
240
267
} ) ,
241
268
[ metrics , thresholds , checkStatus , checkStatusWithInference , isInferenceRunning ]
242
269
) ;
243
270
271
+ // Get combined performance metrics status and message
272
+ const performanceMetricsAlert = useMemo ( ( ) => {
273
+ const performanceAlerts = Object . values ( allAlerts . performance ) ;
274
+
275
+ // Get the worst status (error > warning > success/info/stopped/pending)
276
+ const getStatusPriority = ( status : string ) : number => {
277
+ switch ( status ) {
278
+ case "error" :
279
+ return 2 ;
280
+ case "warning" :
281
+ return 1 ;
282
+ default :
283
+ return 0 ; // info, success, stopped, pending
284
+ }
285
+ } ;
286
+
287
+ const worstStatus = performanceAlerts
288
+ . map ( ( alert ) => alert . status )
289
+ . reduce (
290
+ ( worst , current ) =>
291
+ getStatusPriority ( current ) > getStatusPriority ( worst ) ? current : worst ,
292
+ "success" as string
293
+ ) ;
294
+
295
+ // Build a combined message including both warnings and errors
296
+ const errorMessages = performanceAlerts
297
+ . filter ( ( alert ) => alert . status === "error" )
298
+ . map ( ( alert ) => alert . errorMessage ) ;
299
+
300
+ const warningMessages = performanceAlerts
301
+ . filter ( ( alert ) => alert . status === "warning" )
302
+ . map ( ( alert ) => alert . warningMessage ) ;
303
+
304
+ const messages = [ ...errorMessages , ...warningMessages ] ;
305
+
306
+ return {
307
+ status : worstStatus ,
308
+ message : messages . join ( ". " ) + "." ,
309
+ hasIssue : worstStatus === "warning" || worstStatus === "error" ,
310
+ } ;
311
+ } , [ allAlerts . performance ] ) ;
312
+
244
313
// Separate effects for handling warning and error messages based on metrics
245
314
useEffect ( ( ) => {
246
- Object . entries ( allAlerts ) . forEach ( ( [ alertId , data ] ) => {
315
+ Object . entries ( allAlerts . system ) . forEach ( ( [ alertId , data ] ) => {
247
316
if ( data . status === "error" ) {
248
317
addFlashMessage ( alertId , data . errorMessage , "error" ) ;
249
318
} else if ( data . status === "warning" ) {
@@ -252,7 +321,41 @@ const DeviceStatusPanel = ({ isInferenceRunning, setNotifications }: DeviceStatu
252
321
removeFlashMessage ( alertId ) ;
253
322
}
254
323
} ) ;
255
- } , [ addFlashMessage , removeFlashMessage , allAlerts ] ) ;
324
+ } , [ addFlashMessage , removeFlashMessage , allAlerts . system ] ) ;
325
+
326
+ useEffect ( ( ) => {
327
+ // Handle combined performance metrics alert
328
+ const performanceAlertId = "device-status-performance" ;
329
+ if ( performanceMetricsAlert . hasIssue ) {
330
+ addFlashMessage (
331
+ performanceAlertId ,
332
+ performanceMetricsAlert . message ,
333
+ performanceMetricsAlert . status as FlashbarProps . Type ,
334
+ "Potential Performance Issue"
335
+ ) ;
336
+ } else {
337
+ // For performance messages, convert to info with last contents as reference
338
+ setNotifications ( ( prev ) => {
339
+ const existingMessageIndex = prev . findIndex ( ( message ) => message . id === performanceAlertId ) ;
340
+ if ( existingMessageIndex >= 0 ) {
341
+ const existingMessage = prev [ existingMessageIndex ] ;
342
+ if ( existingMessage . type === "info" ) {
343
+ return prev ; // If the status is already "info", do nothing
344
+ }
345
+ const lastContent = existingMessage . content ;
346
+ const updatedMessages = [ ...prev ] ;
347
+ updatedMessages [ existingMessageIndex ] = {
348
+ ...existingMessage ,
349
+ type : "info" ,
350
+ content : `Last Error: ${ lastContent } ` ,
351
+ header : "Performance issue resolved" ,
352
+ } ;
353
+ return updatedMessages ;
354
+ }
355
+ return prev ;
356
+ } ) ;
357
+ }
358
+ } , [ addFlashMessage , removeFlashMessage , performanceMetricsAlert , setNotifications ] ) ;
256
359
257
360
// Count updates since inference started
258
361
useEffect ( ( ) => {
@@ -306,17 +409,17 @@ const DeviceStatusPanel = ({ isInferenceRunning, setNotifications }: DeviceStatu
306
409
< Box variant = "h4" > CPU</ Box >
307
410
< div style = { { display : "grid" , gridTemplateColumns : "100px auto" , rowGap : "6px" } } >
308
411
< Box > Usage:</ Box >
309
- < StatusIndicator type = { allAlerts [ "device-status-cpu-usage" ] . status } >
412
+ < StatusIndicator type = { allAlerts . performance [ "device-status-cpu-usage" ] . status } >
310
413
{ metrics . cpuUsage } %
311
414
</ StatusIndicator >
312
415
313
416
< Box > Temperature:</ Box >
314
- < StatusIndicator type = { allAlerts [ "device-status-cpu-temp" ] . status } >
417
+ < StatusIndicator type = { allAlerts . performance [ "device-status-cpu-temp" ] . status } >
315
418
{ metrics . temperature } °C
316
419
</ StatusIndicator >
317
420
318
421
< Box > Frequency:</ Box >
319
- < StatusIndicator type = { allAlerts [ "device-status-cpu-freq" ] . status } >
422
+ < StatusIndicator type = { allAlerts . system [ "device-status-cpu-freq" ] . status } >
320
423
{ metrics . cpuFreq } MHz / { metrics . cpuFreqMax } MHz
321
424
</ StatusIndicator >
322
425
</ div >
@@ -327,12 +430,12 @@ const DeviceStatusPanel = ({ isInferenceRunning, setNotifications }: DeviceStatu
327
430
< Box variant = "h4" > Memory Usage</ Box >
328
431
< div style = { { display : "grid" , gridTemplateColumns : "100px auto" , rowGap : "6px" } } >
329
432
< Box > RAM:</ Box >
330
- < StatusIndicator type = { allAlerts [ "device-status-memory-usage" ] . status } >
433
+ < StatusIndicator type = { allAlerts . system [ "device-status-memory-usage" ] . status } >
331
434
{ metrics . memoryUsage } %
332
435
</ StatusIndicator >
333
436
334
437
< Box > Disk:</ Box >
335
- < StatusIndicator type = { allAlerts [ "device-status-disk-usage" ] . status } >
438
+ < StatusIndicator type = { allAlerts . system [ "device-status-disk-usage" ] . status } >
336
439
{ metrics . diskUsage } %
337
440
</ StatusIndicator >
338
441
</ div >
@@ -343,15 +446,15 @@ const DeviceStatusPanel = ({ isInferenceRunning, setNotifications }: DeviceStatu
343
446
< Box variant = "h4" > Performance</ Box >
344
447
< div style = { { display : "grid" , gridTemplateColumns : "100px auto" , rowGap : "6px" } } >
345
448
< Box > Mean Latency:</ Box >
346
- < StatusIndicator type = { isInferenceRunning ? "info" : "stopped" } >
449
+ < StatusIndicator type = { allAlerts . performance [ "device-status-latency" ] . status } >
347
450
{ metrics . latencyMean . toFixed ( 1 ) } ms
348
451
</ StatusIndicator >
349
452
< Box > 95% Latency:</ Box >
350
- < StatusIndicator type = { allAlerts [ "device-status-latency-p95" ] . status } >
453
+ < StatusIndicator type = { allAlerts . performance [ "device-status-latency-p95" ] . status } >
351
454
{ metrics . latencyP95 . toFixed ( 1 ) } ms
352
455
</ StatusIndicator >
353
456
< Box > Frame Rate:</ Box >
354
- < StatusIndicator type = { allAlerts [ "device-status-fps-mean" ] . status } >
457
+ < StatusIndicator type = { allAlerts . performance [ "device-status-fps-mean" ] . status } >
355
458
{ metrics . fpsMean . toFixed ( 1 ) } fps
356
459
</ StatusIndicator >
357
460
</ div >
0 commit comments