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 {
|
func (m Model) eventRows(w, h int) []string {
|
||||||
t := m.theme
|
t := m.theme
|
||||||
header := lipgloss.NewStyle().Foreground(t.P.Accent).Background(t.P.Bg).Bold(true).Render("event stream") +
|
header := lipgloss.NewStyle().Foreground(t.P.Accent).Background(t.P.Bg).Bold(true).Render("event stream") +
|
||||||
t.span(" ", t.P.Bg)
|
t.span(" ", t.P.Bg) + m.eventStreamBadge()
|
||||||
if m.connected {
|
|
||||||
header += lipgloss.NewStyle().Foreground(t.P.OK).Background(t.P.Bg).Render("● live")
|
|
||||||
} else {
|
|
||||||
header += t.span("○ idle", t.P.Faint)
|
|
||||||
}
|
|
||||||
|
|
||||||
s := m.session(m.selectedID)
|
s := m.session(m.selectedID)
|
||||||
if s == nil || len(s.Events) == 0 {
|
if s == nil || len(s.Events) == 0 {
|
||||||
@@ -617,6 +612,30 @@ func (m Model) eventRows(w, h int) []string {
|
|||||||
return append([]string{header, ""}, evRows...)
|
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 ---
|
// --- width helpers ---
|
||||||
|
|
||||||
// shortPath abbreviates the user's home dir to ~ for a compact cwd in the status bar.
|
// shortPath abbreviates the user's home dir to ~ for a compact cwd in the status bar.
|
||||||
|
|||||||
Reference in New Issue
Block a user