Skip to content

Commit a9f3b02

Browse files
committed
Allow deleting already pushed tags
1 parent 083cd4b commit a9f3b02

File tree

5 files changed

+115
-8
lines changed

5 files changed

+115
-8
lines changed

app/src/models/popup.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ export enum PopupType {
6464
StashAndSwitchBranch = 'StashAndSwitchBranch',
6565
ConfirmDiscardStash = 'ConfirmDiscardStash',
6666
ConfirmCheckoutCommit = 'ConfirmCheckoutCommit',
67+
ConfirmDeletePushedTag = 'ConfirmDeletePushedTag',
6768
CreateTutorialRepository = 'CreateTutorialRepository',
6869
ConfirmExitTutorial = 'ConfirmExitTutorial',
6970
PushRejectedDueToMissingWorkflowScope = 'PushRejectedDueToMissingWorkflowScope',
@@ -256,6 +257,11 @@ export type PopupDetail =
256257
repository: Repository
257258
commit: CommitOneLine
258259
}
260+
| {
261+
type: PopupType.ConfirmDeletePushedTag
262+
repository: Repository
263+
tagName: string
264+
}
259265
| {
260266
type: PopupType.CreateTutorialRepository
261267
account: Account

app/src/ui/app.tsx

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,7 @@ import { Banner, BannerType } from '../models/banner'
109109
import { StashAndSwitchBranch } from './stash-changes/stash-and-switch-branch-dialog'
110110
import { ConfirmDiscardStashDialog } from './stashing/confirm-discard-stash'
111111
import { ConfirmCheckoutCommitDialog } from './checkout/confirm-checkout-commit'
112+
import { ConfirmDeletePushedTagDialog } from './tag/confirm-delete-pushed-tag'
112113
import { CreateTutorialRepositoryDialog } from './no-repositories/create-tutorial-repository-dialog'
113114
import { ConfirmExitTutorial } from './tutorial'
114115
import { TutorialStep, isValidTutorialStep } from '../models/tutorial-step'
@@ -2013,6 +2014,19 @@ export class App extends React.Component<IAppProps, IAppState> {
20132014
/>
20142015
)
20152016
}
2017+
case PopupType.ConfirmDeletePushedTag: {
2018+
const { repository, tagName } = popup
2019+
2020+
return (
2021+
<ConfirmDeletePushedTagDialog
2022+
key="confirm-delete-pushed-tag-dialog"
2023+
dispatcher={this.props.dispatcher}
2024+
repository={repository}
2025+
tagName={tagName}
2026+
onDismissed={onPopupDismissedFn}
2027+
/>
2028+
)
2029+
}
20162030
case PopupType.CreateTutorialRepository: {
20172031
return (
20182032
<CreateTutorialRepositoryDialog

app/src/ui/history/commit-list.tsx

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -118,8 +118,8 @@ interface ICommitListProps {
118118
/** Callback to fire to open the dialog to create a new tag on the given commit */
119119
readonly onCreateTag?: (targetCommitSha: string) => void
120120

121-
/** Callback to fire to delete an unpushed tag */
122-
readonly onDeleteTag?: (tagName: string) => void
121+
/** Callback to fire to delete a tag */
122+
readonly onDeleteTag?: (tagName: string, unpushed: boolean) => void
123123

124124
/**
125125
* A handler called whenever the user drops commits on the list to be inserted.
@@ -944,10 +944,10 @@ export class CommitList extends React.Component<
944944
if (commit.tags.length === 1) {
945945
const tagName = commit.tags[0]
946946

947+
const unpushed = unpushedTags.includes(tagName)
947948
return {
948949
label: `Delete tag ${tagName}`,
949-
action: () => onDeleteTag(tagName),
950-
enabled: unpushedTags.includes(tagName),
950+
action: () => onDeleteTag(tagName, unpushed),
951951
}
952952
}
953953

@@ -957,10 +957,10 @@ export class CommitList extends React.Component<
957957
return {
958958
label: 'Delete tag…',
959959
submenu: commit.tags.map(tagName => {
960+
const unpushed = unpushedTagsSet.has(tagName)
960961
return {
961962
label: tagName,
962-
action: () => onDeleteTag(tagName),
963-
enabled: unpushedTagsSet.has(tagName),
963+
action: () => onDeleteTag(tagName, unpushed),
964964
}
965965
}),
966966
}

app/src/ui/history/compare.tsx

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -685,8 +685,17 @@ export class CompareSidebar extends React.Component<
685685
}
686686
}
687687

688-
private onDeleteTag = (tagName: string) => {
689-
this.props.dispatcher.showDeleteTagDialog(this.props.repository, tagName)
688+
private onDeleteTag = (tagName: string, unpushed: boolean) => {
689+
const { repository, dispatcher } = this.props
690+
if (unpushed) {
691+
dispatcher.showDeleteTagDialog(this.props.repository, tagName)
692+
} else {
693+
dispatcher.showPopup({
694+
type: PopupType.ConfirmDeletePushedTag,
695+
tagName: tagName,
696+
repository,
697+
})
698+
}
690699
}
691700

692701
private onCherryPick = (commits: ReadonlyArray<CommitOneLine>) => {
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
import * as React from 'react'
2+
import { Dialog, DialogContent, DialogFooter } from '../dialog'
3+
import { Repository } from '../../models/repository'
4+
import { Dispatcher } from '../dispatcher'
5+
import { Row } from '../lib/row'
6+
import { OkCancelButtonGroup } from '../dialog/ok-cancel-button-group'
7+
8+
interface IConfirmDeletePushedTagProps {
9+
readonly dispatcher: Dispatcher
10+
readonly repository: Repository
11+
readonly tagName: string
12+
readonly onDismissed: () => void
13+
}
14+
15+
interface IConfirmDeletePushedTagState {
16+
readonly isDeleting: boolean
17+
}
18+
/**
19+
* Dialog to confirm deleting an already pushed tag
20+
*/
21+
export class ConfirmDeletePushedTagDialog extends React.Component<
22+
IConfirmDeletePushedTagProps,
23+
IConfirmDeletePushedTagState
24+
> {
25+
public constructor(props: IConfirmDeletePushedTagProps) {
26+
super(props)
27+
28+
this.state = {
29+
isDeleting: false,
30+
}
31+
}
32+
33+
public render() {
34+
const title = __DARWIN__ ? 'Delete Pushed Tag?' : 'Delete pushed tag?'
35+
36+
return (
37+
<Dialog
38+
id="delete-pushed-tag"
39+
type="warning"
40+
title={title}
41+
loading={this.state.isDeleting}
42+
disabled={this.state.isDeleting}
43+
onSubmit={this.onSubmit}
44+
onDismissed={this.props.onDismissed}
45+
ariaDescribedBy="delete-pushed-tag-confirmation"
46+
role="alertdialog"
47+
>
48+
<DialogContent>
49+
<Row id="delete-pushed-tag-confirmation">
50+
This tag has already been pushed to the remote. Are you sure you
51+
want to delete it locally?
52+
</Row>
53+
</DialogContent>
54+
<DialogFooter>
55+
<OkCancelButtonGroup destructive={true} okButtonText="Delete" />
56+
</DialogFooter>
57+
</Dialog>
58+
)
59+
}
60+
61+
private onSubmit = async () => {
62+
const { dispatcher, repository, tagName, onDismissed } = this.props
63+
64+
this.setState({
65+
isDeleting: true,
66+
})
67+
68+
try {
69+
await dispatcher.deleteTag(repository, tagName)
70+
} finally {
71+
this.setState({
72+
isDeleting: false,
73+
})
74+
}
75+
76+
onDismissed()
77+
}
78+
}

0 commit comments

Comments
 (0)