import Foundation import Observation /// `snippet list` — the caller's own snippets at every visibility, or an /// owner's public ones — paginated, plus `snippet create`. @Observable @MainActor final class SnippetListViewModel { let list: PagedListModel /// nil lists the caller's own. let owner: String? private(set) var actionError: String? private(set) var working = false private let client: GitbayClient init(client: GitbayClient, owner: String?) { self.client = client self.owner = owner list = PagedListModel( client: client, argv: ["snippet", "list"] + (owner.map { [$0] } ?? []), emptyMessage: owner == nil ? "No snippets yet. Create one from the + button." : "\(owner ?? "") has no public snippets." ) } var state: LoadState<[Snippet]> { list.state } func load() async { await list.reload() } /// `snippet create [--description ] [--visibility ] /// < file` — the file is bare stdin. An empty description sends no /// flag. Returns the created snippet, or nil with `actionError` set. func create(filename: String, description: String, visibility: String, content: String) async -> Snippet? { var argv = ["snippet", "create", filename.trimmingCharacters(in: .whitespaces)] let description = description.trimmingCharacters(in: .whitespacesAndNewlines) if !description.isEmpty { argv += ["--description", description] } argv += ["--visibility", visibility] working = true actionError = nil defer { working = false } do { let created = try await client.run(argv, stdin: content, as: Snippet.self) await list.reload() return created } catch let error as GitbayError { // Exit 2 here is the server validating the file name, the // size or the per-account cap — written for the person. if case .usage(let message) = error, !message.isEmpty { actionError = message } else { actionError = error.userFacingMessage } return nil } catch { actionError = GitbayError.transport(error).userFacingMessage return nil } } }