Scheduler: inline cron beside name, dynamic description from script headers
Cron input now sits right of the script label in the same row. Below each row: one-line description pulled live from the script header (PURPOSE block or first meaningful comment line) — updates whenever scripts are edited, no plugin changes needed.
This commit is contained in:
@@ -37,9 +37,14 @@
|
||||
.vv-sched-card { margin-bottom: 10px; }
|
||||
.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-job-label { flex: 1; font-size: 14px; min-width: 120px; }
|
||||
.vv-cron { width: 140px; background: #111; border: 1px solid #444; color: #ddd;
|
||||
.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: 14px; min-width: 80px;
|
||||
white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
|
||||
.vv-job-desc { font-size: 12px; color: #555; margin: 2px 0 6px 44px;
|
||||
white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
|
||||
cursor: default; }
|
||||
.vv-cron { width: 140px; flex-shrink: 0; background: #111; border: 1px solid #444; color: #ddd;
|
||||
padding: 4px 8px; border-radius: 4px; font-family: monospace; font-size: 13px; }
|
||||
.vv-children { padding-top: 8px; border-top: 1px solid #333; margin-top: 8px; }
|
||||
.vv-advanced-toggle { background: none; border: 1px solid #555; color: #aaa;
|
||||
|
||||
@@ -59,6 +59,36 @@ function vv_cron_rebuild(array $schedule): bool {
|
||||
return file_put_contents(CRON_FILE, implode("\n", $lines)) !== false;
|
||||
}
|
||||
|
||||
// Extract a one-line description from a bash script header.
|
||||
// Supports two patterns:
|
||||
// 1. # PURPOSE (or # DESCRIPTION) block — returns first non-separator line after it
|
||||
// 2. First meaningful comment line after the banner
|
||||
function vv_script_description(string $path): string {
|
||||
if (!file_exists($path)) return '';
|
||||
$lines = array_slice(file($path) ?: [], 0, 50);
|
||||
$purposeNext = false;
|
||||
$first = '';
|
||||
foreach ($lines as $raw) {
|
||||
$raw = rtrim($raw);
|
||||
if (str_starts_with($raw, '#!')) continue; // shebang
|
||||
if (!str_starts_with($raw, '#')) continue; // non-comment
|
||||
$inner = ltrim(substr($raw, 1)); // strip leading #
|
||||
if (preg_match('/^[\s=\-─━\*]+$/', $inner) || $inner === '') { // separator / blank
|
||||
if ($purposeNext) continue;
|
||||
continue;
|
||||
}
|
||||
if (preg_match('/^\s*(PURPOSE|DESCRIPTION|Description)\s*$/i', $inner)) {
|
||||
$purposeNext = true;
|
||||
continue;
|
||||
}
|
||||
if ($purposeNext) {
|
||||
return mb_substr(trim($inner), 0, 200);
|
||||
}
|
||||
if (!$first) $first = mb_substr(trim($inner), 0, 200);
|
||||
}
|
||||
return $first;
|
||||
}
|
||||
|
||||
// Walk the scripts repo and return the job tree:
|
||||
// orchestrators as top-level, individual scripts as children
|
||||
function vv_job_tree(): array {
|
||||
@@ -76,6 +106,7 @@ function vv_job_tree(): array {
|
||||
$orchs[] = [
|
||||
'id' => $id,
|
||||
'label' => basename($path, '.sh'),
|
||||
'desc' => vv_script_description($path),
|
||||
'type' => 'orchestrator',
|
||||
'enabled' => (bool)($entry['enabled'] ?? false),
|
||||
'cron' => $entry['cron'] ?? '',
|
||||
@@ -120,6 +151,7 @@ function vv_script_children(string $orchPath, array $schedule): array {
|
||||
$children[] = [
|
||||
'id' => $rel,
|
||||
'label' => basename($rel, '.sh'),
|
||||
'desc' => vv_script_description("$scriptsDir/$rel"),
|
||||
'type' => 'script',
|
||||
'enabled' => (bool)($entry['enabled'] ?? false),
|
||||
'cron' => $entry['cron'] ?? '',
|
||||
|
||||
@@ -23,9 +23,11 @@ $tree = vv_job_tree();
|
||||
onchange="vvSaveJob(this)">
|
||||
<span class="vv-slider"></span>
|
||||
</label>
|
||||
<span class="vv-job-label"><?= htmlspecialchars($orch['label']) ?></span>
|
||||
<input type="text" class="vv-cron" value="<?= htmlspecialchars($orch['cron']) ?>"
|
||||
placeholder="cron expression">
|
||||
<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>
|
||||
<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>
|
||||
@@ -35,6 +37,9 @@ $tree = vv_job_tree();
|
||||
<button class="vv-advanced-toggle" onclick="vvToggleAdvanced(this)">Advanced ▸</button>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
<?php if (!empty($orch['desc'])): ?>
|
||||
<div class="vv-job-desc" title="<?= htmlspecialchars($orch['desc']) ?>"><?= htmlspecialchars($orch['desc']) ?></div>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if (!empty($orch['children'])): ?>
|
||||
<div class="vv-children" style="display:none;">
|
||||
@@ -47,15 +52,20 @@ $tree = vv_job_tree();
|
||||
onchange="vvSaveJob(this)">
|
||||
<span class="vv-slider"></span>
|
||||
</label>
|
||||
<span class="vv-job-label"><?= htmlspecialchars($child['label']) ?></span>
|
||||
<input type="text" class="vv-cron" value="<?= htmlspecialchars($child['cron']) ?>"
|
||||
placeholder="cron expression">
|
||||
<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>
|
||||
<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>
|
||||
<span class="vv-job-dot"></span>
|
||||
<span class="vv-job-status"></span>
|
||||
</div>
|
||||
<?php if (!empty($child['desc'])): ?>
|
||||
<div class="vv-job-desc" title="<?= htmlspecialchars($child['desc']) ?>"><?= htmlspecialchars($child['desc']) ?></div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user