Harden worker federation and operator UI
This commit is contained in:
+17
-2
@@ -136,7 +136,9 @@ func (s Server) detail(ctx context.Context, id string) (TaskDetail, error) {
|
||||
if !ok {
|
||||
return TaskDetail{}, domain.ErrNotFound
|
||||
}
|
||||
d := TaskDetail{Task: t, Actions: actions(t)}
|
||||
// Keep collection fields as JSON arrays for browser clients, including
|
||||
// older task records that genuinely have no retained events.
|
||||
d := TaskDetail{Task: t, Events: []domain.Event{}, Actions: actions(t)}
|
||||
for _, e := range s.Store.Events(0) {
|
||||
if e.TaskID != id {
|
||||
continue
|
||||
@@ -165,9 +167,14 @@ func (s Server) detail(ctx context.Context, id string) (TaskDetail, error) {
|
||||
session.Blocker = "capture unavailable: " + err.Error()
|
||||
}
|
||||
d.Session = session
|
||||
} else if t.State == domain.StateBlocked {
|
||||
// A blocked task has no active lease by definition, but must retain its
|
||||
// last observed pane evidence instead of rendering an unexplained void.
|
||||
d.Session = &Session{PaneID: t.LastPaneID, HarnessID: t.LastHarness, AgentStatus: t.PaneState, Blocker: t.Blocker}
|
||||
}
|
||||
return d, nil
|
||||
}
|
||||
|
||||
// captureRevision identifies *what the operator saw*, not when they saw it.
|
||||
// B20: this was UnixNano, so it changed on every read and said nothing about
|
||||
// whether the pane had changed. A content hash changes if and only if the
|
||||
@@ -206,7 +213,15 @@ func actions(t domain.Task) []Action {
|
||||
return []Action{{ID: "handoff", Enabled: active, Reason: "requires a live leased session"}, {ID: "release", Enabled: active, Needs: []string{"reason or handoff_ref"}}, {ID: "block", Enabled: active, Needs: []string{"blocker"}}, {ID: "complete", Enabled: active, Needs: []string{"report_ref", "receipt"}}}
|
||||
}
|
||||
func (s Server) Overview(ctx context.Context) Overview {
|
||||
out := Overview{Tasks: s.Store.Tasks(), UpdatedAt: time.Now().UTC()}
|
||||
// JSON null is not an empty collection to browser clients. In particular,
|
||||
// the shell renders the number of active sessions before any page-level
|
||||
// loading state, so a nil Sessions slice made an otherwise healthy empty
|
||||
// worker pool crash the entire SPA on `sessions.length`.
|
||||
tasks := s.Store.Tasks()
|
||||
if tasks == nil {
|
||||
tasks = []domain.Task{}
|
||||
}
|
||||
out := Overview{Tasks: tasks, Workers: []federation.Worker{}, Sessions: []Session{}, UpdatedAt: time.Now().UTC()}
|
||||
if s.Workers != nil {
|
||||
out.Workers = s.Workers.Snapshot()
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user