Varaverk: rsync flag toggle + stop button

- Rsync/rsync.sh children in Advanced now show as conf_flag type when the
  parent orch controls a *_RSYNC_ENABLED tier flag; toggle writes true/false
  to master.conf instead of comment/uncommenting a SCRIPTS array entry
- Added vv_conf_flag_value() and vv_conf_flag_set() helpers in scheduler.php
- Added api/flag_toggle.php endpoint (validates *_RSYNC_ENABLED pattern)
- Added api/stop.php: kills process group, sweeps stuck locks, updates stat
- vv-flag-badge CSS (amber, monospace) to distinguish from event/script rows
- vvSaveChild() routes conf_flag children to flag_toggle.php unconditionally
- vvApplyOrchState() keeps conf_flag toggle at real flag value; disables when orch off
- vvSaveAll() skips conf_flag children (immediate-save only)
This commit is contained in:
Gmer4Lfe
2026-05-24 22:38:33 -04:00
parent d0d56ed8b9
commit cdd2dfc990
5 changed files with 203 additions and 3 deletions
@@ -71,6 +71,34 @@ foreach ($tree as $orch) {
<?php if (!empty($orch['children'])): ?>
<div class="vv-children" style="display:none;">
<?php foreach ($orch['children'] as $child): $cid = htmlspecialchars($child['id']); ?>
<?php if (($child['type'] ?? 'script') === 'conf_flag'): ?>
<div class="vv-script" data-id="<?= $cid ?>"
data-type="conf_flag"
data-flag-name="<?= htmlspecialchars($child['flag_name']) ?>"
data-flag-value="<?= !empty($child['flag_value']) ? '1' : '0' ?>">
<div class="vv-job-row">
<label class="vv-toggle" title="Toggle <?= htmlspecialchars($child['flag_name']) ?> in master.conf">
<input type="checkbox" class="vv-enabled"
<?= !empty($child['flag_value']) ? 'checked' : '' ?>
onchange="vvSaveChild(this)">
<span class="vv-slider"></span>
</label>
<span class="vv-job-label"><?= htmlspecialchars($child['label']) ?></span>
<span class="vv-flag-badge"><?= htmlspecialchars($child['flag_name']) ?></span>
<span class="vv-save-check"></span>
</div>
<?php if (!empty($child['desc'])): ?>
<div class="vv-job-desc" title="<?= htmlspecialchars($child['desc']) ?>"><?= htmlspecialchars($child['desc']) ?></div>
<?php endif; ?>
<div class="vv-job-actions">
<button class="vv-btn-sm vv-run-btn" onclick="vvRunJob(this)">&#9654; Run</button>
<button class="vv-btn-sm vv-dry-btn" onclick="vvDryRun(this)">&#9654; Dry Run</button>
<?php $childLog = vv_job_log_path($child['id']); ?>
<button class="vv-btn-sm vv-log-btn<?= (file_exists($childLog) && filesize($childLog) > 0) ? ' vv-has-log' : '' ?>" onclick="vvSelectLog(this)">Log</button>
<span class="vv-job-dot"></span>
</div>
</div>
<?php else: ?>
<div class="vv-script" data-id="<?= $cid ?>"
data-conf-managed="<?= $child['conf_managed'] ? '1' : '0' ?>"
data-conf-enabled="<?= $child['conf_enabled'] === true ? '1' : ($child['conf_enabled'] === false ? '0' : '') ?>">
@@ -106,6 +134,7 @@ foreach ($tree as $orch) {
<span class="vv-job-dot"></span>
</div>
</div>
<?php endif; ?>
<?php endforeach; ?>
</div>
<?php endif; ?>
@@ -636,13 +665,22 @@ function vvSaveOrch(el) {
// Apply visual + interactive state to children based on whether orch is on or off.
function vvApplyOrchState(orchCard, orchEnabled) {
orchCard.querySelectorAll('.vv-script').forEach(child => {
const toggle = child.querySelector('.vv-enabled');
const cronInput = child.querySelector('input.vv-cron');
// conf_flag children (e.g. Rsync): toggle reflects real flag value, enabled only when orch is on
if (child.dataset.type === 'conf_flag') {
toggle.checked = child.dataset.flagValue === '1';
toggle.disabled = !orchEnabled;
if (cronInput) { cronInput.disabled = true; cronInput.style.opacity = '0.35'; }
return;
}
const confManaged = child.dataset.confManaged === '1';
const confEnabled = child.dataset.confEnabled === '1';
const toggle = child.querySelector('.vv-enabled');
const cronInput = child.querySelector('input.vv-cron');
if (orchEnabled) {
// Orch is god: set toggle from master.conf state; hide independent cron
// Orch is god: set toggle from master.conf state; dim independent cron
toggle.checked = confManaged ? confEnabled : false;
toggle.disabled = !confManaged;
if (cronInput) { cronInput.disabled = true; cronInput.style.opacity = '0.35'; }
@@ -661,6 +699,7 @@ function vvApplyOrchState(orchCard, orchEnabled) {
}
// Child toggle: conf_toggle when orch is on; scheduler save when orch is off.
// conf_flag children always write directly to master.conf regardless of orch state.
function vvSaveChild(el) {
const child = el.closest('[data-id]');
const orchCard = child.closest('.vv-sched-card');
@@ -668,6 +707,14 @@ function vvSaveChild(el) {
const id = child.dataset.id;
const enabled = el.checked;
if (child.dataset.type === 'conf_flag') {
const name = child.dataset.flagName;
child.dataset.flagValue = enabled ? '1' : '0';
vvPost('/plugins/varaverk/api/flag_toggle.php', {name, enabled: enabled ? '1' : '0'})
.then(d => { if (d.ok) vvFlashSaved(child); });
return;
}
if (orchOn) {
vvPost('/plugins/varaverk/api/conf_toggle.php', {id, enabled: enabled ? '1' : '0'})
.then(d => { if (d.ok) vvFlashSaved(child); });
@@ -682,9 +729,11 @@ 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
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