Show partial folder selections

This commit is contained in:
Mikei386
2026-06-15 20:15:35 +02:00
parent 9249fad65a
commit 68c5d677e6
8 changed files with 29 additions and 9 deletions
+4 -4
View File
@@ -9,12 +9,12 @@ Tag="URBM Unraid Restic Backup Manager backup snapshots restore"
<?php
$pluginRoot = '/plugins/urbm';
?>
<link rel="stylesheet" href="<?= $pluginRoot ?>/assets/urbm.css?v=20260615r020">
<link rel="stylesheet" href="<?= $pluginRoot ?>/assets/urbm.css?v=20260615r021">
<div id="urbm-app" data-api="<?= $pluginRoot ?>/api.php">
<header class="bu-header">
<div class="bu-brand">
<img class="bu-logo" src="<?= $pluginRoot ?>/images/urbm.png?v=20260615r020" alt="URBM-Logo">
<div><h1>URBM <span class="bu-version">2026.06.15.r020</span></h1><p>Restic Backup Manager für Unraid</p></div>
<img class="bu-logo" src="<?= $pluginRoot ?>/images/urbm.png?v=20260615r021" alt="URBM-Logo">
<div><h1>URBM <span class="bu-version">2026.06.15.r021</span></h1><p>Restic Backup Manager für Unraid</p></div>
</div>
<div id="bu-health" class="bu-health" tabindex="0" data-tooltip="Zeigt, ob die URBM-Hintergrundkomponente erreichbar ist. Beispiel: 'Daemon online' bedeutet, dass Jobs gestartet werden können.">Verbindung wird hergestellt...</div>
</header>
@@ -32,4 +32,4 @@ $pluginRoot = '/plugins/urbm';
<div id="bu-tooltip" role="tooltip" aria-hidden="true"></div>
</div>
<script>window.URBM_CSRF = <?= json_encode($var['csrf_token'] ?? '') ?>;</script>
<script src="<?= $pluginRoot ?>/assets/urbm-2026.06.15.r020.js"></script>
<script src="<?= $pluginRoot ?>/assets/urbm-2026.06.15.r021.js"></script>
+3
View File
@@ -80,6 +80,9 @@
.bu-selection-list { display: flex; flex-wrap: wrap; gap: 6px; margin: 10px 0; }
.bu-selection { background: var(--bu-panel-alt); border: 1px solid var(--bu-border); border-radius: 999px; color: var(--bu-text); font-size: 12px; padding: 4px 8px; }
.bu-browser-card input[type="checkbox"], .bu-table input[type="checkbox"] { accent-color: var(--bu-accent); height: 20px; width: 20px; }
.bu-source-partial { background: rgba(255, 140, 47, .09); background: color-mix(in srgb, var(--bu-accent) 9%, transparent); }
.bu-source-partial .bu-source-select { accent-color: var(--bu-accent); }
.bu-partial-label { border: 1px solid var(--bu-accent); border-radius: 999px; color: var(--bu-text); display: inline-block; font-size: 11px; font-weight: 700; margin-left: 8px; padding: 2px 7px; vertical-align: middle; }
.bu-count { align-items: center; border: 1px solid var(--bu-border); border-radius: 999px; display: inline-flex; font-size: 13px; font-weight: 700; padding: 7px 11px; }
.bu-inline-error { background: rgba(180,35,47,.08); border: 1px solid var(--bu-bad); border-radius: 5px; color: var(--bu-bad); font-weight: 600; margin: 10px 0; padding: 10px 12px; }
.bu-inline-info { background: rgba(19,138,98,.08); border: 1px solid var(--bu-good); border-radius: 5px; color: var(--bu-text); font-weight: 600; margin: 10px 0; padding: 10px 12px; }
+8 -1
View File
@@ -448,10 +448,17 @@
const host = document.getElementById('bu-source-browser');
if (!host) return;
const selected = new Set(state.backupSelections);
const rows = state.sourceDirectories.map(item => `<tr><td><input type="checkbox" class="bu-source-select" value="${esc(item.path)}" ${selected.has(item.path)?'checked':''}></td><td>Ordner</td><td>${esc(item.name)}</td><td>${esc(item.path)}</td><td>${button('Öffnen',`open-source-dir:${encodeURIComponent(item.path)}`)}</td></tr>`).join('');
const rows = state.sourceDirectories.map(item => {
const exact=selected.has(item.path);
const prefix=item.path.replace(/\/$/,'')+'/';
const partial=!exact&&state.backupSelections.some(path=>path.startsWith(prefix));
const hint=partial?'Ein oder mehrere Unterordner sind ausgewählt. Klicken, um den gesamten Ordner auszuwählen.':'Diesen Ordner als vollständige Backup-Quelle auswählen.';
return `<tr class="${partial?'bu-source-partial':''}"><td><input type="checkbox" class="bu-source-select" value="${esc(item.path)}" ${exact?'checked':''} data-partial="${partial?'true':'false'}" data-tooltip="${esc(hint)}"></td><td>Ordner</td><td>${esc(item.name)}${partial?'<span class="bu-partial-label">Teilweise ausgewählt</span>':''}</td><td>${esc(item.path)}</td><td>${button('Öffnen',`open-source-dir:${encodeURIComponent(item.path)}`)}</td></tr>`;
}).join('');
const chosen = state.backupSelections.length ? state.backupSelections.map(path=>`<span class="bu-selection">${esc(path)}</span>`).join('') : '<span class="bu-muted">Keine Ordner ausgewählt.</span>';
const error = state.sourceBrowserError ? `<div class="bu-inline-error">${esc(state.sourceBrowserError)}</div>` : '';
host.innerHTML = `<section class="bu-browser-card"><div class="bu-toolbar"><div><h3>Backup-Quellen auswählen</h3><span class="bu-muted">${esc(state.sourceBrowserPath)}</span></div><div class="bu-actions">${state.sourceBrowserPath!=='/'?button('Aktuellen Ordner auswählen','select-current-source'):''}${state.sourceBrowserPath!=='/'?button('Nach oben','source-up'):''}<span class="bu-count">Ausgewählt: ${state.backupSelections.length}</span></div></div>${error}<div class="bu-selection-list">${chosen}</div><div class="bu-browser-scroll"><table class="bu-table"><thead><tr><th>Auswahl</th><th>Typ</th><th>Name</th><th>Pfad</th><th></th></tr></thead><tbody>${rows||'<tr><td colspan="5" class="bu-empty">Keine Unterordner gefunden.</td></tr>'}</tbody></table></div></section>`;
host.querySelectorAll('.bu-source-select[data-partial="true"]').forEach(box=>{ box.indeterminate=true; box.setAttribute('aria-checked','mixed'); });
enhanceTooltips(host);
}