Skip to content
4 changes: 4 additions & 0 deletions common/views.ts
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,10 @@ export interface CreatePullRequestNew {
milestone?: IMilestone;
}

export interface CancelCreatePullRequestNew extends CreatePullRequestNew {
hasUnsavedChanges: boolean;
}

// #region new create view

export interface CreateParamsNew {
Expand Down
5 changes: 5 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,11 @@
"deprecationMessage": "Use the setting 'githubPullRequests.defaultCreateOption' instead.",
"description": "%githubPullRequests.createDraft%"
},
"githubPullRequests.showCreatePullRequestCancelConfirmation": {
"type": "boolean",
"default": true,
"description": "%githubPullRequests.showCreatePullRequestCancelConfirmation%"
},
Comment thread
alexr00 marked this conversation as resolved.
"githubPullRequests.logLevel": {
"type": "string",
"enum": [
Expand Down
1 change: 1 addition & 0 deletions package.nls.json
Original file line number Diff line number Diff line change
Expand Up @@ -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.showCreatePullRequestCancelConfirmation": "Show a confirmation dialog when canceling pull request creation if there are unsaved changes (a manually edited title or description, or any selected labels, assignees, reviewers, projects, or milestone).",
"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.",
Expand Down
1 change: 1 addition & 0 deletions src/common/settingKeys.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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_CREATE_PULL_REQUEST_CANCEL_CONFIRMATION = 'showCreatePullRequestCancelConfirmation';
export const QUICK_DIFF = 'quickDiff';
export const SET_AUTO_MERGE = 'setAutoMerge';
export const SHOW_PULL_REQUEST_NUMBER_IN_TREE = 'showPullRequestNumberInTree';
Expand Down
28 changes: 24 additions & 4 deletions src/github/createPRViewProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import { branchPicks, cachedBranchPicks, getAssigneesQuickPickItems, getLabelOpt
import { ISSUE_EXPRESSION, parseIssueExpressionOutput, variableSubstitution } from './utils';
import { ChangeTemplateReply, DisplayLabel, PreReviewState } from './views';
import { RemoteInfo } from '../../common/types';
import { ChooseBaseRemoteAndBranchResult, ChooseCompareRemoteAndBranchResult, ChooseRemoteAndBranchArgs, CreateParamsNew, CreatePullRequestNew, TitleAndDescriptionArgs } from '../../common/views';
import { CancelCreatePullRequestNew, ChooseBaseRemoteAndBranchResult, ChooseCompareRemoteAndBranchResult, ChooseRemoteAndBranchArgs, CreateParamsNew, CreatePullRequestNew, TitleAndDescriptionArgs } from '../../common/views';
import type { Branch } from '../api/api';
import { debounce } from '../common/async';
import { GitHubServerType } from '../common/authentication';
Expand All @@ -35,7 +35,8 @@ import {
PR_SETTINGS_NAMESPACE,
PULL_REQUEST_DESCRIPTION,
PULL_REQUEST_LABELS,
PUSH_BRANCH
PUSH_BRANCH,
SHOW_CREATE_PULL_REQUEST_CANCEL_CONFIRMATION
} from '../common/settingKeys';
import { ITelemetry } from '../common/telemetry';
import { asPromise, compareIgnoreCase, formatError, promiseWithTimeout } from '../common/utils';
Expand Down Expand Up @@ -567,11 +568,30 @@ export abstract class BaseCreatePullRequestViewProvider<T extends BasePullReques
this.setProjects(createdPR, message.args.projects)]);
}

private async cancel(message: IRequestMessage<CreatePullRequestNew>) {
private async cancel(message: IRequestMessage<CancelCreatePullRequestNew>) {
if (message.args.hasUnsavedChanges
&& vscode.workspace.getConfiguration(PR_SETTINGS_NAMESPACE).get<boolean>(SHOW_CREATE_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 unsaved changes to this pull request 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_CREATE_PULL_REQUEST_CANCEL_CONFIRMATION, false, vscode.ConfigurationTarget.Global);
}
}
// Reply before firing _onDone so the webview receives the message before
// the panel is disposed (disposing clears _webview, making _replyMessage a no-op).
this._replyMessage(message, { cancelled: true });
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);
Comment thread
alexr00 marked this conversation as resolved.
return this._replyMessage(message, undefined);
}

private async openDescriptionSettings(): Promise<void> {
Expand Down
31 changes: 26 additions & 5 deletions webviews/common/createContextNew.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
import { createContext } from 'react';
import { getMessageHandler, MessageHandler, vscode } from './message';
import { RemoteInfo } from '../../common/types';
import { ChooseBaseRemoteAndBranchResult, ChooseCompareRemoteAndBranchResult, ChooseRemoteAndBranchArgs, CreateParamsNew, CreatePullRequestNew, ScrollPosition, TitleAndDescriptionArgs, TitleAndDescriptionResult } from '../../common/views';
import { CancelCreatePullRequestNew, ChooseBaseRemoteAndBranchResult, ChooseCompareRemoteAndBranchResult, ChooseRemoteAndBranchArgs, CreateParamsNew, CreatePullRequestNew, ScrollPosition, TitleAndDescriptionArgs, TitleAndDescriptionResult } from '../../common/views';
import { compareIgnoreCase } from '../../src/common/utils';
import { PreReviewState } from '../../src/github/views';

Expand Down Expand Up @@ -92,12 +92,33 @@ export class CreatePRContextNew {
}
};

public cancelCreate = (): Promise<void> => {
const args = this.copyParams();
vscode.setState(defaultCreateParams);
return this.postMessage({ command: 'pr.cancelCreate', args });
public cancelCreate = async (): Promise<void> => {
const args: CancelCreatePullRequestNew = {
...this.copyParams(),
hasUnsavedChanges: this.hasUnsavedChanges()
};
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);
}
};
Comment thread
alexr00 marked this conversation as resolved.

private hasUnsavedChanges(): boolean {
const params = this.createParams;
const titleEdited = params.pendingTitle !== undefined && params.pendingTitle !== params.defaultTitle;
const descriptionEdited = params.pendingDescription !== undefined && params.pendingDescription !== params.defaultDescription;
const hasLabels = (params.labels?.length ?? 0) > 0;
const hasAssignees = (params.assignees?.length ?? 0) > 0;
Comment on lines +111 to +115
const hasReviewers = (params.reviewers?.length ?? 0) > 0;
const hasProjects = (params.projects?.length ?? 0) > 0;
const hasMilestone = !!params.milestone;
return titleEdited || descriptionEdited || hasLabels || hasAssignees || hasReviewers || hasProjects || hasMilestone;
}

public updateState = (params: Partial<CreateParamsNew>, reset: boolean = false): void => {
this.createParams = reset ? { ...defaultCreateParams, ...params } : { ...this.createParams, ...params };
vscode.setState(this.createParams);
Expand Down