From 66de42f21b14c369281908aa449ea08ea0f3900a Mon Sep 17 00:00:00 2001 From: root Date: Sat, 25 Apr 2026 10:19:41 +0800 Subject: [PATCH] fix: node config save, dbType mismatch, and dark theme support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - ShouldBindJSON → ShouldBind with form tags (axios sends url-encoded) - dbType dropdown value "mysql" → "mariadb" to match backend - Replace inline styles with theme-aware CSS classes for dark mode --- config/version | 2 +- ...-25-fix-node-config-save-and-dark-theme.md | 38 +++++++++++++ web/controller/node.go | 20 +++---- web/html/nodes.html | 54 +++++++++++-------- 4 files changed, 81 insertions(+), 33 deletions(-) create mode 100644 docs/Tasktracking/2026-04-25-fix-node-config-save-and-dark-theme.md diff --git a/config/version b/config/version index 0591f336..631f57b5 100644 --- a/config/version +++ b/config/version @@ -1 +1 @@ -v1.6.6 +v1.6.6.1 diff --git a/docs/Tasktracking/2026-04-25-fix-node-config-save-and-dark-theme.md b/docs/Tasktracking/2026-04-25-fix-node-config-save-and-dark-theme.md new file mode 100644 index 00000000..87933c6e --- /dev/null +++ b/docs/Tasktracking/2026-04-25-fix-node-config-save-and-dark-theme.md @@ -0,0 +1,38 @@ +# 2026-04-25 Fix node config save, dbType mismatch, and dark theme + +## Problem + +### 1. Node config save always fails +The `saveConfig` endpoint in `node.go` used `c.ShouldBindJSON()` which expects +`Content-Type: application/json`. But the global axios interceptor in `axios-init.js` +converts all POST data via `Qs.stringify()` and sends it as +`application/x-www-form-urlencoded`. The backend rejected every save with: +`invalid request (invalid character 's' looking for beginning of value)`. + +### 2. dbType dropdown value mismatch +The frontend `` used `value="mysql"` for the MySQL/MariaDB option, but the +backend checks for `"mariadb"` everywhere (database init, node list query, validation). +Saving through the UI would write `"mysql"`, which the backend would treat as SQLite. + +### 3. Worker node info table invisible in dark theme +The HTML table for the worker's master node info used hardcoded inline styles +(`background:#fafafa`, `border-color:#e8e8e8`). In dark theme, inherited white text +on `#fafafa` background made label cells nearly invisible. + +## Fix + +### Config save +- Changed `ShouldBindJSON` to `ShouldBind` (matches all other controllers in the project) +- Added `form` struct tags to `updateConfigRequest` fields + +### dbType mismatch +- Changed dropdown value from `"mysql"` to `"mariadb"` to match the backend constant + +### Dark theme +- Extracted inline styles into CSS classes (`.node-info-wrap`, `.node-info-table`) +- Added `.dark` theme overrides using existing CSS custom properties + +## Files Changed + +- `web/controller/node.go`: `ShouldBindJSON` → `ShouldBind`, added `form` tags +- `web/html/nodes.html`: Fixed dbType value, replaced inline styles with theme-aware CSS diff --git a/web/controller/node.go b/web/controller/node.go index 1c98b078..09855651 100644 --- a/web/controller/node.go +++ b/web/controller/node.go @@ -151,22 +151,22 @@ func (a *NodeController) getConfig(c *gin.Context) { }, nil) } -// updateConfigRequest is the JSON body for updating node config. +// updateConfigRequest is the form body for updating node config. type updateConfigRequest struct { - SyncInterval int `json:"syncInterval"` - TrafficFlushInterval int `json:"trafficFlushInterval"` - DBType string `json:"dbType"` - DBHost string `json:"dbHost"` - DBPort string `json:"dbPort"` - DBUser string `json:"dbUser"` - DBPass string `json:"dbPass"` - DBName string `json:"dbName"` + SyncInterval int `json:"syncInterval" form:"syncInterval"` + TrafficFlushInterval int `json:"trafficFlushInterval" form:"trafficFlushInterval"` + DBType string `json:"dbType" form:"dbType"` + DBHost string `json:"dbHost" form:"dbHost"` + DBPort string `json:"dbPort" form:"dbPort"` + DBUser string `json:"dbUser" form:"dbUser"` + DBPass string `json:"dbPass" form:"dbPass"` + DBName string `json:"dbName" form:"dbName"` } // updateConfig updates the node configuration in x-ui.json. func (a *NodeController) updateConfig(c *gin.Context) { var req updateConfigRequest - if err := c.ShouldBindJSON(&req); err != nil { + if err := c.ShouldBind(&req); err != nil { jsonMsg(c, "invalid request", err) return } diff --git a/web/html/nodes.html b/web/html/nodes.html index 7f8be569..b063b08c 100644 --- a/web/html/nodes.html +++ b/web/html/nodes.html @@ -1,4 +1,14 @@ {{ template "page/head_start" .}} + {{ template "page/head_end" .}} {{ template "page/body_start" .}} @@ -49,34 +59,34 @@
-
- +
+
- - - + + + - - - + + - - - - - - - - - - - + + + - - + + + + + + + + + +
{{ i18n "pages.nodes.nodeId" }}[[ nodes[0].nodeId ]]
{{ i18n "pages.nodes.nodeId" }}[[ nodes[0].nodeId ]]
{{ i18n "pages.nodes.status" }} +
{{ i18n "pages.nodes.status" }}
{{ i18n "pages.nodes.lastHeartbeat" }}[[ nodes[0].lastHeartbeatAt ? formatTime(nodes[0].lastHeartbeatAt) : '-' ]]
{{ i18n "pages.nodes.lastSync" }}[[ nodes[0].lastSyncAt ? formatTime(nodes[0].lastSyncAt) : '-' ]]
{{ i18n "pages.nodes.syncVersion" }}[[ nodes[0].lastSeenVersion ]]
{{ i18n "pages.nodes.lastHeartbeat" }}[[ nodes[0].lastHeartbeatAt ? formatTime(nodes[0].lastHeartbeatAt) : '-' ]]
{{ i18n "pages.nodes.error" }}[[ nodes[0].lastError || '-' ]]{{ i18n "pages.nodes.lastSync" }}[[ nodes[0].lastSyncAt ? formatTime(nodes[0].lastSyncAt) : '-' ]]
{{ i18n "pages.nodes.syncVersion" }}[[ nodes[0].lastSeenVersion ]]
{{ i18n "pages.nodes.error" }}[[ nodes[0].lastError || '-' ]]
@@ -111,7 +121,7 @@ SQLite - MySQL/MariaDB + MySQL/MariaDB