Auth stack certs tab, arrs db fallbacks, cert monitor cache, conf parser fix

- Auth stack: fold cert monitor into Auth Stack page as fourth tab (Certs);
  remove standalone cert page and top-level tab
- cert_monitor.sh: write JSON status cache to State_Files/cert_status.json
  after each run; expose per-domain days/expiry via _CERT_DAYS/_CERT_EXPIRY globals
- api/cert.php: new — serves cached cert status; falls back to configured
  domains as UNKN when no cache exists; POST action=run triggers live check
- arrs db fallbacks: vv_arr_cleanup_stats/discovery_stats/recovery_stats now
  read from data/*.db files when log JSON files don't yet exist
- config.php vv_conf_vars(): unescape bash \$ → $ so passwords with dollar
  signs read correctly from conf files
- host1.conf: fill in HOST1_NPM_USER/PASS and HOST1_LLDAP_USER/PASS
- Partnership adapter pattern: Unraid-specific container logic extracted to
  Plugin/unraid/Partnership/; platform-agnostic structure stays in Partnership/
- First-run wizard: uniform multi-step flow for all hosts; HOST2 pull moved
  to checklist; auto SSH keygen and API key creation on save
- api/checklist.php: live setup checklist with pull_master action
- Fullscreen toggle: hide Unraid header/menu; state persists via localStorage
This commit is contained in:
Gmer4Lfe
2026-06-05 23:17:30 -04:00
parent 17012bcd8c
commit 9c3ace95a7
43 changed files with 1605 additions and 1167 deletions
+75 -29
View File
@@ -149,7 +149,7 @@ function vv_script_suggested_cron(string $path): array {
// Parse user_script_plug-in.sh into an array of script blocks.
// Each block: title, schedule, desc (array of lines), scripts (array of {rel, cron})
function vv_parse_user_script_template(): array {
$file = SCRIPTS_DIR . '/user_script_plug-in.sh';
$file = SCRIPTS_DIR . '/Plugin/unraid/user_script_plug-in.sh';
if (!file_exists($file)) return [];
$lines = file($file, FILE_IGNORE_NEW_LINES);
$prefix = rtrim(SCRIPTS_DIR, '/') . '/';
@@ -231,41 +231,69 @@ function vv_script_description(string $path): string {
}
function vv_tools_scripts(): array {
$dir = SCRIPTS_DIR . '/Tools';
// Background writers managed automatically — not user-facing tools
static $EXCLUDE = ['api_cache_writer.sh', 'remote_arr_cache_writer.sh'];
$schedule = vv_schedule_load();
$scripts = [];
foreach (glob("$dir/*.sh") ?: [] as $path) {
$rel = 'Tools/' . basename($path);
$entry = $schedule[$rel] ?? [];
$scripts[] = [
'id' => $rel,
'label' => vv_pretty_label(basename($path, '.sh')),
'desc' => vv_script_description($path),
'enabled' => (bool)($entry['enabled'] ?? false),
'cron' => $entry['cron'] ?? '',
'log_enabled' => (bool)($entry['log_enabled'] ?? false),
];
$collect = function(string $dir, string $relPrefix) use ($schedule, $EXCLUDE, &$scripts): void {
foreach (glob("$dir/*.sh") ?: [] as $path) {
$base = basename($path);
if (in_array($base, $EXCLUDE, true)) continue;
$rel = $relPrefix . $base;
$entry = $schedule[$rel] ?? [];
$scripts[] = [
'id' => $rel,
'label' => vv_pretty_label(basename($path, '.sh')),
'desc' => vv_script_description($path),
'enabled' => (bool)($entry['enabled'] ?? false),
'cron' => $entry['cron'] ?? '',
'log_enabled' => (bool)($entry['log_enabled'] ?? false),
];
}
};
// General tools
$collect(SCRIPTS_DIR . '/Tools', 'Tools/');
// Platform adapter tools (Plugin/<platform>/Tools/)
foreach (glob(SCRIPTS_DIR . '/Plugin/*/Tools') ?: [] as $toolsDir) {
$platform = basename(dirname($toolsDir));
$collect($toolsDir, "Plugin/$platform/Tools/");
}
usort($scripts, fn($a, $b) => strcmp($a['label'], $b['label']));
return $scripts;
}
function vv_custom_scripts(): array {
$dir = SCRIPTS_DIR . '/Custom';
$schedule = vv_schedule_load();
$scripts = [];
foreach (glob("$dir/*.sh") ?: [] as $path) {
$rel = 'Custom/' . basename($path);
$entry = $schedule[$rel] ?? [];
$scripts[] = [
'id' => $rel,
'label' => vv_pretty_label(basename($path, '.sh')),
'desc' => vv_script_description($path),
'enabled' => (bool)($entry['enabled'] ?? false),
'cron' => $entry['cron'] ?? '',
'log_enabled' => (bool)($entry['log_enabled'] ?? false),
];
$collect = function(string $dir, string $relPrefix) use ($schedule, &$scripts): void {
foreach (glob("$dir/*.sh") ?: [] as $path) {
$rel = $relPrefix . basename($path);
$entry = $schedule[$rel] ?? [];
$scripts[] = [
'id' => $rel,
'label' => vv_pretty_label(basename($path, '.sh')),
'desc' => vv_script_description($path),
'enabled' => (bool)($entry['enabled'] ?? false),
'cron' => $entry['cron'] ?? '',
'log_enabled' => (bool)($entry['log_enabled'] ?? false),
];
}
};
$collect(SCRIPTS_DIR . '/Custom', 'Custom/');
// Platform adapter custom scripts (Plugin/<platform>/Custom/)
foreach (glob(SCRIPTS_DIR . '/Plugin/*/Custom') ?: [] as $customDir) {
$platform = basename(dirname($customDir));
$collect($customDir, "Plugin/$platform/Custom/");
}
return $scripts;
}
@@ -287,7 +315,7 @@ function vv_orch_conf_arrays(string $orchPath): array {
}
// Return .sh scripts that exist in SCRIPTS_DIR but are not referenced in any
// master.conf *_SCRIPTS array and are not orchestrators or custom scripts.
// master.conf *_SCRIPTS array and are not shown in any other scheduler card.
function vv_script_library(): array {
$scriptsDir = SCRIPTS_DIR;
$confMap = vv_conf_script_map();
@@ -295,7 +323,17 @@ function vv_script_library(): array {
foreach (glob("$scriptsDir/Orchestrators/*.sh") ?: [] as $p) {
$orchIds[] = 'Orchestrators/' . basename($p);
}
$exclude = ['Plugin', '.git', 'Orchestrators', 'Custom', 'Configurations'];
// Scripts already shown in their own cards are not "unlisted"
$schedule = vv_schedule_load();
$cardIds = array_flip(array_merge(
array_column(vv_tools_scripts(), 'id'),
array_column(vv_custom_scripts(), 'id')
));
// UI-only subdirs under Plugin/<platform>/ — no runnable scripts
$pluginUiDirs = ['api', 'include', 'pages', 'css', 'js', 'icons', 'event'];
$exclude = ['.git', 'Orchestrators', 'Custom', 'Configurations'];
$library = [];
try {
$ri = new RecursiveIteratorIterator(
@@ -306,8 +344,16 @@ function vv_script_library(): array {
if (!$rf->isFile() || strtolower($rf->getExtension()) !== 'sh') continue;
$rel = ltrim(str_replace($base, '', $rf->getPathname()), '/');
$parts = explode('/', $rel);
if (count($parts) < 2 || in_array($parts[0], $exclude)) continue;
if (in_array($rel, $orchIds) || isset($confMap[$rel])) continue;
if (in_array($parts[0], $exclude)) continue;
if ($parts[0] === 'Plugin') {
// Require Plugin/<platform>/<category>/<script>.sh — skip root-level adapter files
if (count($parts) < 4) continue;
// Skip UI-only category dirs
if (in_array($parts[2], $pluginUiDirs)) continue;
} elseif (count($parts) < 2) {
continue;
}
if (in_array($rel, $orchIds) || isset($confMap[$rel]) || isset($cardIds[$rel]) || isset($schedule[$rel])) continue;
$library[] = ['id' => $rel, 'label' => vv_pretty_label(basename($rel, '.sh'))];
}
} catch (Exception $e) {}