diff --git a/src/public/index.html b/src/public/index.html
index c240a0b56..e2dc41727 100644
--- a/src/public/index.html
+++ b/src/public/index.html
@@ -796,7 +796,7 @@
PBS Backups |
PVE Backups |
Snapshots |
- 7-Day History |
+ 7-Day History |
@@ -804,7 +804,30 @@
No backup data found matching filters.
- Loading backup status...
+
+
Loading backup status...
+
+
+ PBS
+
+
+ PVE
+
+
+ Snapshots
+
+ •
+
+ Success
+
+
+ Failed
+
+
+ No Activity
+
+
+
diff --git a/src/public/js/ui/backups.js b/src/public/js/ui/backups.js
index a172f926a..cd18c95e7 100644
--- a/src/public/js/ui/backups.js
+++ b/src/public/js/ui/backups.js
@@ -219,35 +219,71 @@ PulseApp.ui.backups = (() => {
displayTimestamp = null;
}
- // Optimized 7-day backup status calculation using pre-calculated boundaries
- const last7DaysBackupStatus = dayBoundaries.map(day => {
+ // Enhanced 7-day backup status calculation with detailed activity info
+ const last7DaysBackupStatus = dayBoundaries.map((day, index) => {
let dailyStatus = 'none';
+ let activityDetails = [];
// Check tasks for this day - using pre-filtered guest tasks
if (guestTasks) {
- const failedTaskOnThisDay = guestTasks.find(task =>
+ const failedTasksOnThisDay = guestTasks.filter(task =>
task.startTime >= day.start && task.startTime < day.end && task.status !== 'OK'
);
- const successfulTaskOnThisDay = guestTasks.find(task =>
+ const successfulTasksOnThisDay = guestTasks.filter(task =>
task.startTime >= day.start && task.startTime < day.end && task.status === 'OK'
);
- if (failedTaskOnThisDay) {
+ // Add task details
+ successfulTasksOnThisDay.forEach(task => {
+ const source = task.source === 'pbs' ? 'PBS' : 'PVE';
+ const location = task.source === 'pbs' ? task.pbsInstanceName : 'Local';
+ activityDetails.push(`✓ ${source} backup${location ? ` (${location})` : ''}`);
+ });
+
+ failedTasksOnThisDay.forEach(task => {
+ const source = task.source === 'pbs' ? 'PBS' : 'PVE';
+ const location = task.source === 'pbs' ? task.pbsInstanceName : 'Local';
+ activityDetails.push(`✗ ${source} backup failed${location ? ` (${location})` : ''}`);
+ });
+
+ if (failedTasksOnThisDay.length > 0) {
dailyStatus = 'failed';
- } else if (successfulTaskOnThisDay) {
+ } else if (successfulTasksOnThisDay.length > 0) {
dailyStatus = 'ok';
- } else if (guestSnapshots) {
- // Check snapshots as fallback - using pre-filtered guest snapshots
- const snapshotOnThisDay = guestSnapshots.some(
- snap => snap['backup-time'] >= day.start && snap['backup-time'] < day.end
- );
- if (snapshotOnThisDay) {
- dailyStatus = 'ok';
- }
}
}
- return dailyStatus;
+ // Check for backup storage activity (snapshots/backups created)
+ if (guestSnapshots && dailyStatus === 'none') {
+ const snapshotsOnThisDay = guestSnapshots.filter(
+ snap => snap['backup-time'] >= day.start && snap['backup-time'] < day.end
+ );
+
+ if (snapshotsOnThisDay.length > 0) {
+ snapshotsOnThisDay.forEach(snap => {
+ if (snap.source === 'pbs') {
+ activityDetails.push(`✓ PBS backup stored (${snap.pbsInstanceName})`);
+ } else if (snap.source === 'pve') {
+ activityDetails.push(`✓ PVE backup stored (${snap.storage || 'Local'})`);
+ }
+ });
+ dailyStatus = 'ok';
+ }
+ }
+
+ // Create day label for tooltip
+ const dayDate = new Date(day.start * 1000);
+ const dayLabel = dayDate.toLocaleDateString('en-US', {
+ weekday: 'short',
+ month: 'short',
+ day: 'numeric'
+ });
+
+ return {
+ status: dailyStatus,
+ details: activityDetails.length > 0 ? activityDetails.join('\n') : 'No backup activity',
+ date: dayLabel
+ };
});
// Calculate separate PBS and PVE backup information
@@ -389,24 +425,24 @@ PulseApp.ui.backups = (() => {
: 'ct-icon bg-green-100 dark:bg-green-900/50 text-green-700 dark:text-green-300 px-1.5 py-0.5 font-medium';
const typeIcon = `${guestStatus.guestType}`;
- // Generate 7-day backup dots
- let sevenDayDots = '';
+ // Generate 7-day backup dots with enhanced tooltips
+ let sevenDayDots = '
';
if (guestStatus.last7DaysBackupStatus && guestStatus.last7DaysBackupStatus.length === 7) {
- guestStatus.last7DaysBackupStatus.forEach(status => {
+ guestStatus.last7DaysBackupStatus.forEach(dayInfo => {
let dotClass = 'bg-gray-300 dark:bg-gray-600'; // Default for 'none'
- let dotTitle = 'No backup';
- if (status === 'ok') {
+ let dotTitle = `${dayInfo.date}: ${dayInfo.details}`;
+
+ if (dayInfo.status === 'ok') {
dotClass = 'bg-green-500';
- dotTitle = 'Successful backup';
- } else if (status === 'failed') {
+ } else if (dayInfo.status === 'failed') {
dotClass = 'bg-red-500';
- dotTitle = 'Failed backup';
}
+
sevenDayDots += ``;
});
} else {
for (let i = 0; i < 7; i++) {
- sevenDayDots += ''; // Placeholder if data is missing
+ sevenDayDots += '';
}
}
sevenDayDots += '
';