ready to merge and ready to discard as states
This commit is contained in:
@@ -512,7 +512,7 @@ struct StateMark: View {
|
||||
switch state.kind {
|
||||
case .working, .merging:
|
||||
Spinner(color: color)
|
||||
case .answer:
|
||||
case .answer, .ready:
|
||||
StateDot(filled: Palette.warn)
|
||||
default:
|
||||
StateDot(filled: nil)
|
||||
|
||||
@@ -98,16 +98,17 @@ private struct ProjectBlock: View {
|
||||
}
|
||||
}
|
||||
|
||||
private func nested(_ active: [ByreTask]) -> [(task: ByreTask, depth: Int)] {
|
||||
@MainActor
|
||||
private func nested(_ store: Store, _ active: [ByreTask]) -> [(task: ByreTask, depth: Int)] {
|
||||
let ids = Set(active.map(\.id))
|
||||
var out: [(task: ByreTask, depth: Int)] = []
|
||||
func add(_ task: ByreTask, _ depth: Int) {
|
||||
out.append((task, depth))
|
||||
for child in active.filter({ $0.parentTaskId == task.id }).reversed() {
|
||||
for child in store.byRank(active.filter({ $0.parentTaskId == task.id }).reversed()) {
|
||||
add(child, depth + 1)
|
||||
}
|
||||
}
|
||||
for task in active where task.parentTaskId == nil || !ids.contains(task.parentTaskId!) {
|
||||
for task in store.byRank(active.filter { $0.parentTaskId == nil || !ids.contains($0.parentTaskId!) }) {
|
||||
add(task, 0)
|
||||
}
|
||||
return out
|
||||
@@ -125,7 +126,7 @@ private struct TaskRows: View {
|
||||
.padding(.vertical, 6)
|
||||
} else {
|
||||
VStack(alignment: .leading, spacing: 0) {
|
||||
ForEach(nested(active), id: \.task.id) { row in
|
||||
ForEach(nested(store, active), id: \.task.id) { row in
|
||||
TaskRow(task: row.task, depth: row.depth)
|
||||
}
|
||||
}
|
||||
@@ -197,7 +198,7 @@ private struct TaskRow: View {
|
||||
}
|
||||
Text(ts.label)
|
||||
.font(Fonts.font(11))
|
||||
.foregroundStyle(ts.kind == .answer ? Palette.warn : Palette.muted)
|
||||
.foregroundStyle(ts.needsYou ? Palette.warn : Palette.muted)
|
||||
.help(ts.title)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,12 +22,16 @@ private let routeHash = Re(#"^#/(task|project)/(\w+)(?:/(\w+))?$"#)
|
||||
|
||||
struct TaskState {
|
||||
enum Kind {
|
||||
case answer, merging, held, working, idle
|
||||
case answer, merging, held, working, ready, idle
|
||||
}
|
||||
|
||||
let kind: Kind
|
||||
let label: String
|
||||
let title: String
|
||||
|
||||
var needsYou: Bool {
|
||||
kind == .answer || kind == .ready
|
||||
}
|
||||
}
|
||||
|
||||
private let workingTitles: [ByreTask.StatePayload: (label: String, title: String)] = [
|
||||
@@ -222,9 +226,42 @@ final class Store {
|
||||
if let working = workingTitles[task.state] {
|
||||
return TaskState(kind: .working, label: working.label, title: working.title)
|
||||
}
|
||||
switch task.ready {
|
||||
case .merge:
|
||||
return TaskState(kind: .ready, label: "Ready to merge", title: "The agent says the task is ready to merge")
|
||||
case .discard:
|
||||
return TaskState(kind: .ready, label: "Ready to discard", title: "The agent suggests discarding the task")
|
||||
case nil:
|
||||
break
|
||||
}
|
||||
return TaskState(kind: .idle, label: "Idle", title: "Waiting for a message")
|
||||
}
|
||||
|
||||
func taskRank(_ task: ByreTask) -> Int {
|
||||
if task.discarding {
|
||||
return 4
|
||||
}
|
||||
switch taskState(task).kind {
|
||||
case .answer: return 0
|
||||
case .ready: return 1
|
||||
case .idle: return 2
|
||||
case .working: return 3
|
||||
case .merging, .held: return 4
|
||||
}
|
||||
}
|
||||
|
||||
func byRank(_ tasks: [ByreTask]) -> [ByreTask] {
|
||||
tasks.enumerated()
|
||||
.sorted { a, b in
|
||||
let ra = taskRank(a.element), rb = taskRank(b.element)
|
||||
if ra != rb {
|
||||
return ra < rb
|
||||
}
|
||||
return a.offset < b.offset
|
||||
}
|
||||
.map(\.element)
|
||||
}
|
||||
|
||||
func currentLead() -> AgentSession? {
|
||||
leadSessions.last(where: { $0.state != .completed }) ?? leadSessions.last
|
||||
}
|
||||
@@ -613,7 +650,7 @@ final class Store {
|
||||
spawn("load projects") {
|
||||
try await self.loadProjects()
|
||||
}
|
||||
case "task.created", "task.merge_title", "task.merge_queued", "task.merge_unqueued", "task.merge_after_review", "task.merge_after_review_ended", "task.merge_after_review_cancelled", "task.parent_merge_started", "task.parent_merge_stopped", "task.merge_started", "task.merge_ended", "task.discard_started", "task.merged", "task.discarded", "task.state":
|
||||
case "task.created", "task.merge_title", "task.merge_queued", "task.merge_unqueued", "task.merge_after_review", "task.merge_after_review_ended", "task.merge_after_review_cancelled", "task.parent_merge_started", "task.parent_merge_stopped", "task.merge_started", "task.merge_ended", "task.discard_started", "task.merged", "task.discarded", "task.state", "task.ready", "task.discard_suggested", "snapshot.created":
|
||||
if let projectId = ev.projectId {
|
||||
spawn("load tasks") {
|
||||
try await self.loadTasks(projectId)
|
||||
@@ -634,6 +671,11 @@ final class Store {
|
||||
spawn("load inbox") {
|
||||
try await self.loadInbox()
|
||||
}
|
||||
if let projectId = ev.projectId {
|
||||
spawn("load tasks") {
|
||||
try await self.loadTasks(projectId)
|
||||
}
|
||||
}
|
||||
case "inbox.updated":
|
||||
clearInbox(try! decodePayload(ev.payload, as: InboxItem.self))
|
||||
spawn("load inbox") {
|
||||
|
||||
@@ -183,11 +183,11 @@ final class SwitcherModel {
|
||||
}
|
||||
.enumerated()
|
||||
.map { i, row in
|
||||
(i: i, project: row.project, task: row.task, count: store.inbox.filter { $0.taskId == row.task.id }.count, visited: row.task.id == store.selectedTaskId ? Double.infinity : visits[row.task.id] ?? 0)
|
||||
(i: i, project: row.project, task: row.task, count: store.inbox.filter { $0.taskId == row.task.id }.count, rank: store.taskRank(row.task), visited: row.task.id == store.selectedTaskId ? Double.infinity : visits[row.task.id] ?? 0)
|
||||
}
|
||||
.sorted { a, b in
|
||||
if (a.count > 0) != (b.count > 0) {
|
||||
return a.count > 0
|
||||
if a.rank != b.rank {
|
||||
return a.rank < b.rank
|
||||
}
|
||||
if a.visited != b.visited {
|
||||
return a.visited < b.visited
|
||||
@@ -409,7 +409,7 @@ private struct SwitcherRowView: View {
|
||||
case .task(let project, let task, let count):
|
||||
let ts = store.taskState(task)
|
||||
let color = taskPalette[task.color]
|
||||
StateDot(filled: ts.kind == .working || ts.kind == .merging ? Palette.ok : ts.kind == .answer ? Palette.warn : nil)
|
||||
StateDot(filled: ts.kind == .working || ts.kind == .merging ? Palette.ok : ts.needsYou ? Palette.warn : nil)
|
||||
.help(ts.title)
|
||||
Text(taskTitle(project, task, color))
|
||||
.lineLimit(1)
|
||||
@@ -427,7 +427,7 @@ private struct SwitcherRowView: View {
|
||||
}
|
||||
Text(ts.label)
|
||||
.font(Fonts.font(11))
|
||||
.foregroundStyle(ts.kind == .answer ? Palette.warn : Palette.muted)
|
||||
.foregroundStyle(ts.needsYou ? Palette.warn : Palette.muted)
|
||||
.help(ts.title)
|
||||
case .project(let p):
|
||||
StateDot(filled: nil)
|
||||
|
||||
Reference in New Issue
Block a user