Varaverk: monitor grid overhaul + Containers & VMs card
Monitor layout (8-col grid): - Row 1: System | Power | CPU | Memory | Network - Row 2: Scripts | Partner & Fallback (span 3) | Containers & VMs (span 4) - Row 3: GPU (span 2) | Transcode (span 2) | Streams (span 4) - Row 4: Parity (cols 1-2) | Pools (cols 3-4) | Array (cols 5-8) New Containers & VMs card: - Reads FolderView3 folders from docker.json; expand/collapse per folder - VMs listed first (virsh); containers show start/stop/webui/edit actions - 2-column balanced layout; collapses to 1 column below 900px - Docker WebUI URLs resolved from dockerMan template XMLs New files: include/vms.php, include/docker_folders.php, api/docker_action.php, api/snapshot.php Responsive: explicit grid-column placements reset at 1024px breakpoint
This commit is contained in:
@@ -805,9 +805,25 @@ Still the same two servers, two households, the same media stack running itself.
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="vv-sched-footer vv-sched-info" id="vv-sched-info-footer">
|
||||
<span id="vv-footer-scheduled"><?= $scheduledJobs ?> of <?= $totalJobs ?> job<?= $totalJobs !== 1 ? 's' : '' ?> scheduled</span>
|
||||
<span id="vv-footer-running"><?= !empty($runningScripts) ? 'Running: ' . htmlspecialchars(implode(', ', $runningScripts)) : 'Idle' ?></span>
|
||||
<div class="vv-sched-footer vv-sched-info vv-snap-footer" id="vv-sched-info-footer">
|
||||
<span class="vv-snap-item">
|
||||
<span class="vv-snap-label">CPU</span>
|
||||
<span class="vv-snap-bar"><span id="vv-snap-cpu-bar"></span></span>
|
||||
<span id="vv-snap-cpu-val" class="vv-snap-val">—</span>
|
||||
</span>
|
||||
<span class="vv-snap-item">
|
||||
<span class="vv-snap-label">RAM</span>
|
||||
<span class="vv-snap-bar"><span id="vv-snap-ram-bar"></span></span>
|
||||
<span id="vv-snap-ram-val" class="vv-snap-val">—</span>
|
||||
</span>
|
||||
<span class="vv-snap-div">·</span>
|
||||
<span id="vv-snap-fallback" class="vv-snap-state">—</span>
|
||||
<span class="vv-snap-div">·</span>
|
||||
<span id="vv-snap-partner" class="vv-snap-partner">—</span>
|
||||
<span class="vv-snap-div">·</span>
|
||||
<span id="vv-snap-streams" class="vv-snap-media">—</span>
|
||||
<span class="vv-snap-div">·</span>
|
||||
<span id="vv-snap-transcodes" class="vv-snap-media">—</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1284,32 +1300,30 @@ function vvSaveChild(el) {
|
||||
|
||||
function vvSaveAll() {
|
||||
const status = document.getElementById('vv-save-all-status');
|
||||
// Collect jobs to save: orchs always; children only when their orch is OFF (orch manages them when on).
|
||||
// conf_flag children are always immediate-save (flag_toggle.php), never batch-saved.
|
||||
const toSave = [];
|
||||
document.querySelectorAll('#vv-sched-left [data-id]').forEach(job => {
|
||||
if (job.classList.contains('vv-script')) {
|
||||
if (job.dataset.type === 'conf_flag') return; // immediate-save only
|
||||
if (job.dataset.type === 'conf_flag') return;
|
||||
const orchCard = job.closest('.vv-sched-card');
|
||||
const orchOn = orchCard?.querySelector('.vv-orch-row .vv-enabled')?.checked ?? false;
|
||||
if (orchOn) return; // child under active orch — cron suppressed, skip
|
||||
if (orchOn) return;
|
||||
}
|
||||
toSave.push(job);
|
||||
});
|
||||
let pending = toSave.length, allOk = true;
|
||||
if (!pending) { vvFlashStatus(status, '✓ Saved', true); return; }
|
||||
if (!toSave.length) { vvFlashStatus(status, '✓ Saved', true); return; }
|
||||
status.textContent = 'Saving…';
|
||||
toSave.forEach(job => {
|
||||
const id = job.dataset.id;
|
||||
const enabled = job.querySelector('.vv-enabled').checked ? '1' : '0';
|
||||
const cron = job.querySelector('.vv-cron')?.value.trim() ?? '';
|
||||
const log_enabled = job.querySelector('.vv-log-enabled')?.checked ? '1' : '0';
|
||||
vvPost('/plugins/varaverk/api/scheduler.php', {id, enabled, cron, log_enabled})
|
||||
.then(d => {
|
||||
if (d.ok) vvFlashSaved(job); else allOk = false;
|
||||
if (--pending === 0) vvFlashStatus(status, allOk ? '✓ All saved' : '✗ Some failed', allOk);
|
||||
});
|
||||
});
|
||||
const batch = toSave.map(job => ({
|
||||
id: job.dataset.id,
|
||||
enabled: job.querySelector('.vv-enabled').checked ? '1' : '0',
|
||||
cron: job.querySelector('.vv-cron')?.value.trim() ?? '',
|
||||
log_enabled: job.querySelector('.vv-log-enabled')?.checked ? '1' : '0',
|
||||
}));
|
||||
vvPost('/plugins/varaverk/api/scheduler.php', {batch: JSON.stringify(batch)})
|
||||
.then(d => {
|
||||
if (d.ok) toSave.forEach(job => vvFlashSaved(job));
|
||||
vvFlashStatus(status, d.ok ? '✓ All saved' : '✗ ' + (d.error ?? 'Failed'), d.ok);
|
||||
})
|
||||
.catch(() => vvFlashStatus(status, '✗ Request failed', false));
|
||||
}
|
||||
|
||||
function vvToggleAdvanced(btn) {
|
||||
@@ -2603,6 +2617,78 @@ function vvToggleFolder(header) {
|
||||
if (chevron) chevron.textContent = open ? '▾' : '▸';
|
||||
}
|
||||
|
||||
// ── Snapshot footer poll ──────────────────────────────────────────────────────
|
||||
let vvSnapTimer = null;
|
||||
function vvPollSnapshot() {
|
||||
fetch('/plugins/varaverk/api/snapshot.php')
|
||||
.then(r => r.json())
|
||||
.then(d => {
|
||||
const cpuBar = document.getElementById('vv-snap-cpu-bar');
|
||||
const cpuVal = document.getElementById('vv-snap-cpu-val');
|
||||
if (cpuBar && cpuVal) {
|
||||
const p = d.cpu_pct ?? 0;
|
||||
cpuBar.style.width = p + '%';
|
||||
cpuBar.style.backgroundColor = p > 85 ? '#f44336' : p > 60 ? '#ff9800' : '#4caf50';
|
||||
cpuVal.textContent = p + '%';
|
||||
}
|
||||
const ramBar = document.getElementById('vv-snap-ram-bar');
|
||||
const ramVal = document.getElementById('vv-snap-ram-val');
|
||||
if (ramBar && ramVal) {
|
||||
const p = d.ram_pct ?? 0;
|
||||
ramBar.style.width = p + '%';
|
||||
ramBar.style.backgroundColor = p > 85 ? '#f44336' : p > 70 ? '#ff9800' : '#4caf50';
|
||||
ramVal.textContent = p + '%';
|
||||
}
|
||||
const fb = document.getElementById('vv-snap-fallback');
|
||||
if (fb) {
|
||||
const s = (d.fallback ?? 'UNKNOWN').toUpperCase();
|
||||
fb.textContent = s;
|
||||
fb.style.color = s === 'NORMAL' ? '#4caf50'
|
||||
: s === 'FAILOVER' ? '#f44336'
|
||||
: s === 'NO_INTERNET' ? '#ff9800' : '#666';
|
||||
}
|
||||
const pt = document.getElementById('vv-snap-partner');
|
||||
if (pt) {
|
||||
if (!d.partner_enabled) {
|
||||
pt.textContent = 'No partnership'; pt.style.color = '#444';
|
||||
} else {
|
||||
const peers = d.peers ?? [];
|
||||
const on = peers.filter(p => p.online === true);
|
||||
const off = peers.filter(p => p.online !== true);
|
||||
if (off.length > 0 && peers.length === 1) {
|
||||
pt.textContent = off[0].hostname + ' ✕'; pt.style.color = '#f44336';
|
||||
} else if (off.length > 0) {
|
||||
pt.textContent = off.length + ' peer' + (off.length > 1 ? 's' : '') + ' down'; pt.style.color = '#f44336';
|
||||
} else if (on.length === 1) {
|
||||
pt.textContent = on[0].hostname + ' ●'; pt.style.color = '#4caf50';
|
||||
} else if (on.length > 1) {
|
||||
pt.textContent = on.length + ' peers ●'; pt.style.color = '#4caf50';
|
||||
} else {
|
||||
pt.textContent = '—'; pt.style.color = '#555';
|
||||
}
|
||||
}
|
||||
}
|
||||
const sm = document.getElementById('vv-snap-streams');
|
||||
if (sm) {
|
||||
const sc = d.stream_count ?? 0;
|
||||
sm.textContent = sc + (sc === 1 ? ' stream' : ' streams');
|
||||
sm.style.color = sc > 0 ? '#aaa' : '#444';
|
||||
}
|
||||
const tc = document.getElementById('vv-snap-transcodes');
|
||||
if (tc) {
|
||||
const n = d.transcode_count ?? 0;
|
||||
tc.textContent = n + (n === 1 ? ' transcode' : ' transcodes');
|
||||
tc.style.color = n > 0 ? '#ff9800' : '#444';
|
||||
}
|
||||
})
|
||||
.catch(() => {});
|
||||
}
|
||||
function vvStartSnapPoll() {
|
||||
if (vvSnapTimer) return;
|
||||
vvPollSnapshot();
|
||||
vvSnapTimer = setInterval(vvPollSnapshot, 10000);
|
||||
}
|
||||
|
||||
function vvGetCurrentFolders() {
|
||||
const folders = {};
|
||||
document.querySelectorAll('.vv-folder-group').forEach(fg => {
|
||||
@@ -2701,5 +2787,6 @@ requestAnimationFrame(function() {
|
||||
}
|
||||
vvFitRight();
|
||||
vvStartStatusPoll();
|
||||
vvStartSnapPoll();
|
||||
});
|
||||
</script>
|
||||
|
||||
Reference in New Issue
Block a user