diff options
| -rw-r--r-- | Hutch.xcodeproj/project.pbxproj | 16 | ||||
| -rw-r--r-- | Hutch/Models/Git.swift | 7 | ||||
| -rw-r--r-- | Hutch/Views/Repositories/ReferencesListView.swift | 13 | ||||
| -rw-r--r-- | Hutch/Views/Repositories/RepositoryDetailViewModel.swift | 42 | ||||
| -rw-r--r-- | Hutch/Views/Repositories/RepositorySettingsView.swift | 2 | ||||
| -rw-r--r-- | Hutch/Views/Repositories/RepositorySettingsViewModel.swift | 4 | ||||
| -rw-r--r-- | codex-fix-refs-type-conflict.md | 89 |
7 files changed, 153 insertions, 20 deletions
diff --git a/Hutch.xcodeproj/project.pbxproj b/Hutch.xcodeproj/project.pbxproj index 71bbc39..cdab899 100644 --- a/Hutch.xcodeproj/project.pbxproj +++ b/Hutch.xcodeproj/project.pbxproj @@ -539,7 +539,7 @@ ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; CODE_SIGN_ENTITLEMENTS = Hutch/Hutch.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 19; + CURRENT_PROJECT_VERSION = 20; DEVELOPMENT_TEAM = ZCNAX3VL9D; ENABLE_PREVIEWS = YES; GENERATE_INFOPLIST_FILE = YES; @@ -556,7 +556,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 2.8.0; + MARKETING_VERSION = 2.8.1; PRODUCT_BUNDLE_IDENTIFIER = net.cleberg.Hutch; PRODUCT_NAME = "$(TARGET_NAME)"; STRING_CATALOG_GENERATE_SYMBOLS = YES; @@ -576,7 +576,7 @@ ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; CODE_SIGN_ENTITLEMENTS = Hutch/Hutch.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 19; + CURRENT_PROJECT_VERSION = 20; DEVELOPMENT_TEAM = ZCNAX3VL9D; ENABLE_PREVIEWS = YES; GENERATE_INFOPLIST_FILE = YES; @@ -593,7 +593,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 2.8.0; + MARKETING_VERSION = 2.8.1; PRODUCT_BUNDLE_IDENTIFIER = net.cleberg.Hutch; PRODUCT_NAME = "$(TARGET_NAME)"; STRING_CATALOG_GENERATE_SYMBOLS = YES; @@ -656,7 +656,7 @@ APPLICATION_EXTENSION_API_ONLY = YES; CODE_SIGN_ENTITLEMENTS = HutchWidgetExtension/HutchWidgetExtension.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 19; + CURRENT_PROJECT_VERSION = 20; DEVELOPMENT_TEAM = ZCNAX3VL9D; GENERATE_INFOPLIST_FILE = NO; INFOPLIST_FILE = HutchWidgetExtension/Info.plist; @@ -666,7 +666,7 @@ "@executable_path/Frameworks", "@executable_path/../../Frameworks", ); - MARKETING_VERSION = 2.8.0; + MARKETING_VERSION = 2.8.1; PRODUCT_BUNDLE_IDENTIFIER = net.cleberg.Hutch.HutchWidgetExtension; PRODUCT_NAME = "$(TARGET_NAME)"; SKIP_INSTALL = YES; @@ -685,7 +685,7 @@ APPLICATION_EXTENSION_API_ONLY = YES; CODE_SIGN_ENTITLEMENTS = HutchWidgetExtension/HutchWidgetExtension.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 19; + CURRENT_PROJECT_VERSION = 20; DEVELOPMENT_TEAM = ZCNAX3VL9D; GENERATE_INFOPLIST_FILE = NO; INFOPLIST_FILE = HutchWidgetExtension/Info.plist; @@ -695,7 +695,7 @@ "@executable_path/Frameworks", "@executable_path/../../Frameworks", ); - MARKETING_VERSION = 2.8.0; + MARKETING_VERSION = 2.8.1; PRODUCT_BUNDLE_IDENTIFIER = net.cleberg.Hutch.HutchWidgetExtension; PRODUCT_NAME = "$(TARGET_NAME)"; SKIP_INSTALL = YES; diff --git a/Hutch/Models/Git.swift b/Hutch/Models/Git.swift index 905822e..a45086b 100644 --- a/Hutch/Models/Git.swift +++ b/Hutch/Models/Git.swift @@ -82,6 +82,13 @@ struct Reference: Codable, Sendable, Hashable { let target: String? } +/// A Git reference enriched with the date of its tip commit or tag, for display in the Refs tab. +struct ReferenceDetail: Sendable, Hashable { + let name: String + let target: String? + let date: Date? +} + // MARK: - TreeEntry /// An entry in a Git tree (file or directory). diff --git a/Hutch/Views/Repositories/ReferencesListView.swift b/Hutch/Views/Repositories/ReferencesListView.swift index 615ba25..6470a42 100644 --- a/Hutch/Views/Repositories/ReferencesListView.swift +++ b/Hutch/Views/Repositories/ReferencesListView.swift @@ -51,14 +51,21 @@ struct ReferencesListView: View { } private struct ReferenceRow: View { - let reference: Reference + let reference: ReferenceDetail let prefix: String var body: some View { HStack { Label { - Text(shortName) - .font(.body.monospaced()) + VStack(alignment: .leading, spacing: 2) { + Text(shortName) + .font(.body.monospaced()) + if let date = reference.date { + Text(date.relativeDescription) + .font(.caption) + .foregroundStyle(.secondary) + } + } } icon: { Image(systemName: icon) .foregroundStyle(iconColor) diff --git a/Hutch/Views/Repositories/RepositoryDetailViewModel.swift b/Hutch/Views/Repositories/RepositoryDetailViewModel.swift index e2eaf4d..72c4d1f 100644 --- a/Hutch/Views/Repositories/RepositoryDetailViewModel.swift +++ b/Hutch/Views/Repositories/RepositoryDetailViewModel.swift @@ -24,10 +24,33 @@ private struct RefsRepository: Decodable, Sendable { } private struct RefsPage: Decodable, Sendable { - let results: [Reference] + let results: [ReferencePayload] let cursor: String? } +/// Decodes a single reference including the optional follow object for date extraction. +private struct ReferencePayload: Decodable, Sendable { + let name: String + let target: String? + let follow: ReferenceFollow? + + func toDetail() -> ReferenceDetail { + // Branches and lightweight tags follow to a Commit (author.time). + // Annotated tags follow to a Tag object (tagger.time). + let date = follow?.author?.time ?? follow?.tagger?.time + return ReferenceDetail(name: name, target: target, date: date) + } +} + +private struct ReferenceFollow: Decodable, Sendable { + let author: ReferenceSignature? + let tagger: ReferenceSignature? +} + +private struct ReferenceSignature: Decodable, Sendable { + let time: Date +} + private struct ReadmeResponse: Decodable, Sendable { let repository: ReadmeRepository? } @@ -98,8 +121,8 @@ final class RepositoryDetailViewModel { // MARK: - References state - private(set) var branches: [Reference] = [] - private(set) var tags: [Reference] = [] + private(set) var branches: [ReferenceDetail] = [] + private(set) var tags: [ReferenceDetail] = [] private(set) var isLoadingRefs = false // MARK: - README state @@ -220,7 +243,14 @@ final class RepositoryDetailViewModel { query refs($rid: ID!) { repository(rid: $rid) { references { - results { name target } + results { + name + target + follow { + ... on Commit { author { time } } + ... on Tag { tagger { time } } + } + } cursor } } @@ -240,8 +270,8 @@ final class RepositoryDetailViewModel { responseType: RefsResponse.self ) let allRefs = result.repository?.references.results ?? [] - branches = allRefs.filter { $0.name.hasPrefix("refs/heads/") } - tags = allRefs.filter { $0.name.hasPrefix("refs/tags/") } + branches = allRefs.filter { $0.name.hasPrefix("refs/heads/") }.map { $0.toDetail() } + tags = allRefs.filter { $0.name.hasPrefix("refs/tags/") }.map { $0.toDetail() } } catch { self.error = error.userFacingMessage } diff --git a/Hutch/Views/Repositories/RepositorySettingsView.swift b/Hutch/Views/Repositories/RepositorySettingsView.swift index aca2ff9..98d3d8a 100644 --- a/Hutch/Views/Repositories/RepositorySettingsView.swift +++ b/Hutch/Views/Repositories/RepositorySettingsView.swift @@ -2,7 +2,7 @@ import SwiftUI struct RepositorySettingsView: View { let repository: RepositorySummary - let branches: [Reference] + let branches: [ReferenceDetail] let client: SRHTClient let onRenamed: (String) -> Void let onDeleted: () -> Void diff --git a/Hutch/Views/Repositories/RepositorySettingsViewModel.swift b/Hutch/Views/Repositories/RepositorySettingsViewModel.swift index 2847cb7..571ae85 100644 --- a/Hutch/Views/Repositories/RepositorySettingsViewModel.swift +++ b/Hutch/Views/Repositories/RepositorySettingsViewModel.swift @@ -102,7 +102,7 @@ final class RepositorySettingsViewModel { // MARK: - Branches (for HEAD picker) - var branches: [Reference] + var branches: [ReferenceDetail] // MARK: - Results @@ -112,7 +112,7 @@ final class RepositorySettingsViewModel { init( repository: RepositorySummary, - branches: [Reference], + branches: [ReferenceDetail], client: SRHTClient ) { self.repositoryId = repository.id diff --git a/codex-fix-refs-type-conflict.md b/codex-fix-refs-type-conflict.md new file mode 100644 index 0000000..4ff2eec --- /dev/null +++ b/codex-fix-refs-type-conflict.md @@ -0,0 +1,89 @@ +# Fix: Conflicting `[Reference]` vs `[ReferenceDetail]` in RepositorySettingsView + +## Background + +`RepositoryDetailViewModel.branches` was recently changed from `[Reference]` to +`[ReferenceDetail]` to support displaying commit dates in the Refs tab. +`ReferenceDetail` has the same `name: String` and `target: String?` fields as +`Reference`, plus an additional `date: Date?`. + +`RepositorySettingsView` and `RepositorySettingsViewModel` still declare their +`branches` parameter as `[Reference]`, causing this compiler error: + +``` +RepositoryDetailView.swift:56:51 +Conflicting arguments to generic parameter 'T' ('[ReferenceDetail]' vs. '[Reference]') +``` + +The settings view model only uses `branches` for the HEAD branch picker +(`selectedHeadReferenceForSave()` accesses `$0.name`). No mapping back to +`Reference` is needed — just update the type throughout the settings layer. + +--- + +## Changes Required + +### 1. `Hutch/Views/Repositories/RepositorySettingsViewModel.swift` + +**Change the stored property type:** + +Find: +```swift +var branches: [Reference] +``` + +Replace with: +```swift +var branches: [ReferenceDetail] +``` + +**Change the `init` parameter type:** + +Find: +```swift +init( + repository: RepositorySummary, + branches: [Reference], + client: SRHTClient +) { +``` + +Replace with: +```swift +init( + repository: RepositorySummary, + branches: [ReferenceDetail], + client: SRHTClient +) { +``` + +### 2. `Hutch/Views/Repositories/RepositorySettingsView.swift` + +**Change the stored property type:** + +Find: +```swift +let branches: [Reference] +``` + +Replace with: +```swift +let branches: [ReferenceDetail] +``` + +--- + +## No Other Changes + +- Do not modify `Reference` or `ReferenceDetail` in `Git.swift`. +- Do not modify `RepositoryDetailView.swift` — the call site is already correct. +- Do not modify `ReferencesListView.swift` or `RepositoryDetailViewModel.swift`. +- `selectedHeadReferenceForSave()` in the settings view model accesses only + `$0.name` on each branch, which exists on `ReferenceDetail` — no logic + changes are needed. + +## Verification + +Build the project. The compiler error at `RepositoryDetailView.swift:56` should +be gone. Confirm the repository settings sheet still opens and the HEAD branch +picker populates correctly. |
