refator_comm1
This commit is contained in:
@@ -37,7 +37,7 @@ function setBadgeCell(cell, textOrState) {
|
|||||||
let html = '';
|
let html = '';
|
||||||
const s = low(textOrState);
|
const s = low(textOrState);
|
||||||
if (/running|online|started/.test(s)) html = badge('running','ok');
|
if (/running|online|started/.test(s)) html = badge('running','ok');
|
||||||
else if (/stopp|shutdown|offline/.test(s)) html = badge('stopped','dark');
|
else if (/stopp|shutdown|offline|stopped/.test(s)) html = badge('stopped','dark');
|
||||||
else if (/working|progress|busy/.test(s)) html = badge('working','info');
|
else if (/working|progress|busy/.test(s)) html = badge('working','info');
|
||||||
else html = badge(textOrState || '—','dark');
|
else html = badge(textOrState || '—','dark');
|
||||||
if (cell.innerHTML !== html) { cell.innerHTML = html; return true; }
|
if (cell.innerHTML !== html) { cell.innerHTML = html; return true; }
|
||||||
@@ -55,25 +55,22 @@ function rebuildTargetSelect(selectEl, currentNode, nodes) {
|
|||||||
if (!selectEl) return [];
|
if (!selectEl) return [];
|
||||||
const current = String(currentNode || '').trim();
|
const current = String(currentNode || '').trim();
|
||||||
const all = (nodes || []).map(n => String(n && (n.name || n.node || n)).trim()).filter(Boolean);
|
const all = (nodes || []).map(n => String(n && (n.name || n.node || n)).trim()).filter(Boolean);
|
||||||
const others = all.filter(n => n !== current);
|
const others = all.filter(n => n && n !== current);
|
||||||
selectEl.innerHTML = others.map(n => `<option value="${n}">${n}</option>`).join('');
|
selectEl.innerHTML = others.map(n => `<option value="${n}">${n}</option>`).join('');
|
||||||
// default: pick the "second node" if exists, otherwise first available other
|
// wybierz pierwszy sensowny inny node
|
||||||
var idx = 0;
|
if (selectEl.options.length > 0) selectEl.selectedIndex = 0;
|
||||||
if (all.length >= 2) {
|
|
||||||
const preferred = all[1];
|
|
||||||
const j = others.indexOf(preferred);
|
|
||||||
if (j >= 0) idx = j;
|
|
||||||
}
|
|
||||||
if (selectEl.options.length > 0) selectEl.selectedIndex = idx;
|
|
||||||
return others;
|
return others;
|
||||||
}
|
}
|
||||||
|
|
||||||
function updateMigrateButton(tr, isRunning) {
|
function updateMigrateButton(tr, rawStatus) {
|
||||||
const btn = q(tr, '.act-migrate');
|
const btn = q(tr, '.act-migrate');
|
||||||
const targetSel = q(tr, '.target-node');
|
const targetSel = q(tr, '.target-node');
|
||||||
const hasTarget = !!(targetSel && targetSel.options && targetSel.options.length > 0);
|
|
||||||
const enable = !!(isRunning && hasTarget);
|
|
||||||
if (!btn) return;
|
if (!btn) return;
|
||||||
|
const hasTarget = !!(targetSel && targetSel.options && targetSel.options.length > 0);
|
||||||
|
const s = low(rawStatus || '');
|
||||||
|
const busy = /working|progress|busy/.test(s);
|
||||||
|
// pozwól offline i online migrate — byle jest docelowy węzeł i nie trwa inna akcja
|
||||||
|
const enable = hasTarget && !busy && s !== '';
|
||||||
if (enable) { btn.removeAttribute('disabled'); btn.classList.remove('disabled'); }
|
if (enable) { btn.removeAttribute('disabled'); btn.classList.remove('disabled'); }
|
||||||
else { btn.setAttribute('disabled',''); btn.classList.add('disabled'); }
|
else { btn.setAttribute('disabled',''); btn.classList.add('disabled'); }
|
||||||
}
|
}
|
||||||
@@ -119,11 +116,13 @@ function ensureWatchOn() {
|
|||||||
const nodeCell = tr2.children[3];
|
const nodeCell = tr2.children[3];
|
||||||
const targetSel = q(tr2, '.target-node');
|
const targetSel = q(tr2, '.target-node');
|
||||||
|
|
||||||
if (msg.type === 'status') {
|
// dopasowane do serwera: type="vm" i "moved"
|
||||||
const stRaw = low(msg.status);
|
if (msg.type === 'vm') {
|
||||||
|
const cur = msg.current || {};
|
||||||
|
const stRaw = low(cur.status || cur.qmpstatus || '');
|
||||||
const changed = setBadgeCell(statusCell, stRaw);
|
const changed = setBadgeCell(statusCell, stRaw);
|
||||||
const isRunning = /running|online|started/.test(stRaw);
|
const isRunning = /running|online|started/.test(stRaw);
|
||||||
updateMigrateButton(tr2, isRunning);
|
updateMigrateButton(tr2, stRaw);
|
||||||
updateActionButtons(tr2, isRunning);
|
updateActionButtons(tr2, isRunning);
|
||||||
if (changed) flashDot(nameCell);
|
if (changed) flashDot(nameCell);
|
||||||
if (stRaw && /running|stopped|shutdown/.test(stRaw)) {
|
if (stRaw && /running|stopped|shutdown/.test(stRaw)) {
|
||||||
@@ -131,8 +130,8 @@ function ensureWatchOn() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (msg.type === 'node' && msg.node) {
|
if (msg.type === 'moved' && msg.new_node) {
|
||||||
const newNode = String(msg.node).trim();
|
const newNode = String(msg.new_node).trim();
|
||||||
if (nodeCell && newNode && txt(nodeCell).trim() !== newNode) {
|
if (nodeCell && newNode && txt(nodeCell).trim() !== newNode) {
|
||||||
nodeCell.textContent = newNode;
|
nodeCell.textContent = newNode;
|
||||||
rebuildTargetSelect(targetSel, newNode, window.__nodesCache || []);
|
rebuildTargetSelect(targetSel, newNode, window.__nodesCache || []);
|
||||||
@@ -191,7 +190,10 @@ export async function startAdminWatches() {
|
|||||||
const targetSel = q(tr, '.target-node');
|
const targetSel = q(tr, '.target-node');
|
||||||
const currentNode = txt(nodeCell).trim();
|
const currentNode = txt(nodeCell).trim();
|
||||||
rebuildTargetSelect(targetSel, currentNode, availableNodes);
|
rebuildTargetSelect(targetSel, currentNode, availableNodes);
|
||||||
updateMigrateButton(tr, /running|online|started/i.test(tr.children[4].innerText));
|
const stRaw = low(tr.children[4].innerText);
|
||||||
|
const isRunning = /running|online|started/.test(stRaw);
|
||||||
|
updateMigrateButton(tr, stRaw);
|
||||||
|
updateActionButtons(tr, isRunning);
|
||||||
});
|
});
|
||||||
|
|
||||||
// delegated events (reliable after refreshes)
|
// delegated events (reliable after refreshes)
|
||||||
@@ -199,21 +201,24 @@ export async function startAdminWatches() {
|
|||||||
const t = ev.target;
|
const t = ev.target;
|
||||||
const btn = t && t.closest ? t.closest('.act-start,.act-stop,.act-shutdown,.act-unlock,.act-migrate') : null;
|
const btn = t && t.closest ? t.closest('.act-start,.act-stop,.act-shutdown,.act-unlock,.act-migrate') : null;
|
||||||
if (!btn) return;
|
if (!btn) return;
|
||||||
|
ev.preventDefault(); ev.stopPropagation(); // <— kluczowe, żeby zawsze doszedł POST
|
||||||
const tr = btn.closest ? btn.closest('tr[data-sid]') : null;
|
const tr = btn.closest ? btn.closest('tr[data-sid]') : null;
|
||||||
if (!tr) return;
|
if (!tr) return;
|
||||||
const sid = tr.getAttribute('data-sid');
|
const sid = tr.getAttribute('data-sid');
|
||||||
const nameCell = tr.children[2];
|
const nameCell = tr.children[2];
|
||||||
|
const statusCell = tr.children[4];
|
||||||
const targetSel = q(tr, '.target-node');
|
const targetSel = q(tr, '.target-node');
|
||||||
|
|
||||||
async function doAction(kind, needsTarget) {
|
async function doAction(kind, needsTarget) {
|
||||||
try {
|
try {
|
||||||
const targetNode = needsTarget ? (targetSel ? targetSel.value : undefined) : undefined;
|
const targetNode = needsTarget ? (targetSel ? targetSel.value : undefined) : undefined;
|
||||||
activeSids.add(sid);
|
activeSids.add(sid);
|
||||||
setBadgeCell(tr.children[4], 'working');
|
setBadgeCell(statusCell, 'working');
|
||||||
updateMigrateButton(tr, false);
|
updateMigrateButton(tr, 'working');
|
||||||
const res = await api.vmAction(sid, kind, targetNode);
|
const res = await api.vmAction(sid, kind, targetNode);
|
||||||
if (res && res.ok) { showToast(`Task ${kind} started for ${safe(txt(nameCell))}`); }
|
if (res && res.ok) { showToast('OK', `Task ${kind} started for ${safe(txt(nameCell))}`, 'success'); }
|
||||||
else { showToast(`Task ${kind} failed for ${safe(txt(nameCell))}`, 'danger'); }
|
else { showToast('Error', `Task ${kind} failed for ${safe(txt(nameCell))}`, 'danger'); }
|
||||||
} catch(e) { showToast(`Error: ${e && e.message ? e.message : e}`, 'danger'); }
|
} catch(e) { showToast('Error', String(e && e.message ? e.message : e), 'danger'); }
|
||||||
}
|
}
|
||||||
if (btn.classList.contains('act-start')) return doAction('start');
|
if (btn.classList.contains('act-start')) return doAction('start');
|
||||||
if (btn.classList.contains('act-stop')) return doAction('stop');
|
if (btn.classList.contains('act-stop')) return doAction('stop');
|
||||||
@@ -255,7 +260,7 @@ export async function startAdminWatches() {
|
|||||||
if (stRaw) {
|
if (stRaw) {
|
||||||
const changed = setBadgeCell(statusCell, stRaw);
|
const changed = setBadgeCell(statusCell, stRaw);
|
||||||
const isRunning = /running|online|started/.test(stRaw);
|
const isRunning = /running|online|started/.test(stRaw);
|
||||||
updateMigrateButton(tr, isRunning);
|
updateMigrateButton(tr, stRaw);
|
||||||
updateActionButtons(tr, isRunning);
|
updateActionButtons(tr, isRunning);
|
||||||
if (changed) flashDot(nameCell);
|
if (changed) flashDot(nameCell);
|
||||||
}
|
}
|
||||||
@@ -284,7 +289,7 @@ export async function startAdminWatches() {
|
|||||||
const stRaw = low((detail.current && (detail.current.status || detail.current.qmpstatus)) || '');
|
const stRaw = low((detail.current && (detail.current.status || detail.current.qmpstatus)) || '');
|
||||||
const changed = setBadgeCell(statusCell, stRaw);
|
const changed = setBadgeCell(statusCell, stRaw);
|
||||||
const isRunning = /running|online|started/.test(stRaw);
|
const isRunning = /running|online|started/.test(stRaw);
|
||||||
updateMigrateButton(tr, isRunning);
|
updateMigrateButton(tr, stRaw);
|
||||||
updateActionButtons(tr, isRunning);
|
updateActionButtons(tr, isRunning);
|
||||||
if (changed) flashDot(nameCell);
|
if (changed) flashDot(nameCell);
|
||||||
|
|
||||||
@@ -304,9 +309,10 @@ export async function startAdminWatches() {
|
|||||||
} catch(e){}
|
} catch(e){}
|
||||||
}, 10000);
|
}, 10000);
|
||||||
|
|
||||||
|
ensureWatchOn();
|
||||||
window.addEventListener('beforeunload', stopAllAdminWatches, { once: true });
|
window.addEventListener('beforeunload', stopAllAdminWatches, { once: true });
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
showToast(`Failed to load list: ${e && e.message ? e.message : e}`, 'danger');
|
showToast('Error', `Failed to load list: ${e && e.message ? e.message : e}`, 'danger');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -314,7 +320,7 @@ export async function startAdminWatches() {
|
|||||||
export async function renderVMAdmin() {
|
export async function renderVMAdmin() {
|
||||||
try { await startAdminWatches(); }
|
try { await startAdminWatches(); }
|
||||||
catch (e) {
|
catch (e) {
|
||||||
showToast(`VM Admin initialization error: ${e && e.message ? e.message : e}`, 'danger');
|
showToast('Error', `VM Admin initialization error: ${e && e.message ? e.message : e}`, 'danger');
|
||||||
console.error(e);
|
console.error(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -144,17 +144,6 @@ footer.site-footer a:hover {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#toast-container {
|
|
||||||
position: fixed;
|
|
||||||
right: max(env(safe-area-inset-right), 1rem);
|
|
||||||
bottom: max(env(safe-area-inset-bottom), 1rem);
|
|
||||||
z-index: 1080;
|
|
||||||
pointer-events: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
#toast-container .toast {
|
|
||||||
pointer-events: auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
#vm-admin table {
|
#vm-admin table {
|
||||||
overflow: visible;
|
overflow: visible;
|
||||||
@@ -169,14 +158,20 @@ footer.site-footer a:hover {
|
|||||||
z-index: 3;
|
z-index: 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
#vm-admin .btn.btn-sm {
|
#toast-container {
|
||||||
line-height: 1.2;
|
position: fixed;
|
||||||
|
right: max(env(safe-area-inset-right), 1rem);
|
||||||
|
bottom: max(env(safe-area-inset-bottom), 1rem);
|
||||||
|
z-index: 1080;
|
||||||
|
pointer-events: none;
|
||||||
|
width: min(480px, 96vw);
|
||||||
|
max-width: min(480px, 96vw);
|
||||||
}
|
}
|
||||||
|
|
||||||
#vm-admin .btn-group .btn {
|
#toast-container .toast {
|
||||||
min-width: 4.2rem;
|
pointer-events: auto;
|
||||||
}
|
max-width: 100%;
|
||||||
|
overflow-wrap: anywhere;
|
||||||
#vm-admin .act-migrate {
|
word-break: break-word;
|
||||||
white-space: nowrap;
|
white-space: normal;
|
||||||
}
|
}
|
Reference in New Issue
Block a user