native macOS codings agent orchestrator
6
fork

Configure Feed

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

Improve archived worktrees discoverability (#196)

Update archive alerts to tell users where to find archived worktrees
(Menu Bar > Worktrees > Archived Worktrees) with the hotkey displayed.
Add "View Archived Worktrees" command to the palette.

authored by

Stefano Bertagno and committed by
GitHub
c0a6f163 1355ec8d

+69 -9
+3
supacode/Features/App/Reducer/AppFeature.swift
··· 590 590 case .commandPalette(.delegate(.archiveWorktree(let worktreeID, let repositoryID))): 591 591 return .send(.repositories(.requestArchiveWorktree(worktreeID, repositoryID))) 592 592 593 + case .commandPalette(.delegate(.viewArchivedWorktrees)): 594 + return .send(.repositories(.selectArchivedWorktrees)) 595 + 593 596 case .commandPalette(.delegate(.refreshWorktrees)): 594 597 return .send(.repositories(.refreshWorktrees)) 595 598
+6 -2
supacode/Features/CommandPalette/CommandPaletteItem.swift
··· 31 31 case newWorktree 32 32 case removeWorktree(Worktree.ID, Repository.ID) 33 33 case archiveWorktree(Worktree.ID, Repository.ID) 34 + case viewArchivedWorktrees 34 35 case refreshWorktrees 35 36 case ghosttyCommand(String) 36 37 case openPullRequest(Worktree.ID) ··· 48 49 49 50 var isGlobal: Bool { 50 51 switch kind { 51 - case .checkForUpdates, .openRepository, .openSettings, .newWorktree, .refreshWorktrees: 52 + case .checkForUpdates, .openRepository, .openSettings, .newWorktree, .viewArchivedWorktrees, 53 + .refreshWorktrees: 52 54 true 53 55 case .ghosttyCommand: 54 56 false ··· 72 74 73 75 var isRootAction: Bool { 74 76 switch kind { 75 - case .checkForUpdates, .openRepository, .openSettings, .newWorktree, .refreshWorktrees: 77 + case .checkForUpdates, .openRepository, .openSettings, .newWorktree, .viewArchivedWorktrees, 78 + .refreshWorktrees: 76 79 true 77 80 case .ghosttyCommand: 78 81 false ··· 101 104 case .openRepository: AppShortcuts.openRepository 102 105 case .openSettings: AppShortcuts.openSettings 103 106 case .newWorktree: AppShortcuts.newWorktree 107 + case .viewArchivedWorktrees: AppShortcuts.archivedWorktrees 104 108 case .refreshWorktrees: AppShortcuts.refreshWorktrees 105 109 case .ghosttyCommand: nil 106 110 case .openPullRequest: AppShortcuts.openPullRequest
+12
supacode/Features/CommandPalette/Reducer/CommandPaletteFeature.swift
··· 38 38 case openRepository 39 39 case removeWorktree(Worktree.ID, Repository.ID) 40 40 case archiveWorktree(Worktree.ID, Repository.ID) 41 + case viewArchivedWorktrees 41 42 case refreshWorktrees 42 43 case ghosttyCommand(String) 43 44 case openPullRequest(Worktree.ID) ··· 195 196 subtitle: nil, 196 197 kind: .refreshWorktrees 197 198 ), 199 + CommandPaletteItem( 200 + id: CommandPaletteItemID.globalViewArchivedWorktrees, 201 + title: "View Archived Worktrees", 202 + subtitle: nil, 203 + kind: .viewArchivedWorktrees 204 + ), 198 205 ] 199 206 if repositories.selectedWorktreeID != nil { 200 207 items.append(contentsOf: ghosttyCommandItems(ghosttyCommands)) ··· 419 426 static let globalOpenRepository = "global.open-repository" 420 427 static let globalNewWorktree = "global.new-worktree" 421 428 static let globalRefreshWorktrees = "global.refresh-worktrees" 429 + static let globalViewArchivedWorktrees = "global.view-archived-worktrees" 422 430 423 431 static var globalIDs: [CommandPaletteItem.ID] { 424 432 [ ··· 427 435 globalOpenRepository, 428 436 globalNewWorktree, 429 437 globalRefreshWorktrees, 438 + globalViewArchivedWorktrees, 430 439 ] 431 440 } 432 441 ··· 532 541 return .removeWorktree(worktreeID, repositoryID) 533 542 case .archiveWorktree(let worktreeID, let repositoryID): 534 543 return .archiveWorktree(worktreeID, repositoryID) 544 + case .viewArchivedWorktrees: 545 + return .viewArchivedWorktrees 535 546 case .refreshWorktrees: 536 547 return .refreshWorktrees 537 548 case .ghosttyCommand(let action): ··· 579 590 .openRepository, 580 591 .removeWorktree, 581 592 .archiveWorktree, 593 + .viewArchivedWorktrees, 582 594 .refreshWorktrees, 583 595 .ghosttyCommand: 584 596 return nil
+8 -2
supacode/Features/CommandPalette/Views/CommandPaletteOverlayView.swift
··· 340 340 341 341 private var badge: String? { 342 342 switch row.kind { 343 - case .checkForUpdates, .openRepository, .openSettings, .newWorktree, .refreshWorktrees, 343 + case .checkForUpdates, .openRepository, .openSettings, .newWorktree, .viewArchivedWorktrees, 344 + .refreshWorktrees, 344 345 .ghosttyCommand, 345 346 .openPullRequest, .markPullRequestReady, .mergePullRequest, .closePullRequest, .copyFailingJobURL, 346 347 .copyCiFailureLogs, ··· 367 368 return "gearshape" 368 369 case .newWorktree: 369 370 return "plus" 371 + case .viewArchivedWorktrees: 372 + return "archivebox" 370 373 case .refreshWorktrees: 371 374 return "arrow.clockwise" 372 375 case .ghosttyCommand: ··· 402 405 403 406 private var emphasis: Bool { 404 407 switch row.kind { 405 - case .checkForUpdates, .openRepository, .openSettings, .newWorktree, .refreshWorktrees, 408 + case .checkForUpdates, .openRepository, .openSettings, .newWorktree, .viewArchivedWorktrees, 409 + .refreshWorktrees, 406 410 .ghosttyCommand, 407 411 .openPullRequest, .markPullRequestReady, .mergePullRequest, .closePullRequest, .copyFailingJobURL, 408 412 .copyCiFailureLogs, ··· 494 498 base = "Open Settings" 495 499 case .newWorktree: 496 500 base = "New Worktree" 501 + case .viewArchivedWorktrees: 502 + base = "View Archived Worktrees" 497 503 case .refreshWorktrees: 498 504 base = "Refresh Worktrees" 499 505 case .ghosttyCommand:
+14 -2
supacode/Features/Repositories/Reducer/RepositoriesFeature.swift
··· 1242 1242 if state.isWorktreeMerged(worktree) { 1243 1243 return .send(.archiveWorktreeConfirmed(worktree.id, repository.id)) 1244 1244 } 1245 + @Shared(.settingsFile) var settingsFile 1246 + let archivedDisplay = 1247 + AppShortcuts.archivedWorktrees 1248 + .effective(from: settingsFile.global.shortcutOverrides)?.display ?? "none" 1245 1249 state.alert = AlertState { 1246 1250 TextState("Archive worktree?") 1247 1251 } actions: { ··· 1252 1256 TextState("Cancel") 1253 1257 } 1254 1258 } message: { 1255 - TextState("Archive \(worktree.name)?") 1259 + TextState( 1260 + "You can find \(worktree.name) later in Menu Bar > Worktrees > Archived Worktrees (\(archivedDisplay))." 1261 + ) 1256 1262 } 1257 1263 return .none 1258 1264 ··· 1286 1292 return .send(.requestArchiveWorktree(target.worktreeID, target.repositoryID)) 1287 1293 } 1288 1294 let count = validTargets.count 1295 + @Shared(.settingsFile) var settingsFile 1296 + let archivedDisplay = 1297 + AppShortcuts.archivedWorktrees 1298 + .effective(from: settingsFile.global.shortcutOverrides)?.display ?? "none" 1289 1299 state.alert = AlertState { 1290 1300 TextState("Archive \(count) worktrees?") 1291 1301 } actions: { ··· 1296 1306 TextState("Cancel") 1297 1307 } 1298 1308 } message: { 1299 - TextState("Archive \(count) worktrees?") 1309 + TextState( 1310 + "You can find them later in Menu Bar > Worktrees > Archived Worktrees (\(archivedDisplay))." 1311 + ) 1300 1312 } 1301 1313 return .none 1302 1314
+17 -1
supacodeTests/AppFeatureCommandPaletteTests.swift
··· 63 63 await store.receive(\.repositories.refreshWorktrees) 64 64 } 65 65 66 + @Test(.dependencies) func viewArchivedWorktreesDispatchesSelectArchived() async { 67 + let store = TestStore(initialState: AppFeature.State()) { 68 + AppFeature() 69 + } 70 + store.exhaustivity = .off 71 + 72 + await store.send(.commandPalette(.delegate(.viewArchivedWorktrees))) 73 + await store.receive(\.repositories.selectArchivedWorktrees) { 74 + $0.repositories.selection = .archivedWorktrees 75 + $0.repositories.sidebarSelectedWorktreeIDs = [] 76 + } 77 + } 78 + 66 79 @Test(.dependencies) func checkForUpdatesDispatchesUpdateAction() async { 67 80 let store = TestStore(initialState: AppFeature.State()) { 68 81 AppFeature() ··· 171 184 AppFeature() 172 185 } 173 186 187 + let archivedDisplay = AppShortcuts.archivedWorktrees.display 174 188 let expectedAlert = AlertState<RepositoriesFeature.Alert> { 175 189 TextState("Archive worktree?") 176 190 } actions: { ··· 181 195 TextState("Cancel") 182 196 } 183 197 } message: { 184 - TextState("Archive \(worktree.name)?") 198 + TextState( 199 + "You can find \(worktree.name) later in Menu Bar > Worktrees > Archived Worktrees (\(archivedDisplay))." 200 + ) 185 201 } 186 202 187 203 await store.send(.commandPalette(.delegate(.archiveWorktree(worktree.id, repository.id))))
+1
supacodeTests/CommandPaletteFeatureTests.swift
··· 16 16 "global.open-repository", 17 17 "global.new-worktree", 18 18 "global.refresh-worktrees", 19 + "global.view-archived-worktrees", 19 20 ] 20 21 #if DEBUG 21 22 expectedIDs.append(contentsOf: [
+8 -2
supacodeTests/RepositoriesFeatureTests.swift
··· 1249 1249 RepositoriesFeature() 1250 1250 } 1251 1251 1252 + let archivedDisplay = AppShortcuts.archivedWorktrees.display 1252 1253 let expectedAlert = AlertState<RepositoriesFeature.Alert> { 1253 1254 TextState("Archive worktree?") 1254 1255 } actions: { ··· 1259 1260 TextState("Cancel") 1260 1261 } 1261 1262 } message: { 1262 - TextState("Archive \(worktree.name)?") 1263 + TextState( 1264 + "You can find \(worktree.name) later in Menu Bar > Worktrees > Archived Worktrees (\(archivedDisplay))." 1265 + ) 1263 1266 } 1264 1267 1265 1268 await store.send(.requestArchiveWorktree(worktree.id, repository.id)) { ··· 1279 1282 RepositoriesFeature() 1280 1283 } 1281 1284 1285 + let archivedDisplay = AppShortcuts.archivedWorktrees.display 1282 1286 let expectedAlert = AlertState<RepositoriesFeature.Alert> { 1283 1287 TextState("Archive 2 worktrees?") 1284 1288 } actions: { ··· 1289 1293 TextState("Cancel") 1290 1294 } 1291 1295 } message: { 1292 - TextState("Archive 2 worktrees?") 1296 + TextState( 1297 + "You can find them later in Menu Bar > Worktrees > Archived Worktrees (\(archivedDisplay))." 1298 + ) 1293 1299 } 1294 1300 1295 1301 await store.send(.requestArchiveWorktrees(targets)) {