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 }