macOS client parity review
This commit is contained in:
+56
-31
@@ -210,9 +210,10 @@ final class ChatModel {
|
||||
}
|
||||
store.jump = nil
|
||||
stuck = false
|
||||
if i > 0, case .agent = rows[i - 1].kind {
|
||||
switch i > 0 ? rows[i - 1].kind : nil {
|
||||
case .agent, .subagentMessage:
|
||||
requestScroll(rows[i - 1].id, .top)
|
||||
} else {
|
||||
default:
|
||||
requestScroll(rows[i].id, .bottom)
|
||||
}
|
||||
}
|
||||
@@ -528,12 +529,15 @@ private struct TranscriptScroll: View {
|
||||
ForEach(model.builder.pending) { p in
|
||||
PendingView(pending: p)
|
||||
}
|
||||
if running {
|
||||
Scanner(color: accent)
|
||||
}
|
||||
}
|
||||
}
|
||||
.scrollTargetLayout()
|
||||
.overlay(alignment: .bottomLeading) {
|
||||
if running && model.key != nil {
|
||||
Scanner(color: accent)
|
||||
.offset(y: 8)
|
||||
}
|
||||
}
|
||||
.padding(16)
|
||||
}
|
||||
.scrollPosition($position)
|
||||
@@ -555,7 +559,10 @@ private struct TranscriptScroll: View {
|
||||
scrollLog.notice("phase \(String(describing: old), privacy: .public) -> \(String(describing: phase), privacy: .public)")
|
||||
scrolling = phase.isScrolling
|
||||
}
|
||||
.onChange(of: model.builder.pending.count) {
|
||||
.onChange(of: model.builder.pending.last?.id) { old, new in
|
||||
guard let new, new > old ?? 0 else {
|
||||
return
|
||||
}
|
||||
scrollLog.notice("pending scrollTo bottom")
|
||||
model.stuck = true
|
||||
position.scrollTo(edge: .bottom)
|
||||
@@ -631,6 +638,7 @@ struct DetailsBox<Summary: View, Content: View>: View {
|
||||
var boxed = true
|
||||
var nested = false
|
||||
var working = false
|
||||
var status: (text: String, color: Color)? = nil
|
||||
@ViewBuilder let summary: Summary
|
||||
@ViewBuilder let content: Content
|
||||
@Environment(\.paneAccent) private var accent
|
||||
@@ -651,6 +659,12 @@ struct DetailsBox<Summary: View, Content: View>: View {
|
||||
.padding(.leading, 4)
|
||||
}
|
||||
Spacer(minLength: 0)
|
||||
if let status {
|
||||
Text(status.text)
|
||||
.font(Fonts.font(12))
|
||||
.foregroundStyle(status.color)
|
||||
.padding(.leading, 12)
|
||||
}
|
||||
}
|
||||
.contentShape(Rectangle())
|
||||
}
|
||||
@@ -738,8 +752,8 @@ struct RowView: View {
|
||||
|
||||
case .byrePrompt(let brief, let when, let blocks):
|
||||
DetailsBox(nested: nested) {
|
||||
Text("byre").font(Fonts.font(12, weight: 600))
|
||||
Text(brief).font(Fonts.font(12)).foregroundStyle(Palette.muted).lineLimit(1)
|
||||
Text(styled([("byre", 600, nil), (" ", 400, nil), (brief, 400, Palette.muted)]))
|
||||
.fixedSize(horizontal: false, vertical: true)
|
||||
Spacer(minLength: 12)
|
||||
WhenText(when: when).font(Fonts.font(12)).foregroundStyle(Palette.muted)
|
||||
} content: {
|
||||
@@ -790,13 +804,9 @@ struct RowView: View {
|
||||
}
|
||||
|
||||
case .subagent(let title, let description, let prompt):
|
||||
DetailsBox(nested: nested, working: model.working(row)) {
|
||||
DetailsBox(nested: nested, working: model.working(row), status: (row.status, row.statusState == .done ? Palette.muted : row.statusState == .error ? Palette.danger : Palette.accent)) {
|
||||
SubagentTag(show: row.tag)
|
||||
Text(styled([(title, 600, nil), (" ", 400, nil), (description, 400, Palette.muted)]))
|
||||
Spacer(minLength: 12)
|
||||
Text(row.status)
|
||||
.font(Fonts.font(12))
|
||||
.foregroundStyle(row.statusState == .done ? Palette.muted : row.statusState == .error ? Palette.danger : Palette.accent)
|
||||
} content: {
|
||||
VStack(alignment: .leading, spacing: 6) {
|
||||
MarkdownView(blocks: prompt, ctx: md)
|
||||
@@ -1014,10 +1024,11 @@ private struct SnapshotRow: View {
|
||||
let taskId: String?
|
||||
@Environment(Store.self) private var store
|
||||
@Environment(Overlays.self) private var overlays
|
||||
@Environment(\.paneAccent) private var accent
|
||||
@ViewState private var forking = false
|
||||
|
||||
var body: some View {
|
||||
let time = snap.createdAt.formatted(Date.FormatStyle().hour(.twoDigits(amPM: .omitted)).minute(.twoDigits).second(.twoDigits))
|
||||
let time = clockText(snap.createdAt)
|
||||
HStack(spacing: 8) {
|
||||
Rectangle().fill(Palette.border).frame(height: 1)
|
||||
Text("snapshot #\(snap.n)")
|
||||
@@ -1058,26 +1069,40 @@ private struct SnapshotRow: View {
|
||||
return Button {
|
||||
store.showReview(snap.n)
|
||||
} label: {
|
||||
HStack(spacing: 2) {
|
||||
Text("review")
|
||||
.font(Fonts.font(11, weight: n > 0 ? 700 : 400))
|
||||
if let review {
|
||||
switch review.state {
|
||||
case .running:
|
||||
Spinner(color: Palette.accent).font(Fonts.font(10)).help("review in progress")
|
||||
case .failed:
|
||||
EmptyView()
|
||||
case .skipped:
|
||||
Text("●").font(Fonts.font(11, weight: 700)).foregroundStyle(Palette.muted).help("skipped: no changes")
|
||||
case .done:
|
||||
if n == 0 {
|
||||
Text("✓").font(Fonts.font(11, weight: 700)).foregroundStyle(Palette.ok).help(review.findingStates.additionalProperties.isEmpty ? "no findings" : "every finding addressed")
|
||||
} else {
|
||||
Badge(count: n).help("\(n) open findings")
|
||||
Text("review")
|
||||
.font(Fonts.font(11, weight: n > 0 ? 700 : 400))
|
||||
.overlay(alignment: .topTrailing) {
|
||||
if let review {
|
||||
switch review.state {
|
||||
case .running:
|
||||
Spinner(color: accent).font(Fonts.font(10)).help("review in progress")
|
||||
.fixedSize()
|
||||
.offset(x: 13, y: -4)
|
||||
case .failed:
|
||||
EmptyView()
|
||||
case .skipped:
|
||||
Text("●").font(Fonts.font(11, weight: 700)).foregroundStyle(Palette.muted).help("skipped: no changes")
|
||||
.fixedSize()
|
||||
.offset(x: 13, y: -7)
|
||||
case .done:
|
||||
if n == 0 {
|
||||
Text("✓").font(Fonts.font(11, weight: 700)).foregroundStyle(Palette.ok).help(review.findingStates.additionalProperties.isEmpty ? "no findings" : "every finding addressed")
|
||||
.fixedSize()
|
||||
.offset(x: 13, y: -7)
|
||||
} else {
|
||||
Text("\(n)")
|
||||
.font(Fonts.font(10, weight: 700))
|
||||
.foregroundStyle(Palette.danger)
|
||||
.frame(height: 14)
|
||||
.padding(.horizontal, 5)
|
||||
.background(Palette.dangerTint, in: Capsule())
|
||||
.help("\(n) open findings")
|
||||
.fixedSize()
|
||||
.offset(x: 15, y: -9)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.buttonStyle(SmallLinkButtonStyle(color: n > 0 ? Palette.warn : Palette.accent))
|
||||
.help("Show the review of snapshot \(snap.n) in the Reviews tab")
|
||||
|
||||
Reference in New Issue
Block a user