Three pre-existing spots used count == 1 ? "" : "s" instead of the inflect syntax CLAUDE.md documents: GitSyncManualFixSheet's step() helper (also switched String -> LocalizedStringKey, another documented anti-pattern), PaperlessService.testConnection(), and AnytypeMCPService.testConnection().
109 lines
4.1 KiB
Swift
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 ^[\(files.count) file](inflect: true) 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: LocalizedStringKey) -> 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)
|
|
}
|
|
}
|
|
}
|