diff --git a/supacode/Commands/WorktreeCommands.swift b/supacode/Commands/WorktreeCommands.swift index d26efe2f..4996e3e9 100644 --- a/supacode/Commands/WorktreeCommands.swift +++ b/supacode/Commands/WorktreeCommands.swift @@ -66,11 +66,14 @@ struct WorktreeCommands: Commands { worktreeMenuButton(entry: entry) } Divider() - Button("Archived Worktrees") { + Button(store.state.repositories.isShowingArchivedWorktrees ? "Exit Archived Worktrees" : "Archived Worktrees") { store.send(.repositories(.selectArchivedWorktrees)) } .modifier(KeyboardShortcutModifier(shortcut: keyboardShortcut(for: AppShortcuts.CommandID.archivedWorktrees))) - .help(helpText(title: "Archived Worktrees", commandID: AppShortcuts.CommandID.archivedWorktrees)) + .help( + helpText( + title: store.state.repositories.isShowingArchivedWorktrees ? "Exit Archived Worktrees" : "Archived Worktrees", + commandID: AppShortcuts.CommandID.archivedWorktrees)) } CommandGroup(replacing: .newItem) { if !customCommands.isEmpty { diff --git a/supacode/Features/Repositories/Reducer/RepositoriesFeature+CoreReducer.swift b/supacode/Features/Repositories/Reducer/RepositoriesFeature+CoreReducer.swift index a1bf0106..b6ba8c96 100644 --- a/supacode/Features/Repositories/Reducer/RepositoriesFeature+CoreReducer.swift +++ b/supacode/Features/Repositories/Reducer/RepositoriesFeature+CoreReducer.swift @@ -345,6 +345,23 @@ extension RepositoriesFeature { case .selectArchivedWorktrees: state.isShelfActive = false + // Toggle: if already showing archived, return to the previous worktree. + if state.isShowingArchivedWorktrees { + if let previousID = state.preArchivedWorktreeID, + state.worktree(for: previousID) != nil + { + setSingleWorktreeSelection(previousID, state: &state, recordHistory: false) + state.openedWorktreeIDs.insert(previousID) + state.pendingTerminalFocusWorktreeIDs.insert(previousID) + return .send(.delegate(.selectedWorktreeChanged(state.worktree(for: previousID)))) + } + state.selection = nil + state.selectedWorkspaceChildID = nil + state.sidebarSelectedWorktreeIDs = [] + return .send(.delegate(.selectedWorktreeChanged(nil))) + } + // Entering archived view — remember current worktree for later restore. + state.preArchivedWorktreeID = state.selectedWorktreeID recordWorktreeHistoryTransition(from: state.selectedWorktreeID, to: nil, state: &state) state.selection = .archivedWorktrees state.selectedWorkspaceChildID = nil diff --git a/supacode/Features/Repositories/Reducer/RepositoriesFeature.swift b/supacode/Features/Repositories/Reducer/RepositoriesFeature.swift index d5a53514..f469d881 100644 --- a/supacode/Features/Repositories/Reducer/RepositoriesFeature.swift +++ b/supacode/Features/Repositories/Reducer/RepositoriesFeature.swift @@ -315,6 +315,7 @@ struct RepositoriesFeature { var lastFocusedWorktreeID: Worktree.ID? var preCanvasWorktreeID: Worktree.ID? var preCanvasTerminalTargetID: Worktree.ID? + var preArchivedWorktreeID: Worktree.ID? var isShelfActive: Bool = false var worktreeHistoryBackStack: [Worktree.ID] = [] var worktreeHistoryForwardStack: [Worktree.ID] = [] diff --git a/supacode/Features/Repositories/Views/SidebarFooterView.swift b/supacode/Features/Repositories/Views/SidebarFooterView.swift index 52919568..72c50b42 100644 --- a/supacode/Features/Repositories/Views/SidebarFooterView.swift +++ b/supacode/Features/Repositories/Views/SidebarFooterView.swift @@ -75,12 +75,12 @@ struct SidebarFooterView: View { Button { store.send(.selectArchivedWorktrees) } label: { - Image(systemName: "archivebox") - .accessibilityLabel("Archived Worktrees") + Image(systemName: store.state.isShowingArchivedWorktrees ? "arrow.uturn.left" : "archivebox") + .accessibilityLabel(store.state.isShowingArchivedWorktrees ? "Exit Archived Worktrees" : "Archived Worktrees") } .help( AppShortcuts.helpText( - title: "Archived Worktrees", + title: store.state.isShowingArchivedWorktrees ? "Exit Archived Worktrees" : "Archived Worktrees", commandID: AppShortcuts.CommandID.archivedWorktrees, in: resolvedKeybindings )) diff --git a/supacodeTests/AppFeatureArchivedSelectionTests.swift b/supacodeTests/AppFeatureArchivedSelectionTests.swift index fc55813d..dcd21792 100644 --- a/supacodeTests/AppFeatureArchivedSelectionTests.swift +++ b/supacodeTests/AppFeatureArchivedSelectionTests.swift @@ -44,6 +44,7 @@ struct AppFeatureArchivedSelectionTests { await store.send(.repositories(.selectArchivedWorktrees)) { $0.repositories.worktreeHistoryBackStack = [worktree.id] $0.repositories.selection = .archivedWorktrees + $0.repositories.preArchivedWorktreeID = worktree.id } await store.receive(\.repositories.delegate.selectedWorktreeChanged) await store.finish() diff --git a/supacodeTests/RepositoriesFeatureTests.swift b/supacodeTests/RepositoriesFeatureTests.swift index 47a8fa21..7c2eb919 100644 --- a/supacodeTests/RepositoriesFeatureTests.swift +++ b/supacodeTests/RepositoriesFeatureTests.swift @@ -2813,6 +2813,7 @@ struct RepositoriesFeatureTests { $0.worktreeHistoryBackStack = [worktree1.id] $0.selection = .archivedWorktrees $0.sidebarSelectedWorktreeIDs = [] + $0.preArchivedWorktreeID = worktree1.id } await store.receive(\.delegate.selectedWorktreeChanged) } @@ -6657,6 +6658,7 @@ struct RepositoriesFeatureTests { $0.worktreeHistoryForwardStack = [] $0.selection = .archivedWorktrees $0.sidebarSelectedWorktreeIDs = [] + $0.preArchivedWorktreeID = wt1.id } await store.receive(\.delegate.selectedWorktreeChanged) } diff --git a/supacodeTests/ShelfFeatureTests.swift b/supacodeTests/ShelfFeatureTests.swift index 5492b20e..14c78b3e 100644 --- a/supacodeTests/ShelfFeatureTests.swift +++ b/supacodeTests/ShelfFeatureTests.swift @@ -868,6 +868,40 @@ struct ShelfFeatureTests { $0.worktreeHistoryBackStack = [worktree.id] $0.selection = .archivedWorktrees $0.sidebarSelectedWorktreeIDs = [] + $0.preArchivedWorktreeID = worktree.id + } + await store.receive(\.delegate.selectedWorktreeChanged) + await store.finish() + } + + @Test(.dependencies) func selectArchivedWorktreesTogglesBackToPreviousWorktree() async { + let rootURL = URL(fileURLWithPath: "/tmp/repo") + let worktree = Worktree( + id: "/tmp/repo/wt1", + name: "wt1", + detail: "", + workingDirectory: URL(fileURLWithPath: "/tmp/repo/wt1"), + repositoryRootURL: rootURL + ) + let repository = Repository( + id: rootURL.path(percentEncoded: false), + rootURL: rootURL, + name: "repo", + worktrees: IdentifiedArray(uniqueElements: [worktree]) + ) + var state = RepositoriesFeature.State(repositories: [repository]) + state.selection = .archivedWorktrees + state.sidebarSelectedWorktreeIDs = [] + state.preArchivedWorktreeID = worktree.id + let store = TestStore(initialState: state) { + RepositoriesFeature() + } + + await store.send(.selectArchivedWorktrees) { + $0.selection = .worktree(worktree.id) + $0.sidebarSelectedWorktreeIDs = [worktree.id] + $0.openedWorktreeIDs = [worktree.id] + $0.pendingTerminalFocusWorktreeIDs = [worktree.id] } await store.receive(\.delegate.selectedWorktreeChanged) await store.finish()