88 lines
2.8 KiB
Swift
88 lines
2.8 KiB
Swift
import Foundation
|
|
|
|
@MainActor
|
|
final class FleetViewModel: ObservableObject {
|
|
struct Row: Equatable, Identifiable {
|
|
let id: UUID
|
|
var instance: Instance
|
|
var status: ConnectionStatus
|
|
var testing: Bool
|
|
}
|
|
|
|
@Published var rows: [Row] = []
|
|
@Published var searchText = ""
|
|
@Published var selectedIDs: Set<UUID> = []
|
|
@Published var selectionMode = false
|
|
@Published var isLoading = false
|
|
@Published var errorMessage: String?
|
|
@Published var showingForm = false
|
|
|
|
private let repository: any InstanceRepository
|
|
private let probe: ConnectionProbe
|
|
private let credentials: any CredentialStore
|
|
|
|
init(
|
|
repository: any InstanceRepository,
|
|
probe: ConnectionProbe,
|
|
credentials: any CredentialStore
|
|
) {
|
|
self.repository = repository
|
|
self.probe = probe
|
|
self.credentials = credentials
|
|
}
|
|
|
|
func refresh() async {
|
|
isLoading = true
|
|
errorMessage = nil
|
|
do {
|
|
let query = InstanceQuery(search: searchText.isEmpty ? nil : searchText)
|
|
let instances = try await repository.list(query)
|
|
rows = instances.map {
|
|
Row(id: $0.id, instance: $0, status: .unknown, testing: true)
|
|
}
|
|
await withTaskGroup(of: Void.self) { group in
|
|
for instance in instances {
|
|
group.addTask { [probe] in
|
|
let result = try? await probe.test(instance)
|
|
await self.applyProbe(instance.id, result)
|
|
}
|
|
}
|
|
}
|
|
} catch {
|
|
errorMessage = "无法刷新节点列表"
|
|
}
|
|
isLoading = false
|
|
}
|
|
|
|
func add(_ input: InstanceInput) async throws {
|
|
let created = try await repository.create(input)
|
|
if let password = input.password, !password.isEmpty {
|
|
try credentials.set(instanceID: created.id, password: password)
|
|
}
|
|
showingForm = false
|
|
await refresh()
|
|
}
|
|
|
|
func delete(_ ids: [UUID]) async {
|
|
for id in ids {
|
|
if let row = rows.first(where: { $0.id == id }) {
|
|
do {
|
|
try await repository.delete(id, expectedRevision: row.instance.configRevision)
|
|
try credentials.remove(instanceID: id)
|
|
} catch {
|
|
errorMessage = "删除 \(row.instance.name) 失败"
|
|
}
|
|
}
|
|
}
|
|
selectedIDs.removeAll()
|
|
selectionMode = false
|
|
await refresh()
|
|
}
|
|
|
|
private func applyProbe(_ id: UUID, _ result: ConnectionResult?) {
|
|
guard let index = rows.firstIndex(where: { $0.id == id }) else { return }
|
|
rows[index].status = result?.status ?? .unknown
|
|
rows[index].testing = false
|
|
}
|
|
}
|