mirror of
https://github.com/rcourtman/Pulse.git
synced 2026-09-10 10:35:51 +00:00
cbd6964ac8
Enhanced backup health status calculations with more accurate age-based categorization and improved UI filtering. Added comprehensive backup data validation test suite and ground truth testing framework. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
153 lines
6.0 KiB
HTML
153 lines
6.0 KiB
HTML
<!DOCTYPE html>
|
|
<html>
|
|
<head>
|
|
<title>Test Backup Health Fix</title>
|
|
<style>
|
|
body { font-family: Arial, sans-serif; padding: 20px; }
|
|
.status { margin: 20px 0; padding: 15px; border: 1px solid #ccc; background: #f0f0f0; }
|
|
.success { background: #d4edda; border-color: #c3e6cb; }
|
|
.error { background: #f8d7da; border-color: #f5c6cb; }
|
|
pre { background: #f4f4f4; padding: 10px; overflow-x: auto; }
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<h1>Backup Health Fix Test</h1>
|
|
|
|
<div id="status" class="status">
|
|
<h3>Instructions:</h3>
|
|
<ol>
|
|
<li>Start the Pulse server: <code>npm run dev</code></li>
|
|
<li>Open this file in a browser</li>
|
|
<li>Open the browser console to see debug logs</li>
|
|
<li>Click "Connect to Pulse" below</li>
|
|
<li>Look for "[Backup Health Debug]" messages in the console</li>
|
|
</ol>
|
|
</div>
|
|
|
|
<button onclick="connectToPulse()">Connect to Pulse</button>
|
|
|
|
<div id="results"></div>
|
|
|
|
<script>
|
|
async function connectToPulse() {
|
|
const statusDiv = document.getElementById('status');
|
|
const resultsDiv = document.getElementById('results');
|
|
|
|
statusDiv.innerHTML = '<p>Connecting to Pulse WebSocket...</p>';
|
|
|
|
try {
|
|
const ws = new WebSocket('ws://localhost:7655');
|
|
|
|
ws.onopen = () => {
|
|
console.log('[Test] Connected to Pulse');
|
|
statusDiv.innerHTML = '<p>Connected! Check the browser console for debug logs.</p>';
|
|
statusDiv.className = 'status success';
|
|
|
|
// Request initial data
|
|
ws.send(JSON.stringify({ type: 'requestData' }));
|
|
};
|
|
|
|
ws.onmessage = (event) => {
|
|
const data = JSON.parse(event.data);
|
|
if (data.type === 'stateUpdate') {
|
|
console.log('[Test] Received state update');
|
|
analyzeBackupData(data);
|
|
}
|
|
};
|
|
|
|
ws.onerror = (error) => {
|
|
console.error('[Test] WebSocket error:', error);
|
|
statusDiv.innerHTML = '<p>Error connecting to Pulse. Make sure the server is running.</p>';
|
|
statusDiv.className = 'status error';
|
|
};
|
|
|
|
ws.onclose = () => {
|
|
console.log('[Test] WebSocket closed');
|
|
};
|
|
|
|
} catch (error) {
|
|
console.error('[Test] Error:', error);
|
|
statusDiv.innerHTML = '<p>Error: ' + error.message + '</p>';
|
|
statusDiv.className = 'status error';
|
|
}
|
|
}
|
|
|
|
function analyzeBackupData(data) {
|
|
const resultsDiv = document.getElementById('results');
|
|
|
|
// Count guests
|
|
const totalGuests = (data.vmsData || []).length + (data.containersData || []).length;
|
|
|
|
// Analyze backup ages
|
|
const now = Date.now() / 1000;
|
|
const categories = {
|
|
'<24h': 0,
|
|
'1-7d': 0,
|
|
'7-14d': 0,
|
|
'>14d': 0,
|
|
'none': 0
|
|
};
|
|
|
|
const allGuests = [...(data.vmsData || []), ...(data.containersData || [])];
|
|
allGuests.forEach(guest => {
|
|
let mostRecentBackup = null;
|
|
|
|
// Check PBS backups
|
|
if (data.pbs && Array.isArray(data.pbs)) {
|
|
data.pbs.forEach(pbsInstance => {
|
|
if (pbsInstance.datastores) {
|
|
pbsInstance.datastores.forEach(ds => {
|
|
if (ds.snapshots) {
|
|
ds.snapshots.forEach(snap => {
|
|
if (snap['backup-id'] == guest.vmid) {
|
|
const backupTime = snap['backup-time'];
|
|
if (!mostRecentBackup || backupTime > mostRecentBackup) {
|
|
mostRecentBackup = backupTime;
|
|
}
|
|
}
|
|
});
|
|
}
|
|
});
|
|
}
|
|
});
|
|
}
|
|
|
|
if (!mostRecentBackup) {
|
|
categories.none++;
|
|
} else {
|
|
const ageSeconds = now - mostRecentBackup;
|
|
const ageDays = ageSeconds / (24 * 60 * 60);
|
|
if (ageDays < 1) categories['<24h']++;
|
|
else if (ageDays <= 7) categories['1-7d']++;
|
|
else if (ageDays <= 14) categories['7-14d']++;
|
|
else categories['>14d']++;
|
|
}
|
|
});
|
|
|
|
// Calculate expected health score
|
|
const totalIssues = categories['>14d'] + categories.none;
|
|
const expectedHealthScore = Math.round(((totalGuests - totalIssues) / totalGuests) * 100);
|
|
|
|
const html = `
|
|
<div class="status">
|
|
<h3>Expected Results:</h3>
|
|
<pre>
|
|
Total Guests: ${totalGuests}
|
|
Health Distribution:
|
|
<24h: ${categories['<24h']} guests
|
|
1-7d: ${categories['1-7d']} guests
|
|
7-14d: ${categories['7-14d']} guests
|
|
>14d: ${categories['>14d']} guests
|
|
none: ${categories.none} guests
|
|
|
|
Expected Health Score: ${expectedHealthScore}%
|
|
</pre>
|
|
<p><strong>Check the browser console for "[Backup Health Debug]" messages to see what the UI is actually calculating.</strong></p>
|
|
</div>
|
|
`;
|
|
|
|
resultsDiv.innerHTML = html;
|
|
}
|
|
</script>
|
|
</body>
|
|
</html> |