Scheduler UI polish + per-script verbose logging + coffee report as orchestrator
- Cron and Advanced button vertically aligned in their respective rows - Verbose checkbox next to Log button — saves immediately, persists to schedule.json - --log flag injected into cron lines, manual Run, and Dry Run when verbose enabled - Coffee report rewritten as lean orchestrator over COFFEE_REPORT_SCRIPTS array - COFFEE_REPORT_SCRIPTS added to master.conf (7 Sunday monitor scripts) - Scheduler Advanced tab auto-discovers children via existing array detection
This commit is contained in:
@@ -422,6 +422,20 @@
|
||||
MONTHLY_RUN_INTERVAL_DAYS=30 # minimum days since last run before running again
|
||||
MONTHLY_LAST_RUN_FILE="/boot/config/monthly_maintenance_last_run.db"
|
||||
|
||||
# ━━━ Sunday Morning Coffee Report ━━━
|
||||
# Orchestrator that runs all Sunday monitor scripts in sequence.
|
||||
# Schedule: 0 7 * * 0 (Sunday 7am — after weekly_sync_maintenance.sh finishes at ~3am)
|
||||
# Each script runs independently and notifies on its own findings.
|
||||
COFFEE_REPORT_SCRIPTS=(
|
||||
"Monitors/zfs_memory_snapshot.sh" # ZFS pool health + ARC + Docker memory snapshot
|
||||
"Monitors/smart_health.sh" # drive SMART attributes — reallocated, pending, temp
|
||||
"Monitors/cert_monitor.sh" # SSL certificate expiry for all configured domains
|
||||
"Monitors/backup_verify.sh" # rsync mirror integrity via independent MD5 checksums
|
||||
"Monitors/bandwidth_monitor.sh" # weekly rsync transfer totals and per-share breakdown
|
||||
"Monitors/emby_session_report.sh" # Emby usage — streams, users, library, transcode ratio
|
||||
"Monitors/weekly_health_digest.sh" # aggregated digest — watchdogs, fallback, skip list
|
||||
)
|
||||
|
||||
# ==============================================================================================
|
||||
# ── RSYNC ─────────────────────────────────────────────────────────────────────────────────────
|
||||
# ==============================================================================================
|
||||
|
||||
Regular → Executable
+89
-930
File diff suppressed because it is too large
Load Diff
@@ -21,6 +21,7 @@ if (!is_dir($logDir)) mkdir($logDir, 0755, true);
|
||||
|
||||
file_put_contents($logFile, date('[Y-m-d H:i:s]') . " [DRY RUN] started\n", FILE_APPEND);
|
||||
|
||||
exec('nohup env DRY_RUN=1 bash ' . escapeshellarg($script) . ' >> ' . escapeshellarg($logFile) . ' 2>&1 </dev/null &');
|
||||
$flags = vv_job_flags($id);
|
||||
exec('nohup env DRY_RUN=1 bash ' . escapeshellarg($script) . ($flags ? " $flags" : '') . ' >> ' . escapeshellarg($logFile) . ' 2>&1 </dev/null &');
|
||||
|
||||
echo json_encode(['ok' => true]);
|
||||
|
||||
@@ -22,6 +22,7 @@ if (!is_dir($logDir)) mkdir($logDir, 0755, true);
|
||||
// Stamp the log so the panel shows when the run started
|
||||
file_put_contents($logFile, date('[Y-m-d H:i:s]') . " Manual run started\n", FILE_APPEND);
|
||||
|
||||
exec('nohup bash ' . escapeshellarg($script) . ' >> ' . escapeshellarg($logFile) . ' 2>&1 </dev/null &');
|
||||
$flags = vv_job_flags($id);
|
||||
exec('nohup bash ' . escapeshellarg($script) . ($flags ? " $flags" : '') . ' >> ' . escapeshellarg($logFile) . ' 2>&1 </dev/null &');
|
||||
|
||||
echo json_encode(['ok' => true]);
|
||||
|
||||
@@ -2,9 +2,10 @@
|
||||
header('Content-Type: application/json');
|
||||
require_once dirname(__DIR__) . '/include/scheduler.php';
|
||||
|
||||
$id = trim($_POST['id'] ?? '');
|
||||
$enabled = (bool)($_POST['enabled'] ?? false);
|
||||
$cron = trim($_POST['cron'] ?? '');
|
||||
$id = trim($_POST['id'] ?? '');
|
||||
$enabled = (bool)($_POST['enabled'] ?? false);
|
||||
$cron = trim($_POST['cron'] ?? '');
|
||||
$log_enabled = ($_POST['log_enabled'] ?? '0') === '1';
|
||||
|
||||
if (!$id) {
|
||||
echo json_encode(['ok' => false, 'error' => 'Missing id']);
|
||||
@@ -17,5 +18,5 @@ if ($cron && !preg_match('/^(\S+\s+){4}\S+$/', $cron)) {
|
||||
exit;
|
||||
}
|
||||
|
||||
$ok = vv_schedule_update($id, $enabled, $cron);
|
||||
$ok = vv_schedule_update($id, $enabled, $cron, $log_enabled);
|
||||
echo json_encode(['ok' => $ok, 'error' => $ok ? null : 'Failed to write schedule']);
|
||||
|
||||
@@ -38,7 +38,6 @@
|
||||
.vv-script { background: #161616; border: 1px solid #333; border-radius: 4px;
|
||||
padding: 6px 10px; margin: 4px 0; margin-left: 20px; }
|
||||
.vv-job-row { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
|
||||
.vv-name-cron { display: flex; align-items: center; gap: 8px; flex: 1; min-width: 0; }
|
||||
.vv-job-label { flex: 1; font-size: 16px; font-weight: bold;
|
||||
color: #6fcf97; min-width: 80px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
|
||||
.vv-job-actions { display: flex; align-items: center; gap: 8px; padding-left: 44px; margin-top: 6px; }
|
||||
@@ -48,11 +47,14 @@
|
||||
cursor: default; }
|
||||
.vv-cron { flex: 0 0 110px; width: 110px; background: #111; border: 1px solid #444; color: #ddd;
|
||||
padding: 4px 6px; border-radius: 4px; font-family: monospace; font-size: 13px; }
|
||||
.vv-log-label { display: flex; align-items: center; gap: 4px; font-size: 12px; color: #888;
|
||||
cursor: pointer; white-space: nowrap; flex-shrink: 0; }
|
||||
.vv-log-label input { cursor: pointer; accent-color: #4caf50; }
|
||||
.vv-log-label:has(input:checked) { color: #4caf50; }
|
||||
.vv-children { padding-top: 8px; border-top: 1px solid #333; margin-top: 8px; }
|
||||
.vv-advanced-toggle { background: none; border: 1px solid #555; color: #aaa;
|
||||
padding: 2px 8px; border-radius: 4px; cursor: pointer; font-size: 12px; }
|
||||
.vv-advanced-toggle:hover { border-color: #888; color: #fff; }
|
||||
.vv-job-status { font-size: 12px; min-width: 20px; }
|
||||
.vv-btn-sm { padding: 3px 10px; background: #2a2a2a; border: 1px solid #555; color: #ccc;
|
||||
border-radius: 4px; cursor: pointer; font-size: 12px; white-space: nowrap; }
|
||||
.vv-btn-sm:hover { border-color: #888; color: #fff; }
|
||||
@@ -70,23 +72,26 @@
|
||||
|
||||
/* Two-panel layout */
|
||||
#vv-sched-layout { display: flex; gap: 16px; align-items: stretch; }
|
||||
#vv-sched-left { flex: 1 1 0; min-width: 0; }
|
||||
#vv-sched-left { flex: 1 1 0; min-width: 0; display: flex; flex-direction: column; }
|
||||
#vv-sched-cards { flex: 1; }
|
||||
#vv-sched-right { display: none; flex: 1 1 0; min-width: 0; flex-direction: column; }
|
||||
#vv-sched-right.vv-panel-visible { display: flex; }
|
||||
#vv-sched-right > .vv-card { flex: 1; display: flex; flex-direction: column; min-height: 0; }
|
||||
.vv-log-right-pre { flex: 1; min-height: 0; max-height: none; }
|
||||
.vv-log-card { flex: 1; display: flex; flex-direction: column; padding-bottom: 0; }
|
||||
.vv-log-right-pre { max-height: none; overflow-y: auto; }
|
||||
|
||||
/* Mobile: stack vertically, right panel full-width below cards */
|
||||
@media (max-width: 880px) {
|
||||
#vv-sched-layout { flex-direction: column; align-items: stretch; }
|
||||
#vv-sched-left { flex: none; width: 100%; }
|
||||
#vv-sched-right { flex-direction: column; width: 100%; }
|
||||
.vv-log-right-pre { min-height: 260px; max-height: 340px; flex: none; }
|
||||
.vv-log-right-pre { min-height: 260px; max-height: 340px; }
|
||||
}
|
||||
|
||||
/* Card footer */
|
||||
.vv-card-footer { display: flex; align-items: center; gap: 10px;
|
||||
margin-top: 12px; padding-top: 10px; border-top: 1px solid #333; }
|
||||
/* Shared footer (Save Schedule left, info right) — same min-height so log card ends level with script cards */
|
||||
.vv-sched-footer { display: flex; align-items: center; gap: 10px;
|
||||
margin-top: 12px; padding: 10px 0; border-top: 1px solid #333;
|
||||
flex-shrink: 0; min-height: 72px; box-sizing: border-box; }
|
||||
.vv-sched-info { color: #666; font-size: 14px; display: flex; flex-direction: column; gap: 9px; }
|
||||
.vv-save-btn { padding: 5px 18px; background: #4caf50; border: none; color: #fff;
|
||||
border-radius: 4px; cursor: pointer; font-size: 13px; }
|
||||
.vv-save-btn:hover { background: #388e3c; }
|
||||
|
||||
@@ -20,18 +20,24 @@ function vv_schedule_save(array $schedule): bool {
|
||||
return file_put_contents(SCHEDULE_FILE, json_encode($schedule, JSON_PRETTY_PRINT)) !== false;
|
||||
}
|
||||
|
||||
function vv_schedule_update(string $id, bool $enabled, string $cron): bool {
|
||||
function vv_schedule_update(string $id, bool $enabled, string $cron, bool $log_enabled = false): bool {
|
||||
$schedule = vv_schedule_load();
|
||||
$schedule[$id] = [
|
||||
'id' => $id,
|
||||
'enabled' => $enabled,
|
||||
'cron' => $cron,
|
||||
'updated' => date('c'),
|
||||
'id' => $id,
|
||||
'enabled' => $enabled,
|
||||
'cron' => $cron,
|
||||
'log_enabled' => $log_enabled,
|
||||
'updated' => date('c'),
|
||||
];
|
||||
if (!vv_schedule_save($schedule)) return false;
|
||||
return vv_cron_rebuild($schedule);
|
||||
}
|
||||
|
||||
function vv_job_flags(string $id): string {
|
||||
$schedule = vv_schedule_load();
|
||||
return !empty($schedule[$id]['log_enabled']) ? '--log' : '';
|
||||
}
|
||||
|
||||
define('LOG_DIR', '/var/log/varaverk');
|
||||
|
||||
function vv_job_log_path(string $id): string {
|
||||
@@ -52,7 +58,8 @@ function vv_cron_rebuild(array $schedule): bool {
|
||||
$logFile = vv_job_log_path($entry['id']);
|
||||
$logDir = dirname($logFile);
|
||||
if (!is_dir($logDir)) mkdir($logDir, 0755, true);
|
||||
$lines[] = "{$entry['cron']} " . CRON_USER . " bash \"$script\" >> \"$logFile\" 2>&1";
|
||||
$flags = !empty($entry['log_enabled']) ? ' --log' : '';
|
||||
$lines[] = "{$entry['cron']} " . CRON_USER . " bash \"$script\"$flags >> \"$logFile\" 2>&1";
|
||||
}
|
||||
$lines[] = "";
|
||||
|
||||
@@ -103,13 +110,14 @@ function vv_job_tree(): array {
|
||||
$id = 'Orchestrators/' . basename($path);
|
||||
$entry = $schedule[$id] ?? ['enabled' => false, 'cron' => ''];
|
||||
$orchs[] = [
|
||||
'id' => $id,
|
||||
'label' => basename($path, '.sh'),
|
||||
'desc' => vv_script_description($path),
|
||||
'type' => 'orchestrator',
|
||||
'enabled' => (bool)($entry['enabled'] ?? false),
|
||||
'cron' => $entry['cron'] ?? '',
|
||||
'children' => vv_script_children($path, $schedule),
|
||||
'id' => $id,
|
||||
'label' => basename($path, '.sh'),
|
||||
'desc' => vv_script_description($path),
|
||||
'type' => 'orchestrator',
|
||||
'enabled' => (bool)($entry['enabled'] ?? false),
|
||||
'cron' => $entry['cron'] ?? '',
|
||||
'log_enabled' => (bool)($entry['log_enabled'] ?? false),
|
||||
'children' => vv_script_children($path, $schedule),
|
||||
];
|
||||
}
|
||||
return $orchs;
|
||||
@@ -148,12 +156,13 @@ function vv_script_children(string $orchPath, array $schedule): array {
|
||||
$seen[$rel] = true;
|
||||
$entry = $schedule[$rel] ?? ['enabled' => false, 'cron' => ''];
|
||||
$children[] = [
|
||||
'id' => $rel,
|
||||
'label' => basename($rel, '.sh'),
|
||||
'desc' => vv_script_description("$scriptsDir/$rel"),
|
||||
'type' => 'script',
|
||||
'enabled' => (bool)($entry['enabled'] ?? false),
|
||||
'cron' => $entry['cron'] ?? '',
|
||||
'id' => $rel,
|
||||
'label' => basename($rel, '.sh'),
|
||||
'desc' => vv_script_description("$scriptsDir/$rel"),
|
||||
'type' => 'script',
|
||||
'enabled' => (bool)($entry['enabled'] ?? false),
|
||||
'cron' => $entry['cron'] ?? '',
|
||||
'log_enabled' => (bool)($entry['log_enabled'] ?? false),
|
||||
];
|
||||
};
|
||||
|
||||
|
||||
@@ -12,6 +12,7 @@ $tree = vv_job_tree();
|
||||
|
||||
<!-- ── Left: script cards ── -->
|
||||
<div id="vv-sched-left">
|
||||
<div id="vv-sched-cards">
|
||||
|
||||
<?php foreach ($tree as $orch): $oid = htmlspecialchars($orch['id']); ?>
|
||||
<div class="vv-card vv-wide vv-sched-card" data-id="<?= $oid ?>">
|
||||
@@ -23,15 +24,9 @@ $tree = vv_job_tree();
|
||||
onchange="vvSaveJob(this)">
|
||||
<span class="vv-slider"></span>
|
||||
</label>
|
||||
<div class="vv-name-cron">
|
||||
<span class="vv-job-label"><?= htmlspecialchars($orch['label']) ?></span>
|
||||
<input type="text" class="vv-cron" value="<?= htmlspecialchars($orch['cron']) ?>"
|
||||
placeholder="cron expression">
|
||||
</div>
|
||||
<span class="vv-job-status"></span>
|
||||
<?php if (!empty($orch['children'])): ?>
|
||||
<button class="vv-advanced-toggle" onclick="vvToggleAdvanced(this)">Advanced ▸</button>
|
||||
<?php endif; ?>
|
||||
<span class="vv-job-label"><?= htmlspecialchars($orch['label']) ?></span>
|
||||
<input type="text" class="vv-cron" value="<?= htmlspecialchars($orch['cron']) ?>"
|
||||
placeholder="cron expression">
|
||||
</div>
|
||||
<?php if (!empty($orch['desc'])): ?>
|
||||
<div class="vv-job-desc" title="<?= htmlspecialchars($orch['desc']) ?>"><?= htmlspecialchars($orch['desc']) ?></div>
|
||||
@@ -40,7 +35,16 @@ $tree = vv_job_tree();
|
||||
<button class="vv-btn-sm vv-run-btn" onclick="vvRunJob(this)">▶ Run</button>
|
||||
<button class="vv-btn-sm vv-dry-btn" onclick="vvDryRun(this)">▶ Dry Run</button>
|
||||
<button class="vv-btn-sm" onclick="vvSelectLog(this)">Log</button>
|
||||
<label class="vv-log-label" title="Enable verbose --log output">
|
||||
<input type="checkbox" class="vv-log-enabled"
|
||||
<?= $orch['log_enabled'] ? 'checked' : '' ?>
|
||||
onchange="vvSaveJob(this)">
|
||||
<span>Verbose</span>
|
||||
</label>
|
||||
<span class="vv-job-dot"></span>
|
||||
<?php if (!empty($orch['children'])): ?>
|
||||
<button class="vv-advanced-toggle" style="margin-left:auto;width:110px" onclick="vvToggleAdvanced(this)">Advanced ▸</button>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
|
||||
<?php if (!empty($orch['children'])): ?>
|
||||
@@ -54,12 +58,9 @@ $tree = vv_job_tree();
|
||||
onchange="vvSaveJob(this)">
|
||||
<span class="vv-slider"></span>
|
||||
</label>
|
||||
<div class="vv-name-cron">
|
||||
<span class="vv-job-label"><?= htmlspecialchars($child['label']) ?></span>
|
||||
<input type="text" class="vv-cron" value="<?= htmlspecialchars($child['cron']) ?>"
|
||||
placeholder="cron expression">
|
||||
</div>
|
||||
<span class="vv-job-status"></span>
|
||||
<span class="vv-job-label"><?= htmlspecialchars($child['label']) ?></span>
|
||||
<input type="text" class="vv-cron" value="<?= htmlspecialchars($child['cron']) ?>"
|
||||
placeholder="cron expression">
|
||||
</div>
|
||||
<?php if (!empty($child['desc'])): ?>
|
||||
<div class="vv-job-desc" title="<?= htmlspecialchars($child['desc']) ?>"><?= htmlspecialchars($child['desc']) ?></div>
|
||||
@@ -68,6 +69,12 @@ $tree = vv_job_tree();
|
||||
<button class="vv-btn-sm vv-run-btn" onclick="vvRunJob(this)">▶ Run</button>
|
||||
<button class="vv-btn-sm vv-dry-btn" onclick="vvDryRun(this)">▶ Dry Run</button>
|
||||
<button class="vv-btn-sm" onclick="vvSelectLog(this)">Log</button>
|
||||
<label class="vv-log-label" title="Enable verbose --log output">
|
||||
<input type="checkbox" class="vv-log-enabled"
|
||||
<?= $child['log_enabled'] ? 'checked' : '' ?>
|
||||
onchange="vvSaveJob(this)">
|
||||
<span>Verbose</span>
|
||||
</label>
|
||||
<span class="vv-job-dot"></span>
|
||||
</div>
|
||||
</div>
|
||||
@@ -78,8 +85,10 @@ $tree = vv_job_tree();
|
||||
</div>
|
||||
<?php endforeach; ?>
|
||||
|
||||
</div><!-- /#vv-sched-cards -->
|
||||
|
||||
<!-- Single global save -->
|
||||
<div class="vv-card-footer" style="margin-top:4px;">
|
||||
<div class="vv-sched-footer">
|
||||
<button class="vv-save-btn" onclick="vvSaveAll(this)">Save Schedule</button>
|
||||
<span id="vv-save-all-status" class="vv-save-status"></span>
|
||||
</div>
|
||||
@@ -88,7 +97,7 @@ $tree = vv_job_tree();
|
||||
|
||||
<!-- ── Right: persistent log panel ── -->
|
||||
<div id="vv-sched-right">
|
||||
<div class="vv-card">
|
||||
<div class="vv-card vv-log-card">
|
||||
<div class="vv-log-toolbar" style="margin-bottom:8px;">
|
||||
<div style="display:flex;align-items:center;gap:8px;">
|
||||
<span id="vv-log-title" style="font-size:13px;font-weight:bold;color:#ccc;">No script selected</span>
|
||||
@@ -101,6 +110,29 @@ $tree = vv_job_tree();
|
||||
</div>
|
||||
<pre id="vv-log-pre" class="vv-log-pre vv-log-right-pre">Click Log, Run, or Dry Run on a script to view output here.</pre>
|
||||
</div>
|
||||
<?php
|
||||
$totalJobs = 0; $scheduledJobs = 0;
|
||||
foreach ($tree as $orch) {
|
||||
$totalJobs++;
|
||||
if (!empty($orch['cron']) && $orch['enabled']) $scheduledJobs++;
|
||||
foreach (($orch['children'] ?? []) as $child) {
|
||||
$totalJobs++;
|
||||
if (!empty($child['cron']) && $child['enabled']) $scheduledJobs++;
|
||||
}
|
||||
}
|
||||
$runningScripts = [];
|
||||
exec('pgrep -af bash 2>/dev/null', $psLines);
|
||||
foreach ($psLines as $line) {
|
||||
if (preg_match('#' . preg_quote(SCRIPTS_DIR, '#') . '/([^\s]+\.sh)#', $line, $rm)) {
|
||||
$runningScripts[] = basename($rm[1], '.sh');
|
||||
}
|
||||
}
|
||||
$runningScripts = array_unique($runningScripts);
|
||||
?>
|
||||
<div class="vv-sched-footer vv-sched-info">
|
||||
<span><?= $scheduledJobs ?> of <?= $totalJobs ?> job<?= $totalJobs !== 1 ? 's' : '' ?> scheduled</span>
|
||||
<span><?= !empty($runningScripts) ? 'Currently Running: ' . htmlspecialchars(implode(', ', $runningScripts)) : 'Currently Running scripts: none' ?></span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div><!-- /#vv-sched-layout -->
|
||||
@@ -122,6 +154,40 @@ function vvPost(url, data) {
|
||||
}).then(r => r.json());
|
||||
}
|
||||
|
||||
function vvFitRight() {
|
||||
const right = document.getElementById('vv-sched-right');
|
||||
if (!right.classList.contains('vv-panel-visible')) return;
|
||||
const left = document.getElementById('vv-sched-left');
|
||||
|
||||
const lf = left.querySelector('.vv-sched-footer');
|
||||
const rf = right.querySelector('.vv-sched-info');
|
||||
const toolbar = right.querySelector('.vv-log-toolbar');
|
||||
const pre = document.getElementById('vv-log-pre');
|
||||
|
||||
// Read viewport rects BEFORE any mutations
|
||||
const leftRect = left.getBoundingClientRect();
|
||||
const rightRect = right.getBoundingClientRect();
|
||||
|
||||
// Match footer heights
|
||||
rf.style.height = lf.offsetHeight + 'px';
|
||||
|
||||
// Pin right panel bottom to left panel bottom using viewport coords
|
||||
right.style.height = Math.round(leftRect.bottom - rightRect.top) + 'px';
|
||||
|
||||
// Pre fills from toolbar bottom to footer border, leaving 12px card padding below
|
||||
// -12 footer margin, -12 card padding-bottom, -8 toolbar margin-bottom
|
||||
const preH = Math.max(80, lf.getBoundingClientRect().top - 32 - toolbar.getBoundingClientRect().bottom);
|
||||
pre.style.maxHeight = 'none';
|
||||
pre.style.height = preH + 'px';
|
||||
|
||||
console.log('[vvFitRight]', {
|
||||
leftBottom: Math.round(leftRect.bottom), rightTop: Math.round(rightRect.top),
|
||||
rightBottomAfter: Math.round(right.getBoundingClientRect().bottom),
|
||||
rfH: lf.offsetHeight, preH, preActual: pre.offsetHeight,
|
||||
});
|
||||
}
|
||||
window.addEventListener('resize', vvFitRight);
|
||||
|
||||
// Open the right panel for a given job id
|
||||
function vvOpenRight(id) {
|
||||
// Deselect old
|
||||
@@ -137,6 +203,7 @@ function vvOpenRight(id) {
|
||||
const name = id.replace(/\.sh$/, '').split('/').pop();
|
||||
document.getElementById('vv-log-title').textContent = name;
|
||||
document.getElementById('vv-sched-right').classList.add('vv-panel-visible');
|
||||
requestAnimationFrame(vvFitRight);
|
||||
|
||||
vvFetchRight();
|
||||
if (!vvPollTimer) vvPollTimer = setInterval(vvFetchRight, 2000);
|
||||
@@ -220,13 +287,12 @@ function vvDryRun(btn) {
|
||||
}
|
||||
|
||||
function vvSaveJob(el) {
|
||||
const job = el.closest('[data-id]');
|
||||
const id = job.dataset.id;
|
||||
const enabled = job.querySelector('.vv-enabled').checked ? '1' : '0';
|
||||
const cron = job.querySelector('.vv-cron').value.trim();
|
||||
const status = job.querySelector('.vv-job-status');
|
||||
vvPost('/plugins/varaverk/api/scheduler.php', {id, enabled, cron})
|
||||
.then(d => { if (status) vvFlashStatus(status, d.ok ? '✓' : '✗ ' + (d.error ?? ''), d.ok); });
|
||||
const job = el.closest('[data-id]');
|
||||
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});
|
||||
}
|
||||
|
||||
function vvSaveAll() {
|
||||
@@ -236,10 +302,11 @@ function vvSaveAll() {
|
||||
if (!pending) { vvFlashStatus(status, '✗ No jobs found', false); return; }
|
||||
status.textContent = 'Saving…';
|
||||
jobs.forEach(job => {
|
||||
const id = job.dataset.id;
|
||||
const enabled = job.querySelector('.vv-enabled').checked ? '1' : '0';
|
||||
const cron = job.querySelector('.vv-cron').value.trim();
|
||||
vvPost('/plugins/varaverk/api/scheduler.php', {id, enabled, cron})
|
||||
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) allOk = false;
|
||||
if (--pending === 0) vvFlashStatus(status, allOk ? '✓ Saved' : '✗ Some failed', allOk);
|
||||
|
||||
Reference in New Issue
Block a user