import Foundation import Observation /// `snippet show ` with every file's content, plus the writes an /// owner has: `snippet edit`, `snippet file set`, `snippet file remove` /// and `snippet delete`. @Observable @MainActor final class SnippetDetailViewModel { private(set) var state: LoadState = .loading private(set) var actionError: String? private(set) var working = false private let client: GitbayClient let id: String init(client: GitbayClient, id: String) { self.client = client self.id = id } func load() async { do { state = .loaded(try await client.read(["snippet", "show", id], as: Snippet.self)) } catch { state = .from(error) } } /// `snippet edit [--description ] [--visibility ]`: a nil /// field is left as it is. An empty description clears it. func edit(description: String?, visibility: String?) async { var argv = ["snippet", "edit", id] if let description { argv += ["--description", description] } if let visibility { argv += ["--visibility", visibility] } await perform(argv) } /// `snippet file set < file`: adds the file or /// replaces its content. func setFile(_ name: String, content: String) async { await perform(["snippet", "file", "set", id, name.trimmingCharacters(in: .whitespaces)], stdin: content) } func removeFile(_ name: String) async { await perform(["snippet", "file", "remove", id, name]) } /// `snippet delete `. There is nothing to reload afterwards; the /// screen pops on true. func delete() async -> Bool { working = true actionError = nil defer { working = false } do { try await client.run(["snippet", "delete", id]) return true } catch let error as GitbayError { actionError = error.userFacingMessage return false } catch { actionError = GitbayError.transport(error).userFacingMessage return false } } 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 { if case .usage(let message) = error, !message.isEmpty { actionError = message } else { actionError = error.userFacingMessage } } catch { actionError = GitbayError.transport(error).userFacingMessage } } }