Skip to content

Commit dce5441

Browse files
committed
Delete local branch
Fixes #308
1 parent bc8f205 commit dce5441

File tree

7 files changed

+103
-16
lines changed

7 files changed

+103
-16
lines changed

src/components/BranchMenu.tsx

Lines changed: 38 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,10 @@ import * as React from 'react';
66
import { FixedSizeList, ListChildComponentProps } from 'react-window';
77
import { classes } from 'typestyle';
88
import { Logger } from '../logger';
9+
import { hiddenButtonStyle } from '../style/ActionButtonStyle';
910
import {
1011
activeListItemClass,
12+
branchNameClass,
1113
filterClass,
1214
filterClearClass,
1315
filterInputClass,
@@ -17,8 +19,9 @@ import {
1719
newBranchButtonClass,
1820
wrapperClass
1921
} from '../style/BranchMenu';
20-
import { branchIcon } from '../style/icons';
22+
import { branchIcon, trashIcon } from '../style/icons';
2123
import { Git, IGitExtension, Level } from '../tokens';
24+
import { ActionButton } from './ActionButton';
2225
import { NewBranchDialog } from './NewBranchDialog';
2326

2427
const CHANGES_ERR_MSG =
@@ -254,7 +257,18 @@ export class BranchMenu extends React.Component<
254257
style={style}
255258
>
256259
<branchIcon.react className={listItemIconClass} tag="span" />
257-
{branch.name}
260+
<span className={branchNameClass}>{branch.name}</span>
261+
{!branch.is_remote_branch && !isActive && (
262+
<ActionButton
263+
className={hiddenButtonStyle}
264+
icon={trashIcon}
265+
title={'Delete this branch'}
266+
onClick={(event: React.MouseEvent) => {
267+
event.stopPropagation();
268+
this._onDeleteBranch(branch.name);
269+
}}
270+
/>
271+
)}
258272
</ListItem>
259273
);
260274
};
@@ -297,6 +311,28 @@ export class BranchMenu extends React.Component<
297311
});
298312
};
299313

314+
/**
315+
* Callback on delete branch name button
316+
*
317+
* @param branchName Branch name
318+
*/
319+
private _onDeleteBranch = async (branchName: string): Promise<void> => {
320+
const acknowledgement = await showDialog<void>({
321+
title: 'Delete branch',
322+
body: (
323+
<p>
324+
{`The branch '${branchName}' will be deleted. This can not be undone.`}
325+
<br />
326+
Please confirm you want to delete it.
327+
</p>
328+
),
329+
buttons: [Dialog.cancelButton(), Dialog.warnButton({ label: 'Delete' })]
330+
});
331+
if (acknowledgement.button.accept) {
332+
await this.props.model.deleteBranch(branchName);
333+
}
334+
};
335+
300336
/**
301337
* Callback invoked upon clicking a button to create a new branch.
302338
*

src/components/TagMenu.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import * as React from 'react';
66
import { FixedSizeList, ListChildComponentProps } from 'react-window';
77
import { Logger } from '../logger';
88
import {
9+
branchNameClass,
910
filterClass,
1011
filterClearClass,
1112
filterInputClass,
@@ -241,7 +242,7 @@ export class TagMenu extends React.Component<ITagMenuProps, ITagMenuState> {
241242
style={style}
242243
>
243244
<tagIcon.react className={listItemIconClass} tag="span" />
244-
{tag}
245+
<span className={branchNameClass}>{tag}</span>
245246
</ListItem>
246247
);
247248
};

src/model.ts

Lines changed: 28 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -486,15 +486,23 @@ export class GitExtension implements IGitExtension {
486486
}
487487

488488
/**
489-
* Dispose of model resources.
489+
* Delete a branch
490+
*
491+
* @param branchName Branch name
492+
* @returns promise which resolves when the branch has been deleted.
493+
*
494+
* @throws {Git.NotInRepository} If the current path is not a Git repository
495+
* @throws {Git.GitResponseError} If the server response is not ok
496+
* @throws {ServerConnection.NetworkError} If the request cannot be made
490497
*/
491-
dispose(): void {
492-
if (this.isDisposed) {
493-
return;
494-
}
495-
this._isDisposed = true;
496-
this._poll.dispose();
497-
Signal.clearData(this);
498+
async deleteBranch(branchName: string): Promise<void> {
499+
const path = await this._getPathRespository();
500+
await this._taskHandler.execute<void>('git:branch:delete', async () => {
501+
return await requestAPI<void>('branch_delete', 'POST', {
502+
current_path: path,
503+
branch: branchName
504+
});
505+
});
498506
}
499507

500508
/**
@@ -530,6 +538,18 @@ export class GitExtension implements IGitExtension {
530538
return data;
531539
}
532540

541+
/**
542+
* Dispose of model resources.
543+
*/
544+
dispose(): void {
545+
if (this.isDisposed) {
546+
return;
547+
}
548+
this._isDisposed = true;
549+
this._poll.dispose();
550+
Signal.clearData(this);
551+
}
552+
533553
/**
534554
* Ensure a .gitignore file exists
535555
*

src/style/BranchMenu.ts

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,12 @@
11
import { style } from 'typestyle';
2+
import { showButtonOnHover } from './ActionButtonStyle';
3+
4+
export const branchNameClass = style({
5+
flex: '1 1 auto',
6+
textOverflow: 'ellipsis',
7+
overflow: 'hidden',
8+
whiteSpace: 'nowrap'
9+
});
210

311
export const wrapperClass = style({
412
marginTop: '6px',
@@ -105,11 +113,12 @@ export const newBranchButtonClass = style({
105113
}
106114
});
107115

108-
export const listItemClass = style({
109-
paddingTop: '4px!important',
110-
paddingBottom: '4px!important',
111-
paddingLeft: '11px!important'
112-
});
116+
export const listItemClass = style(
117+
{
118+
padding: '4px 11px!important'
119+
},
120+
showButtonOnHover
121+
);
113122

114123
export const activeListItemClass = style({
115124
color: 'white!important',

src/style/icons.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import pushSvg from '../../style/icons/push.svg';
1616
import removeSvg from '../../style/icons/remove.svg';
1717
import rewindSvg from '../../style/icons/rewind.svg';
1818
import tagSvg from '../../style/icons/tag.svg';
19+
import trashSvg from '../../style/icons/trash.svg';
1920

2021
export const gitIcon = new LabIcon({ name: 'git', svgstr: gitSvg });
2122
export const addIcon = new LabIcon({
@@ -74,3 +75,7 @@ export const tagIcon = new LabIcon({
7475
name: 'git:tag',
7576
svgstr: tagSvg
7677
});
78+
export const trashIcon = new LabIcon({
79+
name: 'git:trash',
80+
svgstr: trashSvg
81+
});

src/tokens.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -206,6 +206,18 @@ export interface IGitExtension extends IDisposable {
206206
*/
207207
config(options?: JSONObject): Promise<JSONObject | void>;
208208

209+
/**
210+
* Delete a branch
211+
*
212+
* @param branchName Branch name
213+
* @returns promise which resolves when the branch has been deleted.
214+
*
215+
* @throws {Git.NotInRepository} If the current path is not a Git repository
216+
* @throws {Git.GitResponseError} If the server response is not ok
217+
* @throws {ServerConnection.NetworkError} If the request cannot be made
218+
*/
219+
deleteBranch(branchName: string): Promise<void>;
220+
209221
/**
210222
* Fetch commit information.
211223
*

style/icons/trash.svg

Lines changed: 4 additions & 0 deletions
Loading

0 commit comments

Comments
 (0)