fix(tui-go): event-stream badge tracks session status, not just the socket
The EVENTS panel showed "● live" off m.connected alone, so a completed/failed/ paused session kept reading "live" as long as the websocket was up — stale, since a terminal session emits no more events. Derive the badge from the selected session's Status (the same vocabulary the status bar uses): ✓ done, ✗ failed, ‖ paused, ● live while active, ○ idle when disconnected. event_badge_test.go covers all five. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,33 @@
|
||||
package app
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
// The event-stream badge must track the selected session's lifecycle, not just the socket:
|
||||
// a terminal/paused session emits no more events, so it must not keep reading "● live".
|
||||
func TestEventStreamBadgeReflectsSessionStatus(t *testing.T) {
|
||||
cases := []struct{ status, want string }{
|
||||
{"ACTIVE", "● live"},
|
||||
{"COMPLETED", "✓ done"},
|
||||
{"FAILED", "✗ failed"},
|
||||
{"PAUSED awaiting approval", "‖ paused"},
|
||||
}
|
||||
for _, c := range cases {
|
||||
m := inSessionModel(120, 40)
|
||||
m.connected = true
|
||||
m.sessions[0].Status = c.status
|
||||
if got := m.eventStreamBadge(); !strings.Contains(got, c.want) {
|
||||
t.Errorf("status %q: badge = %q, want substring %q", c.status, got, c.want)
|
||||
}
|
||||
}
|
||||
|
||||
// Disconnected always reads idle, regardless of the session's status.
|
||||
m := inSessionModel(120, 40)
|
||||
m.connected = false
|
||||
m.sessions[0].Status = "ACTIVE"
|
||||
if got := m.eventStreamBadge(); !strings.Contains(got, "○ idle") {
|
||||
t.Errorf("disconnected: badge = %q, want idle", got)
|
||||
}
|
||||
}
|
||||
@@ -590,12 +590,7 @@ func (m Model) buildTranscriptRows(w int) ([]string, []int) {
|
||||
func (m Model) eventRows(w, h int) []string {
|
||||
t := m.theme
|
||||
header := lipgloss.NewStyle().Foreground(t.P.Accent).Background(t.P.Bg).Bold(true).Render("event stream") +
|
||||
t.span(" ", t.P.Bg)
|
||||
if m.connected {
|
||||
header += lipgloss.NewStyle().Foreground(t.P.OK).Background(t.P.Bg).Render("● live")
|
||||
} else {
|
||||
header += t.span("○ idle", t.P.Faint)
|
||||
}
|
||||
t.span(" ", t.P.Bg) + m.eventStreamBadge()
|
||||
|
||||
s := m.session(m.selectedID)
|
||||
if s == nil || len(s.Events) == 0 {
|
||||
@@ -617,6 +612,30 @@ func (m Model) eventRows(w, h int) []string {
|
||||
return append([]string{header, ""}, evRows...)
|
||||
}
|
||||
|
||||
// eventStreamBadge reflects whether the *selected session's* stream is still live, not
|
||||
// just whether the socket is connected: a completed / failed / paused session emits no
|
||||
// more events, so the old connection-only "● live" went stale the moment a session ended.
|
||||
func (m Model) eventStreamBadge() string {
|
||||
t := m.theme
|
||||
if !m.connected {
|
||||
return t.span("○ idle", t.P.Faint)
|
||||
}
|
||||
if s := m.session(m.selectedID); s != nil {
|
||||
badge := func(fg lipgloss.Color, text string) string {
|
||||
return lipgloss.NewStyle().Foreground(fg).Background(t.P.Bg).Render(text)
|
||||
}
|
||||
switch u := strings.ToUpper(s.Status); {
|
||||
case strings.Contains(u, "FAIL"):
|
||||
return badge(t.P.Bad, "✗ failed")
|
||||
case strings.Contains(u, "COMPLETE"):
|
||||
return badge(t.P.OK, "✓ done")
|
||||
case strings.Contains(u, "PAUSE"):
|
||||
return badge(t.P.Warn, "‖ paused")
|
||||
}
|
||||
}
|
||||
return lipgloss.NewStyle().Foreground(t.P.OK).Background(t.P.Bg).Render("● live")
|
||||
}
|
||||
|
||||
// --- width helpers ---
|
||||
|
||||
// shortPath abbreviates the user's home dir to ~ for a compact cwd in the status bar.
|
||||
|
||||
Reference in New Issue
Block a user