refactor(backup): move location field schema to a generated JSON
The per-type field map lived hardcoded in backup-page.js. Add a webuiGenerateBackupSchema generator that emits the type -> ordered field list to data/backup/generated/schema.json (wired into the backup regen chain and the CLI 'webui generate backup'). The editor fetches it into this.locSchema and reads it via locFieldsForType; BACKUP_LOC_FIELDS_BY_TYPE stays only as a fallback if the fetch fails. Keeps the data-in-generators pattern consistent — the schema now has one backend source of truth. The dynamic show/hide behaviors (SSH auth, path mode, engine filtering) remain frontend logic by nature. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> Signed-off-by: librelad <librelad@digitalangels.vip>
This commit is contained in:
parent
d1ffb806bd
commit
d6e7df8ada
@ -51,9 +51,11 @@ const BACKUP_LOC_FIELD_DEFS = {
|
||||
KEEP_YEARLY: { title: 'Keep yearly', description: 'One snapshot per year for this many years.' }
|
||||
};
|
||||
|
||||
// Type leads each list: it's the choice that shapes the rest of the form, so
|
||||
// it renders before the friendly Name. ENGINE stays here but is filtered into
|
||||
// the Advanced tab by locFieldGroups.
|
||||
// Fallback for the per-type field schema. The live source is the generator-
|
||||
// emitted data/backup/generated/schema.json (loaded into this.locSchema and
|
||||
// read via locFieldsForType); this map is only used if that fetch fails.
|
||||
// Type leads each list (it shapes the rest of the form); ENGINE stays in the
|
||||
// list but locFieldGroups folds it into the Advanced tab.
|
||||
const BACKUP_LOC_FIELDS_BY_TYPE = {
|
||||
local: ['TYPE', 'NAME', 'ENGINE', 'PATH_MODE', 'PATH', 'APPEND_ONLY'],
|
||||
sftp: ['TYPE', 'NAME', 'ENGINE', 'SSH_USER', 'SSH_HOST', 'SSH_PORT', 'SSH_PATH', 'SSH_AUTH', 'SSH_PASS', 'URI', 'APPEND_ONLY'],
|
||||
@ -286,13 +288,15 @@ class BackupPage {
|
||||
|
||||
async refreshAll() {
|
||||
const ts = Date.now();
|
||||
const [dashboard, locations] = await Promise.all([
|
||||
const [dashboard, locations, , schema] = await Promise.all([
|
||||
this.fetchJson(`/data/backup/generated/dashboard.json?t=${ts}`),
|
||||
this.fetchJson(`/data/backup/generated/locations.json?t=${ts}`),
|
||||
this.loadSystemConfigs()
|
||||
this.loadSystemConfigs(),
|
||||
this.fetchJson(`/data/backup/generated/schema.json?t=${ts}`)
|
||||
]);
|
||||
this.dashboard = dashboard;
|
||||
this.locations = locations;
|
||||
this.locSchema = schema;
|
||||
this.snapshotsByLoc = {};
|
||||
|
||||
if (!this.engines.length) await this.loadEngines();
|
||||
@ -1400,7 +1404,7 @@ class BackupPage {
|
||||
const idx = parseInt(modal.dataset.locIdx, 10);
|
||||
const loc = locOverride || (this.locations?.locations || []).find(l => l.idx === idx) || {};
|
||||
|
||||
const suffixes = BACKUP_LOC_FIELDS_BY_TYPE[type] || BACKUP_LOC_FIELDS_BY_TYPE.local;
|
||||
const suffixes = this.locFieldsForType(type);
|
||||
container.innerHTML = this.renderLocFields(idx, suffixes, loc);
|
||||
this.tagFieldsForSave(container);
|
||||
}
|
||||
@ -1494,9 +1498,18 @@ class BackupPage {
|
||||
};
|
||||
}
|
||||
|
||||
/* Ordered field list for a location type. Primary source is the generator-
|
||||
emitted schema.json (this.locSchema); BACKUP_LOC_FIELDS_BY_TYPE is the
|
||||
fallback if that file didn't load. */
|
||||
locFieldsForType(type) {
|
||||
return this.locSchema?.types?.[type]
|
||||
|| BACKUP_LOC_FIELDS_BY_TYPE[type]
|
||||
|| BACKUP_LOC_FIELDS_BY_TYPE.local;
|
||||
}
|
||||
|
||||
/* Split a type's fields into the Connection tab vs the Advanced tab. */
|
||||
locFieldGroups(idx, type) {
|
||||
const suffixes = BACKUP_LOC_FIELDS_BY_TYPE[type] || BACKUP_LOC_FIELDS_BY_TYPE.local;
|
||||
const suffixes = this.locFieldsForType(type);
|
||||
const connection = [];
|
||||
const advanced = [];
|
||||
for (const suffix of suffixes) {
|
||||
|
||||
@ -23,6 +23,7 @@ cliHandleWebuiCommands()
|
||||
webuiGenerateBackupDashboard
|
||||
webuiGenerateBackupSnapshots "${options:-all}"
|
||||
webuiGenerateBackupAppStatus
|
||||
webuiGenerateBackupSchema
|
||||
webuiGenerateBackupPasswords
|
||||
elif [ "$config_type" = "system" ]; then
|
||||
webuiSystemUpdate
|
||||
|
||||
51
scripts/webui/data/generators/backup/webui_backup_schema.sh
Normal file
51
scripts/webui/data/generators/backup/webui_backup_schema.sh
Normal file
@ -0,0 +1,51 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Source of truth for the Locations editor form layout: which CFG_BACKUP_LOC_*
|
||||
# fields apply to each backup location type, in render order. Emitted as
|
||||
# data/backup/generated/schema.json so the frontend builds the form from data
|
||||
# instead of a hardcoded map (it keeps a fallback only). ENGINE stays in the
|
||||
# list — the frontend folds it into the Advanced tab via the per-field
|
||||
# "advanced" flag from configs.json; this file is purely about applicability
|
||||
# and order.
|
||||
|
||||
webuiGenerateBackupSchema()
|
||||
{
|
||||
local out_dir="$containers_dir/libreportal/frontend/data/backup/generated"
|
||||
local out_file="$out_dir/schema.json"
|
||||
sudo mkdir -p "$out_dir"
|
||||
|
||||
# "<type>|FIELD,FIELD,..." — order here is the form's render order.
|
||||
local rows=(
|
||||
"local|TYPE,NAME,ENGINE,PATH_MODE,PATH,APPEND_ONLY"
|
||||
"sftp|TYPE,NAME,ENGINE,SSH_USER,SSH_HOST,SSH_PORT,SSH_PATH,SSH_AUTH,SSH_PASS,URI,APPEND_ONLY"
|
||||
"rest|TYPE,NAME,ENGINE,URI,APPEND_ONLY"
|
||||
"s3|TYPE,NAME,ENGINE,URI,S3_ACCESS_KEY,S3_SECRET_KEY,APPEND_ONLY"
|
||||
"b2|TYPE,NAME,ENGINE,URI,B2_ACCOUNT_ID,B2_ACCOUNT_KEY,APPEND_ONLY"
|
||||
"gs|TYPE,NAME,ENGINE,URI,APPEND_ONLY"
|
||||
"azure|TYPE,NAME,ENGINE,URI,APPEND_ONLY"
|
||||
"rclone|TYPE,NAME,ENGINE,URI,APPEND_ONLY"
|
||||
)
|
||||
|
||||
local json="{\"generated_at\":\"$(date -Iseconds)\",\"types\":{"
|
||||
local first=true row type fields f farr firstf
|
||||
for row in "${rows[@]}"; do
|
||||
type="${row%%|*}"
|
||||
fields="${row#*|}"
|
||||
$first || json+=","
|
||||
first=false
|
||||
json+="\"$type\":["
|
||||
firstf=true
|
||||
IFS=',' read -ra farr <<< "$fields"
|
||||
for f in "${farr[@]}"; do
|
||||
$firstf || json+=","
|
||||
firstf=false
|
||||
json+="\"$f\""
|
||||
done
|
||||
json+="]"
|
||||
done
|
||||
json+="}}"
|
||||
|
||||
echo "$json" | sudo tee "$out_file" >/dev/null
|
||||
createTouch "$out_file" "$docker_install_user" "silent"
|
||||
isSuccessful "Backup location schema regenerated"
|
||||
}
|
||||
@ -82,7 +82,7 @@ webuiLibrePortalUpdate() {
|
||||
fi
|
||||
|
||||
# Generate Backup locations / snapshots / engines / dashboards
|
||||
local result=$(webuiGenerateBackupLocations && webuiGenerateBackupDashboard && webuiGenerateBackupSnapshots all && webuiGenerateBackupAppStatus && webuiGenerateBackupEngines && webuiGenerateBackupPasswords)
|
||||
local result=$(webuiGenerateBackupLocations && webuiGenerateBackupDashboard && webuiGenerateBackupSnapshots all && webuiGenerateBackupAppStatus && webuiGenerateBackupEngines && webuiGenerateBackupSchema && webuiGenerateBackupPasswords)
|
||||
checkSuccess "Refreshed backup dashboard data..."
|
||||
|
||||
# Sync app icons
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user