librelad 82989069e2 refactor(backup): decompose backup-page god-file into 13 responsibility files
Faithful prototype-augment split of backup-page.js (2353->753 line base) into
fetch-client, dashboard, snapshots, locations, location-fields, ssh-key,
retention-presets, configuration, engine-details, location-modal,
snapshot-actions, migrate (+ the earlier cron-schedule). Methods relocated
verbatim (mechanical sed/awk extraction, no logic change); all augment
BackupPage.prototype and load after the base via the ordered kernel loader.
Verified: all 99 original methods present exactly once across base+clusters,
no duplicates, all 14 files node --check clean.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Signed-off-by: librelad <librelad@digitalangels.vip>
2026-05-30 14:02:45 +01:00

85 lines
4.3 KiB
JavaScript

// Auto-extracted from backup-page.js (verbatim) — augments BackupPage.prototype. Loaded after the base.
Object.assign(BackupPage.prototype, {
enhanceEngineDetailsButton() {
const selector = '[name="CFG_BACKUP_ENGINE"], [name^="CFG_BACKUP_LOC_"][name$="_ENGINE"]';
document.querySelectorAll(`#config-section ${selector}, .backup-location-details ${selector}`).forEach((engineInput) => {
const customSelect = engineInput.closest('.custom-select');
const wrapTarget = customSelect || engineInput;
const group = wrapTarget.closest('.field-group') || wrapTarget.parentElement;
if (!group || group.dataset.engineDetailsBound === '1') return;
group.dataset.engineDetailsBound = '1';
const btn = document.createElement('button');
btn.type = 'button';
btn.className = 'backup-secondary-btn backup-engine-details-btn';
btn.dataset.action = 'open-engine-details';
btn.innerHTML = `
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<circle cx="12" cy="12" r="10"></circle>
<line x1="12" y1="16" x2="12" y2="12"></line>
<line x1="12" y1="8" x2="12.01" y2="8"></line>
</svg>
Details
`;
const wrap = document.createElement('div');
wrap.className = 'backup-engine-input-row';
wrapTarget.parentNode.insertBefore(wrap, wrapTarget);
wrap.appendChild(wrapTarget);
wrap.appendChild(btn);
});
},
async openEngineDetailsModal(triggerEl) {
const modal = document.getElementById('backup-engine-modal');
const body = document.getElementById('backup-engine-modal-body');
const title = document.getElementById('backup-engine-modal-title');
if (!modal || !body) return;
// Find the engine select adjacent to the Details button that fired
// this event so per-location Details work even when the user has
// changed the select but not saved yet.
let engineId = (window.systemConfigs?.CFG_BACKUP_ENGINE || 'restic').trim();
const row = triggerEl?.closest('.backup-engine-input-row');
const sel = row?.querySelector('select, input');
if (sel && sel.value) engineId = sel.value.trim();
body.innerHTML = `<div class="backup-empty-state">Loading engine details…</div>`;
modal.classList.add('open');
const data = await this.fetchJson(`/data/backup/generated/engines/${encodeURIComponent(engineId)}.json?t=${Date.now()}`);
if (!data) {
body.innerHTML = `
<div class="backup-empty-state">
No details file for engine "<strong>${this.escape(engineId)}</strong>".<br>
Add <code>scripts/backup/engines/${this.escape(engineId)}.json</code> and run the WebUI regen.
</div>
`;
return;
}
if (title) title.textContent = `Backup engine: ${data.name || engineId}`;
const propsHTML = (data.properties || []).map(p =>
`<tr><th>${this.escape(p.label)}</th><td>${this.escape(p.value)}</td></tr>`
).join('');
const featsHTML = (data.features || []).map(f => `<li>${this.escape(f)}</li>`).join('');
const docsHTML = data.docs_url
? `<a href="${this.escape(data.docs_url)}" target="_blank" rel="noopener noreferrer" class="backup-engine-docs-link">${this.escape(data.docs_url)} ↗</a>`
: '';
const logoHTML = data.logo
? `<img class="backup-engine-logo" src="${this.escape(data.logo)}" alt="" onerror="this.style.display='none'">`
: '';
body.innerHTML = `
<div class="backup-engine-modal-head">
${logoHTML}
<div>
<h4>${this.escape(data.name || engineId)}</h4>
<p class="backup-card-hint">${this.escape(data.tagline || '')}</p>
</div>
</div>
${propsHTML ? `<table class="backup-engine-props">${propsHTML}</table>` : ''}
${featsHTML ? `<h5>Highlights</h5><ul class="backup-engine-features">${featsHTML}</ul>` : ''}
${docsHTML ? `<h5>Documentation</h5><p>${docsHTML}</p>` : ''}
`;
},
});