mirror of
https://github.com/multica-ai/multica.git
synced 2026-07-15 14:19:13 +02:00
SwiftUI app (iOS 17+) with zero third-party dependencies: - Passwordless email authentication with Keychain token storage - Workspace selection and multi-workspace support - Issue list grouped by status with search and filtering - Issue detail with inline status/priority/assignee editing - Comments with threaded display and compose - Agent task runs history and real-time execution log streaming - WebSocket integration for live updates
64 lines
1.8 KiB
Swift
64 lines
1.8 KiB
Swift
import Foundation
|
|
|
|
@MainActor
|
|
@Observable
|
|
final class IssueListViewModel {
|
|
var issues: [Issue] = []
|
|
var isLoading = false
|
|
var error: String?
|
|
var statusFilter: IssueStatus?
|
|
var searchText = ""
|
|
|
|
var filteredIssues: [Issue] {
|
|
var result = issues
|
|
if let statusFilter {
|
|
result = result.filter { $0.status == statusFilter }
|
|
}
|
|
if !searchText.isEmpty {
|
|
result = result.filter {
|
|
$0.title.localizedCaseInsensitiveContains(searchText) ||
|
|
$0.identifier.localizedCaseInsensitiveContains(searchText)
|
|
}
|
|
}
|
|
return result
|
|
}
|
|
|
|
// Group issues by status for sectioned display
|
|
var issuesByStatus: [(IssueStatus, [Issue])] {
|
|
let grouped = Dictionary(grouping: filteredIssues, by: \.status)
|
|
let order: [IssueStatus] = [.inProgress, .todo, .inReview, .blocked, .backlog, .done, .cancelled]
|
|
return order.compactMap { status in
|
|
guard let issues = grouped[status], !issues.isEmpty else { return nil }
|
|
return (status, issues)
|
|
}
|
|
}
|
|
|
|
func loadIssues() async {
|
|
isLoading = true
|
|
error = nil
|
|
do {
|
|
issues = try await APIClient.shared.listIssues()
|
|
} catch {
|
|
self.error = error.localizedDescription
|
|
}
|
|
isLoading = false
|
|
}
|
|
|
|
func refresh() async {
|
|
do {
|
|
issues = try await APIClient.shared.listIssues()
|
|
} catch {
|
|
self.error = error.localizedDescription
|
|
}
|
|
}
|
|
|
|
func deleteIssue(_ issue: Issue) async {
|
|
do {
|
|
try await APIClient.shared.deleteIssue(issue.id)
|
|
issues.removeAll { $0.id == issue.id }
|
|
} catch {
|
|
self.error = error.localizedDescription
|
|
}
|
|
}
|
|
}
|