feat(tui): show dependency readiness on the task board
Each task row gets a 2-col glyph — ● ready (workable now) / ○ waiting (blocked) / blank — and the detail pane shows "ready to work" or "blocked — waiting on <ids>", fed by the new GET /tasks ready/blockedBy fields. Makes a decomposed graph legible at a glance; a dependency-blocked task is status TODO (not the red BLOCKED lifecycle state), so the glyph is what distinguishes them. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -27,6 +27,10 @@ type TaskSummary struct {
|
||||
Notes []TaskNoteWire `json:"notes"`
|
||||
CreatedAt string `json:"createdAt"`
|
||||
UpdatedAt string `json:"updatedAt"`
|
||||
// Dependency-graph status from the server: Ready = workable now (TODO, no unmet deps);
|
||||
// BlockedBy = ids of unfinished tasks this one waits on. Absent on older servers → zero values.
|
||||
Ready bool `json:"ready"`
|
||||
BlockedBy []string `json:"blockedBy"`
|
||||
}
|
||||
|
||||
type TaskLinkWire struct {
|
||||
@@ -336,14 +340,29 @@ func (m Model) taskListRow(tasks []TaskSummary, i int) string {
|
||||
if tk.Claimant != "" {
|
||||
claim = " @" + shortSessionID(tk.Claimant)
|
||||
}
|
||||
titleW := m.modalWidth() - 6 - 12 - 1 - 12 - 1 - len([]rune(claim))
|
||||
readyCell := taskReadyCell(t, tk) // 2-col dependency-readiness glyph
|
||||
titleW := m.modalWidth() - 6 - 12 - 1 - 12 - 1 - 2 - 1 - len([]rune(claim))
|
||||
if titleW < 8 {
|
||||
titleW = 8
|
||||
}
|
||||
titleCell := mbg(t, padRaw(truncate(tk.Title, titleW), titleW), t.P.Fg)
|
||||
claimCell := mbg(t, claim, t.P.Faint)
|
||||
|
||||
return marker + idCell + " " + statusCell + " " + titleCell + claimCell
|
||||
return marker + idCell + " " + statusCell + " " + readyCell + " " + titleCell + claimCell
|
||||
}
|
||||
|
||||
// taskReadyCell is a 2-column glyph showing dependency-graph readiness, so a decomposed graph reads
|
||||
// at a glance: a filled dot when the task is workable now (TODO, no unmet deps), a hollow dot when it
|
||||
// is waiting on unfinished blockers, blank for anything already in flight or finished.
|
||||
func taskReadyCell(t Theme, tk TaskSummary) string {
|
||||
switch {
|
||||
case tk.Ready:
|
||||
return lipgloss.NewStyle().Foreground(t.P.OK).Background(t.P.BgPanel).Render(padRaw("●", 2))
|
||||
case len(tk.BlockedBy) > 0:
|
||||
return lipgloss.NewStyle().Foreground(t.P.Dim).Background(t.P.BgPanel).Render(padRaw("○", 2))
|
||||
default:
|
||||
return mbg(t, " ", t.P.BgPanel)
|
||||
}
|
||||
}
|
||||
|
||||
func (m Model) taskDetailModal() string {
|
||||
@@ -407,6 +426,11 @@ func (m Model) taskDetailBody(width int) []string {
|
||||
if tk.Claimant != "" {
|
||||
out = append(out, mbg(t, "claimant: "+tk.Claimant, t.P.Faint))
|
||||
}
|
||||
if tk.Ready {
|
||||
out = append(out, mbg(t, "● ready to work (no unmet dependencies)", t.P.OK))
|
||||
} else if len(tk.BlockedBy) > 0 {
|
||||
out = append(out, mbg(t, "○ blocked — waiting on "+strings.Join(tk.BlockedBy, ", "), t.P.Dim))
|
||||
}
|
||||
out = append(out, "")
|
||||
|
||||
if tk.Goal != "" {
|
||||
|
||||
Reference in New Issue
Block a user