Let an installation add its own tabs without the repo having to name them
This commit is contained in:
+12
@@ -43,3 +43,15 @@ Plugin/dist/
|
|||||||
*.swp
|
*.swp
|
||||||
*~
|
*~
|
||||||
.vscode/
|
.vscode/
|
||||||
|
|
||||||
|
# ── Local-only plugin surfaces (per-installation, never pushed) ───────────────
|
||||||
|
# Varaverk.page discovers pages/local/*.php and registers each as a tab; api/local/ holds their
|
||||||
|
# endpoints. Both are symlinks into a store outside this repo, so what they contain belongs to
|
||||||
|
# one installation and is not part of the project. The tracked loader is deliberately generic —
|
||||||
|
# it names no page — so the public mirror never learns what a given server runs here.
|
||||||
|
#
|
||||||
|
# No trailing slash on either pattern. These paths are symlinks, not directories, and git treats
|
||||||
|
# a symlink as a blob — a "dir/" pattern does not match one, so the entries sat untracked rather
|
||||||
|
# than ignored, which is the same near-miss the *.bak rule above documents.
|
||||||
|
Plugin/unraid/pages/local
|
||||||
|
Plugin/unraid/api/local
|
||||||
|
|||||||
@@ -477,8 +477,42 @@ $validTabs = ['monitor', 'scheduler', 'watchdog', 'partnership', 'fallback', 'ar
|
|||||||
$_vv_ai = vv_ai_owner_ui_on();
|
$_vv_ai = vv_ai_owner_ui_on();
|
||||||
if ($_vv_ai) $validTabs[] = 'ai';
|
if ($_vv_ai) $validTabs[] = 'ai';
|
||||||
|
|
||||||
|
// ── Local pages ───────────────────────────────────────────────────────────────────────────────
|
||||||
|
// pages/local/ is gitignored, so whatever is in it belongs to this installation alone and never
|
||||||
|
// reaches the public mirror. This loader is the tracked half: a generic extension point that
|
||||||
|
// knows nothing about what it is loading.
|
||||||
|
//
|
||||||
|
// It exists because the alternative — a tracked `if (file_exists(pages/thing.php))` per private
|
||||||
|
// page — puts the name and purpose of every private page into the public repo, which defeats the
|
||||||
|
// point of keeping the page out of it.
|
||||||
|
//
|
||||||
|
// Discovered rather than configured: a conf key listing local pages would itself be a tracked
|
||||||
|
// file naming them, and an untracked one would be a second thing to keep in sync with the
|
||||||
|
// directory. The directory is the declaration.
|
||||||
|
//
|
||||||
|
// The label comes from a `// vv-local-page: Name` line in the first 2KB of the file, falling back
|
||||||
|
// to the capitalised id. Reading it out of the file keeps the page self-describing — nothing
|
||||||
|
// outside it has to be edited to add one.
|
||||||
|
$localPages = [];
|
||||||
|
foreach (glob("$pluginDir/pages/local/*.php") ?: [] as $_lp) {
|
||||||
|
$_id = basename($_lp, '.php');
|
||||||
|
// Ids are restricted and collisions rejected: $tab is user input that becomes an include
|
||||||
|
// path below, and a local page must never be able to shadow a real tab.
|
||||||
|
if (!preg_match('/^[a-z0-9][a-z0-9_-]{0,31}$/', $_id)) continue;
|
||||||
|
if (in_array($_id, $validTabs, true)) continue;
|
||||||
|
$_lbl = ucfirst($_id);
|
||||||
|
if (preg_match('/^\s*(?:\/\/|#)\s*vv-local-page:\s*(.+)$/m', (string)@file_get_contents($_lp, false, null, 0, 2048), $_m)) {
|
||||||
|
$_lbl = trim($_m[1]);
|
||||||
|
}
|
||||||
|
$localPages[$_id] = ['path' => $_lp, 'label' => $_lbl];
|
||||||
|
$validTabs[] = $_id;
|
||||||
|
}
|
||||||
|
unset($_lp, $_id, $_lbl, $_m);
|
||||||
|
|
||||||
if (!in_array($tab, $validTabs)) $tab = 'monitor';
|
if (!in_array($tab, $validTabs)) $tab = 'monitor';
|
||||||
$tabLabels = ['monitor' => 'Monitor', 'scheduler' => 'Scheduler', 'watchdog' => 'Watchdog', 'partnership' => 'Partnership', 'fallback' => 'FallBack', 'arrs' => 'Media Stack', 'rsync' => 'Rsync', 'auth' => 'Auth Stack', 'settings' => 'Settings', 'ai' => 'AI'];
|
$tabLabels = ['monitor' => 'Monitor', 'scheduler' => 'Scheduler', 'watchdog' => 'Watchdog', 'partnership' => 'Partnership', 'fallback' => 'FallBack', 'arrs' => 'Media Stack', 'rsync' => 'Rsync', 'auth' => 'Auth Stack', 'settings' => 'Settings', 'ai' => 'AI'];
|
||||||
|
foreach ($localPages as $_id => $_lp) $tabLabels[$_id] = $_lp['label'];
|
||||||
|
unset($_id, $_lp);
|
||||||
|
|
||||||
// Cache stamp for the stylesheet and script below. Both are served straight off the plugin
|
// Cache stamp for the stylesheet and script below. Both are served straight off the plugin
|
||||||
// directory at a path that never changes, so a browser holding an old copy keeps using it after
|
// directory at a path that never changes, so a browser holding an old copy keeps using it after
|
||||||
@@ -521,9 +555,12 @@ foreach (['css/varaverk.css', 'js/varaverk.js'] as $_vv_a) {
|
|||||||
<!-- Tab content -->
|
<!-- Tab content -->
|
||||||
<div id="vv-content">
|
<div id="vv-content">
|
||||||
<?php
|
<?php
|
||||||
$page = "$pluginDir/pages/$tab.php";
|
// Local pages resolve from the map built above, never by composing a path out of $tab —
|
||||||
|
// the map's keys were validated against a strict pattern, so nothing user-supplied
|
||||||
|
// reaches an include.
|
||||||
|
$page = isset($localPages[$tab]) ? $localPages[$tab]['path'] : "$pluginDir/pages/$tab.php";
|
||||||
if (file_exists($page)) include $page;
|
if (file_exists($page)) include $page;
|
||||||
else echo "<p>Page not found: $tab</p>";
|
else echo "<p>Page not found: " . htmlspecialchars($tab, ENT_QUOTES) . "</p>";
|
||||||
?>
|
?>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user