Files
oai-swift/oAI/Views/Screens/GitSyncManualFixSheet.swift
T
rune e2284aba2b Show manual sync-conflict fix instructions in-app instead of deep-linking to Help
NSWorkspace.shared.open() silently drops #fragment anchors on file://
URLs, so "Fix It Myself" always landed on the Help Book index instead
of the relevant section. Replaced with GitSyncManualFixSheet, an
in-app sheet showing the real conflicting filenames and sync path.

Also indent conversation rows one level deeper than their containing
folder in the sidebar and conversation list, so nesting is visible on
the conversations themselves and not just the folder headers.
2026-08-04 12:21:15 +02:00

109 lines
4.1 KiB
Swift

//
// GitSyncManualFixSheet.swift
// Confab
//
// Manual-fix instructions for Git Sync's "untracked working tree files" pull failure —
// shown in-app instead of deep-linking to the Help Book (NSWorkspace.shared.open() drops
// #fragment anchors on file:// URLs, so an anchored help link always landed on the index).
//
// SPDX-License-Identifier: PolyForm-Noncommercial-1.0.0
// Copyright (C) 2026 Rune Olsen
//
// This file is part of Confab.
//
// Confab is licensed under the PolyForm Noncommercial License 1.0.0.
// You may use, study, modify, and share it for any noncommercial
// purpose. Commercial use — including selling Confab or any part of
// it, standalone or bundled into another product or service —
// requires a separate commercial license from the copyright holder.
//
// See the LICENSE file or
// <https://polyformproject.org/licenses/noncommercial/1.0.0> for
// the full license text. For commercial licensing, contact Rune
// Olsen via <https://confab.no>.
import SwiftUI
struct GitSyncManualFixSheet: View {
let files: [String]
let syncPath: String
let onDone: () -> Void
var body: some View {
VStack(alignment: .leading, spacing: 20) {
HStack(spacing: 12) {
Image(systemName: "wrench.and.screwdriver")
.font(.title2)
.foregroundStyle(.secondary)
VStack(alignment: .leading, spacing: 2) {
Text("Fix It Yourself")
.font(.system(size: 17, weight: .semibold))
Text("Four steps, then Confab takes over again")
.font(.system(size: 13))
.foregroundStyle(.secondary)
}
Spacer()
}
VStack(alignment: .leading, spacing: 14) {
step(1, "Open your sync folder:")
Text(syncPath)
.font(.system(size: 13, design: .monospaced))
.textSelection(.enabled)
.padding(10)
.frame(maxWidth: .infinity, alignment: .leading)
.background(Color.secondary.opacity(0.08))
.clipShape(RoundedRectangle(cornerRadius: 8))
step(2, "Delete the file\(files.count == 1 ? "" : "s") named in the error:")
VStack(alignment: .leading, spacing: 4) {
ForEach(files, id: \.self) { file in
Text(file)
.font(.system(size: 13, design: .monospaced))
}
}
.textSelection(.enabled)
.padding(10)
.frame(maxWidth: .infinity, alignment: .leading)
.background(Color.secondary.opacity(0.08))
.clipShape(RoundedRectangle(cornerRadius: 8))
step(3, "Open Terminal, cd into that folder, and run this once:")
Text("git pull --ff-only")
.font(.system(size: 13, design: .monospaced))
.textSelection(.enabled)
.padding(10)
.frame(maxWidth: .infinity, alignment: .leading)
.background(Color.secondary.opacity(0.08))
.clipShape(RoundedRectangle(cornerRadius: 8))
step(4, "That's it — Confab will regenerate the file correctly on its next sync.")
}
HStack {
Spacer()
Button("Done") {
onDone()
}
.buttonStyle(.borderedProminent)
.keyboardShortcut(.return, modifiers: [])
}
}
.padding(24)
.frame(width: 480)
}
@ViewBuilder
private func step(_ number: Int, _ text: String) -> some View {
HStack(alignment: .firstTextBaseline, spacing: 8) {
Text("\(number).")
.font(.system(size: 13, weight: .semibold))
.foregroundStyle(.secondary)
Text(text)
.font(.system(size: 13))
.fixedSize(horizontal: false, vertical: true)
}
}
}