import Foundation /// `profile set` — unlike every other filter or edit in the app, `--link` /// replaces the whole set rather than appending, so every link the form /// wants to keep is sent on every save. The form is always seeded from /// the current profile, so every other field is also sent every time, /// including empty ones: `--description ""` clears, omitting the flag /// would leave the old value alone. /// /// The about text is not here. It is a file in `/.gitbay`, written /// through the file editor like any other file. nonisolated struct ProfileEdit: Equatable, Sendable { nonisolated struct Link: Equatable, Sendable, Identifiable { var id = UUID() var label: String var url: String } var description: String var website: String var links: [Link] init(description: String = "", website: String = "", links: [Link] = []) { self.description = description self.website = website self.links = links } init(from profile: ProfileViewModel.Profile) { description = profile.description ?? "" website = profile.website ?? "" links = (profile.links ?? []).map { Link(label: $0.label ?? "", url: $0.url) } } /// At most 5 links and every link needs a URL — the server enforces /// both, but the form should not let a save reach it that way. A /// label may not contain `|` either: the server splits a link on its /// first pipe, so a label carrying one would silently corrupt the URL /// rather than be rejected. var validationError: String? { if links.count > 5 { return "At most 5 links." } if links.contains(where: { $0.url.trimmingCharacters(in: .whitespaces).isEmpty }) { return "A link needs a URL." } if links.contains(where: { $0.label.contains("|") }) { return "A link label can't contain \"|\" — that's what separates it from the URL." } return nil } func flags() -> [String] { var flags = ["--description", description, "--website", website] if links.isEmpty { flags += ["--link", ""] } else { for link in links { let label = link.label.trimmingCharacters(in: .whitespaces) flags += ["--link", label.isEmpty ? link.url : "\(label)|\(link.url)"] } } return flags } }