Build log: jump to failure opens at the failed step's start !149

merged merged by cmc on 2026-09-30 03:58 UTC · krz/gitbay-ios:jump-to-failed-step into main

1 file changed, +11 −3

Layout: unified · split

gitbay/Views/Builds/BuildDetailView.swift +11 −3
@@ -243,7 +243,8 @@ struct BuildDetailView: View {
243 isOpenByDefault(section, in: detail) != toggled.contains(section.n) 243 isOpenByDefault(section, in: detail) != toggled.contains(section.n)
244 } 244 }
245 245
246 /// To the end of the failed step, where its error is, or of the log. 246 /// To the top of the failed step, so its output reads from the start,
247 /// or to the last line of the log.
247 private func scroll(to target: Jump, in detail: BuildDetail, proxy: ScrollViewProxy) { 248 private func scroll(to target: Jump, in detail: BuildDetail, proxy: ScrollViewProxy) {
248 let log = detail.lines 249 let log = detail.lines
249 let index = target == .failure ? log.failed : log.sections.indices.last 250 let index = target == .failure ? log.failed : log.sections.indices.last
@@ -251,10 +252,17 @@ struct BuildDetailView: View {
251 let section = log.sections[index] 252 let section = log.sections[index]
252 query = "" 253 query = ""
253 if !isOpen(section, in: detail) { toggled.formSymmetricDifference([section.n]) } 254 if !isOpen(section, in: detail) { toggled.formSymmetricDifference([section.n]) }
254 let anchor: AnyHashable = section.lines.last.map { AnyHashable($0.id) } ?? AnyHashable("step-\(section.n)") 255 // An unstepped log has no headers; its top is the first line.
256 let step: AnyHashable = log.stepped || section.lines.isEmpty
257 ? AnyHashable("step-\(section.n)") : AnyHashable(section.lines[0].id)
258 let last: AnyHashable = section.lines.last.map { AnyHashable($0.id) } ?? step
255 // Let the opened section lay out before scrolling into it. 259 // Let the opened section lay out before scrolling into it.
256 Task { @MainActor in 260 Task { @MainActor in
257 proxy.scrollTo(anchor, anchor: .bottom) 261 if target == .failure {
262 proxy.scrollTo(step, anchor: .top)
263 } else {
264 proxy.scrollTo(last, anchor: .bottom)
265 }
258 } 266 }
259 } 267 }
260} 268}