fix: reload returns 200 JSON on error, fix missing buttons, handle non-JSON responses, add -buildvcs=false

This commit is contained in:
Claus Lohmar 2026-07-24 10:08:12 +00:00
parent e14164921c
commit 8b0bd75f29
3 changed files with 18 additions and 7 deletions

View file

@ -501,7 +501,7 @@ install_plugin() {
# Build the plugin # Build the plugin
info "Building plugin binary..." info "Building plugin binary..."
(cd "$plugin_dir" && go build -o dhcp-lease-manager .) || { (cd "$plugin_dir" && go build -buildvcs=false -o dhcp-lease-manager .) || {
err "Plugin build failed. Check Go installation." err "Plugin build failed. Check Go installation."
exit 1 exit 1
} }

View file

@ -302,7 +302,12 @@ func handleUnpinLease(w http.ResponseWriter, r *http.Request) {
func handleReload(w http.ResponseWriter, r *http.Request) { func handleReload(w http.ResponseWriter, r *http.Request) {
if err := reloadDnsmasq(); err != nil { if err := reloadDnsmasq(); err != nil {
log.Printf("ERROR reloading dnsmasq: %v", err) log.Printf("ERROR reloading dnsmasq: %v", err)
writeJSON(w, http.StatusInternalServerError, ErrorResponse{Error: err.Error()}) // Return 200 even on error — Zoraxy may intercept non-200
// responses and replace them with HTML error pages.
writeJSON(w, http.StatusOK, PinResponse{
Success: false,
Message: fmt.Sprintf("reload failed: %v", err),
})
return return
} }
writeJSON(w, http.StatusOK, PinResponse{Success: true, Message: "dnsmasq reloaded"}) writeJSON(w, http.StatusOK, PinResponse{Success: true, Message: "dnsmasq reloaded"})

View file

@ -30,10 +30,16 @@ async function apiFetch(path, opts) {
opts.body = JSON.stringify(opts.body); opts.body = JSON.stringify(opts.body);
opts.headers['Content-Type'] = 'application/json'; opts.headers['Content-Type'] = 'application/json';
} }
const res = await fetch(API_BASE + path, opts); var res = await fetch(API_BASE + path, opts);
const data = await res.json(); var text = await res.text();
try {
var data = JSON.parse(text);
} catch (e) {
// Zoraxy may intercept error responses and return HTML
throw new Error('Unexpected response (status ' + res.status + '). Check plugin is running.');
}
if (!res.ok) { if (!res.ok) {
throw new Error(data.error || data.message || 'Request failed'); throw new Error(data.error || data.message || 'Request failed (status ' + res.status + ')');
} }
return data; return data;
} }
@ -74,8 +80,8 @@ function renderLeases(data) {
'</td>' + '</td>' +
'<td class="actions-cell">' + '<td class="actions-cell">' +
(isPermanent (isPermanent
? '<button class="btn btn-danger btn-sm" data-action="unpin" data-mac="' + escAttr(lease.mac) + '" data-ip="' + escAttr(lease.ip) + '" data-hostname="' + escAttr(lease.hostname) + '">Unpin</button>' ? '<button class="btn btn-danger" data-action="unpin" data-mac="' + escAttr(lease.mac) + '" data-ip="' + escAttr(lease.ip) + '" data-hostname="' + escAttr(lease.hostname) + '">Unpin</button>'
: '<button class="btn btn-primary btn-sm" data-action="pin" data-mac="' + escAttr(lease.mac) + '" data-ip="' + escAttr(lease.ip) + '" data-hostname="' + escAttr(lease.hostname) + '">Pin</button>' : '<button class="btn btn-primary" data-action="pin" data-mac="' + escAttr(lease.mac) + '" data-ip="' + escAttr(lease.ip) + '" data-hostname="' + escAttr(lease.hostname) + '">Pin</button>'
) + ) +
'</td>' + '</td>' +
'</tr>' '</tr>'