Compact run stage cards

This commit is contained in:
Ian Gulliver
2026-10-21 10:21:41 -07:00
parent e8758536d0
commit 3dfd59115e
+47 -26
View File
@@ -54,6 +54,15 @@ private func stageLabel(_ s: RunStage) -> String {
return "waiting to start"
}
@MainActor
private func taskLink(_ taskId: String, _ label: String, bold: Bool = false) -> AttributedString {
var a = AttributedString(label)
a.link = AppLink.task(taskId)
a.foregroundColor = Palette.accent
a.font = Fonts.font(13, weight: bold ? 700 : 400)
return a
}
private func stateColor(_ state: String) -> Color {
switch state {
case "running": Palette.accent
@@ -195,20 +204,37 @@ private struct StageCard: View {
let stage: RunStage
var body: some View {
let only = stage.attempts.count == 1 ? stage.attempts[0] : nil
VStack(alignment: .leading, spacing: 2) {
HStack(alignment: .firstTextBaseline, spacing: 10) {
Text(stage.name).font(Fonts.font(13, weight: 700))
if let only {
Text(taskLink(only.taskId, stage.name, bold: true))
} else {
Text(stage.name).font(Fonts.font(13, weight: 700))
}
Text(stageLabel(stage))
.font(Fonts.font(11))
.foregroundStyle(stateColor(stage.state.rawValue))
if only?.discarding == true {
Text("discarding…").font(Fonts.font(11)).foregroundStyle(Palette.muted)
}
}
Text(stage.after.isEmpty ? "starts from the brief" : "after \(stage.after.map { "“\($0)”" }.joined(separator: ", "))")
.font(Fonts.font(11))
.foregroundStyle(Palette.muted)
if !stage.attempts.isEmpty {
if let only, only.title.caseInsensitiveCompare(stage.name) != .orderedSame {
Text("task “\(only.title)”")
.font(Fonts.font(11))
.foregroundStyle(Palette.muted)
}
if !stage.after.isEmpty {
Text("after \(stage.after.map { "“\($0)”" }.joined(separator: ", "))")
.font(Fonts.font(11))
.foregroundStyle(Palette.muted)
}
if let only {
AttemptRow(run: run, stage: stage, attempt: only, index: 0, solo: true)
} else if !stage.attempts.isEmpty {
VStack(alignment: .leading, spacing: 8) {
ForEach(Array(stage.attempts.enumerated()), id: \.offset) { i, a in
AttemptRow(run: run, stage: stage, attempt: a, index: i)
AttemptRow(run: run, stage: stage, attempt: a, index: i, solo: false)
}
}
.padding(.top, 8)
@@ -227,22 +253,23 @@ private struct AttemptRow: View {
let stage: RunStage
let attempt: StageAttempt
let index: Int
let solo: Bool
@Environment(Store.self) private var store
var body: some View {
let a = attempt
let fed = run.stages.flatMap { s in s.attempts.filter { d in d.inputs.contains { $0.taskId == a.taskId } }.map(\.taskId) }
VStack(alignment: .leading, spacing: 2) {
HStack(alignment: .firstTextBaseline, spacing: 10) {
if stage.attempts.count > 1 {
if !solo {
HStack(alignment: .firstTextBaseline, spacing: 10) {
Text("#\(index + 1)").foregroundStyle(Palette.muted)
}
Text(link(a.taskId, a.title, bold: a.taskId == store.selectedTaskId))
Text(attemptLabel(a))
.font(Fonts.font(11))
.foregroundStyle(stateColor(a.state.rawValue))
if a.discarding {
Text("discarding…").font(Fonts.font(11)).foregroundStyle(Palette.muted)
Text(taskLink(a.taskId, a.title, bold: a.taskId == store.selectedTaskId))
Text(attemptLabel(a))
.font(Fonts.font(11))
.foregroundStyle(stateColor(a.state.rawValue))
if a.discarding {
Text("discarding…").font(Fonts.font(11)).foregroundStyle(Palette.muted)
}
}
}
if let from = a.forkedFrom {
@@ -273,9 +300,11 @@ private struct AttemptRow: View {
.padding(.top, 6)
}
}
.padding(.top, 8)
.padding(.top, solo ? 0 : 8)
.overlay(alignment: .top) {
Rectangle().fill(Palette.border).frame(height: 1)
if !solo {
Rectangle().fill(Palette.border).frame(height: 1)
}
}
}
@@ -299,19 +328,11 @@ private struct AttemptRow: View {
return store.findTask(taskId)?.title ?? taskId
}
private func link(_ taskId: String, _ label: String, bold: Bool = false) -> AttributedString {
var a = AttributedString(label)
a.link = AppLink.task(taskId)
a.foregroundColor = Palette.accent
a.font = Fonts.font(13, weight: bold ? 700 : 400)
return a
}
private func line(_ parts: [(String, String?)]) -> some View {
var out = AttributedString()
for (text, taskId) in parts {
if let taskId {
var a = link(taskId, text)
var a = taskLink(taskId, text)
a.font = Fonts.font(11)
out += a
} else {