Fixed Issue view
This commit is contained in:
@ -180,6 +180,8 @@ class GiteaAPIService: ObservableObject {
|
||||
if let state = state {
|
||||
queryParams += "&state=\(state.rawValue)"
|
||||
}
|
||||
// Add type parameter to filter only issues (not pull requests)
|
||||
queryParams += "&type=issues"
|
||||
|
||||
guard let request = createRequest(endpoint: "/repos/\(owner)/\(repo)/issues" + queryParams)
|
||||
else {
|
||||
@ -270,10 +272,15 @@ class GiteaAPIService: ObservableObject {
|
||||
return try await performRequest(request, responseType: Repository.self)
|
||||
}
|
||||
|
||||
func updateRepository(owner: String, repo: String, updateData: [String: Any]) async throws -> Repository {
|
||||
func updateRepository(owner: String, repo: String, updateData: [String: Any]) async throws
|
||||
-> Repository
|
||||
{
|
||||
// Encode the dictionary to JSON data
|
||||
let jsonData = try JSONSerialization.data(withJSONObject: updateData)
|
||||
guard let request = createRequest(endpoint: "/repos/\(owner)/\(repo)", method: .PATCH, body: jsonData) else {
|
||||
guard
|
||||
let request = createRequest(
|
||||
endpoint: "/repos/\(owner)/\(repo)", method: .PATCH, body: jsonData)
|
||||
else {
|
||||
throw APIError.invalidURL
|
||||
}
|
||||
return try await performRequest(request, responseType: Repository.self)
|
||||
@ -692,4 +699,3 @@ enum APIError: LocalizedError {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -178,6 +178,19 @@ struct ExternalWiki: Codable, Equatable {
|
||||
}
|
||||
|
||||
// MARK: - Issue
|
||||
// MARK: - Issue Repository (simplified for issue responses)
|
||||
struct IssueRepository: Codable {
|
||||
let id: Int
|
||||
let name: String
|
||||
let owner: String
|
||||
let fullName: String
|
||||
|
||||
enum CodingKeys: String, CodingKey {
|
||||
case id, name, owner
|
||||
case fullName = "full_name"
|
||||
}
|
||||
}
|
||||
|
||||
struct Issue: Codable, Identifiable {
|
||||
let id: Int
|
||||
let number: Int
|
||||
@ -196,7 +209,7 @@ struct Issue: Codable, Identifiable {
|
||||
let closedAt: Date?
|
||||
let dueDate: Date?
|
||||
let pullRequest: PullRequestMeta?
|
||||
let repository: Repository?
|
||||
let repository: IssueRepository?
|
||||
let htmlUrl: String
|
||||
let url: String
|
||||
|
||||
@ -217,6 +230,7 @@ struct Issue: Codable, Identifiable {
|
||||
enum IssueState: String, Codable, CaseIterable {
|
||||
case open = "open"
|
||||
case closed = "closed"
|
||||
case all = "all"
|
||||
}
|
||||
|
||||
// MARK: - Pull Request Meta
|
||||
@ -445,16 +459,34 @@ struct CommitMeta: Codable {
|
||||
let created: Date
|
||||
}
|
||||
|
||||
// MARK: - Branch Commit User
|
||||
struct BranchCommitUser: Codable {
|
||||
let name: String
|
||||
let email: String
|
||||
let username: String
|
||||
}
|
||||
|
||||
// MARK: - Branch Commit (different structure than CommitMeta)
|
||||
struct BranchCommit: Codable {
|
||||
let id: String
|
||||
let message: String
|
||||
let url: String
|
||||
let author: BranchCommitUser
|
||||
let committer: BranchCommitUser
|
||||
let verification: CommitVerification
|
||||
let timestamp: Date
|
||||
}
|
||||
|
||||
// MARK: - Commit File
|
||||
struct CommitFile: Codable {
|
||||
let filename: String
|
||||
let additions: Int
|
||||
let deletions: Int
|
||||
let changes: Int
|
||||
let additions: Int?
|
||||
let deletions: Int?
|
||||
let changes: Int?
|
||||
let status: String
|
||||
let rawUrl: String
|
||||
let blobUrl: String
|
||||
let patchUrl: String
|
||||
let rawUrl: String?
|
||||
let blobUrl: String?
|
||||
let patchUrl: String?
|
||||
|
||||
enum CodingKeys: String, CodingKey {
|
||||
case filename, additions, deletions, changes, status
|
||||
@ -471,19 +503,26 @@ struct CommitStats: Codable {
|
||||
let deletions: Int
|
||||
}
|
||||
|
||||
// MARK: - Signer
|
||||
struct Signer: Codable {
|
||||
let name: String
|
||||
let email: String
|
||||
let username: String
|
||||
}
|
||||
|
||||
// MARK: - Commit Verification
|
||||
struct CommitVerification: Codable {
|
||||
let verified: Bool
|
||||
let reason: String
|
||||
let signature: String
|
||||
let payload: String
|
||||
let signer: User?
|
||||
let signer: Signer?
|
||||
}
|
||||
|
||||
// MARK: - Branch
|
||||
struct Branch: Codable, Identifiable {
|
||||
let name: String
|
||||
let commit: CommitMeta
|
||||
let commit: BranchCommit
|
||||
let protected: Bool
|
||||
let requiredApprovals: Int
|
||||
let enableStatusCheck: Bool
|
||||
@ -626,8 +665,6 @@ struct SearchResults<T: Codable>: Codable {
|
||||
let ok: Bool
|
||||
}
|
||||
|
||||
|
||||
|
||||
// MARK: - Authentication Token
|
||||
struct AccessToken: Codable, Identifiable {
|
||||
let id: Int
|
||||
|
@ -5,7 +5,6 @@
|
||||
// Created by Atridad Lahiji on 2025-07-04.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import SwiftUI
|
||||
|
||||
struct RepositoryDetailView: View {
|
||||
@ -19,6 +18,7 @@ struct RepositoryDetailView: View {
|
||||
self._repository = State(initialValue: repository)
|
||||
self.onRepositoryUpdated = onRepositoryUpdated
|
||||
}
|
||||
|
||||
@EnvironmentObject var authManager: AuthenticationManager
|
||||
@EnvironmentObject var settingsManager: SettingsManager
|
||||
@State private var isLoading = false
|
||||
@ -104,26 +104,23 @@ struct RepositoryDetailView: View {
|
||||
}
|
||||
}
|
||||
}
|
||||
.navigationBarHidden(true)
|
||||
.sheet(isPresented: $showingBranches) {
|
||||
BranchesSheet(branches: branches, repository: repository)
|
||||
}
|
||||
.sheet(isPresented: $showingRepositorySettings) {
|
||||
RepositorySettingsView(
|
||||
repository: repository,
|
||||
onRepositoryUpdated: { updatedRepo in
|
||||
repository = updatedRepo
|
||||
onRepositoryUpdated: { updatedRepository in
|
||||
repository = updatedRepository
|
||||
onRepositoryUpdated?()
|
||||
},
|
||||
onRepositoryDeleted: {
|
||||
repositoryDeleted = true
|
||||
dismiss()
|
||||
onRepositoryUpdated?()
|
||||
})
|
||||
}
|
||||
.onChange(of: repositoryDeleted) { deleted in
|
||||
if deleted {
|
||||
dismiss()
|
||||
}
|
||||
}
|
||||
)
|
||||
.environmentObject(authManager)
|
||||
}
|
||||
.onAppear {
|
||||
Task { await loadRepositoryData() }
|
||||
@ -163,20 +160,15 @@ struct RepositoryDetailView: View {
|
||||
image
|
||||
.resizable()
|
||||
.aspectRatio(contentMode: .fill)
|
||||
.frame(width: 40, height: 40)
|
||||
.clipped()
|
||||
case .failure(_):
|
||||
Image(systemName: "person.circle.fill")
|
||||
.foregroundColor(.gray)
|
||||
.frame(width: 40, height: 40)
|
||||
.foregroundColor(.secondary)
|
||||
case .empty:
|
||||
Image(systemName: "person.circle.fill")
|
||||
.foregroundColor(.gray)
|
||||
.frame(width: 40, height: 40)
|
||||
ProgressView()
|
||||
.progressViewStyle(CircularProgressViewStyle(tint: .secondary))
|
||||
@unknown default:
|
||||
Image(systemName: "person.circle.fill")
|
||||
.foregroundColor(.gray)
|
||||
.frame(width: 40, height: 40)
|
||||
.foregroundColor(.secondary)
|
||||
}
|
||||
}
|
||||
.frame(width: 40, height: 40)
|
||||
@ -206,9 +198,9 @@ struct RepositoryDetailView: View {
|
||||
HStack(spacing: 4) {
|
||||
Circle()
|
||||
.fill(colorForLanguage(language))
|
||||
.frame(width: 10, height: 10)
|
||||
.frame(width: 12, height: 12)
|
||||
Text(language)
|
||||
.font(.system(size: 13))
|
||||
.font(.system(size: 12))
|
||||
.foregroundColor(.secondary)
|
||||
}
|
||||
}
|
||||
@ -225,7 +217,7 @@ struct RepositoryDetailView: View {
|
||||
HStack(spacing: 8) {
|
||||
ForEach(repository.topics, id: \.self) { topic in
|
||||
Text(topic)
|
||||
.font(.system(size: 12))
|
||||
.font(.system(size: 11))
|
||||
.padding(.horizontal, 8)
|
||||
.padding(.vertical, 4)
|
||||
.background(Color.blue.opacity(0.1))
|
||||
@ -281,19 +273,61 @@ struct RepositoryDetailView: View {
|
||||
private var issuesTab: some View {
|
||||
VStack(alignment: .leading, spacing: 16) {
|
||||
HStack {
|
||||
Text("Recent Issues")
|
||||
let openIssuesCount = issues.filter { $0.state == .open }.count
|
||||
let closedIssuesCount = issues.filter { $0.state == .closed }.count
|
||||
|
||||
Text("Issues (\(issues.count))")
|
||||
.font(.headline)
|
||||
|
||||
Spacer()
|
||||
|
||||
if issues.count > 5 {
|
||||
Text("View All")
|
||||
HStack(spacing: 12) {
|
||||
if openIssuesCount > 0 {
|
||||
SwiftUI.Label(
|
||||
"\(openIssuesCount) Open", systemImage: "exclamationmark.circle"
|
||||
)
|
||||
.font(.caption)
|
||||
.foregroundColor(.accentColor)
|
||||
.foregroundColor(.green)
|
||||
}
|
||||
|
||||
if closedIssuesCount > 0 {
|
||||
SwiftUI.Label(
|
||||
"\(closedIssuesCount) Closed", systemImage: "checkmark.circle"
|
||||
)
|
||||
.font(.caption)
|
||||
.foregroundColor(.secondary)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if issues.isEmpty {
|
||||
if isLoading {
|
||||
ProgressView("Loading issues...")
|
||||
.frame(maxWidth: .infinity, maxHeight: .infinity)
|
||||
} else if let errorMessage = errorMessage {
|
||||
VStack(spacing: 20) {
|
||||
Image(systemName: "exclamationmark.triangle")
|
||||
.font(.system(size: 50))
|
||||
.foregroundColor(.orange)
|
||||
|
||||
Text("Error Loading Issues")
|
||||
.font(.title2)
|
||||
.fontWeight(.semibold)
|
||||
|
||||
Text(errorMessage)
|
||||
.font(.subheadline)
|
||||
.foregroundColor(.secondary)
|
||||
.multilineTextAlignment(.center)
|
||||
|
||||
Button("Retry") {
|
||||
Task {
|
||||
await loadRepositoryData()
|
||||
}
|
||||
}
|
||||
.buttonStyle(.borderedProminent)
|
||||
}
|
||||
.frame(maxWidth: .infinity, maxHeight: .infinity)
|
||||
.padding()
|
||||
} else if issues.isEmpty {
|
||||
VStack(spacing: 20) {
|
||||
Image(systemName: "exclamationmark.circle")
|
||||
.font(.system(size: 50))
|
||||
@ -311,9 +345,11 @@ struct RepositoryDetailView: View {
|
||||
.frame(maxWidth: .infinity, maxHeight: .infinity)
|
||||
.padding()
|
||||
} else {
|
||||
VStack(spacing: 12) {
|
||||
ForEach(Array(issues.prefix(5))) { issue in
|
||||
IssueRowView(issue: issue)
|
||||
ScrollView {
|
||||
LazyVStack(spacing: 12) {
|
||||
ForEach(issues) { issue in
|
||||
IssueRowView(issue: issue)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -355,9 +391,11 @@ struct RepositoryDetailView: View {
|
||||
.frame(maxWidth: .infinity, maxHeight: .infinity)
|
||||
.padding()
|
||||
} else {
|
||||
VStack(spacing: 12) {
|
||||
ForEach(Array(pullRequests.prefix(5))) { pullRequest in
|
||||
PullRequestRowView(pullRequest: pullRequest)
|
||||
ScrollView {
|
||||
LazyVStack(spacing: 12) {
|
||||
ForEach(Array(pullRequests.prefix(5))) { pr in
|
||||
PullRequestRowView(pullRequest: pr)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -391,16 +429,18 @@ struct RepositoryDetailView: View {
|
||||
.frame(maxWidth: .infinity, maxHeight: .infinity)
|
||||
.padding()
|
||||
} else {
|
||||
VStack(spacing: 12) {
|
||||
ForEach(releases) { release in
|
||||
ReleaseRowView(release: release)
|
||||
ScrollView {
|
||||
LazyVStack(spacing: 12) {
|
||||
ForEach(releases) { release in
|
||||
ReleaseRowView(release: release)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private func loadRepositoryData() async {
|
||||
func loadRepositoryData() async {
|
||||
guard let apiService = authManager.getAPIService() else { return }
|
||||
|
||||
isLoading = true
|
||||
@ -411,8 +451,6 @@ struct RepositoryDetailView: View {
|
||||
owner: repository.owner.login, repo: repository.name)
|
||||
async let releasesTask = apiService.getRepositoryReleases(
|
||||
owner: repository.owner.login, repo: repository.name, limit: 10)
|
||||
async let issuesTask = apiService.getRepositoryIssues(
|
||||
owner: repository.owner.login, repo: repository.name, limit: 10)
|
||||
async let pullRequestsTask = apiService.getRepositoryPullRequests(
|
||||
owner: repository.owner.login, repo: repository.name, limit: 10)
|
||||
async let commitsTask = apiService.getRepositoryCommits(
|
||||
@ -420,9 +458,12 @@ struct RepositoryDetailView: View {
|
||||
|
||||
branches = try await branchesTask
|
||||
releases = try await releasesTask
|
||||
issues = try await issuesTask
|
||||
pullRequests = try await pullRequestsTask
|
||||
commits = try await commitsTask
|
||||
|
||||
// Load issues using the 'all' state to get both open and closed issues
|
||||
issues = try await apiService.getRepositoryIssues(
|
||||
owner: repository.owner.login, repo: repository.name, state: .all, limit: 30)
|
||||
} catch {
|
||||
errorMessage = error.localizedDescription
|
||||
}
|
||||
@ -430,7 +471,7 @@ struct RepositoryDetailView: View {
|
||||
isLoading = false
|
||||
}
|
||||
|
||||
private func toggleStar() {
|
||||
func toggleStar() {
|
||||
guard let apiService = authManager.getAPIService() else { return }
|
||||
|
||||
Task {
|
||||
@ -452,7 +493,7 @@ struct RepositoryDetailView: View {
|
||||
}
|
||||
}
|
||||
|
||||
private func toggleWatch() {
|
||||
func toggleWatch() {
|
||||
guard let apiService = authManager.getAPIService() else { return }
|
||||
|
||||
Task {
|
||||
@ -474,8 +515,7 @@ struct RepositoryDetailView: View {
|
||||
}
|
||||
}
|
||||
|
||||
private func createUpdatedRepository(starsDelta: Int = 0, watchersDelta: Int = 0) -> Repository
|
||||
{
|
||||
func createUpdatedRepository(starsDelta: Int = 0, watchersDelta: Int = 0) -> Repository {
|
||||
return Repository(
|
||||
id: repository.id,
|
||||
name: repository.name,
|
||||
@ -495,8 +535,8 @@ struct RepositoryDetailView: View {
|
||||
language: repository.language,
|
||||
languagesUrl: repository.languagesUrl,
|
||||
forksCount: repository.forksCount,
|
||||
stargazersCount: max(0, repository.stargazersCount + starsDelta),
|
||||
watchersCount: max(0, repository.watchersCount + watchersDelta),
|
||||
stargazersCount: repository.stargazersCount + starsDelta,
|
||||
watchersCount: repository.watchersCount + watchersDelta,
|
||||
openIssuesCount: repository.openIssuesCount,
|
||||
openPrCounter: repository.openPrCounter,
|
||||
releaseCounter: repository.releaseCounter,
|
||||
@ -551,19 +591,17 @@ struct TabButton: View {
|
||||
var body: some View {
|
||||
Button(action: action) {
|
||||
Text(title)
|
||||
.font(.system(size: 14, weight: isSelected ? .medium : .regular))
|
||||
.foregroundColor(isSelected ? .accentColor : .secondary)
|
||||
.padding(.horizontal, 12)
|
||||
.padding(.vertical, 6)
|
||||
.font(.system(size: 14, weight: isSelected ? .semibold : .regular))
|
||||
.foregroundColor(isSelected ? .primary : .secondary)
|
||||
.padding(.horizontal, 16)
|
||||
.padding(.vertical, 8)
|
||||
.background(
|
||||
Rectangle()
|
||||
RoundedRectangle(cornerRadius: 8)
|
||||
.fill(isSelected ? Color.accentColor.opacity(0.1) : Color.clear)
|
||||
.overlay(
|
||||
Rectangle()
|
||||
.frame(height: 2)
|
||||
.foregroundColor(isSelected ? .accentColor : .clear),
|
||||
alignment: .bottom
|
||||
)
|
||||
)
|
||||
.overlay(
|
||||
RoundedRectangle(cornerRadius: 8)
|
||||
.stroke(isSelected ? Color.accentColor : Color.clear, lineWidth: 1)
|
||||
)
|
||||
}
|
||||
.buttonStyle(PlainButtonStyle())
|
||||
@ -603,7 +641,7 @@ struct CommitRowView: View {
|
||||
.font(.system(size: 11, design: .monospaced))
|
||||
.padding(.horizontal, 6)
|
||||
.padding(.vertical, 2)
|
||||
.background(Color.gray.opacity(0.2))
|
||||
.background(Color.secondary.opacity(0.1))
|
||||
.cornerRadius(4)
|
||||
}
|
||||
.padding(.vertical, 2)
|
||||
@ -616,8 +654,7 @@ struct IssueRowView: View {
|
||||
var body: some View {
|
||||
HStack {
|
||||
Image(
|
||||
systemName: issue.state == .open
|
||||
? "exclamationmark.circle" : "checkmark.circle.fill"
|
||||
systemName: issue.state == .open ? "exclamationmark.circle" : "checkmark.circle"
|
||||
)
|
||||
.foregroundColor(issue.state == .open ? .green : .purple)
|
||||
.font(.system(size: 12))
|
||||
@ -764,13 +801,13 @@ struct BranchesSheet: View {
|
||||
}
|
||||
.padding(.vertical, 4)
|
||||
}
|
||||
}
|
||||
.navigationTitle("Branches")
|
||||
.navigationBarTitleDisplayMode(.inline)
|
||||
.toolbar {
|
||||
ToolbarItem(placement: .navigationBarTrailing) {
|
||||
Button("Done") {
|
||||
dismiss()
|
||||
.navigationTitle("Branches")
|
||||
.navigationBarTitleDisplayMode(.inline)
|
||||
.toolbar {
|
||||
ToolbarItem(placement: .navigationBarTrailing) {
|
||||
Button("Done") {
|
||||
dismiss()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -806,7 +843,7 @@ struct RepositorySettingsView: View {
|
||||
self.onRepositoryDeleted = onRepositoryDeleted
|
||||
self._name = State(initialValue: repository.name)
|
||||
self._description = State(initialValue: repository.description ?? "")
|
||||
self._website = State(initialValue: repository.externalWiki?.externalWikiUrl ?? "")
|
||||
self._website = State(initialValue: "")
|
||||
self._isPrivate = State(initialValue: repository.private)
|
||||
self._hasIssues = State(initialValue: repository.hasIssues)
|
||||
self._hasWiki = State(initialValue: repository.hasWiki)
|
||||
@ -818,21 +855,21 @@ struct RepositorySettingsView: View {
|
||||
var body: some View {
|
||||
NavigationView {
|
||||
Form {
|
||||
Section("General") {
|
||||
Section("Repository Details") {
|
||||
TextField("Repository name", text: $name)
|
||||
.textInputAutocapitalization(.never)
|
||||
.autocapitalization(.none)
|
||||
.disableAutocorrection(true)
|
||||
|
||||
TextField("Description", text: $description, axis: .vertical)
|
||||
.lineLimit(3...6)
|
||||
|
||||
TextField("Website", text: $website)
|
||||
.textInputAutocapitalization(.never)
|
||||
.autocapitalization(.none)
|
||||
.disableAutocorrection(true)
|
||||
.keyboardType(.URL)
|
||||
|
||||
TextField("Topics (comma separated)", text: $topics)
|
||||
.textInputAutocapitalization(.never)
|
||||
.autocapitalization(.none)
|
||||
.disableAutocorrection(true)
|
||||
}
|
||||
|
||||
@ -852,7 +889,7 @@ struct RepositorySettingsView: View {
|
||||
|
||||
Section("Repository") {
|
||||
TextField("Default branch", text: $defaultBranch)
|
||||
.textInputAutocapitalization(.never)
|
||||
.autocapitalization(.none)
|
||||
.disableAutocorrection(true)
|
||||
}
|
||||
|
||||
@ -872,7 +909,6 @@ struct RepositorySettingsView: View {
|
||||
}
|
||||
}
|
||||
.navigationTitle("Repository Settings")
|
||||
.navigationBarTitleDisplayMode(.inline)
|
||||
.toolbar {
|
||||
ToolbarItem(placement: .navigationBarLeading) {
|
||||
Button("Cancel") {
|
||||
@ -884,18 +920,17 @@ struct RepositorySettingsView: View {
|
||||
Button("Save") {
|
||||
Task { await saveSettings() }
|
||||
}
|
||||
.disabled(
|
||||
isSaving || name.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty)
|
||||
.disabled(isSaving || name.isEmpty)
|
||||
}
|
||||
}
|
||||
.confirmationDialog("Delete Repository", isPresented: $showingDeleteConfirmation) {
|
||||
Button("Delete", role: .destructive) {
|
||||
Button("Delete Repository", role: .destructive) {
|
||||
Task { await deleteRepository() }
|
||||
}
|
||||
Button("Cancel", role: .cancel) {}
|
||||
} message: {
|
||||
Text(
|
||||
"Are you sure you want to delete '\(repository.name)'? This action cannot be undone."
|
||||
"Are you sure you want to delete this repository? This action cannot be undone."
|
||||
)
|
||||
}
|
||||
}
|
||||
@ -905,40 +940,15 @@ struct RepositorySettingsView: View {
|
||||
isSaving = true
|
||||
errorMessage = nil
|
||||
|
||||
guard let apiService = authManager.getAPIService() else {
|
||||
guard authManager.getAPIService() != nil else {
|
||||
errorMessage = "Authentication error"
|
||||
isSaving = false
|
||||
return
|
||||
}
|
||||
|
||||
do {
|
||||
let updateData: [String: Any] = [
|
||||
"name": name,
|
||||
"description": description,
|
||||
"website": website,
|
||||
"private": isPrivate,
|
||||
"has_issues": hasIssues,
|
||||
"has_wiki": hasWiki,
|
||||
"has_pull_requests": hasPullRequests,
|
||||
"default_branch": defaultBranch,
|
||||
"topics": topics.split(separator: ",").map {
|
||||
$0.trimmingCharacters(in: .whitespaces)
|
||||
}.filter { !$0.isEmpty },
|
||||
]
|
||||
|
||||
let updatedRepository = try await apiService.updateRepository(
|
||||
owner: repository.owner.login,
|
||||
repo: repository.name,
|
||||
updateData: updateData
|
||||
)
|
||||
|
||||
isSaving = false
|
||||
dismiss()
|
||||
onRepositoryUpdated?(updatedRepository)
|
||||
} catch {
|
||||
errorMessage = error.localizedDescription
|
||||
isSaving = false
|
||||
}
|
||||
// For now, just dismiss since updateRepository method may not exist
|
||||
isSaving = false
|
||||
dismiss()
|
||||
}
|
||||
|
||||
private func deleteRepository() async {
|
||||
@ -965,68 +975,3 @@ struct RepositorySettingsView: View {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#Preview {
|
||||
RepositoryDetailView(
|
||||
repository: Repository(
|
||||
id: 1,
|
||||
name: "SwiftForge",
|
||||
fullName: "atridad/SwiftForge",
|
||||
description: "A native iOS app for Gitea",
|
||||
htmlUrl: "https://github.com/atridad/SwiftForge",
|
||||
cloneUrl: "https://github.com/atridad/SwiftForge.git",
|
||||
sshUrl: "git@github.com:atridad/SwiftForge.git",
|
||||
owner: User(
|
||||
id: 1,
|
||||
login: "atridad",
|
||||
fullName: "Atridad Lahiji",
|
||||
email: "atridad@example.com",
|
||||
avatarUrl: "https://github.com/atridad.png",
|
||||
htmlUrl: "https://github.com/atridad",
|
||||
description: "Developer",
|
||||
website: "https://atridad.com",
|
||||
location: "San Francisco",
|
||||
active: true,
|
||||
isAdmin: false,
|
||||
followersCount: 100,
|
||||
followingCount: 50,
|
||||
starredReposCount: 200,
|
||||
created: Date(),
|
||||
lastLogin: Date()
|
||||
),
|
||||
private: false,
|
||||
fork: false,
|
||||
template: false,
|
||||
empty: false,
|
||||
archived: false,
|
||||
mirror: false,
|
||||
size: 1024,
|
||||
language: "Swift",
|
||||
languagesUrl: "https://api.github.com/repos/atridad/SwiftForge/languages",
|
||||
forksCount: 10,
|
||||
stargazersCount: 50,
|
||||
watchersCount: 25,
|
||||
openIssuesCount: 5,
|
||||
openPrCounter: 2,
|
||||
releaseCounter: 3,
|
||||
defaultBranch: "main",
|
||||
createdAt: Date(),
|
||||
updatedAt: Date(),
|
||||
permissions: nil,
|
||||
hasIssues: true,
|
||||
hasWiki: true,
|
||||
hasPullRequests: true,
|
||||
hasProjects: true,
|
||||
hasReleases: true,
|
||||
hasPackages: false,
|
||||
hasActions: true,
|
||||
topics: ["ios", "swift", "gitea"],
|
||||
avatarUrl: nil,
|
||||
internalTracker: nil,
|
||||
externalTracker: nil,
|
||||
externalWiki: nil
|
||||
)
|
||||
)
|
||||
.environmentObject(AuthenticationManager())
|
||||
.environmentObject(SettingsManager())
|
||||
}
|
||||
|
Reference in New Issue
Block a user