diff --git a/package.json b/package.json index 388c22181e..cb0bf15ed3 100644 --- a/package.json +++ b/package.json @@ -153,6 +153,11 @@ "deprecationMessage": "Use the setting 'githubPullRequests.defaultCreateOption' instead.", "description": "%githubPullRequests.createDraft%" }, + "githubPullRequests.showPullRequestCancelConfirmation": { + "type": "boolean", + "default": true, + "description": "%githubPullRequests.showPullRequestCancelConfirmation%" + }, "githubPullRequests.logLevel": { "type": "string", "enum": [ diff --git a/package.nls.json b/package.nls.json index ed80e9bbf5..46625f0a6c 100644 --- a/package.nls.json +++ b/package.nls.json @@ -13,6 +13,7 @@ "githubPullRequests.defaultCreateOption.createDraft": "The pull request will be created as a draft.", "githubPullRequests.defaultCreateOption.createAutoMerge": "The pull request will be created with auto-merge enabled. The merge method selected will be the default for the repo or the value of `githubPullRequests.defaultMergeMethod` if set.", "githubPullRequests.createDraft": "Whether the \"Draft\" checkbox will be checked by default when creating a pull request.", + "githubPullRequests.showPullRequestCancelConfirmation": "Show a confirmation dialog when canceling pull request creation if the description has been edited.", "githubPullRequests.logLevel.description": "Logging for GitHub Pull Request extension. The log is emitted to the output channel named GitHub Pull Request.", "githubPullRequests.logLevel.markdownDeprecationMessage": { "message": "Log level is now controlled by the [Developer: Set Log Level...](command:workbench.action.setLogLevel) command. You can set the log level for the current session and also the default log level from there.", diff --git a/src/common/settingKeys.ts b/src/common/settingKeys.ts index ba0654cc23..2ac936b813 100644 --- a/src/common/settingKeys.ts +++ b/src/common/settingKeys.ts @@ -29,6 +29,7 @@ export const QUERIES = 'queries'; export const PULL_REQUEST_LABELS = 'labelCreated'; export const FOCUSED_MODE = 'focusedMode'; export const CREATE_DRAFT = 'createDraft'; +export const SHOW_PULL_REQUEST_CANCEL_CONFIRMATION = 'showPullRequestCancelConfirmation'; export const QUICK_DIFF = 'quickDiff'; export const SET_AUTO_MERGE = 'setAutoMerge'; export const SHOW_PULL_REQUEST_NUMBER_IN_TREE = 'showPullRequestNumberInTree'; diff --git a/src/github/createPRViewProvider.ts b/src/github/createPRViewProvider.ts index 1a9d245633..c3eac9f921 100644 --- a/src/github/createPRViewProvider.ts +++ b/src/github/createPRViewProvider.ts @@ -35,7 +35,8 @@ import { PR_SETTINGS_NAMESPACE, PULL_REQUEST_DESCRIPTION, PULL_REQUEST_LABELS, - PUSH_BRANCH + PUSH_BRANCH, + SHOW_PULL_REQUEST_CANCEL_CONFIRMATION } from '../common/settingKeys'; import { ITelemetry } from '../common/telemetry'; import { asPromise, compareIgnoreCase, formatError, promiseWithTimeout } from '../common/utils'; @@ -561,10 +562,27 @@ export abstract class BaseCreatePullRequestViewProvider) { + if (message.args.body && message.args.body.length > 0 + && vscode.workspace.getConfiguration(PR_SETTINGS_NAMESPACE).get(SHOW_PULL_REQUEST_CANCEL_CONFIRMATION, true)) { + const discard = vscode.l10n.t('Discard'); + const dontAskAgain = vscode.l10n.t('Don\'t Ask Again'); + const result = await vscode.window.showWarningMessage( + vscode.l10n.t('Are you sure you want to cancel creating this pull request?'), + { modal: true, detail: vscode.l10n.t('Your pull request title and description will be lost.') }, + discard, + dontAskAgain + ); + if (result !== discard && result !== dontAskAgain) { + return this._replyMessage(message, { cancelled: false }); + } + if (result === dontAskAgain) { + await vscode.workspace.getConfiguration(PR_SETTINGS_NAMESPACE).update(SHOW_PULL_REQUEST_CANCEL_CONFIRMATION, false, vscode.ConfigurationTarget.Global); + } + } this._onDone.fire(undefined); // Re-fetch the automerge info so that it's updated for next time. await this.getMergeConfiguration(message.args.owner, message.args.repo, true); - return this._replyMessage(message, undefined); + return this._replyMessage(message, { cancelled: true }); } private async openDescriptionSettings(): Promise { diff --git a/webviews/common/createContextNew.ts b/webviews/common/createContextNew.ts index b1bec93809..677bb4d4fd 100644 --- a/webviews/common/createContextNew.ts +++ b/webviews/common/createContextNew.ts @@ -92,10 +92,16 @@ export class CreatePRContextNew { } }; - public cancelCreate = (): Promise => { + public cancelCreate = async (): Promise => { const args = this.copyParams(); - vscode.setState(defaultCreateParams); - return this.postMessage({ command: 'pr.cancelCreate', args }); + const result = await this.postMessage({ command: 'pr.cancelCreate', args }) as { cancelled?: boolean } | undefined; + // Only clear persisted state if the extension explicitly confirmed the + // cancellation. Otherwise (e.g. the user declined the confirmation + // dialog, or the message did not get a response) preserve the user's + // in-progress title/description. + if (result?.cancelled === true) { + vscode.setState(defaultCreateParams); + } }; public updateState = (params: Partial, reset: boolean = false): void => {