native macOS codings agent orchestrator
6
fork

Configure Feed

Select the types of activity you want to include in your feed.

Merge pull request #89 from supabitapp/settings-notification-worktree-jump-toggle

Add setting for notification worktree reordering

authored by

khoi and committed by
GitHub
da2ae6cc c4b47357

+100 -1
+7
supacode/Features/App/Reducer/AppFeature.swift
··· 266 266 ) 267 267 ), 268 268 .send( 269 + .repositories( 270 + .setMoveNotifiedWorktreeToTop( 271 + settings.moveNotifiedWorktreeToTop 272 + ) 273 + ) 274 + ), 275 + .send( 269 276 .updates( 270 277 .applySettings( 271 278 updateChannel: settings.updateChannel,
+7 -1
supacode/Features/Repositories/Reducer/RepositoriesFeature.swift
··· 75 75 var pinnedWorktreeIDs: [Worktree.ID] = [] 76 76 var archivedWorktreeIDs: [Worktree.ID] = [] 77 77 var automaticallyArchiveMergedWorktrees = false 78 + var moveNotifiedWorktreeToTop = true 78 79 var lastFocusedWorktreeID: Worktree.ID? 79 80 var shouldRestoreLastFocusedWorktree = false 80 81 var shouldSelectFirstAfterReload = false ··· 213 214 ) 214 215 case setGithubIntegrationEnabled(Bool) 215 216 case setAutomaticallyArchiveMergedWorktrees(Bool) 217 + case setMoveNotifiedWorktreeToTop(Bool) 216 218 case pullRequestAction(Worktree.ID, PullRequestAction) 217 219 case showToast(StatusToast) 218 220 case dismissToast ··· 1792 1794 1793 1795 var effects: [Effect<Action>] = [] 1794 1796 1795 - if !state.isMainWorktree(worktree), !state.isWorktreePinned(worktree) { 1797 + if state.moveNotifiedWorktreeToTop, !state.isMainWorktree(worktree), !state.isWorktreePinned(worktree) { 1796 1798 let reordered = reorderedUnpinnedWorktreeIDs( 1797 1799 for: worktreeID, 1798 1800 in: repository, ··· 2328 2330 2329 2331 case .setAutomaticallyArchiveMergedWorktrees(let isEnabled): 2330 2332 state.automaticallyArchiveMergedWorktrees = isEnabled 2333 + return .none 2334 + 2335 + case .setMoveNotifiedWorktreeToTop(let isEnabled): 2336 + state.moveNotifiedWorktreeToTop = isEnabled 2331 2337 return .none 2332 2338 2333 2339 case .openRepositorySettings(let repositoryID):
+7
supacode/Features/Settings/Models/GlobalSettings.swift
··· 7 7 var updatesAutomaticallyDownloadUpdates: Bool 8 8 var inAppNotificationsEnabled: Bool 9 9 var notificationSoundEnabled: Bool 10 + var moveNotifiedWorktreeToTop: Bool 10 11 var analyticsEnabled: Bool 11 12 var crashReportsEnabled: Bool 12 13 var githubIntegrationEnabled: Bool ··· 23 24 updatesAutomaticallyDownloadUpdates: false, 24 25 inAppNotificationsEnabled: true, 25 26 notificationSoundEnabled: true, 27 + moveNotifiedWorktreeToTop: true, 26 28 analyticsEnabled: true, 27 29 crashReportsEnabled: true, 28 30 githubIntegrationEnabled: true, ··· 40 42 updatesAutomaticallyDownloadUpdates: Bool, 41 43 inAppNotificationsEnabled: Bool, 42 44 notificationSoundEnabled: Bool, 45 + moveNotifiedWorktreeToTop: Bool, 43 46 analyticsEnabled: Bool, 44 47 crashReportsEnabled: Bool, 45 48 githubIntegrationEnabled: Bool, ··· 55 58 self.updatesAutomaticallyDownloadUpdates = updatesAutomaticallyDownloadUpdates 56 59 self.inAppNotificationsEnabled = inAppNotificationsEnabled 57 60 self.notificationSoundEnabled = notificationSoundEnabled 61 + self.moveNotifiedWorktreeToTop = moveNotifiedWorktreeToTop 58 62 self.analyticsEnabled = analyticsEnabled 59 63 self.crashReportsEnabled = crashReportsEnabled 60 64 self.githubIntegrationEnabled = githubIntegrationEnabled ··· 83 87 notificationSoundEnabled = 84 88 try container.decodeIfPresent(Bool.self, forKey: .notificationSoundEnabled) 85 89 ?? Self.default.notificationSoundEnabled 90 + moveNotifiedWorktreeToTop = 91 + try container.decodeIfPresent(Bool.self, forKey: .moveNotifiedWorktreeToTop) 92 + ?? Self.default.moveNotifiedWorktreeToTop 86 93 analyticsEnabled = 87 94 try container.decodeIfPresent(Bool.self, forKey: .analyticsEnabled) 88 95 ?? Self.default.analyticsEnabled
+4
supacode/Features/Settings/Reducer/SettingsFeature.swift
··· 13 13 var updatesAutomaticallyDownloadUpdates: Bool 14 14 var inAppNotificationsEnabled: Bool 15 15 var notificationSoundEnabled: Bool 16 + var moveNotifiedWorktreeToTop: Bool 16 17 var analyticsEnabled: Bool 17 18 var crashReportsEnabled: Bool 18 19 var githubIntegrationEnabled: Bool ··· 32 33 updatesAutomaticallyDownloadUpdates = settings.updatesAutomaticallyDownloadUpdates 33 34 inAppNotificationsEnabled = settings.inAppNotificationsEnabled 34 35 notificationSoundEnabled = settings.notificationSoundEnabled 36 + moveNotifiedWorktreeToTop = settings.moveNotifiedWorktreeToTop 35 37 analyticsEnabled = settings.analyticsEnabled 36 38 crashReportsEnabled = settings.crashReportsEnabled 37 39 githubIntegrationEnabled = settings.githubIntegrationEnabled ··· 50 52 updatesAutomaticallyDownloadUpdates: updatesAutomaticallyDownloadUpdates, 51 53 inAppNotificationsEnabled: inAppNotificationsEnabled, 52 54 notificationSoundEnabled: notificationSoundEnabled, 55 + moveNotifiedWorktreeToTop: moveNotifiedWorktreeToTop, 53 56 analyticsEnabled: analyticsEnabled, 54 57 crashReportsEnabled: crashReportsEnabled, 55 58 githubIntegrationEnabled: githubIntegrationEnabled, ··· 104 107 state.updatesAutomaticallyDownloadUpdates = normalizedSettings.updatesAutomaticallyDownloadUpdates 105 108 state.inAppNotificationsEnabled = normalizedSettings.inAppNotificationsEnabled 106 109 state.notificationSoundEnabled = normalizedSettings.notificationSoundEnabled 110 + state.moveNotifiedWorktreeToTop = normalizedSettings.moveNotifiedWorktreeToTop 107 111 state.analyticsEnabled = normalizedSettings.analyticsEnabled 108 112 state.crashReportsEnabled = normalizedSettings.crashReportsEnabled 109 113 state.githubIntegrationEnabled = normalizedSettings.githubIntegrationEnabled
+5
supacode/Features/Settings/Views/NotificationsSettingsView.swift
··· 18 18 isOn: $store.notificationSoundEnabled 19 19 ) 20 20 .help("Play a sound when a notification is received") 21 + Toggle( 22 + "Move notified worktree to top", 23 + isOn: $store.moveNotifiedWorktreeToTop 24 + ) 25 + .help("Bring the worktree to the top when the terminal receives a notification") 21 26 } 22 27 } 23 28 .formStyle(.grouped)
+33
supacodeTests/AppFeatureSettingsChangedTests.swift
··· 1 + import ComposableArchitecture 2 + import DependenciesTestSupport 3 + import Testing 4 + 5 + @testable import supacode 6 + 7 + @MainActor 8 + struct AppFeatureSettingsChangedTests { 9 + @Test(.dependencies) func settingsChangedPropagatesRepositorySettings() async { 10 + var settings = GlobalSettings.default 11 + settings.githubIntegrationEnabled = false 12 + settings.automaticallyArchiveMergedWorktrees = true 13 + settings.moveNotifiedWorktreeToTop = false 14 + let store = TestStore(initialState: AppFeature.State()) { 15 + AppFeature() 16 + } 17 + 18 + await store.send(.settings(.delegate(.settingsChanged(settings)))) 19 + await store.receive(\.repositories.setGithubIntegrationEnabled) { 20 + $0.repositories.githubIntegrationAvailability = .disabled 21 + } 22 + await store.receive(\.repositories.setAutomaticallyArchiveMergedWorktrees) { 23 + $0.repositories.automaticallyArchiveMergedWorktrees = true 24 + } 25 + await store.receive(\.repositories.setMoveNotifiedWorktreeToTop) { 26 + $0.repositories.moveNotifiedWorktreeToTop = false 27 + } 28 + await store.receive(\.updates.applySettings) { 29 + $0.updates.didConfigureUpdates = true 30 + } 31 + await store.finish() 32 + } 33 + }
+30
supacodeTests/RepositoriesFeatureTests.swift
··· 845 845 #expect(store.state.statusToast == nil) 846 846 } 847 847 848 + @Test func worktreeNotificationReceivedDoesNotReorderWhenMoveToTopDisabled() async { 849 + let repoRoot = "/tmp/repo" 850 + let mainWorktree = makeWorktree(id: repoRoot, name: "main", repoRoot: repoRoot) 851 + let featureA = makeWorktree(id: "/tmp/repo/a", name: "a", repoRoot: repoRoot) 852 + let featureB = makeWorktree(id: "/tmp/repo/b", name: "b", repoRoot: repoRoot) 853 + let repository = makeRepository(id: repoRoot, worktrees: [mainWorktree, featureA, featureB]) 854 + var state = makeState(repositories: [repository]) 855 + state.worktreeOrderByRepository[repoRoot] = [featureA.id, featureB.id] 856 + state.moveNotifiedWorktreeToTop = false 857 + let store = TestStore(initialState: state) { 858 + RepositoriesFeature() 859 + } 860 + 861 + await store.send(.worktreeNotificationReceived(featureB.id)) 862 + #expect(store.state.worktreeOrderByRepository[repoRoot] == [featureA.id, featureB.id]) 863 + #expect(store.state.statusToast == nil) 864 + } 865 + 866 + @Test func setMoveNotifiedWorktreeToTopUpdatesState() async { 867 + var state = makeState(repositories: []) 868 + state.moveNotifiedWorktreeToTop = true 869 + let store = TestStore(initialState: state) { 870 + RepositoriesFeature() 871 + } 872 + 873 + await store.send(.setMoveNotifiedWorktreeToTop(false)) { 874 + $0.moveNotifiedWorktreeToTop = false 875 + } 876 + } 877 + 848 878 @Test func worktreeBranchNameLoadedPreservesCreatedAt() async { 849 879 let createdAt = Date(timeIntervalSince1970: 1_737_303_600) 850 880 let worktree = makeWorktree(id: "/tmp/wt", name: "eagle", createdAt: createdAt)
+6
supacodeTests/SettingsFeatureTests.swift
··· 19 19 updatesAutomaticallyDownloadUpdates: true, 20 20 inAppNotificationsEnabled: false, 21 21 notificationSoundEnabled: true, 22 + moveNotifiedWorktreeToTop: false, 22 23 analyticsEnabled: false, 23 24 crashReportsEnabled: true, 24 25 githubIntegrationEnabled: true, ··· 43 44 $0.updatesAutomaticallyDownloadUpdates = true 44 45 $0.inAppNotificationsEnabled = false 45 46 $0.notificationSoundEnabled = true 47 + $0.moveNotifiedWorktreeToTop = false 46 48 $0.analyticsEnabled = false 47 49 $0.crashReportsEnabled = true 48 50 $0.githubIntegrationEnabled = true ··· 63 65 updatesAutomaticallyDownloadUpdates: false, 64 66 inAppNotificationsEnabled: false, 65 67 notificationSoundEnabled: false, 68 + moveNotifiedWorktreeToTop: true, 66 69 analyticsEnabled: true, 67 70 crashReportsEnabled: false, 68 71 githubIntegrationEnabled: true, ··· 89 92 updatesAutomaticallyDownloadUpdates: initialSettings.updatesAutomaticallyDownloadUpdates, 90 93 inAppNotificationsEnabled: initialSettings.inAppNotificationsEnabled, 91 94 notificationSoundEnabled: initialSettings.notificationSoundEnabled, 95 + moveNotifiedWorktreeToTop: initialSettings.moveNotifiedWorktreeToTop, 92 96 analyticsEnabled: initialSettings.analyticsEnabled, 93 97 crashReportsEnabled: initialSettings.crashReportsEnabled, 94 98 githubIntegrationEnabled: initialSettings.githubIntegrationEnabled, ··· 138 142 updatesAutomaticallyDownloadUpdates: true, 139 143 inAppNotificationsEnabled: false, 140 144 notificationSoundEnabled: false, 145 + moveNotifiedWorktreeToTop: true, 141 146 analyticsEnabled: true, 142 147 crashReportsEnabled: false, 143 148 githubIntegrationEnabled: true, ··· 155 160 $0.updatesAutomaticallyDownloadUpdates = true 156 161 $0.inAppNotificationsEnabled = false 157 162 $0.notificationSoundEnabled = false 163 + $0.moveNotifiedWorktreeToTop = true 158 164 $0.analyticsEnabled = true 159 165 $0.crashReportsEnabled = false 160 166 $0.githubIntegrationEnabled = true
+1
supacodeTests/SettingsFilePersistenceTests.swift
··· 102 102 #expect(settings.global.updatesAutomaticallyDownloadUpdates == true) 103 103 #expect(settings.global.inAppNotificationsEnabled == true) 104 104 #expect(settings.global.notificationSoundEnabled == true) 105 + #expect(settings.global.moveNotifiedWorktreeToTop == true) 105 106 #expect(settings.global.analyticsEnabled == true) 106 107 #expect(settings.global.crashReportsEnabled == true) 107 108 #expect(settings.global.githubIntegrationEnabled == true)