import Foundation import Observation /// `webhook list`, `webhook add` and `webhook remove` for one repository. @Observable @MainActor final class WebhookListViewModel { private(set) var state: LoadState<[Webhook]> = .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 { state = .loading do { let hooks = try await client.readList(["webhook", "list", repoPath], of: Webhook.self) state = hooks.isEmpty ? .empty("No webhooks yet.") : .loaded(hooks) } catch { state = .from(error) } } /// `webhook add [--secret -] [--events ]` — an empty /// secret or event list is left out, so the server applies its default. /// The secret travels on stdin; the server refuses it in argv. func add(url: String, secret: String, events: String) async -> Bool { let url = url.trimmingCharacters(in: .whitespaces) guard !url.isEmpty else { return false } var argv = ["webhook", "add", repoPath, url] let secret = secret.trimmingCharacters(in: .whitespaces) if !secret.isEmpty { argv += ["--secret", "-"] } let events = events.trimmingCharacters(in: .whitespaces) if !events.isEmpty { argv += ["--events", events] } await perform(argv, stdin: secret.isEmpty ? nil : secret + "\n") return actionError == nil } func remove(id: Int64) async { await perform(["webhook", "remove", repoPath, String(id)]) } private func perform(_ argv: [String], stdin: String? = nil) async { working = true actionError = nil defer { working = false } do { try await client.run(argv, stdin: stdin) await load() } catch let error as GitbayError { actionError = error.userFacingMessage } catch { actionError = GitbayError.transport(error).userFacingMessage } } } /// `webhook deliveries` and `webhook redeliver`. @Observable @MainActor final class WebhookDeliveriesViewModel { private(set) var state: LoadState<[WebhookDelivery]> = .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 { state = .loading do { let rows = try await client.readList( ["webhook", "deliveries", repoPath], of: WebhookDelivery.self) state = rows.isEmpty ? .empty("No deliveries yet.") : .loaded(rows) } catch { state = .from(error) } } func redeliver(id: Int64) async { working = true actionError = nil defer { working = false } do { try await client.run(["webhook", "redeliver", repoPath, String(id)]) await load() } catch let error as GitbayError { actionError = error.userFacingMessage } catch { actionError = GitbayError.transport(error).userFacingMessage } } }