import Foundation import Observation /// `wiki list` — the pages, and which one is the landing page. nonisolated struct WikiListing: Decodable, Sendable, Hashable { let path: String let home: String? let pages: [String] } /// `wiki show` — one page's source. Rendered by format, as a README is. nonisolated struct WikiPage: Decodable, Sendable, Hashable { let path: String let page: String let file: String let size: Int let binary: Bool? let content: String? var isBinary: Bool { binary ?? false } } /// A repository's wiki. The pages live in a companion repo and are /// edited by pushing to it, so this is a reading surface only — the /// same write interface every surface has. @Observable @MainActor final class WikiViewModel { private(set) var state: LoadState = .loading private let client: GitbayClient let repoPath: String init(client: GitbayClient, repoPath: String) { self.client = client self.repoPath = repoPath } func load() async { do { let listing = try await client.read( ["wiki", "list", repoPath], as: WikiListing.self) state = listing.pages.isEmpty ? .empty("This wiki has no pages yet.") : .loaded(listing) } catch { state = .from(error) } } } /// One wiki page. @Observable @MainActor final class WikiPageViewModel { private(set) var state: LoadState = .loading private let client: GitbayClient let repoPath: String let page: String init(client: GitbayClient, repoPath: String, page: String) { self.client = client self.repoPath = repoPath self.page = page } func load() async { do { state = .loaded(try await client.read( ["wiki", "show", repoPath, page], as: WikiPage.self)) } catch { state = .from(error) } } }