Team Ai
Apppublic

EmDubyaJr/sql-backup-guardian

sourceHugging Faceupdated 1y agoView on Hugging Face
0likes
script.js371 linesDownload Raw Back to root
1 2// Processed backup data3const backupData = [4    {5        id: 1,6        name: "model",7        server: "BISQL2016",8        type: "Full",9        date: "2023-10-23T07:05:00",10        size: "N/A",11        status: "Success",12        recoveryModel: "FULL",13        logReuseWaitDesc: "LOG_BACKUP",14        lastDiffBackup: null,15        lastLogBackup: null,16        lastCheckDB: "2023-10-22T16:00:00"17    },18    {19        id: 2,20        name: "BrightStar_DW",21        server: "BISQL2016",22        type: "Full",23        date: "2023-10-22T23:21:00",24        size: "N/A",25        status: "Success",26        recoveryModel: "SIMPLE",27        logReuseWaitDesc: "NOTHING",28        lastDiffBackup: null,29        lastLogBackup: null,30        lastCheckDB: "2023-10-19T16:15:00"31    },32    {33        id: 3,34        name: "DBA",35        server: "BISQL2016",36        type: "Full",37        date: "2023-10-22T23:21:00",38        size: "N/A",39        status: "Success",40        recoveryModel: "SIMPLE",41        logReuseWaitDesc: "NOTHING",42        lastDiffBackup: null,43        lastLogBackup: null,44        lastCheckDB: "2023-10-19T16:25:00"45    },46    // Add more entries from the provided data...47{48        id: 2,49        name: "OrdersDB",50        type: "Differential",51        date: "2023-06-15T01:00:00Z",52        size: "4.2 GB",53        status: "Success",54        recoveryModel: "Full",55        backupPath: "E:\\Backups\\OrdersDB_Diff_20230615.bak",56        duration: "5 min",57        compression: "Enabled",58        expiration: "2023-06-22"59    },60    {61        id: 3,62        name: "InventoryDB",63        type: "Log",64        date: "2023-06-15T10:15:00Z",65        size: "1.8 GB",66        status: "Success",67        recoveryModel: "Full",68        backupPath: "E:\\Backups\\InventoryDB_Log_20230615.trn",69        duration: "2 min",70        compression: "Enabled",71        expiration: "2023-06-16"72    },73    {74        id: 4,75        name: "ReportingDB",76        type: "Full",77        date: "2023-06-14T22:00:00Z",78        size: "8.7 GB",79        status: "Warning",80        recoveryModel: "Simple",81        backupPath: "E:\\Backups\\ReportingDB_Full_20230614.bak",82        duration: "10 min",83        compression: "Disabled",84        expiration: "2023-07-14"85    },86    {87        id: 5,88        name: "HRDB",89        type: "Full",90        date: "2023-06-10T02:00:00Z",91        size: "3.5 GB",92        status: "Error",93        recoveryModel: "Full",94        backupPath: "E:\\Backups\\HRDB_Full_20230610.bak",95        duration: "8 min",96        compression: "Enabled",97        expiration: "2023-07-10"98    },99    {100        id: 6,101        name: "ProductsDB",102        type: "Full",103        date: "2023-06-15T03:00:00Z",104        size: "7.1 GB",105        status: "Success",106        recoveryModel: "Full",107        backupPath: "E:\\Backups\\ProductsDB_Full_20230615.bak",108        duration: "12 min",109        compression: "Enabled",110        expiration: "2023-07-15"111    },112    {113        id: 7,114        name: "LogisticsDB",115        type: "Differential",116        date: "2023-06-15T04:30:00Z",117        size: "2.9 GB",118        status: "Success",119        recoveryModel: "Full",120        backupPath: "E:\\Backups\\LogisticsDB_Diff_20230615.bak",121        duration: "4 min",122        compression: "Enabled",123        expiration: "2023-06-22"124    },125    {126        id: 8,127        name: "FinanceDB",128        type: "Full",129        date: "2023-06-13T01:00:00Z",130        size: "5.6 GB",131        status: "Warning",132        recoveryModel: "Full",133        backupPath: "E:\\Backups\\FinanceDB_Full_20230613.bak",134        duration: "9 min",135        compression: "Enabled",136        expiration: "2023-07-13"137    },138    {139        id: 9,140        name: "SupportDB",141        type: "Log",142        date: "2023-06-15T09:00:00Z",143        size: "0.8 GB",144        status: "Success",145        recoveryModel: "Full",146        backupPath: "E:\\Backups\\SupportDB_Log_20230615.trn",147        duration: "1 min",148        compression: "Enabled",149        expiration: "2023-06-16"150    },151    {152        id: 10,153        name: "AnalyticsDB",154        type: "Full",155        date: "2023-06-12T03:00:00Z",156        size: "14.2 GB",157        status: "Error",158        recoveryModel: "Simple",159        backupPath: "E:\\Backups\\AnalyticsDB_Full_20230612.bak",160        duration: "18 min",161        compression: "Disabled",162        expiration: "2023-07-12"163    }164];165 166// Pagination variables167let currentPage = 1;168const itemsPerPage = 8;169// Load backup data and render table170function loadBackupData() {171    // Update stats172    document.getElementById('total-databases').textContent = backupData.length;173    document.getElementById('backed-up-today').textContent = backupData.filter(b => {174        const backupDate = new Date(b.date);175        const today = new Date();176        return backupDate.toDateString() === today.toDateString();177    }).length;178    179    // Calculate at-risk databases (no backup in last 24 hours or log backup required)180    const atRiskCount = backupData.filter(b => {181        const backupDate = new Date(b.date);182        const now = new Date();183        const hoursSinceBackup = (now - backupDate) / (1000 * 60 * 60);184        185        // Check if FULL recovery model needs log backup186        const needsLogBackup = b.recoveryModel === 'FULL' && 187                              b.logReuseWaitDesc === 'LOG_BACKUP' && 188                              (!b.lastLogBackup || (new Date() - new Date(b.lastLogBackup)) > 24 * 60 * 60 * 1000);189        190        return hoursSinceBackup > 24 || needsLogBackup;191    }).length;192    193    document.getElementById('at-risk').textContent = atRiskCount;194// Render table195    renderTable();196}197// Render the backup table with pagination198function renderTable() {199    const tableBody = document.getElementById('backup-table-body');200    tableBody.innerHTML = '';201    202    const startIdx = (currentPage - 1) * itemsPerPage;203    const endIdx = Math.min(startIdx + itemsPerPage, backupData.length);204    205    for (let i = startIdx; i < endIdx; i++) {206        const backup = backupData[i];207        const row = document.createElement('tr');208        209        // Format date for display210        const backupDate = new Date(backup.date);211        const formattedDate = backupDate.toLocaleString();212        213        // Calculate time since last backup214        const now = new Date();215        const hoursSinceBackup = Math.round((now - backupDate) / (1000 * 60 * 60));216        217        // Determine status badge color based on backup age and log requirements218        let statusClass = '';219        let statusText = '';220        221        if (hoursSinceBackup > 48) {222            statusClass = 'bg-red-100 text-red-800 pulse-warning';223            statusText = 'Critical';224        } 225        else if (hoursSinceBackup > 24 || 226                (backup.recoveryModel === 'FULL' && backup.logReuseWaitDesc === 'LOG_BACKUP' && !backup.lastLogBackup)) {227            statusClass = 'bg-amber-100 text-amber-800';228            statusText = 'Warning';229        }230        else {231            statusClass = 'bg-green-100 text-green-800';232            statusText = 'OK';233        }234row.innerHTML = `235            <td class="px-6 py-4 whitespace-nowrap">236                <div class="flex items-center">237                    <i data-feather="server" class="w-4 h-4 text-gray-500 mr-1"></i>238                    <span class="text-sm font-medium text-gray-700">${backup.server}</span>239                </div>240            </td>241            <td class="px-6 py-4 whitespace-nowrap">242                <div class="flex items-center">243                    <i data-feather="database" class="w-4 h-4 text-blue-500 mr-2"></i>244                    <span class="font-medium">${backup.name}</span>245                </div>246            </td>247            <td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">248                ${formattedDate}249            </td>250            <td class="px-6 py-4 whitespace-nowrap">251                <span class="px-2 py-1 text-xs rounded-full bg-blue-100 text-blue-800">${backup.recoveryModel}</span>252            </td>253            <td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">254                ${hoursSinceBackup} hours ago255            </td>256            <td class="px-6 py-4 whitespace-nowrap">257                <span class="px-2 py-1 text-xs rounded-full ${statusClass}">${statusText}</span>258            </td>259<td class="px-6 py-4 whitespace-nowrap text-sm font-medium">260                <button onclick="showBackupDetails(${backup.id})" class="text-blue-600 hover:text-blue-900 mr-3">Details</button>261                <button class="text-gray-600 hover:text-gray-900">Restore</button>262            </td>263        `;264        265        tableBody.appendChild(row);266    }267    268    // Update pagination info269    document.getElementById('showing-from').textContent = startIdx + 1;270    document.getElementById('showing-to').textContent = endIdx;271    document.getElementById('total-items').textContent = backupData.length;272    273    // Update pagination buttons274    document.getElementById('prev-btn').disabled = currentPage === 1;275    document.getElementById('next-btn').disabled = endIdx >= backupData.length;276    277    // Replace feather icons in new elements278    feather.replace();279}280// Show backup details in modal281function showBackupDetails(backupId) {282    const backup = backupData.find(b => b.id === backupId);283    if (!backup) return;284    285    const modal = document.getElementById('backup-details-modal');286    document.getElementById('modal-title').textContent = `Backup Details: ${backup.name} (${backup.server})`;287    288    // Format dates for display289    const backupDate = new Date(backup.date);290    const formattedDate = backupDate.toLocaleString();291    const lastCheckDBDate = new Date(backup.lastCheckDB);292    const formattedCheckDB = lastCheckDBDate.toLocaleString();293// Determine status badge color294    let statusClass = '';295    if (backup.status === 'Success') {296        statusClass = 'bg-green-100 text-green-800';297    } else if (backup.status === 'Warning') {298        statusClass = 'bg-amber-100 text-amber-800';299    } else if (backup.status === 'Error') {300        statusClass = 'bg-red-100 text-red-800';301    }302    303    document.getElementById('modal-content').innerHTML = `304        <div class="grid grid-cols-1 md:grid-cols-2 gap-4 mb-4">305            <div>306                <h4 class="text-sm font-medium text-gray-500">Server</h4>307                <p class="mt-1 text-sm text-gray-900">${backup.server}</p>308            </div>309            <div>310                <h4 class="text-sm font-medium text-gray-500">Database</h4>311                <p class="mt-1 text-sm text-gray-900">${backup.name}</p>312            </div>313            <div>314                <h4 class="text-sm font-medium text-gray-500">Recovery Model</h4>315                <p class="mt-1 text-sm text-gray-900">${backup.recoveryModel}</p>316            </div>317            <div>318                <h4 class="text-sm font-medium text-gray-500">Log Reuse Wait</h4>319                <p class="mt-1 text-sm text-gray-900">${backup.logReuseWaitDesc}</p>320            </div>321            <div>322                <h4 class="text-sm font-medium text-gray-500">Last Full Backup</h4>323                <p class="mt-1 text-sm text-gray-900">${formattedDate}</p>324            </div>325            <div>326                <h4 class="text-sm font-medium text-gray-500">Last Differential</h4>327                <p class="mt-1 text-sm text-gray-900">${backup.lastDiffBackup || 'None'}</p>328            </div>329            <div>330                <h4 class="text-sm font-medium text-gray-500">Last Log Backup</h4>331                <p class="mt-1 text-sm text-gray-900">${backup.lastLogBackup || 'None'}</p>332            </div>333            <div>334                <h4 class="text-sm font-medium text-gray-500">Last DBCC CheckDB</h4>335                <p class="mt-1 text-sm text-gray-900">${formattedCheckDB}</p>336            </div>337        </div>338<div class="flex justify-end">339            <button class="px-4 py-2 bg-blue-600 text-white rounded-lg hover:bg-blue-700 flex items-center gap-2">340                <i data-feather="download" class="w-4 h-4"></i>341                Download Backup342            </button>343        </div>344    `;345    346    modal.classList.remove('hidden');347    feather.replace();348}349 350// Event listeners351document.addEventListener('DOMContentLoaded', function() {352    // Pagination buttons353    document.getElementById('prev-btn').addEventListener('click', function() {354        if (currentPage > 1) {355            currentPage--;356            renderTable();357        }358    });359    360    document.getElementById('next-btn').addEventListener('click', function() {361        if ((currentPage * itemsPerPage) < backupData.length) {362            currentPage++;363            renderTable();364        }365    });366    367    // Close modal button368    document.getElementById('close-modal').addEventListener('click', function() {369        document.getElementById('backup-details-modal').classList.add('hidden');370    });371});