When a plugin's requirements.txt includes a package installed via the
system package manager (dnf/apt), pip fails with 'uninstall-no-record-file'
because it can't replace the system-tracked copy. The package is present
and functional, but the missing marker caused the install to be retried
on every service restart.
Detect this specific error pattern: if the only pip failure is
uninstall-no-record-file, write the .dependencies_installed marker and
log a warning instead of returning False, suppressing the repeated warning.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Backup endpoints: replace raw str(e) in user-facing responses with a
generic message; full exception still logged via exc_info=True
- hardware/status: change ok:null to ok:false for PermissionError and
json.JSONDecodeError so the UI's hw.ok===false check triggers correctly
- base.html: dispatch htmx:ready from the fallback load path so any
deferred listeners fire on CDN-fallback loads too
- loadTabContent: also listen for htmx-load-failed so overview/wifi/plugins
fall back to direct fetch when HTMX is completely unavailable
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The 5-second setTimeout fallbacks for plugins and overview were firing
before the htmx:ready event arrived, logging spurious warnings. Each
timer now self-cancels via htmx:ready so the fallback only triggers
when HTMX genuinely fails to load.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Add all backup API routes to api_v3.py: preview, list, export,
validate, restore (with plugin reinstall), download, delete
- Fix PermissionError on /hardware/status: return graceful 200 instead
of 500 when the status file is owned by a different user; also fix
root cause by writing the file world-readable (0o644) in display_manager
- Fix HTMX race: dispatch htmx:ready window event from HTMX onload
callback; loadTabContent now waits for that event instead of
immediately falling back to direct fetch (eliminating the
"HTMX not available" console warning on initial load)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The 500ms fallback setTimeout was calling attachInstallButtonHandler()
unconditionally even when the plugins partial wasn't in the DOM, causing
a spurious console.warn on every page load. Add the same element-existence
check already present on the htmx:afterSettle listener.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
In the catch block of all 11 hx-on:htmx:after-request handlers, check
xhr.status >= 400 and downgrade s to 'error' so a failed action that
returns an HTML error page (or other non-JSON body) surfaces as an error
toast instead of the optimistic 'success'/'info' default.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Replace silent catch(e){} in all 11 hx-on:htmx:after-request handlers with a
pattern that sets default message/status before the try block and calls
showNotification(m,s) unconditionally after it, so a fallback toast is shown
whenever xhr is absent or responseText is not valid JSON.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- base.html: add htmx:afterSettle listener to set data-loaded on tab
containers after HTMX swaps their content, preventing the overview
partial from being re-fetched (and handlers lost) on every tab switch
- base.html: call htmx.process() in loadOverviewDirect/loadPluginsDirect
fallbacks so buttons get HTMX handlers even if HTMX finished its
initial body scan before the fallback fetch completed
- overview.html + index.html (11 buttons): replace event.detail.xhr.responseJSON
(undefined in HTMX 1.9.x) with JSON.parse(event.detail.xhr.responseText)
so quick action toast notifications actually fire
- plugins_manager.js: add guarded htmx:afterSettle listener that only calls
attachInstallButtonHandler when #install-plugin-from-url is in the DOM,
eliminating the spurious console warning on non-plugin tab loads
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>