@@ -69,11 +69,6 @@ PulseApp.ui.backupDetailCard = (() => {
69
69
}
70
70
71
71
function getCompactOverview ( backups , stats ) {
72
- // Debug: Log what the detail card is receiving
73
- console . log ( '[Backup Health Debug] getCompactOverview received:' , {
74
- backupsCount : backups . length ,
75
- stats : stats
76
- } ) ;
77
72
78
73
// Calculate critical metrics
79
74
const now = new Date ( ) ;
@@ -294,6 +289,9 @@ PulseApp.ui.backupDetailCard = (() => {
294
289
? ( new Date ( ) - mostRecent ) / ( 1000 * 60 * 60 * 24 )
295
290
: Infinity ;
296
291
292
+ // Get filtered backup types and counts based on active filter
293
+ const filteredBackupData = getFilteredBackupData ( guest , filterInfo ) ;
294
+
297
295
return `
298
296
<div class="grid grid-cols-12 gap-1 px-1 py-0.5 text-[11px] hover:bg-gray-50 dark:hover:bg-gray-700/30 rounded">
299
297
<div class="col-span-5 flex items-center gap-1 min-w-0">
@@ -302,12 +300,10 @@ PulseApp.ui.backupDetailCard = (() => {
302
300
<span class="truncate text-gray-700 dark:text-gray-300">${ guest . guestName } </span>
303
301
</div>
304
302
<div class="col-span-3 flex items-center justify-center gap-1 text-[9px]">
305
- ${ guest . pbsBackups > 0 ? '<span class="text-purple-600 dark:text-purple-400 font-medium">PBS</span>' : '' }
306
- ${ guest . pveBackups > 0 ? '<span class="text-orange-600 dark:text-orange-400 font-medium">PVE</span>' : '' }
307
- ${ guest . snapshotCount > 0 ? '<span class="text-yellow-600 dark:text-yellow-400 font-medium">SNAP</span>' : '' }
303
+ ${ filteredBackupData . typeLabels }
308
304
</div>
309
305
<div class="col-span-2 text-right text-gray-600 dark:text-gray-400">
310
- ${ guest . pbsBackups + guest . pveBackups + guest . snapshotCount }
306
+ ${ filteredBackupData . totalCount }
311
307
</div>
312
308
<div class="col-span-2 text-right font-medium ${ getAgeColor ( ageInDays ) } ">
313
309
${ formatAge ( ageInDays ) }
@@ -322,7 +318,7 @@ PulseApp.ui.backupDetailCard = (() => {
322
318
}
323
319
324
320
function getSingleDateContent ( data ) {
325
- const { date, backups, stats } = data ;
321
+ const { date, backups, stats, filterInfo } = data ;
326
322
327
323
if ( ! backups || backups . length === 0 ) {
328
324
return getEmptyState ( false ) ;
@@ -344,38 +340,166 @@ PulseApp.ui.backupDetailCard = (() => {
344
340
<span class="text-xs text-gray-500 dark:text-gray-400">${ stats . totalGuests } guests</span>
345
341
</div>
346
342
<div class="flex items-center gap-3 mt-1 text-[10px]">
347
- ${ stats . pbsCount > 0 ? `<span class="text-purple-600 dark:text-purple-400">PBS: ${ stats . pbsCount } </span>` : '' }
348
- ${ stats . pveCount > 0 ? `<span class="text-orange-600 dark:text-orange-400">PVE: ${ stats . pveCount } </span>` : '' }
349
- ${ stats . snapshotCount > 0 ? `<span class="text-yellow-600 dark:text-yellow-400">Snap: ${ stats . snapshotCount } </span>` : '' }
343
+ ${ getFilteredStatsDisplay ( stats , filterInfo ) }
350
344
</div>
351
345
</div>
352
346
353
347
<!-- Guest List -->
354
348
<div class="flex-1 overflow-y-auto">
355
349
<div class="space-y-0.5">
356
- ${ sortedBackups . map ( backup => `
357
- <div class="flex items-center justify-between px-1 py-0.5 text-[11px] hover:bg-gray-50 dark:hover:bg-gray-700/30 rounded">
358
- <div class="flex items-center gap-1 min-w-0">
359
- <span class="text-[9px] font-medium ${ backup . type === 'VM' ? 'text-blue-600 dark:text-blue-400' : 'text-green-600 dark:text-green-400' } ">${ backup . type } </span>
360
- <span class="font-mono text-gray-600 dark:text-gray-400">${ backup . vmid } </span>
361
- <span class="truncate text-gray-700 dark:text-gray-300">${ backup . name } </span>
362
- </div>
363
- <div class="flex items-center gap-2 ml-2">
364
- <div class="flex items-center gap-1 text-[9px]">
365
- ${ backup . types . includes ( 'pbsSnapshots' ) ? '<span class="text-purple-600 dark:text-purple-400 font-medium">PBS</span>' : '' }
366
- ${ backup . types . includes ( 'pveBackups' ) ? '<span class="text-orange-600 dark:text-orange-400 font-medium">PVE</span>' : '' }
367
- ${ backup . types . includes ( 'vmSnapshots' ) ? '<span class="text-yellow-600 dark:text-yellow-400 font-medium">SNAP</span>' : '' }
350
+ ${ sortedBackups . map ( backup => {
351
+ // Get filtered backup types and counts based on active filter
352
+ const filteredBackupData = getFilteredSingleDateBackupData ( backup , filterInfo ) ;
353
+
354
+ return `
355
+ <div class="flex items-center justify-between px-1 py-0.5 text-[11px] hover:bg-gray-50 dark:hover:bg-gray-700/30 rounded">
356
+ <div class="flex items-center gap-1 min-w-0">
357
+ <span class="text-[9px] font-medium ${ backup . type === 'VM' ? 'text-blue-600 dark:text-blue-400' : 'text-green-600 dark:text-green-400' } ">${ backup . type } </span>
358
+ <span class="font-mono text-gray-600 dark:text-gray-400">${ backup . vmid } </span>
359
+ <span class="truncate text-gray-700 dark:text-gray-300">${ backup . name } </span>
360
+ </div>
361
+ <div class="flex items-center gap-2 ml-2">
362
+ <div class="flex items-center gap-1 text-[9px]">
363
+ ${ filteredBackupData . typeLabels }
364
+ </div>
365
+ <span class="text-gray-600 dark:text-gray-400">${ filteredBackupData . backupCount } </span>
368
366
</div>
369
- <span class="text-gray-600 dark:text-gray-400">${ backup . backupCount } </span>
370
367
</div>
371
- </div>
372
- ` ) . join ( '' ) }
368
+ ` ;
369
+ } ) . join ( '' ) }
373
370
</div>
374
371
</div>
375
372
</div>
376
373
` ;
377
374
}
378
375
376
+ // Get filtered backup data based on active filter
377
+ function getFilteredBackupData ( guest , filterInfo ) {
378
+ if ( ! guest ) return { typeLabels : '' , totalCount : 0 } ;
379
+
380
+ const backupType = filterInfo ?. backupType ;
381
+
382
+ // If no specific backup type filter is active, show all types
383
+ if ( ! backupType || backupType === 'all' ) {
384
+ const typeLabels = [
385
+ guest . pbsBackups > 0 ? '<span class="text-purple-600 dark:text-purple-400 font-medium">PBS</span>' : '' ,
386
+ guest . pveBackups > 0 ? '<span class="text-orange-600 dark:text-orange-400 font-medium">PVE</span>' : '' ,
387
+ guest . snapshotCount > 0 ? '<span class="text-yellow-600 dark:text-yellow-400 font-medium">SNAP</span>' : ''
388
+ ] . filter ( label => label ) . join ( '' ) ;
389
+
390
+ return {
391
+ typeLabels,
392
+ totalCount : guest . pbsBackups + guest . pveBackups + guest . snapshotCount
393
+ } ;
394
+ }
395
+
396
+ // Show only the filtered backup type
397
+ switch ( backupType ) {
398
+ case 'pbs' :
399
+ return {
400
+ typeLabels : guest . pbsBackups > 0 ? '<span class="text-purple-600 dark:text-purple-400 font-medium">PBS</span>' : '' ,
401
+ totalCount : guest . pbsBackups
402
+ } ;
403
+ case 'pve' :
404
+ return {
405
+ typeLabels : guest . pveBackups > 0 ? '<span class="text-orange-600 dark:text-orange-400 font-medium">PVE</span>' : '' ,
406
+ totalCount : guest . pveBackups
407
+ } ;
408
+ case 'snapshots' :
409
+ return {
410
+ typeLabels : guest . snapshotCount > 0 ? '<span class="text-yellow-600 dark:text-yellow-400 font-medium">SNAP</span>' : '' ,
411
+ totalCount : guest . snapshotCount
412
+ } ;
413
+ default :
414
+ return {
415
+ typeLabels : '' ,
416
+ totalCount : 0
417
+ } ;
418
+ }
419
+ }
420
+
421
+ // Get filtered backup data for single date view based on active filter
422
+ function getFilteredSingleDateBackupData ( backup , filterInfo ) {
423
+ if ( ! backup ) return { typeLabels : '' , backupCount : 0 } ;
424
+
425
+ const backupType = filterInfo ?. backupType ;
426
+
427
+ // If no specific backup type filter is active, show all types
428
+ if ( ! backupType || backupType === 'all' ) {
429
+ const typeLabels = [
430
+ backup . types . includes ( 'pbsSnapshots' ) ? '<span class="text-purple-600 dark:text-purple-400 font-medium">PBS</span>' : '' ,
431
+ backup . types . includes ( 'pveBackups' ) ? '<span class="text-orange-600 dark:text-orange-400 font-medium">PVE</span>' : '' ,
432
+ backup . types . includes ( 'vmSnapshots' ) ? '<span class="text-yellow-600 dark:text-yellow-400 font-medium">SNAP</span>' : ''
433
+ ] . filter ( label => label ) . join ( '' ) ;
434
+
435
+ return {
436
+ typeLabels,
437
+ backupCount : backup . backupCount
438
+ } ;
439
+ }
440
+
441
+ // Show only the filtered backup type
442
+ const typeMapping = {
443
+ 'pbs' : 'pbsSnapshots' ,
444
+ 'pve' : 'pveBackups' ,
445
+ 'snapshots' : 'vmSnapshots'
446
+ } ;
447
+
448
+ const targetType = typeMapping [ backupType ] ;
449
+ if ( backup . types . includes ( targetType ) ) {
450
+ switch ( backupType ) {
451
+ case 'pbs' :
452
+ return {
453
+ typeLabels : '<span class="text-purple-600 dark:text-purple-400 font-medium">PBS</span>' ,
454
+ backupCount : backup . backupCount // Note: This shows total count, which may include other types
455
+ } ;
456
+ case 'pve' :
457
+ return {
458
+ typeLabels : '<span class="text-orange-600 dark:text-orange-400 font-medium">PVE</span>' ,
459
+ backupCount : backup . backupCount
460
+ } ;
461
+ case 'snapshots' :
462
+ return {
463
+ typeLabels : '<span class="text-yellow-600 dark:text-yellow-400 font-medium">SNAP</span>' ,
464
+ backupCount : backup . backupCount
465
+ } ;
466
+ }
467
+ }
468
+
469
+ return {
470
+ typeLabels : '' ,
471
+ backupCount : 0
472
+ } ;
473
+ }
474
+
475
+ // Get filtered stats display for single date view
476
+ function getFilteredStatsDisplay ( stats , filterInfo ) {
477
+ if ( ! stats ) return '' ;
478
+
479
+ const backupType = filterInfo ?. backupType ;
480
+
481
+ // If no specific backup type filter is active, show all stats
482
+ if ( ! backupType || backupType === 'all' ) {
483
+ return [
484
+ stats . pbsCount > 0 ? `<span class="text-purple-600 dark:text-purple-400">PBS: ${ stats . pbsCount } </span>` : '' ,
485
+ stats . pveCount > 0 ? `<span class="text-orange-600 dark:text-orange-400">PVE: ${ stats . pveCount } </span>` : '' ,
486
+ stats . snapshotCount > 0 ? `<span class="text-yellow-600 dark:text-yellow-400">Snap: ${ stats . snapshotCount } </span>` : ''
487
+ ] . filter ( stat => stat ) . join ( '' ) ;
488
+ }
489
+
490
+ // Show only the filtered backup type stat
491
+ switch ( backupType ) {
492
+ case 'pbs' :
493
+ return stats . pbsCount > 0 ? `<span class="text-purple-600 dark:text-purple-400">PBS: ${ stats . pbsCount } </span>` : '' ;
494
+ case 'pve' :
495
+ return stats . pveCount > 0 ? `<span class="text-orange-600 dark:text-orange-400">PVE: ${ stats . pveCount } </span>` : '' ;
496
+ case 'snapshots' :
497
+ return stats . snapshotCount > 0 ? `<span class="text-yellow-600 dark:text-yellow-400">Snap: ${ stats . snapshotCount } </span>` : '' ;
498
+ default :
499
+ return '' ;
500
+ }
501
+ }
502
+
379
503
// Helper functions
380
504
function formatAge ( ageInDays ) {
381
505
if ( ageInDays === Infinity ) return 'Never' ;
@@ -438,14 +562,34 @@ PulseApp.ui.backupDetailCard = (() => {
438
562
const updateContent = ( ) => {
439
563
const newContent = ! data ? getEmptyState ( false ) : getDetailContent ( data ) ;
440
564
565
+ // Find scrollable container and preserve scroll position
566
+ const scrollableContainer = contentDiv . querySelector ( '.overflow-y-auto' ) ;
567
+ const scrollTop = scrollableContainer ? scrollableContainer . scrollTop : 0 ;
568
+
441
569
if ( ! instant ) {
442
570
contentDiv . style . opacity = '0' ;
443
571
setTimeout ( ( ) => {
444
572
contentDiv . innerHTML = newContent ;
445
573
contentDiv . style . opacity = '1' ;
574
+
575
+ // Restore scroll position
576
+ requestAnimationFrame ( ( ) => {
577
+ const newScrollableContainer = contentDiv . querySelector ( '.overflow-y-auto' ) ;
578
+ if ( newScrollableContainer && scrollTop > 0 ) {
579
+ newScrollableContainer . scrollTop = scrollTop ;
580
+ }
581
+ } ) ;
446
582
} , 150 ) ;
447
583
} else {
448
584
contentDiv . innerHTML = newContent ;
585
+
586
+ // Restore scroll position for instant updates
587
+ requestAnimationFrame ( ( ) => {
588
+ const newScrollableContainer = contentDiv . querySelector ( '.overflow-y-auto' ) ;
589
+ if ( newScrollableContainer && scrollTop > 0 ) {
590
+ newScrollableContainer . scrollTop = scrollTop ;
591
+ }
592
+ } ) ;
449
593
}
450
594
} ;
451
595
0 commit comments