Align backup and snapshot browsers

This commit is contained in:
Mikei386
2026-06-14 12:16:37 +02:00
parent a475819eb7
commit a068bf5689
8 changed files with 22 additions and 13 deletions
+5 -3
View File
@@ -60,6 +60,7 @@
'cancel-form': 'Verwirft ungespeicherte Eingaben und kehrt zur Übersicht zurück.',
'browser-up': 'Öffnet im Snapshot-Browser das übergeordnete Verzeichnis.',
'source-up': 'Öffnet im Ordner-Browser das übergeordnete Verzeichnis.',
'select-current-source': 'Wählt den aktuell geöffneten Ordner vollständig als Backup-Quelle aus.',
'select-current-restore': 'Wählt den aktuell geöffneten Snapshot-Ordner vollständig für die Wiederherstellung aus.',
};
@@ -226,7 +227,7 @@
<label>Repository<select name="repositoryId" required>${options}</select></label><label>Schedule (cron)<input name="cron" value="${esc(job.schedule?.cron || '0 2 * * *')}"></label>
<label>Consistency<select name="consistency"><option value="live">Live</option><option value="stop" ${job.consistency?.mode==='stop'?'selected':''}>Controlled stop</option></select></label>
<label>Compression<select name="compression">${['auto','off','max'].map(v=>`<option ${v===(job.compression||'auto')?'selected':''}>${v}</option>`).join('')}</select></label>
<div class="wide"><h3>Backup folders</h3><div class="bu-muted">Select one or more folders. Open navigates into a folder without selecting it.</div><div id="bu-source-browser" class="bu-browser"></div></div>
<div class="wide"><h3>Backup folders</h3><div class="bu-muted">Select folders exactly like files and folders in the snapshot browser.</div><div id="bu-source-browser"></div></div>
<label class="wide">Additional manual paths or workload IDs<textarea name="sources">${esc(source)}</textarea></label>
<label class="wide">Exclude patterns, one per line<textarea name="excludes">${esc((job.excludes||[]).join('\n'))}</textarea></label>
<label>Shutdown timeout (seconds)<input name="shutdownSecs" type="number" min="1" value="${job.shutdownTimeoutSeconds || 120}"></label>
@@ -240,9 +241,9 @@
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><strong>${esc(item.name)}</strong><br><span class="bu-muted">${esc(item.path)}</span></td><td>${button('Open',`open-source-dir:${encodeURIComponent(item.path)}`)}</td></tr>`).join('');
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>dir</td><td>${esc(item.name)}</td><td>${esc(item.path)}</td><td>${button('Open',`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">No folders selected.</span>';
host.innerHTML = `<div class="bu-browser-head"><div><strong>Folder: ${esc(state.sourceBrowserPath)}</strong></div><div>${state.sourceBrowserPath!=='/'?button('Up','source-up'):''}</div></div><div class="bu-selection-list">${chosen}</div><table class="bu-table"><thead><tr><th>Select</th><th>Folder</th><th></th></tr></thead><tbody>${rows||'<tr><td colspan="3" class="bu-empty">No subfolders found.</td></tr>'}</tbody></table>`;
host.innerHTML = `<section class="bu-browser-card"><div class="bu-toolbar"><div><h3>Backup source browser</h3><span class="bu-muted">${esc(state.sourceBrowserPath)}</span></div><div class="bu-actions">${state.sourceBrowserPath!=='/'?button('Select current folder','select-current-source'):''}${state.sourceBrowserPath!=='/'?button('Up','source-up'):''}<span class="bu-count">Selected: ${state.backupSelections.length}</span></div></div><div class="bu-selection-list">${chosen}</div><div class="bu-browser-scroll"><table class="bu-table"><thead><tr><th>Select</th><th>Type</th><th>Name</th><th>Path</th><th></th></tr></thead><tbody>${rows||'<tr><td colspan="5" class="bu-empty">No subfolders found.</td></tr>'}</tbody></table></div></section>`;
enhanceTooltips(host);
}
@@ -335,6 +336,7 @@
if (name === 'browse') { state.selectedSnapshot=a; state.browserPath='/'; state.restoreIncludes=[]; state.files=await api(`/v1/repositories/${state.snapshotRepo}/snapshots/${a}/files?path=${encodeURIComponent('/')}`); return render(); }
if (name === 'open-source-dir') { return loadSourceDirectories(decodeURIComponent(a)); }
if (name === 'source-up') { const parent=state.sourceBrowserPath==='/'?'/':state.sourceBrowserPath.split('/').slice(0,-1).join('/')||'/'; return loadSourceDirectories(parent==='/mnt'?'/':parent); }
if (name === 'select-current-source') { if(!state.backupSelections.includes(state.sourceBrowserPath)) state.backupSelections.push(state.sourceBrowserPath); return renderSourceBrowser(); }
if (name === 'open-dir') { state.browserPath=decodeURIComponent(a); state.files=await api(`/v1/repositories/${state.snapshotRepo}/snapshots/${state.selectedSnapshot}/files?path=${encodeURIComponent(state.browserPath)}`); return render(); }
if (name === 'browser-up') { state.browserPath=state.browserPath.replace(/\/$/,'').split('/').slice(0,-1).join('/')||'/'; state.files=await api(`/v1/repositories/${state.snapshotRepo}/snapshots/${state.selectedSnapshot}/files?path=${encodeURIComponent(state.browserPath)}`); return render(); }
if (name === 'select-current-restore') { if(!state.restoreIncludes.includes(state.browserPath)) state.restoreIncludes.push(state.browserPath); return render(); }