feat: v1.1.0 — backup module, IPAM node binding, HA, task queue, theme CSS
- Backup module: full CRUD for storages, backup files, scheduled jobs (APScheduler) - Proxmox client: storage/backup/restore/HA methods - IPAM: proxmox_node field, server+node binding for networks and allocations - Task queue service: improvements and new task types - Monitoring worker: extended metrics and alerts - HA support: add/remove VMs from Proxmox HA groups - tasks.html: new task tracking page - proxmox_vms.html: major UI update (bulk ops, HA, snapshots) - backups.html: full backup management UI (3 tabs) - base.html: sidebar backup link, websocket manager - theme.css: full CSS variables theme, 395 lines added - migrations: migration #15 (BackupJob), #16 (proxmox_node) - RBAC: backup resource permissions - websocket_manager.py: new module for WS connections
This commit is contained in:
@@ -966,6 +966,7 @@ function restoreFiltersFromUrl() {
|
||||
|
||||
// Bulk selection state
|
||||
let selectedVMs = new Set(); // Set of "server_id-vmid" keys
|
||||
let currentPageVMsCache = []; // sorted page items cache used by getCurrentPageVMs
|
||||
let currentTaskId = null;
|
||||
let taskPollInterval = null;
|
||||
|
||||
@@ -1002,7 +1003,7 @@ function toggleSelectAll(event) {
|
||||
// checked уже изменён браузером к моменту вызова onclick
|
||||
const isChecked = checkbox.checked;
|
||||
|
||||
console.log('toggleSelectAll:', { isChecked, selectedVMsSize: selectedVMs.size });
|
||||
debugLog('toggleSelectAll:', { isChecked, selectedVMsSize: selectedVMs.size });
|
||||
|
||||
const checkboxes = document.querySelectorAll('.vm-row-checkbox');
|
||||
|
||||
@@ -1025,7 +1026,7 @@ function toggleSelectAll(event) {
|
||||
});
|
||||
}
|
||||
|
||||
console.log('After toggleSelectAll:', { selectedVMsSize: selectedVMs.size, isChecked });
|
||||
debugLog('After toggleSelectAll:', { selectedVMsSize: selectedVMs.size, isChecked });
|
||||
|
||||
updateBulkActionsBar();
|
||||
}
|
||||
@@ -1091,9 +1092,7 @@ function updateSelectAllCheckbox() {
|
||||
}
|
||||
|
||||
function getCurrentPageVMs() {
|
||||
const start = (currentPageNum - 1) * pageSizeNum;
|
||||
const end = start + pageSizeNum;
|
||||
return filteredVMs.slice(start, end);
|
||||
return currentPageVMsCache;
|
||||
}
|
||||
|
||||
function getSelectedVMsData() {
|
||||
@@ -1162,9 +1161,9 @@ async function bulkAction(action) {
|
||||
bulkOperationAction = action;
|
||||
|
||||
// Show pending status with spinner for all selected items
|
||||
console.log('[bulkAction] Setting pending status for items:', items);
|
||||
debugLog('[bulkAction] Setting pending status for items:', items);
|
||||
items.forEach(item => {
|
||||
console.log(`[bulkAction] Calling updateVMStatusUI for server_id=${item.server_id}, vmid=${item.vmid}, action=${action}`);
|
||||
debugLog(`[bulkAction] Calling updateVMStatusUI for server_id=${item.server_id}, vmid=${item.vmid}, action=${action}`);
|
||||
updateVMStatusUI(item.server_id, item.vmid, 'pending', action);
|
||||
});
|
||||
|
||||
@@ -1439,6 +1438,7 @@ function renderTable() {
|
||||
const start = (currentPageNum - 1) * pageSizeNum;
|
||||
const end = start + pageSizeNum;
|
||||
const pageItems = sorted.slice(start, end);
|
||||
currentPageVMsCache = pageItems;
|
||||
|
||||
if (pageItems.length === 0) {
|
||||
tbody.innerHTML = `
|
||||
@@ -1816,7 +1816,7 @@ async function vmAction(action, serverId, vmid, type, node, vmName) {
|
||||
function updateVMStatusUI(serverId, vmid, status, action = null) {
|
||||
const elementId = `vm-status-${serverId}-${vmid}`;
|
||||
const statusEl = document.getElementById(elementId);
|
||||
console.log(`[updateVMStatusUI] Looking for element: ${elementId}, found: ${!!statusEl}, status: ${status}, action: ${action}`);
|
||||
debugLog(`[updateVMStatusUI] Looking for element: ${elementId}, found: ${!!statusEl}, status: ${status}, action: ${action}`);
|
||||
if (!statusEl) {
|
||||
console.warn(`[updateVMStatusUI] Element not found: ${elementId}`);
|
||||
return;
|
||||
@@ -1837,8 +1837,7 @@ function updateVMStatusUI(serverId, vmid, status, action = null) {
|
||||
action === 'restart' ? '{{ t("restarting") }}' :
|
||||
action === 'shutdown' ? '{{ t("shutting_down") }}' : '...';
|
||||
statusEl.innerHTML = `<span class="status-spinner"></span> ${actionLabel}`;
|
||||
console.log(`[updateVMStatusUI] Set pending with spinner: ${statusEl.innerHTML}`);
|
||||
} else if (status === 'running') {
|
||||
debugLog(`[updateVMStatusUI] Set pending with spinner: ${statusEl.innerHTML}`); } else if (status === 'running') {
|
||||
statusEl.textContent = t('active');
|
||||
} else {
|
||||
statusEl.textContent = t('inactive');
|
||||
|
||||
Reference in New Issue
Block a user