Task and run navigation inside Work>work; explain what a run and a merge are
This commit is contained in:
76
tui/work.go
76
tui/work.go
@@ -32,6 +32,7 @@ type pickTasksMsg struct {
|
||||
|
||||
type workMsg struct {
|
||||
task paperclip.Issue
|
||||
tasks []paperclip.Issue
|
||||
runs []paperclip.Run
|
||||
activity []paperclip.Activity
|
||||
cost paperclip.Cost
|
||||
@@ -63,6 +64,7 @@ type workModel struct {
|
||||
toolAt int
|
||||
|
||||
// choosing a task here, so the screen does not depend on the Board
|
||||
taskList []paperclip.Issue
|
||||
picking bool
|
||||
pickList []paperclip.Issue
|
||||
pickNames map[string]string
|
||||
@@ -111,9 +113,18 @@ func (m workModel) load() tea.Cmd {
|
||||
return errMsg{err}
|
||||
}
|
||||
runs, _ := c.Runs(id)
|
||||
var list []paperclip.Issue
|
||||
if all, err := c.Issues(); err == nil {
|
||||
cfg, _ := readHarnessFile(folder)
|
||||
for _, i := range all {
|
||||
if i.ProjectID == cfg["paperclip.project"] {
|
||||
list = append(list, i)
|
||||
}
|
||||
}
|
||||
}
|
||||
act, _ := c.Activity(id)
|
||||
cost, _ := c.CostSummary(id)
|
||||
msg := workMsg{task: task, runs: runs, activity: act, cost: cost}
|
||||
msg := workMsg{task: task, runs: runs, activity: act, cost: cost, tasks: list}
|
||||
if ws := task.Workspace; ws != nil && ws.CWD != "" {
|
||||
msg.diff, msg.diffErr = worktreeDiff(ws.CWD, ws.BaseRef)
|
||||
} else {
|
||||
@@ -234,6 +245,35 @@ func (m workModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
||||
case "t":
|
||||
m.tools = true
|
||||
return m, nil
|
||||
case "n", "p":
|
||||
if len(m.taskList) == 0 {
|
||||
return m, nil
|
||||
}
|
||||
at := -1
|
||||
for i, t := range m.taskList {
|
||||
if t.ID == m.task.ID {
|
||||
at = i
|
||||
}
|
||||
}
|
||||
if at < 0 {
|
||||
at = 0
|
||||
}
|
||||
if msg.String() == "n" {
|
||||
at = (at + 1) % len(m.taskList)
|
||||
} else {
|
||||
at = (at + len(m.taskList) - 1) % len(m.taskList)
|
||||
}
|
||||
chosen := m.taskList[at]
|
||||
if err := rememberTask(m.folder, chosen.Identifier); err != nil {
|
||||
m.err = err
|
||||
return m, nil
|
||||
}
|
||||
m.explicit = true
|
||||
m.issue = chosen.ID
|
||||
m.task = chosen
|
||||
m.tab = 0
|
||||
m.runAt = 0
|
||||
return m, m.load()
|
||||
case "o":
|
||||
c := m.client
|
||||
folder := m.folder
|
||||
@@ -334,6 +374,9 @@ func (m workModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
||||
|
||||
case workMsg:
|
||||
m.task = msg.task
|
||||
if msg.tasks != nil {
|
||||
m.taskList = msg.tasks
|
||||
}
|
||||
m.runs = msg.runs
|
||||
m.activity = msg.activity
|
||||
m.cost = msg.cost
|
||||
@@ -374,7 +417,13 @@ func (m workModel) View() string {
|
||||
head := titleStyle.Render("Work") + mutedStyle2().Render(" · ")
|
||||
if m.task.Identifier != "" {
|
||||
head += lipgloss.NewStyle().Foreground(lipgloss.Color(active.Text)).Render(m.task.Identifier)
|
||||
head += mutedStyle2().Render(" " + truncateVisible(m.task.Title, max(10, m.width-50)))
|
||||
head += mutedStyle2().Render(" " + truncateVisible(m.task.Title, max(10, m.width-60)))
|
||||
for i, t := range m.taskList {
|
||||
if t.ID == m.task.ID {
|
||||
head += mutedStyle2().Render(fmt.Sprintf(" task %d of %d", i+1, len(m.taskList)))
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
state := "read " + m.readAt.Format("15:04:05")
|
||||
if m.readAt.IsZero() {
|
||||
@@ -403,8 +452,13 @@ func (m workModel) View() string {
|
||||
if cmd := verifyFromDescription(m.task.Description); cmd != "" {
|
||||
verify = "verify command: " + cmd
|
||||
}
|
||||
return helpOverlay("merge "+m.task.Identifier+"?", [][2]string{
|
||||
{"what happens", "rebase onto the base branch"},
|
||||
branch := "(no branch yet)"
|
||||
if m.task.Workspace != nil && m.task.Workspace.Branch != "" {
|
||||
branch = m.task.Workspace.Branch
|
||||
}
|
||||
return helpOverlay("merge "+m.task.Identifier+" into main?", [][2]string{
|
||||
{"what is merged", branch + " → " + baseRefOf(m.task)},
|
||||
{"what happens", "rebase the branch onto the base, then merge it"},
|
||||
{"", verify},
|
||||
{"", "ocr reviews the change; a critical finding refuses the merge"},
|
||||
{"", "merge, then re-run the checks on the base branch"},
|
||||
@@ -435,8 +489,12 @@ func (m workModel) View() string {
|
||||
return helpOverlay("open a tool pane here", entries, m.width, m.height)
|
||||
}
|
||||
|
||||
title := "the work"
|
||||
if m.tab == 0 {
|
||||
title = fmt.Sprintf("the work · %s", fmtCount(len(m.runs), "run", "runs"))
|
||||
}
|
||||
p := panel{
|
||||
title: "the work", width: m.width, height: m.height - 2,
|
||||
title: title, width: m.width, height: m.height - 2,
|
||||
tabs: workTabs, active: m.tab, focused: true,
|
||||
}
|
||||
|
||||
@@ -674,3 +732,11 @@ func (m workModel) factsLines(width int) []string {
|
||||
row("cost", fmt.Sprintf("%d cent(s), %d run(s), %d tokens out", m.cost.CostCents, m.cost.RunCount, m.cost.OutputTokens))
|
||||
return out
|
||||
}
|
||||
|
||||
// baseRefOf is the branch a task's work will be merged into.
|
||||
func baseRefOf(t paperclip.Issue) string {
|
||||
if t.Workspace != nil && t.Workspace.BaseRef != "" {
|
||||
return t.Workspace.BaseRef
|
||||
}
|
||||
return "main"
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user