Add review workflows, tree-shaped workflows and a workflow editor

This commit is contained in:
Ian Gulliver
2026-10-20 18:52:04 -07:00
parent 9869fad988
commit f2188c53eb
31 changed files with 2179 additions and 863 deletions
+51 -11
View File
@@ -1,15 +1,41 @@
import ByreAPI
import SwiftUI
private enum Editing: Equatable {
case none, new, existing(String)
}
struct WorkflowsView: View {
@ViewState private var editing = Editing.none
var body: some View {
switch editing {
case .none:
list
case .new:
WorkflowEditor(original: nil) { editing = .none }
case .existing(let name):
WorkflowEditor(original: name) { editing = .none }
.id(name)
}
}
private var list: some View {
ScrollView {
VStack(alignment: .leading, spacing: 0) {
Text("Workflows run a brief through stages, each its own task. Run asks your lead to start one, so you can add the project and the brief first.")
.foregroundStyle(Palette.muted)
.fixedSize(horizontal: false, vertical: true)
.padding(.top, 16)
WorkflowList()
HStack(alignment: .firstTextBaseline, spacing: 12) {
Text("Workflows run a brief through stages, each its own task. Run asks your lead to start one, so you can add the project and the brief first.")
.foregroundStyle(Palette.muted)
.fixedSize(horizontal: false, vertical: true)
.frame(maxWidth: .infinity, alignment: .leading)
Button("new") {
editing = .new
}
.buttonStyle(SmallLinkButtonStyle())
.help("Write a new workflow")
}
.padding(.top, 16)
WorkflowList { editing = .existing($0) }
}
.padding(.horizontal, 16)
.padding(.top, 8)
@@ -22,6 +48,7 @@ struct WorkflowsView: View {
}
private struct WorkflowList: View {
let edit: (String) -> Void
@Environment(Store.self) private var store
@ViewState private var list: [WorkflowSummary]?
@ViewState private var failure: String?
@@ -35,7 +62,7 @@ private struct WorkflowList: View {
hint("No saved workflows. Ask your lead to write one.")
} else {
ForEach(list.sorted { $0.name.localizedStandardCompare($1.name) == .orderedAscending }, id: \.name) { w in
WorkflowRow(workflow: w)
WorkflowRow(workflow: w) { edit(w.name) }
}
}
} else if let failure {
@@ -81,14 +108,20 @@ private struct WorkflowList: View {
private struct WorkflowRow: View {
let workflow: WorkflowSummary
let edit: () -> Void
@Environment(Store.self) private var store
@Environment(Overlays.self) private var overlays
var body: some View {
HStack(alignment: .firstTextBaseline, spacing: 12) {
VStack(alignment: .leading, spacing: 2) {
Text(workflow.name)
.font(Fonts.font(13, weight: 700))
HStack(alignment: .firstTextBaseline, spacing: 6) {
Text(workflow.name)
.font(Fonts.font(13, weight: 700))
if workflow.kind == .review {
Text("reviews snapshots").font(Fonts.font(11)).foregroundStyle(Palette.muted)
}
}
if !workflow.description.isEmpty {
Text(workflow.description)
.foregroundStyle(Palette.muted)
@@ -97,11 +130,18 @@ private struct WorkflowRow: View {
.textSelection(.enabled)
.frame(maxWidth: .infinity, alignment: .leading)
.fixedSize(horizontal: false, vertical: true)
Button("run") {
run()
Button("edit") {
edit()
}
.buttonStyle(SmallLinkButtonStyle())
.help("Open the Lead tab with a request to run this workflow in its composer")
.help("See and change this workflow's steps and prompts")
if workflow.kind == .task {
Button("run") {
run()
}
.buttonStyle(SmallLinkButtonStyle())
.help("Open the Lead tab with a request to run this workflow in its composer")
}
}
.padding(.vertical, 6)
.overlay(alignment: .top) {