Skip to content

Commit 62338a9

Browse files
authored
feat(dashboard): branch and repository removal (#7047)
* rename menu option to 'Remove branch from CodeSandbox' * query defaultBranch from repository on branch fragment * do not show 'remove branch from codesandbox' if default branch * allow removing repositories through the branch menu * handle repository removal from the recent page * rename 'remove from codesandbox' to 'remove repository from codesandbox' on the RepositoryMenu * trigger repository removal from branch menu * do not show option to remove repository if branch is contribution * handle branch removal from contributions page * fix typecheck
1 parent 942d385 commit 62338a9

File tree

7 files changed

+93
-36
lines changed

7 files changed

+93
-36
lines changed

packages/app/src/app/graphql/types.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2290,7 +2290,7 @@ export type BranchFragment = { __typename?: 'Branch' } & Pick<
22902290
project: { __typename?: 'Project' } & {
22912291
repository: { __typename?: 'GitHubRepository' } & Pick<
22922292
GitHubRepository,
2293-
'name' | 'owner'
2293+
'defaultBranch' | 'name' | 'owner'
22942294
>;
22952295
};
22962296
};

packages/app/src/app/overmind/effects/gql/dashboard/fragments.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -225,6 +225,7 @@ export const branchFragment = gql`
225225
project {
226226
repository {
227227
... on GitHubRepository {
228+
defaultBranch
228229
name
229230
owner
230231
}

packages/app/src/app/overmind/namespaces/dashboard/actions.ts

Lines changed: 31 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2115,27 +2115,32 @@ export const removeBranchFromRepository = async (
21152115
try {
21162116
await effects.api.removeBranchFromRepository(owner, repoName, name);
21172117

2118+
// Manually remove the data from the state based on the
2119+
// current page. Then sync in the background.
21182120
if (page === 'repositories') {
21192121
const repository = state.dashboard.repositories?.find(
21202122
r => r.repository.owner === owner && r.repository.name === repoName
21212123
);
21222124

21232125
if (repository) {
2124-
// Manually remove the data from the state.
21252126
repository.branches = repository.branches.filter(b => b.id !== id);
21262127
}
21272128

2128-
// Then sync in the background.
21292129
actions.dashboard.getRepositoriesByTeam({ bypassLoading: true });
21302130
}
21312131

2132+
if (page === 'my-contributions') {
2133+
state.dashboard.contributions =
2134+
state.dashboard.contributions?.filter(b => b.id !== id) ?? [];
2135+
2136+
actions.dashboard.getContributionBranches();
2137+
}
2138+
21322139
if (page === 'recent') {
2133-
// First, manually remove the data from the state.
21342140
state.dashboard.sandboxes.RECENT_BRANCHES =
21352141
state.dashboard.sandboxes.RECENT_BRANCHES?.filter(b => b.id !== id) ??
21362142
[];
21372143

2138-
// Then sync in the background.
21392144
actions.dashboard.getStartPageSandboxes();
21402145
}
21412146
} catch (error) {
@@ -2151,26 +2156,40 @@ type ProjectToRemove = {
21512156
owner: string;
21522157
name: string;
21532158
teamId: string;
2159+
page: PageTypes;
21542160
};
21552161
export const removeRepositoryFromTeam = async (
21562162
context: Context,
21572163
project: ProjectToRemove
21582164
) => {
21592165
const { actions, state, effects } = context;
2160-
const { owner, name, teamId } = project;
2166+
const { owner, name, teamId, page } = project;
21612167

21622168
state.dashboard.removingRepository = { owner, name };
21632169

21642170
try {
21652171
await effects.api.removeRepositoryFromTeam(owner, name, teamId);
21662172

2167-
// First, manually remove the data from the state.
2168-
state.dashboard.repositories =
2169-
state.dashboard.repositories?.filter(
2170-
r => r.repository.owner !== owner || r.repository.name !== name
2171-
) ?? [];
2172-
// Then sync in the background.
2173-
actions.dashboard.getRepositoriesByTeam({ bypassLoading: true });
2173+
if (page === 'recent') {
2174+
// First, manually remove the data from the state.
2175+
state.dashboard.sandboxes.RECENT_BRANCHES =
2176+
state.dashboard.sandboxes.RECENT_BRANCHES?.filter(b => {
2177+
const branchRepo = b.project.repository;
2178+
2179+
return branchRepo.owner === owner && branchRepo.name === name;
2180+
}) ?? [];
2181+
2182+
// Then sync in the background.
2183+
actions.dashboard.getStartPageSandboxes();
2184+
} else {
2185+
// First, manually remove the data from the state.
2186+
state.dashboard.repositories =
2187+
state.dashboard.repositories?.filter(
2188+
r => r.repository.owner !== owner || r.repository.name !== name
2189+
) ?? [];
2190+
// Then sync in the background.
2191+
actions.dashboard.getRepositoriesByTeam({ bypassLoading: true });
2192+
}
21742193
} catch (error) {
21752194
effects.notificationToast.error(
21762195
`Failed to remove project ${owner}/${name}`

packages/app/src/app/pages/Dashboard/Components/Branch/index.tsx

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ type BranchProps = DashboardBranch & {
2020
};
2121
export const Branch: React.FC<BranchProps> = ({ branch, page }) => {
2222
const {
23-
dashboard: { removingBranch, viewMode },
23+
dashboard: { removingBranch, removingRepository, viewMode },
2424
} = useAppState();
2525
const { selectedIds, onRightClick, onMenuEvent } = useSelection();
2626
const { name, project } = branch;
@@ -38,11 +38,16 @@ export const Branch: React.FC<BranchProps> = ({ branch, page }) => {
3838
trackImprovedDashboardEvent(MAP_BRANCH_EVENT_TO_PAGE_TYPE[page]);
3939
};
4040

41+
const isParentRepositoryBeingRemoved =
42+
removingRepository?.owner === project.repository.owner &&
43+
removingRepository?.name === project.repository.name;
44+
4145
const props = {
4246
branch,
4347
branchUrl,
4448
selected: selectedIds.includes(branch.id),
45-
isBeingRemoved: removingBranch?.id === branch.id,
49+
isBeingRemoved:
50+
removingBranch?.id === branch.id || isParentRepositoryBeingRemoved,
4651
onContextMenu: handleContextMenu,
4752
onClick: handleClick,
4853
/**

packages/app/src/app/pages/Dashboard/Components/Selection/ContextMenu.tsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,9 @@ export const ContextMenu: React.FC<IContextMenuProps> = ({
129129
} else if (selectedItems[0].type === 'branch') {
130130
menu = <BranchMenu branch={selectedItems[0].branch} page={page} />;
131131
} else if (selectedItems[0].type === 'repository') {
132-
menu = <RepositoryMenu repository={selectedItems[0].repository} />;
132+
menu = (
133+
<RepositoryMenu repository={selectedItems[0].repository} page={page} />
134+
);
133135
} else if (selectedItems.length > 1) {
134136
menu = (
135137
<MultiMenu

packages/app/src/app/pages/Dashboard/Components/Selection/ContextMenus/BranchMenu.tsx

Lines changed: 45 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -16,14 +16,20 @@ type BranchMenuProps = {
1616
page: PageTypes;
1717
};
1818
export const BranchMenu: React.FC<BranchMenuProps> = ({ branch, page }) => {
19-
const { removeBranchFromRepository } = useActions().dashboard;
20-
const { removingBranch } = useAppState().dashboard;
19+
const {
20+
removeBranchFromRepository,
21+
removeRepositoryFromTeam,
22+
} = useActions().dashboard;
23+
const {
24+
activeTeam,
25+
dashboard: { removingBranch, removingRepository },
26+
} = useAppState();
2127
const { visible, setVisibility, position } = React.useContext(Context);
2228

2329
const { id, name, project, contribution } = branch;
2430
const branchUrl = v2BranchUrl({ name, project });
2531

26-
const { name: repoName, owner } = project.repository;
32+
const { name: repoName, owner, defaultBranch } = project.repository;
2733

2834
const githubUrl = githubRepoUrl({
2935
branch: name,
@@ -36,6 +42,8 @@ export const BranchMenu: React.FC<BranchMenuProps> = ({ branch, page }) => {
3642

3743
const history = useHistory();
3844

45+
const canRemoveBranch = name !== defaultBranch;
46+
3947
return (
4048
<Menu.ContextMenu
4149
visible={visible}
@@ -61,22 +69,40 @@ export const BranchMenu: React.FC<BranchMenuProps> = ({ branch, page }) => {
6169
<MenuItem onSelect={() => history.push(repoUrl)}>
6270
Open repository
6371
</MenuItem>
64-
<Menu.Divider />
65-
<MenuItem
66-
disabled={removingBranch}
67-
onSelect={() =>
68-
!removingBranch &&
69-
removeBranchFromRepository({
70-
id,
71-
owner,
72-
repoName,
73-
name,
74-
page,
75-
})
76-
}
77-
>
78-
Remove from CodeSandbox
79-
</MenuItem>
72+
{(canRemoveBranch || !contribution) && <Menu.Divider />}
73+
{canRemoveBranch && (
74+
<MenuItem
75+
disabled={removingBranch}
76+
onSelect={() =>
77+
!removingBranch &&
78+
removeBranchFromRepository({
79+
id,
80+
owner,
81+
repoName,
82+
name,
83+
page,
84+
})
85+
}
86+
>
87+
Remove branch from CodeSandbox
88+
</MenuItem>
89+
)}
90+
{!contribution && (
91+
<MenuItem
92+
disabled={removingRepository}
93+
onSelect={() =>
94+
!removingRepository &&
95+
removeRepositoryFromTeam({
96+
owner,
97+
name: repoName,
98+
teamId: activeTeam,
99+
page,
100+
})
101+
}
102+
>
103+
Remove repository from CodeSandbox
104+
</MenuItem>
105+
)}
80106
</Menu.ContextMenu>
81107
);
82108
};

packages/app/src/app/pages/Dashboard/Components/Selection/ContextMenus/RepositoryMenu.tsx

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,16 @@ import {
99
} from '@codesandbox/common/lib/utils/url-generator';
1010
import { useActions, useAppState } from 'app/overmind';
1111
import { quotes } from 'app/utils/quotes';
12+
import { PageTypes } from 'app/overmind/namespaces/dashboard/types';
1213
import { Context, MenuItem } from '../ContextMenu';
1314

1415
type RepositoryMenuProps = {
1516
repository: Repository;
17+
page: PageTypes;
1618
};
1719
export const RepositoryMenu: React.FC<RepositoryMenuProps> = ({
1820
repository,
21+
page,
1922
}) => {
2023
const {
2124
activeTeam,
@@ -106,10 +109,11 @@ export const RepositoryMenu: React.FC<RepositoryMenuProps> = ({
106109
owner: providerRepository.owner,
107110
name: providerRepository.name,
108111
teamId: activeTeam,
112+
page,
109113
})
110114
}
111115
>
112-
Remove from CodeSandbox
116+
Remove repository from CodeSandbox
113117
</MenuItem>
114118
</Menu.ContextMenu>
115119
);

0 commit comments

Comments
 (0)