Files
proxy/internal/tui/dashboard.go
T
2026-08-30 15:49:04 +08:00

101 lines
2.6 KiB
Go

package tui
import "proxyctl/internal/app"
func targetActionLabel(kind app.TargetActionKind) string {
switch kind {
case app.EnableTargetAction:
return "Enable"
case app.DisableTargetAction:
return "Disable"
case app.ApplyProfileTargetAction:
return "Apply Profile"
case app.ResolveDriftTargetAction:
return "Resolve"
case app.ReapplyActiveProfileAction:
return "Reapply Active Profile"
case app.RestoreOriginalAction:
return "Restore Original"
default:
return "Unavailable"
}
}
type dashboardPane uint8
const (
targetListPane dashboardPane = iota
targetDetailsPane
)
// targetCatalog owns the dashboard's product-ordered Target projection. It is
// the only place where availability filtering and identity-based selection are
// combined, so rendering and input handling cannot accidentally select by a
// transient row number.
type targetCatalog struct {
items []app.TargetSnapshot
}
func newTargetCatalog(snapshot app.Snapshot, includeUnavailable bool, selectedID string) targetCatalog {
items := make([]app.TargetSnapshot, 0, len(snapshot.Targets))
for _, item := range snapshot.Targets {
// Available Targets are the routine default. If progressive detection
// proves the selected identity unavailable, keep that one row visible
// until the user selects another Target rather than silently moving the
// selection to a different product.
if item.Available || includeUnavailable || item.ID == selectedID || item.DetectionPhase != app.TargetReady {
items = append(items, item)
}
}
return targetCatalog{items: items}
}
func (c targetCatalog) firstID() string {
if len(c.items) == 0 {
return ""
}
return c.items[0].ID
}
func (c targetCatalog) index(id string) int {
for i := range c.items {
if c.items[i].ID == id {
return i
}
}
return -1
}
func (c targetCatalog) selected(id string) (app.TargetSnapshot, bool) {
index := c.index(id)
if index < 0 {
return app.TargetSnapshot{}, false
}
return c.items[index], true
}
func (c targetCatalog) move(id string, delta int) string {
if len(c.items) == 0 {
return ""
}
index := c.index(id)
if index < 0 {
index = 0
}
index = max(0, min(len(c.items)-1, index+delta))
return c.items[index].ID
}
// retain keeps an identity when possible and otherwise chooses the product row
// nearest its former position. This is used after refresh and visibility
// changes; terminal resize never needs to touch selection at all.
func (c targetCatalog) retain(id string, formerIndex int) string {
if c.index(id) >= 0 {
return id
}
if len(c.items) == 0 {
return ""
}
return c.items[max(0, min(len(c.items)-1, formerIndex))].ID
}