feat: implement server-wide management actions and enhance TUI dashboard

This commit is contained in:
2026-03-04 20:51:02 +00:00
parent 150f9d2990
commit ddec55871b
13 changed files with 621 additions and 52 deletions
+64 -3
View File
@@ -14,6 +14,12 @@ const (
IntentLoadLogs IntentKind = "load_logs"
IntentTick IntentKind = "tick"
IntentQuit IntentKind = "quit"
// Server-wide bulk operations
IntentStartAll IntentKind = "start_all"
IntentStopAll IntentKind = "stop_all"
IntentRestartAll IntentKind = "restart_all"
IntentKillAll IntentKind = "kill_all"
)
// Intent is pure data describing a side effect to execute.
@@ -45,9 +51,11 @@ func Update(model Model, msg interface{}) (Model, []Intent) {
case MsgAgentsLoaded:
model.Agents = m.Agents
// Clamp cursor
if model.Cursor >= len(model.Agents) && len(model.Agents) > 0 {
model.Cursor = len(model.Agents) - 1
// Clamp cursor only on screens that use the agent list
if model.Screen == ScreenAgentList {
if model.Cursor >= len(model.Agents) && len(model.Agents) > 0 {
model.Cursor = len(model.Agents) - 1
}
}
return model, []Intent{{Kind: IntentTick}}
@@ -59,6 +67,14 @@ func Update(model Model, msg interface{}) (Model, []Intent) {
}
return model, []Intent{{Kind: IntentLoadAgents}}
case MsgServerActionDone:
if m.Failed == 0 {
model.StatusMsg = fmt.Sprintf("%s: %d agents OK", m.Action, m.Total)
} else {
model.StatusMsg = fmt.Sprintf("%s: %d/%d failed", m.Action, m.Failed, m.Total)
}
return model, []Intent{{Kind: IntentLoadAgents}}
case MsgLogsLoaded:
model.LogLines = m.Lines
model.LogScroll = max(0, len(m.Lines)-visibleLogLines(model))
@@ -92,6 +108,8 @@ func updateKey(model Model, key KeyMsg) (Model, []Intent) {
return updateAgentActions(model, key)
case ScreenLogs:
return updateLogs(model, key)
case ScreenServer:
return updateServerScreen(model, key)
}
return model, nil
}
@@ -109,6 +127,11 @@ func updateMainScreen(model Model, key KeyMsg) (Model, []Intent) {
model.Screen = ScreenAgentList
model.Cursor = 0
return model, []Intent{{Kind: IntentLoadAgents}}
case "Server":
model.Screen = ScreenServer
model.Cursor = 0
model.StatusMsg = ""
return model, []Intent{{Kind: IntentLoadAgents}}
case "Quit":
return model, []Intent{{Kind: IntentQuit}}
}
@@ -210,6 +233,44 @@ func updateLogs(model Model, key KeyMsg) (Model, []Intent) {
return model, nil
}
func updateServerScreen(model Model, key KeyMsg) (Model, []Intent) {
opts := ServerMenuOptions()
switch key.Str {
case "0":
model.Screen = ScreenMain
model.Cursor = 0
model.StatusMsg = ""
case "up", "k":
model.Cursor = clamp(model.Cursor-1, 0, len(opts)-1)
case "down", "j":
model.Cursor = clamp(model.Cursor+1, 0, len(opts)-1)
case "enter":
if model.Cursor < len(opts) {
return executeServerAction(model, opts[model.Cursor].Label)
}
}
return model, nil
}
func executeServerAction(model Model, action string) (Model, []Intent) {
switch action {
case "Start All":
model.StatusMsg = "Starting all agents..."
return model, []Intent{{Kind: IntentStartAll}}
case "Stop All":
model.StatusMsg = "Stopping all agents..."
return model, []Intent{{Kind: IntentStopAll}}
case "Restart All":
model.StatusMsg = "Restarting all agents..."
return model, []Intent{{Kind: IntentRestartAll}}
case "Kill All":
model.StatusMsg = "Killing all agents..."
return model, []Intent{{Kind: IntentKillAll}}
}
return model, nil
}
// ── pure helpers ─────────────────────────────────────────────────────────
func visibleLogLines(m Model) int {