Compare commits
2 Commits
46843de50f
...
4b8f2c698c
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4b8f2c698c | ||
|
|
c5ecc520aa |
@ -723,6 +723,47 @@
|
|||||||
border-top: 1px dashed rgba(var(--text-rgb), 0.08);
|
border-top: 1px dashed rgba(var(--text-rgb), 0.08);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Full-width "Advanced" disclosure in the location editor's Connection
|
||||||
|
section. Reveals the advanced fields (URI override, SSH port, append-only). */
|
||||||
|
.backup-loc-advanced-toggle {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
width: 100%;
|
||||||
|
margin-top: 14px;
|
||||||
|
padding: 10px 12px;
|
||||||
|
background: rgba(var(--text-rgb), 0.03);
|
||||||
|
border: 1px solid rgba(var(--text-rgb), 0.08);
|
||||||
|
border-radius: 8px;
|
||||||
|
color: var(--text-primary);
|
||||||
|
font: inherit;
|
||||||
|
font-size: 0.9rem;
|
||||||
|
font-weight: 600;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: background 0.15s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.backup-loc-advanced-toggle:hover {
|
||||||
|
background: rgba(var(--text-rgb), 0.06);
|
||||||
|
}
|
||||||
|
|
||||||
|
.backup-loc-advanced-chevron {
|
||||||
|
transition: transform 0.15s ease;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.backup-loc-advanced-toggle.open .backup-loc-advanced-chevron {
|
||||||
|
transform: rotate(90deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
.backup-loc-advanced {
|
||||||
|
margin-top: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.backup-loc-advanced[hidden] {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
.backup-form-footer {
|
.backup-form-footer {
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: flex-end;
|
justify-content: flex-end;
|
||||||
|
|||||||
@ -198,6 +198,18 @@ class BackupPage {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const advToggle = e.target.closest('[data-action="toggle-loc-advanced"]');
|
||||||
|
if (advToggle) {
|
||||||
|
const sec = document.getElementById(advToggle.dataset.target);
|
||||||
|
if (sec) {
|
||||||
|
const show = sec.hasAttribute('hidden');
|
||||||
|
sec.toggleAttribute('hidden', !show);
|
||||||
|
advToggle.setAttribute('aria-expanded', show ? 'true' : 'false');
|
||||||
|
advToggle.classList.toggle('open', show);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (e.target.closest('[data-close-modal]') || e.target.matches('.backup-modal')) {
|
if (e.target.closest('[data-close-modal]') || e.target.matches('.backup-modal')) {
|
||||||
this.closeAllModals();
|
this.closeAllModals();
|
||||||
return;
|
return;
|
||||||
@ -263,7 +275,8 @@ class BackupPage {
|
|||||||
const ts = Date.now();
|
const ts = Date.now();
|
||||||
const [dashboard, locations] = await Promise.all([
|
const [dashboard, locations] = await Promise.all([
|
||||||
this.fetchJson(`/data/backup/generated/dashboard.json?t=${ts}`),
|
this.fetchJson(`/data/backup/generated/dashboard.json?t=${ts}`),
|
||||||
this.fetchJson(`/data/backup/generated/locations.json?t=${ts}`)
|
this.fetchJson(`/data/backup/generated/locations.json?t=${ts}`),
|
||||||
|
this.loadSystemConfigs()
|
||||||
]);
|
]);
|
||||||
this.dashboard = dashboard;
|
this.dashboard = dashboard;
|
||||||
this.locations = locations;
|
this.locations = locations;
|
||||||
@ -285,6 +298,19 @@ class BackupPage {
|
|||||||
catch { return null; }
|
catch { return null; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Load the unified config file once for the Locations editor: configData
|
||||||
|
carries field metadata (titles/descriptions/options/advanced) the editor
|
||||||
|
renders from; systemConfigs is the flat key->value map used for default
|
||||||
|
lookups (e.g. CFG_BACKUP_ENGINE) and save-time change detection. */
|
||||||
|
async loadSystemConfigs() {
|
||||||
|
const data = await this.fetchJson(`/data/config/generated/configs.json?t=${Date.now()}`);
|
||||||
|
if (!data) return;
|
||||||
|
window.configData = data;
|
||||||
|
const flat = {};
|
||||||
|
for (const [k, v] of Object.entries(data.config || {})) flat[k] = v?.value ?? '';
|
||||||
|
window.systemConfigs = flat;
|
||||||
|
}
|
||||||
|
|
||||||
async loadEngines() {
|
async loadEngines() {
|
||||||
const ts = Date.now();
|
const ts = Date.now();
|
||||||
const index = await this.fetchJson(`/data/backup/generated/engines/index.json?t=${ts}`);
|
const index = await this.fetchJson(`/data/backup/generated/engines/index.json?t=${ts}`);
|
||||||
@ -1400,19 +1426,61 @@ class BackupPage {
|
|||||||
KEEP_YEARLY: loc.keep_yearly
|
KEEP_YEARLY: loc.keep_yearly
|
||||||
};
|
};
|
||||||
|
|
||||||
// Single .config-fields grid, exactly like /config's renderer — the grid
|
// Field metadata now comes from configs.json (window.configData): the
|
||||||
// (repeat(3, 1fr)) handles the row layout itself, and hidden fields
|
// generator emits CFG_BACKUP_LOC_N_* titles/descriptions plus an
|
||||||
// (PATH_MODE/SSH/etc.) drop out cleanly without leaving column gaps.
|
// "advanced" flag. BACKUP_LOC_FIELD_DEFS stays only as a fallback for a
|
||||||
let html = '<div class="config-fields">';
|
// sparse location.config that doesn't describe a field yet.
|
||||||
for (const suffix of suffixes) {
|
const advancedFallback = new Set(['URI', 'SSH_PORT', 'APPEND_ONLY']);
|
||||||
const def = BACKUP_LOC_FIELD_DEFS[suffix];
|
const fieldMeta = (suffix) => {
|
||||||
if (!def) continue;
|
|
||||||
const key = `CFG_BACKUP_LOC_${idx}_${suffix}`;
|
const key = `CFG_BACKUP_LOC_${idx}_${suffix}`;
|
||||||
|
const cfg = window.configData?.config?.[key] || {};
|
||||||
|
const def = BACKUP_LOC_FIELD_DEFS[suffix] || {};
|
||||||
|
// Fallback set keeps these advanced even on legacy locations whose
|
||||||
|
// location.config predates the **ADVANCED** marker; configData can
|
||||||
|
// additionally flag others.
|
||||||
|
const advanced = advancedFallback.has(suffix) || cfg.advanced === true;
|
||||||
|
return {
|
||||||
|
key,
|
||||||
|
exists: !!(cfg.title || cfg.description || BACKUP_LOC_FIELD_DEFS[suffix]),
|
||||||
|
title: cfg.title || def.title || suffix,
|
||||||
|
description: cfg.description ?? def.description ?? '',
|
||||||
|
advanced
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
const renderField = (suffix) => {
|
||||||
|
const m = fieldMeta(suffix);
|
||||||
const value = (locValueLookup[suffix] ?? '').toString();
|
const value = (locValueLookup[suffix] ?? '').toString();
|
||||||
const fieldId = `config-${key}`;
|
return ConfigShared.generateField(`config-${m.key}`, m.key, value, m.title, m.description, {}, {});
|
||||||
html += ConfigShared.generateField(fieldId, key, value, def.title, def.description, {}, {});
|
};
|
||||||
|
|
||||||
|
const basic = [];
|
||||||
|
const advanced = [];
|
||||||
|
for (const suffix of suffixes) {
|
||||||
|
const m = fieldMeta(suffix);
|
||||||
|
if (!m.exists) continue;
|
||||||
|
(m.advanced ? advanced : basic).push(suffix);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Basics stay in the .config-fields grid (same as /config). Advanced
|
||||||
|
// fields (URI override, SSH port, append-only) tuck behind a full-width
|
||||||
|
// disclosure so the common case opens simple.
|
||||||
|
let html = '<div class="config-fields">';
|
||||||
|
html += basic.map(renderField).join('');
|
||||||
html += '</div>';
|
html += '</div>';
|
||||||
|
|
||||||
|
if (advanced.length) {
|
||||||
|
const secId = `backup-loc-${idx}-advanced`;
|
||||||
|
html += `
|
||||||
|
<button type="button" class="backup-loc-advanced-toggle" data-action="toggle-loc-advanced" data-target="${secId}" aria-expanded="false" aria-controls="${secId}">
|
||||||
|
<svg class="backup-loc-advanced-chevron" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="9 18 15 12 9 6"></polyline></svg>
|
||||||
|
<span>Advanced</span>
|
||||||
|
</button>
|
||||||
|
<div class="config-fields backup-loc-advanced" id="${secId}" hidden>
|
||||||
|
${advanced.map(renderField).join('')}
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
}
|
||||||
return html;
|
return html;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1615,10 +1683,6 @@ class BackupPage {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async reloadAfterSave() {
|
async reloadAfterSave() {
|
||||||
try {
|
|
||||||
const r = await fetch(`/data/config/generated/configs.json?t=${Date.now()}`);
|
|
||||||
if (r.ok) window.systemConfigs = await r.json();
|
|
||||||
} catch {}
|
|
||||||
await this.refreshAll();
|
await this.refreshAll();
|
||||||
this.render();
|
this.render();
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user