mirror of
https://github.com/rcourtman/Pulse.git
synced 2026-09-22 19:23:31 +00:00
Refactor(ui/backups): Decompose updateBackupsTab into focused helper functions
This commit is contained in:
+165
-176
@@ -29,47 +29,13 @@ PulseApp.ui.backups = (() => {
|
||||
}
|
||||
}
|
||||
|
||||
function updateBackupsTab() {
|
||||
const tableContainer = document.getElementById('backups-table-container');
|
||||
const tableBody = document.getElementById('backups-overview-tbody');
|
||||
const loadingMsg = document.getElementById('backups-loading-message');
|
||||
const noDataMsg = document.getElementById('backups-no-data-message');
|
||||
const statusTextElement = document.getElementById('backups-status-text');
|
||||
|
||||
if (!tableContainer || !tableBody || !loadingMsg || !noDataMsg || !statusTextElement) {
|
||||
console.error("UI elements for Backups tab not found!");
|
||||
return;
|
||||
}
|
||||
|
||||
function _getInitialBackupData() {
|
||||
const vmsData = PulseApp.state.get('vmsData') || [];
|
||||
const containersData = PulseApp.state.get('containersData') || [];
|
||||
const pbsDataArray = PulseApp.state.get('pbsDataArray') || [];
|
||||
const initialDataReceived = PulseApp.state.get('initialDataReceived');
|
||||
|
||||
const allGuests = [...vmsData, ...containersData];
|
||||
|
||||
if (!initialDataReceived) {
|
||||
loadingMsg.classList.remove('hidden');
|
||||
tableContainer.classList.add('hidden');
|
||||
noDataMsg.classList.add('hidden');
|
||||
return;
|
||||
}
|
||||
|
||||
if (allGuests.length === 0) {
|
||||
loadingMsg.classList.add('hidden');
|
||||
tableContainer.classList.add('hidden');
|
||||
noDataMsg.textContent = "No Proxmox guests (VMs/Containers) found.";
|
||||
noDataMsg.classList.remove('hidden');
|
||||
return;
|
||||
}
|
||||
|
||||
loadingMsg.classList.add('hidden');
|
||||
|
||||
const backupStatusByGuest = [];
|
||||
const now = Math.floor(Date.now() / 1000);
|
||||
const sevenDaysAgo = now - (7 * 24 * 60 * 60);
|
||||
const threeDaysAgo = now - (3 * 24 * 60 * 60);
|
||||
|
||||
const allRecentBackupTasks = pbsDataArray.flatMap(pbs =>
|
||||
(pbs.backupTasks?.recentTasks || []).map(task => ({
|
||||
...task,
|
||||
@@ -91,75 +57,74 @@ PulseApp.ui.backups = (() => {
|
||||
)
|
||||
);
|
||||
|
||||
allGuests.forEach(guest => {
|
||||
const guestId = String(guest.vmid);
|
||||
const guestTypePve = guest.type === 'qemu' ? 'vm' : 'ct';
|
||||
return { allGuests, initialDataReceived, allRecentBackupTasks, allSnapshots };
|
||||
}
|
||||
|
||||
const guestSnapshots = allSnapshots.filter(snap =>
|
||||
String(snap.backupVMID) === guestId && snap.backupType === guestTypePve
|
||||
);
|
||||
const totalBackups = guestSnapshots.length;
|
||||
const latestSnapshot = guestSnapshots.reduce((latest, snap) => {
|
||||
return (!latest || (snap['backup-time'] && snap['backup-time'] > latest['backup-time'])) ? snap : latest;
|
||||
}, null);
|
||||
const latestSnapshotTime = latestSnapshot ? latestSnapshot['backup-time'] : null;
|
||||
function _determineGuestBackupStatus(guest, allSnapshots, allRecentBackupTasks) {
|
||||
const guestId = String(guest.vmid);
|
||||
const guestTypePve = guest.type === 'qemu' ? 'vm' : 'ct';
|
||||
const now = Math.floor(Date.now() / 1000);
|
||||
const sevenDaysAgo = now - (7 * 24 * 60 * 60);
|
||||
const threeDaysAgo = now - (3 * 24 * 60 * 60);
|
||||
|
||||
const guestTasks = allRecentBackupTasks.filter(task =>
|
||||
task.guestId === guestId && task.guestTypePbs === guestTypePve
|
||||
);
|
||||
const latestTask = guestTasks.reduce((latest, task) => {
|
||||
return (!latest || (task.startTime && task.startTime > latest.startTime)) ? task : latest;
|
||||
}, null);
|
||||
const guestSnapshots = allSnapshots.filter(snap =>
|
||||
String(snap.backupVMID) === guestId && snap.backupType === guestTypePve
|
||||
);
|
||||
const totalBackups = guestSnapshots.length;
|
||||
const latestSnapshot = guestSnapshots.reduce((latest, snap) => {
|
||||
return (!latest || (snap['backup-time'] && snap['backup-time'] > latest['backup-time'])) ? snap : latest;
|
||||
}, null);
|
||||
const latestSnapshotTime = latestSnapshot ? latestSnapshot['backup-time'] : null;
|
||||
|
||||
let healthStatus = 'none';
|
||||
let displayTimestamp = latestSnapshotTime;
|
||||
const guestTasks = allRecentBackupTasks.filter(task =>
|
||||
task.guestId === guestId && task.guestTypePbs === guestTypePve
|
||||
);
|
||||
const latestTask = guestTasks.reduce((latest, task) => {
|
||||
return (!latest || (task.startTime && task.startTime > latest.startTime)) ? task : latest;
|
||||
}, null);
|
||||
|
||||
if (latestTask) {
|
||||
displayTimestamp = latestTask.startTime;
|
||||
if (latestTask.status === 'OK') {
|
||||
if (latestTask.startTime >= threeDaysAgo) {
|
||||
healthStatus = 'ok';
|
||||
} else if (latestTask.startTime >= sevenDaysAgo) {
|
||||
healthStatus = 'stale';
|
||||
} else {
|
||||
healthStatus = 'old';
|
||||
}
|
||||
} else {
|
||||
healthStatus = 'failed';
|
||||
}
|
||||
} else if (latestSnapshotTime) {
|
||||
if (latestSnapshotTime >= threeDaysAgo) {
|
||||
healthStatus = 'ok';
|
||||
} else if (latestSnapshotTime >= sevenDaysAgo) {
|
||||
healthStatus = 'stale';
|
||||
} else {
|
||||
healthStatus = 'old';
|
||||
}
|
||||
let healthStatus = 'none';
|
||||
let displayTimestamp = latestSnapshotTime;
|
||||
|
||||
if (latestTask) {
|
||||
displayTimestamp = latestTask.startTime;
|
||||
if (latestTask.status === 'OK') {
|
||||
if (latestTask.startTime >= threeDaysAgo) healthStatus = 'ok';
|
||||
else if (latestTask.startTime >= sevenDaysAgo) healthStatus = 'stale';
|
||||
else healthStatus = 'old';
|
||||
} else {
|
||||
healthStatus = 'none';
|
||||
displayTimestamp = null;
|
||||
healthStatus = 'failed';
|
||||
}
|
||||
} else if (latestSnapshotTime) {
|
||||
if (latestSnapshotTime >= threeDaysAgo) healthStatus = 'ok';
|
||||
else if (latestSnapshotTime >= sevenDaysAgo) healthStatus = 'stale';
|
||||
else healthStatus = 'old';
|
||||
} else {
|
||||
healthStatus = 'none';
|
||||
displayTimestamp = null;
|
||||
}
|
||||
|
||||
backupStatusByGuest.push({
|
||||
guestName: guest.name || `Guest ${guest.vmid}`,
|
||||
guestId: guest.vmid,
|
||||
guestType: guest.type === 'qemu' ? 'VM' : 'LXC',
|
||||
node: guest.node,
|
||||
guestPveStatus: guest.status,
|
||||
latestBackupTime: displayTimestamp,
|
||||
pbsInstanceName: latestSnapshot?.pbsInstanceName || latestTask?.pbsInstanceName || 'N/A',
|
||||
datastoreName: latestSnapshot?.datastoreName || 'N/A',
|
||||
totalBackups: totalBackups,
|
||||
backupHealthStatus: healthStatus
|
||||
});
|
||||
});
|
||||
return {
|
||||
guestName: guest.name || `Guest ${guest.vmid}`,
|
||||
guestId: guest.vmid,
|
||||
guestType: guest.type === 'qemu' ? 'VM' : 'LXC',
|
||||
node: guest.node,
|
||||
guestPveStatus: guest.status,
|
||||
latestBackupTime: displayTimestamp,
|
||||
pbsInstanceName: latestSnapshot?.pbsInstanceName || latestTask?.pbsInstanceName || 'N/A',
|
||||
datastoreName: latestSnapshot?.datastoreName || 'N/A',
|
||||
totalBackups: totalBackups,
|
||||
backupHealthStatus: healthStatus
|
||||
};
|
||||
}
|
||||
|
||||
function _filterBackupData(backupStatusByGuest, backupsSearchInput) {
|
||||
const currentBackupsSearchTerm = backupsSearchInput ? backupsSearchInput.value.toLowerCase() : '';
|
||||
const backupsSearchTerms = currentBackupsSearchTerm.split(',').map(term => term.trim()).filter(term => term);
|
||||
const backupsFilterHealth = PulseApp.state.get('backupsFilterHealth');
|
||||
const backupsFilterGuestType = PulseApp.state.get('backupsFilterGuestType');
|
||||
|
||||
const filteredBackupStatus = backupStatusByGuest.filter(item => {
|
||||
return backupStatusByGuest.filter(item => {
|
||||
const healthMatch = (backupsFilterHealth === 'all') ||
|
||||
(backupsFilterHealth === 'ok' && (item.backupHealthStatus === 'ok' || item.backupHealthStatus === 'stale')) ||
|
||||
(backupsFilterHealth === 'warning' && (item.backupHealthStatus === 'old')) ||
|
||||
@@ -173,98 +138,134 @@ PulseApp.ui.backups = (() => {
|
||||
if (!typeMatch) return false;
|
||||
|
||||
if (backupsSearchTerms.length > 0) {
|
||||
const nameMatch = backupsSearchTerms.some(term =>
|
||||
return backupsSearchTerms.some(term =>
|
||||
(item.guestName?.toLowerCase() || '').includes(term) ||
|
||||
(item.node?.toLowerCase() || '').includes(term) ||
|
||||
(item.guestId?.toString() || '').includes(term)
|
||||
);
|
||||
if (!nameMatch) return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
function _renderBackupTableRow(guestStatus) {
|
||||
const row = document.createElement('tr');
|
||||
row.className = `transition-all duration-150 ease-out hover:bg-gray-100 dark:hover:bg-gray-700 hover:shadow-md hover:-translate-y-px ${guestStatus.guestPveStatus === 'stopped' ? 'opacity-60 grayscale' : ''}`;
|
||||
|
||||
const latestBackupFormatted = guestStatus.latestBackupTime
|
||||
? PulseApp.utils.formatPbsTimestamp(guestStatus.latestBackupTime)
|
||||
: '<span class="text-gray-400">No backups found</span>';
|
||||
|
||||
let healthIndicator = '';
|
||||
switch (guestStatus.backupHealthStatus) {
|
||||
case 'ok': healthIndicator = '<span class="text-green-600 dark:text-green-400" title="OK">●</span>'; break;
|
||||
case 'stale': healthIndicator = '<span class="text-yellow-600 dark:text-yellow-400" title="Stale">●</span>'; break;
|
||||
case 'failed': healthIndicator = '<span class="text-red-600 dark:text-red-400 font-bold" title="Failed">✖</span>'; break;
|
||||
case 'old': healthIndicator = '<span class="text-orange-600 dark:text-orange-400" title="Old">●</span>'; break;
|
||||
case 'none': healthIndicator = '<span class="text-gray-400 dark:text-gray-500" title="None">-</span>'; break;
|
||||
}
|
||||
|
||||
const typeIconClass = guestStatus.guestType === 'VM'
|
||||
? 'vm-icon bg-blue-100 dark:bg-blue-900/50 text-blue-700 dark:text-blue-300 px-1.5 py-0.5 font-medium'
|
||||
: '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 = `<span class="type-icon inline-block rounded text-xs align-middle ${typeIconClass}">${guestStatus.guestType}</span>`;
|
||||
|
||||
row.innerHTML = `
|
||||
<td class="p-1 px-2 whitespace-nowrap text-center">${healthIndicator}</td>
|
||||
<td class="p-1 px-2 whitespace-nowrap font-medium text-gray-900 dark:text-gray-100" title="${guestStatus.guestName}">${guestStatus.guestName}</td>
|
||||
<td class="p-1 px-2 text-gray-500 dark:text-gray-400">${guestStatus.guestId}</td>
|
||||
<td class="p-1 px-2">${typeIcon}</td>
|
||||
<td class="p-1 px-2 whitespace-nowrap text-gray-500 dark:text-gray-400">${guestStatus.node}</td>
|
||||
<td class="p-1 px-2 whitespace-nowrap text-gray-500 dark:text-gray-400">${latestBackupFormatted}</td>
|
||||
<td class="p-1 px-2 whitespace-nowrap text-gray-500 dark:text-gray-400">${guestStatus.pbsInstanceName}</td>
|
||||
<td class="p-1 px-2 whitespace-nowrap text-gray-500 dark:text-gray-400">${guestStatus.datastoreName}</td>
|
||||
<td class="p-1 px-2 text-gray-500 dark:text-gray-400">${guestStatus.totalBackups}</td>
|
||||
`;
|
||||
return row;
|
||||
}
|
||||
|
||||
function _updateBackupStatusMessages(statusTextElement, visibleCount, backupsSearchInput) {
|
||||
if (!statusTextElement) return;
|
||||
|
||||
const currentBackupsSearchTerm = backupsSearchInput ? backupsSearchInput.value : '';
|
||||
const backupsFilterGuestType = PulseApp.state.get('backupsFilterGuestType');
|
||||
const backupsFilterHealth = PulseApp.state.get('backupsFilterHealth');
|
||||
|
||||
const statusBaseText = `Updated: ${new Date().toLocaleTimeString()}`;
|
||||
let statusFilterText = currentBackupsSearchTerm ? ` | Filter: "${currentBackupsSearchTerm}"` : '';
|
||||
const typeFilterLabel = backupsFilterGuestType !== 'all' ? backupsFilterGuestType.toUpperCase() : '';
|
||||
const healthFilterLabel = backupsFilterHealth !== 'all' ? backupsFilterHealth.charAt(0).toUpperCase() + backupsFilterHealth.slice(1) : '';
|
||||
const otherFilters = [typeFilterLabel, healthFilterLabel].filter(Boolean).join('/');
|
||||
if (otherFilters) {
|
||||
statusFilterText += ` | ${otherFilters}`;
|
||||
}
|
||||
const statusCountText = ` | Showing ${visibleCount} guests`;
|
||||
statusTextElement.textContent = statusBaseText + statusFilterText + statusCountText;
|
||||
}
|
||||
|
||||
|
||||
function updateBackupsTab() {
|
||||
const tableContainer = document.getElementById('backups-table-container');
|
||||
const tableBody = document.getElementById('backups-overview-tbody');
|
||||
const loadingMsg = document.getElementById('backups-loading-message');
|
||||
const noDataMsg = document.getElementById('backups-no-data-message');
|
||||
const statusTextElement = document.getElementById('backups-status-text');
|
||||
|
||||
if (!tableContainer || !tableBody || !loadingMsg || !noDataMsg || !statusTextElement) {
|
||||
console.error("UI elements for Backups tab not found!");
|
||||
return;
|
||||
}
|
||||
|
||||
const { allGuests, initialDataReceived, allRecentBackupTasks, allSnapshots } = _getInitialBackupData();
|
||||
|
||||
if (!initialDataReceived) {
|
||||
loadingMsg.classList.remove('hidden');
|
||||
tableContainer.classList.add('hidden');
|
||||
noDataMsg.classList.add('hidden');
|
||||
return;
|
||||
}
|
||||
|
||||
if (allGuests.length === 0) {
|
||||
loadingMsg.classList.add('hidden');
|
||||
tableContainer.classList.add('hidden');
|
||||
noDataMsg.textContent = "No Proxmox guests (VMs/Containers) found.";
|
||||
noDataMsg.classList.remove('hidden');
|
||||
_updateBackupStatusMessages(statusTextElement, 0, backupsSearchInput);
|
||||
return;
|
||||
}
|
||||
loadingMsg.classList.add('hidden');
|
||||
|
||||
const backupStatusByGuest = allGuests.map(guest => _determineGuestBackupStatus(guest, allSnapshots, allRecentBackupTasks));
|
||||
const filteredBackupStatus = _filterBackupData(backupStatusByGuest, backupsSearchInput);
|
||||
|
||||
const sortStateBackups = PulseApp.state.getSortState('backups');
|
||||
const sortedBackupStatus = PulseApp.utils.sortData(filteredBackupStatus, sortStateBackups.column, sortStateBackups.direction, 'backups');
|
||||
|
||||
tableBody.innerHTML = '';
|
||||
let visibleCount = 0;
|
||||
if (sortedBackupStatus.length > 0) {
|
||||
sortedBackupStatus.forEach(guestStatus => {
|
||||
const row = tableBody.insertRow();
|
||||
row.className = `transition-all duration-150 ease-out hover:bg-gray-100 dark:hover:bg-gray-700 hover:shadow-md hover:-translate-y-px ${guestStatus.guestPveStatus === 'stopped' ? 'opacity-60 grayscale' : ''}`;
|
||||
|
||||
const latestBackupFormatted = guestStatus.latestBackupTime
|
||||
? PulseApp.utils.formatPbsTimestamp(guestStatus.latestBackupTime)
|
||||
: '<span class="text-gray-400">No backups found</span>';
|
||||
|
||||
let healthIndicator = '';
|
||||
switch (guestStatus.backupHealthStatus) {
|
||||
case 'ok':
|
||||
healthIndicator = '<span class="text-green-600 dark:text-green-400" title="OK">●</span>';
|
||||
break;
|
||||
case 'stale':
|
||||
healthIndicator = '<span class="text-yellow-600 dark:text-yellow-400" title="Stale">●</span>';
|
||||
break;
|
||||
case 'failed':
|
||||
healthIndicator = '<span class="text-red-600 dark:text-red-400 font-bold" title="Failed">✖</span>';
|
||||
break;
|
||||
case 'old':
|
||||
healthIndicator = '<span class="text-orange-600 dark:text-orange-400" title="Old">●</span>';
|
||||
break;
|
||||
case 'none':
|
||||
healthIndicator = '<span class="text-gray-400 dark:text-gray-500" title="None">-</span>';
|
||||
break;
|
||||
}
|
||||
|
||||
const typeIconClass = guestStatus.guestType === 'VM'
|
||||
? 'vm-icon bg-blue-100 dark:bg-blue-900/50 text-blue-700 dark:text-blue-300 px-1.5 py-0.5 font-medium'
|
||||
: '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 = `<span class="type-icon inline-block rounded text-xs align-middle ${typeIconClass}">${guestStatus.guestType}</span>`;
|
||||
|
||||
row.innerHTML = `
|
||||
<td class="p-1 px-2 whitespace-nowrap text-center">${healthIndicator}</td>
|
||||
<td class="p-1 px-2 whitespace-nowrap font-medium text-gray-900 dark:text-gray-100" title="${guestStatus.guestName}">${guestStatus.guestName}</td>
|
||||
<td class="p-1 px-2 text-gray-500 dark:text-gray-400">${guestStatus.guestId}</td>
|
||||
<td class="p-1 px-2">${typeIcon}</td>
|
||||
<td class="p-1 px-2 whitespace-nowrap text-gray-500 dark:text-gray-400">${guestStatus.node}</td>
|
||||
<td class="p-1 px-2 whitespace-nowrap text-gray-500 dark:text-gray-400">${latestBackupFormatted}</td>
|
||||
<td class="p-1 px-2 whitespace-nowrap text-gray-500 dark:text-gray-400">${guestStatus.pbsInstanceName}</td>
|
||||
<td class="p-1 px-2 whitespace-nowrap text-gray-500 dark:text-gray-400">${guestStatus.datastoreName}</td>
|
||||
<td class="p-1 px-2 text-gray-500 dark:text-gray-400">${guestStatus.totalBackups}</td>
|
||||
`;
|
||||
visibleCount++;
|
||||
const row = _renderBackupTableRow(guestStatus);
|
||||
tableBody.appendChild(row);
|
||||
});
|
||||
|
||||
loadingMsg.classList.add('hidden');
|
||||
noDataMsg.classList.add('hidden');
|
||||
tableContainer.classList.remove('hidden');
|
||||
} else {
|
||||
loadingMsg.classList.add('hidden');
|
||||
tableContainer.classList.add('hidden');
|
||||
let emptyMessage = "No backup information found for any guests.";
|
||||
if (backupStatusByGuest.length === 0) {
|
||||
if (allGuests.length === 0) {
|
||||
emptyMessage = "No Proxmox guests (VMs/Containers) found.";
|
||||
} else {
|
||||
emptyMessage = "No backup information found for any guests.";
|
||||
}
|
||||
}
|
||||
else if (filteredBackupStatus.length === 0) {
|
||||
const typeFilterText = backupsFilterGuestType === 'all' ? '' : `Type: ${backupsFilterGuestType.toUpperCase()}`;
|
||||
const filtersApplied = [typeFilterText].filter(Boolean).join(', ');
|
||||
if (backupStatusByGuest.length > 0 && filteredBackupStatus.length === 0) { // Data exists, but filters hide all
|
||||
const currentBackupsSearchTerm = backupsSearchInput ? backupsSearchInput.value : '';
|
||||
const backupsFilterGuestType = PulseApp.state.get('backupsFilterGuestType');
|
||||
const typeFilterText = backupsFilterGuestType === 'all' ? '' : `Type: ${backupsFilterGuestType.toUpperCase()}`;
|
||||
const filtersApplied = [typeFilterText].filter(Boolean).join(', ');
|
||||
|
||||
if (filtersApplied) {
|
||||
emptyMessage = `No guests found matching the selected filters (${filtersApplied}).`;
|
||||
} else {
|
||||
emptyMessage = "No guests with backup information found.";
|
||||
}
|
||||
}
|
||||
if (filteredBackupStatus.length === 0 && backupsSearchTerms.length > 0) {
|
||||
emptyMessage = `No guests found matching search "${currentBackupsSearchTerm}".`;
|
||||
if (filtersApplied) {
|
||||
emptyMessage += ` and filters (${filtersApplied})`;
|
||||
}
|
||||
if (currentBackupsSearchTerm) {
|
||||
emptyMessage = `No guests found matching search "${currentBackupsSearchTerm}"`;
|
||||
if (filtersApplied) emptyMessage += ` and filters (${filtersApplied})`;
|
||||
} else if (filtersApplied) {
|
||||
emptyMessage = `No guests found matching the selected filters (${filtersApplied}).`;
|
||||
} else {
|
||||
emptyMessage = "No guests with backup information found matching current filters.";
|
||||
}
|
||||
}
|
||||
noDataMsg.textContent = emptyMessage;
|
||||
noDataMsg.classList.remove('hidden');
|
||||
@@ -277,19 +278,7 @@ PulseApp.ui.backups = (() => {
|
||||
} else {
|
||||
console.warn('[Backups] PulseApp.ui.common not available for updateSortUI');
|
||||
}
|
||||
|
||||
if (statusTextElement) {
|
||||
const statusBaseText = `Updated: ${new Date().toLocaleTimeString()}`;
|
||||
let statusFilterText = currentBackupsSearchTerm ? ` | Filter: "${currentBackupsSearchTerm}"` : '';
|
||||
const typeFilterLabel = backupsFilterGuestType !== 'all' ? backupsFilterGuestType.toUpperCase() : '';
|
||||
const healthFilterLabel = backupsFilterHealth !== 'all' ? backupsFilterHealth.charAt(0).toUpperCase() + backupsFilterHealth.slice(1) : '';
|
||||
const otherFilters = [typeFilterLabel, healthFilterLabel].filter(Boolean).join('/');
|
||||
if (otherFilters) {
|
||||
statusFilterText += ` | ${otherFilters}`;
|
||||
}
|
||||
let statusCountText = ` | Showing ${visibleCount} guests`;
|
||||
statusTextElement.textContent = statusBaseText + statusFilterText + statusCountText;
|
||||
}
|
||||
_updateBackupStatusMessages(statusTextElement, sortedBackupStatus.length, backupsSearchInput);
|
||||
}
|
||||
|
||||
function resetBackupsView() {
|
||||
@@ -316,4 +305,4 @@ PulseApp.ui.backups = (() => {
|
||||
updateBackupsTab,
|
||||
resetBackupsView
|
||||
};
|
||||
})();
|
||||
})();
|
||||
|
||||
Reference in New Issue
Block a user