import Foundation import Observation /// The repo settings screen: `repo settings show` for the admin knobs, /// `repo show` for description/topics/visibility, and one write command /// per control. Non-admins get the server's refusal verbatim. @Observable @MainActor final class RepoSettingsViewModel { nonisolated struct Loaded: Sendable, Hashable { let settings: RepoSettings let detail: RepoDetail } private(set) var state: LoadState = .loading private(set) var actionError: String? private(set) var working = false private let client: GitbayClient let repoPath: String init(client: GitbayClient, repoPath: String) { self.client = client self.repoPath = repoPath } func load() async { do { async let settings = client.read( ["repo", "settings", "show", repoPath], as: RepoSettings.self) async let detail = client.read(["repo", "show", repoPath], as: RepoDetail.self) state = .loaded(Loaded(settings: try await settings, detail: try await detail)) } catch { state = .from(error) } } // MARK: - Writes, one command per knob func setDescription(_ text: String) async { await perform(["repo", "settings", "description", repoPath, text]) } func setWebsite(_ url: String) async { await perform(["repo", "settings", "website", repoPath, url]) } func setVisibility(_ visibility: String) async { await perform(["repo", "settings", "visibility", repoPath, visibility]) } func setGitDaemon(_ on: Bool) async { await perform(["repo", "settings", "git-daemon", repoPath, on ? "on" : "off"]) } func protectBranch(_ branch: String) async { await perform(["repo", "settings", "protect", repoPath, branch]) } func unprotectBranch(_ branch: String) async { await perform(["repo", "settings", "unprotect", repoPath, branch]) } func setRequireApprovals(_ count: Int) async { await perform(["repo", "settings", "require-approvals", repoPath, String(count)]) } func setRequireResolved(_ on: Bool) async { await perform(["repo", "settings", "require-resolved", repoPath, on ? "on" : "off"]) } func setRequireChecks(_ on: Bool) async { await perform(["repo", "settings", "require-checks", repoPath, on ? "on" : "off"]) } func setRequireSigned(_ on: Bool) async { await perform(["repo", "settings", "require-signed", repoPath, on ? "on" : "off"]) } func addTopic(_ topic: String) async { await perform(["repo", "topics", "add", repoPath, topic]) } func removeTopic(_ topic: String) async { await perform(["repo", "topics", "remove", repoPath, topic]) } private func perform(_ argv: [String]) async { working = true actionError = nil defer { working = false } do { try await client.run(argv) await load() } catch let error as GitbayError { actionError = error.userFacingMessage } catch { actionError = GitbayError.transport(error).userFacingMessage } } }