Paste and drop images into every box that talks to an agent
This commit is contained in:
@@ -261,7 +261,7 @@ private struct ChangesHead: View {
|
||||
}
|
||||
Spacer(minLength: 0)
|
||||
if let taskId = store.selectedTaskId, let drafts = store.drafts {
|
||||
let n = drafts.lineComments(taskId).filter { !trimmed($0.text).isEmpty }.count
|
||||
let n = drafts.lineComments(taskId).filter(lineCommentReady(store.images, taskId)).count
|
||||
if n > 0 {
|
||||
Button("Send \(n) \(n == 1 ? "comment" : "comments")") {
|
||||
sendComments(taskId, drafts)
|
||||
@@ -277,12 +277,18 @@ private struct ChangesHead: View {
|
||||
}
|
||||
|
||||
private func sendComments(_ taskId: String, _ drafts: Drafts) {
|
||||
let sent = drafts.takeLineComments(taskId)
|
||||
let sent = drafts.takeLineComments(taskId, ready: lineCommentReady(store.images, taskId))
|
||||
let keys = sent.map { lineCommentImageKey(taskId, $0.anchor) }
|
||||
let imgs = keys.map { store.images.take($0) }
|
||||
Task {
|
||||
do {
|
||||
try await store.messageTask(taskId, commentsMessage(sent))
|
||||
let ids = try await uploadImages(store.api, imgs.flatMap { $0 })
|
||||
try await store.messageTask(taskId, commentsMessage(sent, imgs.map(\.count)), images: ids)
|
||||
} catch {
|
||||
drafts.restoreLineComments(taskId, sent)
|
||||
for (key, i) in zip(keys, imgs) {
|
||||
store.images.restore(key, i)
|
||||
}
|
||||
overlays.showAlert(errorText(error))
|
||||
}
|
||||
}
|
||||
@@ -530,9 +536,21 @@ private func patchRows(_ lines: ArraySlice<String>, _ path: String) -> [DiffRow]
|
||||
}
|
||||
}
|
||||
|
||||
func commentsMessage(_ comments: [LineComment]) -> String {
|
||||
comments.map { c in
|
||||
"`\(c.anchor.path):\(c.anchor.line)`\(c.anchor.old ? " (removed line)" : "")\n> \(c.anchor.quote)\n\n\(trimmed(c.text))"
|
||||
func lineCommentImageKey(_ taskId: String, _ anchor: LineAnchor) -> String {
|
||||
"comment:\(taskId):\(anchor.path):\(anchor.line):\(anchor.old):\(anchor.quote)"
|
||||
}
|
||||
|
||||
@MainActor
|
||||
func lineCommentReady(_ images: ImageDrafts, _ taskId: String) -> (LineComment) -> Bool {
|
||||
{ c in !trimmed(c.text).isEmpty || images.has(lineCommentImageKey(taskId, c.anchor)) }
|
||||
}
|
||||
|
||||
func commentsMessage(_ comments: [LineComment], _ imageCounts: [Int]) -> String {
|
||||
var first = 1
|
||||
return zip(comments, imageCounts).map { c, n in
|
||||
let attached = n == 0 ? "" : n == 1 ? "(image \(first) attached)" : "(images \(first)–\(first + n - 1) attached)"
|
||||
first += n
|
||||
return ["`\(c.anchor.path):\(c.anchor.line)`\(c.anchor.old ? " (removed line)" : "")\n> \(c.anchor.quote)", trimmed(c.text), attached].filter { !$0.isEmpty }.joined(separator: "\n\n")
|
||||
}.joined(separator: "\n\n")
|
||||
}
|
||||
|
||||
@@ -576,7 +594,7 @@ struct DiffLines: View {
|
||||
let comment = drafts.lineComment(taskId, anchor)
|
||||
DiffLineRow(row: row, mark: comment != nil, hoverable: true)
|
||||
.simultaneousGesture(TapGesture().onEnded {
|
||||
drafts.toggleLineComment(taskId, anchor)
|
||||
drafts.toggleLineComment(taskId, anchor, ready: lineCommentReady(store.images, taskId))
|
||||
})
|
||||
if comment != nil {
|
||||
LineCommentBox(drafts: drafts, taskId: taskId, anchor: anchor)
|
||||
@@ -642,11 +660,15 @@ private struct LineCommentBox: View {
|
||||
let drafts: Drafts
|
||||
let taskId: String
|
||||
let anchor: LineAnchor
|
||||
@Environment(Store.self) private var store
|
||||
@FocusState private var focused: Bool
|
||||
|
||||
var body: some View {
|
||||
let text = Binding(get: { drafts.lineComment(taskId, anchor)?.text ?? "" }, set: { drafts.setLineComment(taskId, anchor, $0) })
|
||||
let key = lineCommentImageKey(taskId, anchor)
|
||||
VStack(alignment: .trailing, spacing: 4) {
|
||||
Thumbnails(key: key)
|
||||
.frame(maxWidth: .infinity, alignment: .leading)
|
||||
TextEditor(text: text)
|
||||
.font(Fonts.font(12))
|
||||
.scrollContentBackground(.hidden)
|
||||
@@ -666,7 +688,9 @@ private struct LineCommentBox: View {
|
||||
}
|
||||
}
|
||||
.overlay(RoundedRectangle(cornerRadius: 6).stroke(focused ? Palette.accent : Palette.border))
|
||||
.imageInput(key)
|
||||
Button("remove") {
|
||||
_ = store.images.take(key)
|
||||
drafts.dropLineComment(taskId, anchor)
|
||||
}
|
||||
.buttonStyle(SmallLinkButtonStyle())
|
||||
|
||||
Reference in New Issue
Block a user