feat: DB-agent feature sync with conflict detection

- ConsoleFeature 增加 Available/Conflict 字段
- pageConsole 显示 agent 全部能力(含不可用的),不可用项 disabled
- DB 已启用但 agent 不可用时标记为冲突 ⚠
- 不可用功能 hover 显示原因
This commit is contained in:
tian 2026-05-12 13:57:03 +08:00
parent 700d964524
commit 7eca9454b0
2 changed files with 32 additions and 10 deletions

View File

@ -933,9 +933,10 @@ func (u *UI) pageConsole(w http.ResponseWriter, r *http.Request) {
}
features := make([]ConsoleFeature, 0, len(capsResp.Capabilities))
for _, c := range capsResp.Capabilities {
if c.Available {
features = append(features, ConsoleFeature{Key: c.Key, Label: c.Label, Description: c.Description, Enabled: false})
}
features = append(features, ConsoleFeature{
Key: c.Key, Label: c.Label, Description: c.Description,
Available: c.Available, Enabled: false,
})
}
deviceAvailableFeatures[dev.DeviceID] = features
}
@ -1038,19 +1039,36 @@ func (u *UI) pageConsole(w http.ResponseWriter, r *http.Request) {
activeKeys = map[string]bool{}
}
// Features from device capabilities (filtered by agent /v1/capabilities).
// Fall back to persisted keys if agent doesn't respond.
// Features from device capabilities (from agent /v1/capabilities).
// Overlay persisted DB state for checkmarks and conflict detection.
available := deviceAvailableFeatures[dev.DeviceID]
var features []ConsoleFeature
if len(available) > 0 {
for _, f := range available {
f.Enabled = activeKeys[f.Key]
// Conflict: user enabled a feature that the device no longer supports.
if f.Enabled && !f.Available {
f.Conflict = true
}
features = append(features, f)
}
} else {
// Old agent: use persisted keys to show at least what's configured.
// Show persisted features that the agent didn't report (e.g. new features
// added to registry but old agent doesn't know them).
seen := map[string]bool{}
for _, f := range features {
seen[f.Key] = true
}
for key := range activeKeys {
features = append(features, ConsoleFeature{Key: key, Label: key, Enabled: true})
if !seen[key] {
features = append(features, ConsoleFeature{
Key: key, Label: key, Enabled: true, Available: false, Conflict: true,
})
}
}
} else {
// Old agent: show persisted keys.
for key := range activeKeys {
features = append(features, ConsoleFeature{Key: key, Label: key, Enabled: true, Available: true})
}
}
@ -4732,4 +4750,6 @@ type ConsoleFeature struct {
Label string
Description string
Enabled bool
Available bool // device actually supports this (from agent /v1/capabilities)
Conflict bool // enabled in DB but unavailable on device
}

View File

@ -61,8 +61,10 @@
<table class="console-feature-table">
{{range $f := $cd.Features}}
<tr>
<td class="console-feature-check"><input type="checkbox" name="device_{{$cd.Device.DeviceID}}_feature" value="{{$f.Key}}"{{if $f.Enabled}} checked{{end}}></td>
<td class="console-feature-label" title="{{$f.Description}}">{{$f.Label}}</td>
<td class="console-feature-check"><input type="checkbox" name="device_{{$cd.Device.DeviceID}}_feature" value="{{$f.Key}}"{{if $f.Enabled}} checked{{end}}{{if not $f.Available}} disabled{{end}}></td>
<td class="console-feature-label{{if $f.Conflict}} text-danger{{else if not $f.Available}} text-muted{{end}}" title="{{$f.Description}}{{if $f.Conflict}} (设备已不支持){{else if not $f.Available}} (设备不支持){{end}}">
{{$f.Label}}{{if $f.Conflict}} ⚠{{end}}
</td>
</tr>
{{end}}
</table>