Change : Backup pick
This commit is contained in:
@@ -113,11 +113,48 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-section">
|
||||
<div class="form-section-title">STEP 3 — SELECT APPS TO RESTORE</div>
|
||||
<p style="color:var(--text3); font-size:12px; margin-bottom:10px;">
|
||||
All apps are restored by default. Uncheck the ones you don't want touched —
|
||||
only the checked apps will be restored, and they're force-restored even if
|
||||
currently running and healthy.
|
||||
</p>
|
||||
<div id="apps-checkbox-group" style="display:flex; flex-wrap:wrap; gap:8px;">
|
||||
<label class="radio-card small" style="cursor:pointer;">
|
||||
<input type="checkbox" value="frappe" checked style="margin-right:6px;">
|
||||
<span>🧾 Frappe / ERPNext</span>
|
||||
</label>
|
||||
<label class="radio-card small" style="cursor:pointer;">
|
||||
<input type="checkbox" value="odoo" checked style="margin-right:6px;">
|
||||
<span>🟣 Odoo</span>
|
||||
</label>
|
||||
<label class="radio-card small" style="cursor:pointer;">
|
||||
<input type="checkbox" value="nextcloud" checked style="margin-right:6px;">
|
||||
<span>☁️ Nextcloud</span>
|
||||
</label>
|
||||
<label class="radio-card small" style="cursor:pointer;">
|
||||
<input type="checkbox" value="mautic" checked style="margin-right:6px;">
|
||||
<span>📣 Mautic</span>
|
||||
</label>
|
||||
<label class="radio-card small" style="cursor:pointer;">
|
||||
<input type="checkbox" value="n8n" checked style="margin-right:6px;">
|
||||
<span>🔁 n8n</span>
|
||||
</label>
|
||||
</div>
|
||||
<div style="margin-top:10px; display:flex; gap:8px;">
|
||||
<button type="button" class="btn btn-sm" onclick="nvSetAllApps(true)">Select All</button>
|
||||
<button type="button" class="btn btn-sm" onclick="nvSetAllApps(false)">Select None</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-section">
|
||||
<button class="btn btn-danger btn-lg" onclick="nvLaunchRestore()" id="restore-btn">
|
||||
<i class="fas fa-play"></i> Start Restore
|
||||
</button>
|
||||
<p style="color:var(--text3); font-size:12px; margin-top:8px;">⚠ Healthy running containers are skipped.</p>
|
||||
<p style="color:var(--text3); font-size:12px; margin-top:8px;" id="restore-warning-text">
|
||||
⚠ Full restore (all apps checked): healthy running containers are skipped.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -182,11 +219,48 @@ function nvGetSelection() {
|
||||
return { source, file, key };
|
||||
}
|
||||
|
||||
// ── App selection (Step 3) ────────────────────────────────────────────────────
|
||||
function nvGetAppsCheckboxes() {
|
||||
return Array.from(document.querySelectorAll('#apps-checkbox-group input[type="checkbox"]'));
|
||||
}
|
||||
|
||||
// Returns [] when every app is checked (= full restore, no filter needed),
|
||||
// otherwise returns the list of explicitly checked app keys.
|
||||
function nvGetSelectedApps() {
|
||||
const boxes = nvGetAppsCheckboxes();
|
||||
const checked = boxes.filter(b => b.checked).map(b => b.value);
|
||||
return checked.length === boxes.length ? [] : checked;
|
||||
}
|
||||
|
||||
function nvSetAllApps(state) {
|
||||
nvGetAppsCheckboxes().forEach(b => b.checked = state);
|
||||
nvUpdateRestoreWarning();
|
||||
}
|
||||
|
||||
function nvUpdateRestoreWarning() {
|
||||
const selected = nvGetSelectedApps();
|
||||
const el = document.getElementById('restore-warning-text');
|
||||
if (selected.length === 0) {
|
||||
el.textContent = '⚠ Full restore (all apps checked): healthy running containers are skipped.';
|
||||
} else {
|
||||
el.textContent = `⚠ Selective restore: only ${selected.join(', ')} will be touched — forced even if currently healthy.`;
|
||||
}
|
||||
}
|
||||
|
||||
document.addEventListener('change', (e) => {
|
||||
if (e.target.closest('#apps-checkbox-group')) nvUpdateRestoreWarning();
|
||||
});
|
||||
|
||||
// ── Launch restore ────────────────────────────────────────────────────────────
|
||||
async function nvLaunchRestore() {
|
||||
const { source, file, key } = nvGetSelection();
|
||||
if (!file) { alert('Please select a backup file.'); return; }
|
||||
|
||||
const appsCheckboxes = nvGetAppsCheckboxes();
|
||||
const checkedCount = appsCheckboxes.filter(b => b.checked).length;
|
||||
if (checkedCount === 0) { alert('Select at least one app to restore.'); return; }
|
||||
const selectedApps = nvGetSelectedApps();
|
||||
|
||||
const target = document.querySelector('input[name="restore_target"]:checked')?.value || 'local';
|
||||
const authMethod = document.querySelector('input[name="auth_method"]:checked')?.value || 'key';
|
||||
|
||||
@@ -194,6 +268,7 @@ async function nvLaunchRestore() {
|
||||
backup_source: source,
|
||||
backup_file: file,
|
||||
cloud_key: key,
|
||||
apps: selectedApps,
|
||||
target,
|
||||
remote_ip: document.getElementById('remote-ip')?.value || '',
|
||||
remote_port: document.getElementById('remote-port')?.value || '22',
|
||||
@@ -211,9 +286,12 @@ async function nvLaunchRestore() {
|
||||
|
||||
btn.disabled = true;
|
||||
wrapper.style.display = '';
|
||||
const scopeMsg = selectedApps.length
|
||||
? `🎯 Restoring only: ${selectedApps.join(', ')}`
|
||||
: '🚀 Starting full restore…';
|
||||
logEl.innerHTML = source === 'cloud'
|
||||
? '<div style="color:var(--accent2)">☁️ Downloading backup from R2, please wait…</div>'
|
||||
: '<div style="color:var(--accent2)">🚀 Starting restore…</div>';
|
||||
? `<div style="color:var(--accent2)">☁️ Downloading backup from R2, please wait…</div><div style="color:var(--accent2)">${scopeMsg}</div>`
|
||||
: `<div style="color:var(--accent2)">${scopeMsg}</div>`;
|
||||
badge.textContent = 'Running…';
|
||||
badge.style.cssText = 'background:rgba(59,130,246,0.15);color:var(--accent2);';
|
||||
|
||||
|
||||
Reference in New Issue
Block a user