native macOS codings agent orchestrator
6
fork

Configure Feed

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

Merge pull request #119 from barrettj/feature/up-down-ignore-collapsed

Skip collapsed repositories in worktree navigation

authored by

khoi and committed by
GitHub
d1287fce 0aa727ae

+102 -11
+9 -1
supacode/Features/Repositories/Reducer/RepositoriesFeature.swift
··· 86 86 var inFlightPullRequestRefreshRepositoryIDs: Set<Repository.ID> = [] 87 87 var queuedPullRequestRefreshByRepositoryID: [Repository.ID: PendingPullRequestRefresh] = [:] 88 88 var sidebarSelectedWorktreeIDs: Set<Worktree.ID> = [] 89 + @Shared(.appStorage("sidebarCollapsedRepositoryIDs")) var collapsedRepositoryIDs: [Repository.ID] = [] 89 90 @Presents var worktreeCreationPrompt: WorktreeCreationPromptFeature.State? 90 91 @Presents var alert: AlertState<Alert>? 91 92 } ··· 2616 2617 selection?.worktreeID 2617 2618 } 2618 2619 2620 + var expandedRepositoryIDs: Set<Repository.ID> { 2621 + let repositoryIDs = Set(repositories.map(\.id)) 2622 + let collapsedSet = Set(collapsedRepositoryIDs).intersection(repositoryIDs) 2623 + let pendingRepositoryIDs = Set(pendingWorktrees.map(\.repositoryID)) 2624 + return repositoryIDs.subtracting(collapsedSet).union(pendingRepositoryIDs) 2625 + } 2626 + 2619 2627 func worktreeID(byOffset offset: Int) -> Worktree.ID? { 2620 - let rows = orderedWorktreeRows() 2628 + let rows = orderedWorktreeRows(includingRepositoryIDs: expandedRepositoryIDs) 2621 2629 guard !rows.isEmpty else { return nil } 2622 2630 if let currentID = selectedWorktreeID, 2623 2631 let currentIndex = rows.firstIndex(where: { $0.id == currentID })
+1 -10
supacode/Features/Repositories/Views/SidebarView.swift
··· 11 11 var body: some View { 12 12 let state = store.state 13 13 let repositoryIDs = Set(state.repositories.map(\.id)) 14 - let expandedRepoIDs = expandedRepositoryIDs(state: state, repositoryIDs: repositoryIDs) 14 + let expandedRepoIDs = state.expandedRepositoryIDs 15 15 let expandedRepoIDsBinding = expandedRepoIDsBinding( 16 16 repositoryIDs: repositoryIDs, 17 17 expandedRepoIDs: expandedRepoIDs ··· 49 49 $0 = Array(collapsed).sorted() 50 50 } 51 51 } 52 - } 53 - 54 - private func expandedRepositoryIDs( 55 - state: RepositoriesFeature.State, 56 - repositoryIDs: Set<Repository.ID> 57 - ) -> Set<Repository.ID> { 58 - let pendingRepositoryIDs = Set(state.pendingWorktrees.map(\.repositoryID)) 59 - let collapsedSet = Set(collapsedRepositoryIDs).intersection(repositoryIDs) 60 - return repositoryIDs.subtracting(collapsedSet).union(pendingRepositoryIDs) 61 52 } 62 53 63 54 private func expandedRepoIDsBinding(
+92
supacodeTests/RepositoriesFeatureTests.swift
··· 1908 1908 await store.receive(\.delegate.selectedWorktreeChanged) 1909 1909 } 1910 1910 1911 + @Test func selectNextWorktreeSkipsCollapsedRepository() async { 1912 + let wt1 = makeWorktree(id: "/tmp/repo1/wt1", name: "alpha", repoRoot: "/tmp/repo1") 1913 + let wt2 = makeWorktree(id: "/tmp/repo2/wt2", name: "beta", repoRoot: "/tmp/repo2") 1914 + let wt3 = makeWorktree(id: "/tmp/repo3/wt3", name: "gamma", repoRoot: "/tmp/repo3") 1915 + let repo1 = makeRepository(id: "/tmp/repo1", worktrees: [wt1]) 1916 + let repo2 = makeRepository(id: "/tmp/repo2", worktrees: [wt2]) 1917 + let repo3 = makeRepository(id: "/tmp/repo3", worktrees: [wt3]) 1918 + var state = makeState(repositories: [repo1, repo2, repo3]) 1919 + state.selection = .worktree(wt1.id) 1920 + state.$collapsedRepositoryIDs.withLock { $0 = [repo2.id] } 1921 + let store = TestStore(initialState: state) { 1922 + RepositoriesFeature() 1923 + } 1924 + 1925 + await store.send(.selectNextWorktree) 1926 + await store.receive(\.selectWorktree) { 1927 + $0.selection = .worktree(wt3.id) 1928 + $0.sidebarSelectedWorktreeIDs = [wt3.id] 1929 + } 1930 + await store.receive(\.delegate.selectedWorktreeChanged) 1931 + } 1932 + 1933 + @Test func selectPreviousWorktreeSkipsCollapsedRepository() async { 1934 + let wt1 = makeWorktree(id: "/tmp/repo1/wt1", name: "alpha", repoRoot: "/tmp/repo1") 1935 + let wt2 = makeWorktree(id: "/tmp/repo2/wt2", name: "beta", repoRoot: "/tmp/repo2") 1936 + let wt3 = makeWorktree(id: "/tmp/repo3/wt3", name: "gamma", repoRoot: "/tmp/repo3") 1937 + let repo1 = makeRepository(id: "/tmp/repo1", worktrees: [wt1]) 1938 + let repo2 = makeRepository(id: "/tmp/repo2", worktrees: [wt2]) 1939 + let repo3 = makeRepository(id: "/tmp/repo3", worktrees: [wt3]) 1940 + var state = makeState(repositories: [repo1, repo2, repo3]) 1941 + state.selection = .worktree(wt3.id) 1942 + state.$collapsedRepositoryIDs.withLock { $0 = [repo2.id] } 1943 + let store = TestStore(initialState: state) { 1944 + RepositoriesFeature() 1945 + } 1946 + 1947 + await store.send(.selectPreviousWorktree) 1948 + await store.receive(\.selectWorktree) { 1949 + $0.selection = .worktree(wt1.id) 1950 + $0.sidebarSelectedWorktreeIDs = [wt1.id] 1951 + } 1952 + await store.receive(\.delegate.selectedWorktreeChanged) 1953 + } 1954 + 1955 + @Test func selectNextWorktreeAllCollapsedIsNoOp() async { 1956 + let wt1 = makeWorktree(id: "/tmp/repo1/wt1", name: "alpha", repoRoot: "/tmp/repo1") 1957 + let repo1 = makeRepository(id: "/tmp/repo1", worktrees: [wt1]) 1958 + var state = makeState(repositories: [repo1]) 1959 + state.selection = .worktree(wt1.id) 1960 + state.$collapsedRepositoryIDs.withLock { $0 = [repo1.id] } 1961 + let store = TestStore(initialState: state) { 1962 + RepositoriesFeature() 1963 + } 1964 + 1965 + await store.send(.selectNextWorktree) 1966 + } 1967 + 1968 + @Test func selectPreviousWorktreeAllCollapsedIsNoOp() async { 1969 + let wt1 = makeWorktree(id: "/tmp/repo1/wt1", name: "alpha", repoRoot: "/tmp/repo1") 1970 + let repo1 = makeRepository(id: "/tmp/repo1", worktrees: [wt1]) 1971 + var state = makeState(repositories: [repo1]) 1972 + state.selection = .worktree(wt1.id) 1973 + state.$collapsedRepositoryIDs.withLock { $0 = [repo1.id] } 1974 + let store = TestStore(initialState: state) { 1975 + RepositoriesFeature() 1976 + } 1977 + 1978 + await store.send(.selectPreviousWorktree) 1979 + } 1980 + 1981 + @Test func selectNextWorktreeWrapsAroundSkippingCollapsedRepo() async { 1982 + let wt1 = makeWorktree(id: "/tmp/repo1/wt1", name: "alpha", repoRoot: "/tmp/repo1") 1983 + let wt2 = makeWorktree(id: "/tmp/repo2/wt2", name: "beta", repoRoot: "/tmp/repo2") 1984 + let wt3 = makeWorktree(id: "/tmp/repo3/wt3", name: "gamma", repoRoot: "/tmp/repo3") 1985 + let repo1 = makeRepository(id: "/tmp/repo1", worktrees: [wt1]) 1986 + let repo2 = makeRepository(id: "/tmp/repo2", worktrees: [wt2]) 1987 + let repo3 = makeRepository(id: "/tmp/repo3", worktrees: [wt3]) 1988 + var state = makeState(repositories: [repo1, repo2, repo3]) 1989 + state.selection = .worktree(wt3.id) 1990 + state.$collapsedRepositoryIDs.withLock { $0 = [repo2.id] } 1991 + let store = TestStore(initialState: state) { 1992 + RepositoriesFeature() 1993 + } 1994 + 1995 + await store.send(.selectNextWorktree) 1996 + await store.receive(\.selectWorktree) { 1997 + $0.selection = .worktree(wt1.id) 1998 + $0.sidebarSelectedWorktreeIDs = [wt1.id] 1999 + } 2000 + await store.receive(\.delegate.selectedWorktreeChanged) 2001 + } 2002 + 1911 2003 private func makeWorktree( 1912 2004 id: String, 1913 2005 name: String,