fix(webui): stop the loader double-loading scripts, and the sidebar noise
Two recurring console errors, each masking real ones.
"Identifier 'BackupAppCard' has already been declared": the app has two
script loaders that could not see each other's work. The boot-time
system loader injects tags with NO id and dedupes by script[src]; the
SPA's loadScript injects with an id and deduped ONLY by that id. So a
file both of them load — backup-app-card.js is on the boot list AND in
the overview Backups tab's asset chain — loaded twice whenever the SPA
loaded second: its getElementById check cannot see an id-less tag. The
class redeclared with an uncaught SyntaxError. The blindness was
one-directional, which is why it looked sporadic. spaClean.loadScript
now also matches by src, closing the asymmetry for every shared file,
not just this one.
"ConfigSidebar: config-categories-list element not found", three to
four times per navigation: renderConfig populated the admin sidebar
unconditionally, but the backup center's Configuration tab EMBEDS that
renderer inside its own pane (renderConfig('backup', <target>)), where
the sidebar element legitimately does not exist — and the refresh
coordinator re-renders that tab on every task event. Populating is now
skipped when a target is passed: an embedded render does not own the
admin shell. The error stays for target-less renders, where a missing
sidebar genuinely is a broken shell.
Verified in a live session: repeated sweeps across /tasks, the overview
Backups tab (Configuration sub-tab included) and a per-app Backups page
produce zero new occurrences of either error — confirmed against a
live console buffer via a sentinel, since the buffer retains the
pre-fix history and re-reading it can look like recurrence.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
parent
429e750266
commit
b3b9f9a18b
@ -162,8 +162,13 @@ if (typeof window.ConfigManager === 'undefined') {
|
|||||||
// Load configuration data
|
// Load configuration data
|
||||||
const configData = await this.core.loadConfig(category);
|
const configData = await this.core.loadConfig(category);
|
||||||
|
|
||||||
// Populate sidebar with categories
|
// Populate sidebar with categories — but only when rendering into the
|
||||||
this.sidebar.populateSidebar();
|
// admin shell. A `target` means an EMBEDDED render (the backup center's
|
||||||
|
// Configuration tab reuses this renderer inside its own pane), where
|
||||||
|
// config-categories-list legitimately does not exist; populating there
|
||||||
|
// logged "element not found" as an error on every repaint, and the
|
||||||
|
// refresh coordinator repaints on every task event.
|
||||||
|
if (!target) this.sidebar.populateSidebar();
|
||||||
|
|
||||||
if (Object.keys(configData).length === 0) {
|
if (Object.keys(configData).length === 0) {
|
||||||
configSection.innerHTML = '<div class="no-config"><h3>No Configuration Available</h3><p>No configuration items found for this category.</p></div>';
|
configSection.innerHTML = '<div class="no-config"><h3>No Configuration Available</h3><p>No configuration items found for this category.</p></div>';
|
||||||
|
|||||||
@ -528,6 +528,16 @@ class LibrePortalSPAClean {
|
|||||||
if (document.getElementById(scriptId)) {
|
if (document.getElementById(scriptId)) {
|
||||||
return; // Already loaded
|
return; // Already loaded
|
||||||
}
|
}
|
||||||
|
// Also recognise tags the boot-time system loader injected: it dedupes by
|
||||||
|
// src and adds NO id, so the id check above cannot see its scripts. That
|
||||||
|
// one-way blindness is how backup-app-card.js loaded twice — boot loads it
|
||||||
|
// id-less, the overview's Backups tab loads it again through here, and
|
||||||
|
// `class BackupAppCard` redeclares with an uncaught SyntaxError. The system
|
||||||
|
// loader's own attribute check already covers scripts WE inject, so
|
||||||
|
// matching by src here closes the asymmetry for every shared file.
|
||||||
|
if (document.querySelector(`script[src="${src}"]`)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
const script = document.createElement('script');
|
const script = document.createElement('script');
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user