gitbay/Snippets/SnippetListViewModel.swift
65 lines · 2380 bytes
3 symbols in this file
1import Foundation
2import Observation
3
4/// `snippet list` — the caller's own snippets at every visibility, or an
5/// owner's public ones — paginated, plus `snippet create`.
6@Observable
7@MainActor
8final class SnippetListViewModel {
9
10 let list: PagedListModel<Snippet>
11 /// nil lists the caller's own.
12 let owner: String?
13 private(set) var actionError: String?
14 private(set) var working = false
15
16 private let client: GitbayClient
17
18 init(client: GitbayClient, owner: String?) {
19 self.client = client
20 self.owner = owner
21 list = PagedListModel(
22 client: client,
23 argv: ["snippet", "list"] + (owner.map { [$0] } ?? []),
24 emptyMessage: owner == nil
25 ? "No snippets yet. Create one from the + button."
26 : "\(owner ?? "") has no public snippets."
27 )
28 }
29
30 var state: LoadState<[Snippet]> { list.state }
31
32 func load() async {
33 await list.reload()
34 }
35
36 /// `snippet create <filename> [--description <d>] [--visibility <v>]
37 /// < file` — the file is bare stdin. An empty description sends no
38 /// flag. Returns the created snippet, or nil with `actionError` set.
39 func create(filename: String, description: String, visibility: String, content: String) async -> Snippet? {
40 var argv = ["snippet", "create", filename.trimmingCharacters(in: .whitespaces)]
41 let description = description.trimmingCharacters(in: .whitespacesAndNewlines)
42 if !description.isEmpty { argv += ["--description", description] }
43 argv += ["--visibility", visibility]
44 working = true
45 actionError = nil
46 defer { working = false }
47 do {
48 let created = try await client.run(argv, stdin: content, as: Snippet.self)
49 await list.reload()
50 return created
51 } catch let error as GitbayError {
52 // Exit 2 here is the server validating the file name, the
53 // size or the per-account cap — written for the person.
54 if case .usage(let message) = error, !message.isEmpty {
55 actionError = message
56 } else {
57 actionError = error.userFacingMessage
58 }
59 return nil
60 } catch {
61 actionError = GitbayError.transport(error).userFacingMessage
62 return nil
63 }
64 }
65}