Move dialog functions to separate file
This commit is contained in:
135
extensions/ql-vscode/src/common/vscode/dialog.ts
Normal file
135
extensions/ql-vscode/src/common/vscode/dialog.ts
Normal file
@@ -0,0 +1,135 @@
|
|||||||
|
import { env, Uri, window } from "vscode";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Opens a modal dialog for the user to make a yes/no choice.
|
||||||
|
*
|
||||||
|
* @param message The message to show.
|
||||||
|
* @param modal If true (the default), show a modal dialog box, otherwise dialog is non-modal and can
|
||||||
|
* be closed even if the user does not make a choice.
|
||||||
|
* @param yesTitle The text in the box indicating the affirmative choice.
|
||||||
|
* @param noTitle The text in the box indicating the negative choice.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* `true` if the user clicks 'Yes',
|
||||||
|
* `false` if the user clicks 'No' or cancels the dialog,
|
||||||
|
* `undefined` if the dialog is closed without the user making a choice.
|
||||||
|
*/
|
||||||
|
export async function showBinaryChoiceDialog(
|
||||||
|
message: string,
|
||||||
|
modal = true,
|
||||||
|
yesTitle = "Yes",
|
||||||
|
noTitle = "No",
|
||||||
|
): Promise<boolean | undefined> {
|
||||||
|
const yesItem = { title: yesTitle, isCloseAffordance: false };
|
||||||
|
const noItem = { title: noTitle, isCloseAffordance: true };
|
||||||
|
const chosenItem = await window.showInformationMessage(
|
||||||
|
message,
|
||||||
|
{ modal },
|
||||||
|
yesItem,
|
||||||
|
noItem,
|
||||||
|
);
|
||||||
|
if (!chosenItem) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
return chosenItem?.title === yesItem.title;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Opens a modal dialog for the user to make a yes/no choice.
|
||||||
|
*
|
||||||
|
* @param message The message to show.
|
||||||
|
* @param modal If true (the default), show a modal dialog box, otherwise dialog is non-modal and can
|
||||||
|
* be closed even if the user does not make a choice.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* `true` if the user clicks 'Yes',
|
||||||
|
* `false` if the user clicks 'No' or cancels the dialog,
|
||||||
|
* `undefined` if the dialog is closed without the user making a choice.
|
||||||
|
*/
|
||||||
|
export async function showBinaryChoiceWithUrlDialog(
|
||||||
|
message: string,
|
||||||
|
url: string,
|
||||||
|
): Promise<boolean | undefined> {
|
||||||
|
const urlItem = { title: "More Information", isCloseAffordance: false };
|
||||||
|
const yesItem = { title: "Yes", isCloseAffordance: false };
|
||||||
|
const noItem = { title: "No", isCloseAffordance: true };
|
||||||
|
let chosenItem;
|
||||||
|
|
||||||
|
// Keep the dialog open as long as the user is clicking the 'more information' option.
|
||||||
|
// To prevent an infinite loop, if the user clicks 'more information' 5 times, close the dialog and return cancelled
|
||||||
|
let count = 0;
|
||||||
|
do {
|
||||||
|
chosenItem = await window.showInformationMessage(
|
||||||
|
message,
|
||||||
|
{ modal: true },
|
||||||
|
urlItem,
|
||||||
|
yesItem,
|
||||||
|
noItem,
|
||||||
|
);
|
||||||
|
if (chosenItem === urlItem) {
|
||||||
|
await env.openExternal(Uri.parse(url, true));
|
||||||
|
}
|
||||||
|
count++;
|
||||||
|
} while (chosenItem === urlItem && count < 5);
|
||||||
|
|
||||||
|
if (!chosenItem || chosenItem.title === urlItem.title) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
return chosenItem.title === yesItem.title;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Show an information message with a customisable action.
|
||||||
|
* @param message The message to show.
|
||||||
|
* @param actionMessage The call to action message.
|
||||||
|
*
|
||||||
|
* @return `true` if the user clicks the action, `false` if the user cancels the dialog.
|
||||||
|
*/
|
||||||
|
export async function showInformationMessageWithAction(
|
||||||
|
message: string,
|
||||||
|
actionMessage: string,
|
||||||
|
): Promise<boolean> {
|
||||||
|
const actionItem = { title: actionMessage, isCloseAffordance: false };
|
||||||
|
const chosenItem = await window.showInformationMessage(message, actionItem);
|
||||||
|
return chosenItem === actionItem;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Opens a modal dialog for the user to make a choice between yes/no/never be asked again.
|
||||||
|
*
|
||||||
|
* @param message The message to show.
|
||||||
|
* @param modal If true (the default), show a modal dialog box, otherwise dialog is non-modal and can
|
||||||
|
* be closed even if the user does not make a choice.
|
||||||
|
* @param yesTitle The text in the box indicating the affirmative choice.
|
||||||
|
* @param noTitle The text in the box indicating the negative choice.
|
||||||
|
* @param neverTitle The text in the box indicating the opt out choice.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* `Yes` if the user clicks 'Yes',
|
||||||
|
* `No` if the user clicks 'No' or cancels the dialog,
|
||||||
|
* `No, and never ask me again` if the user clicks 'No, and never ask me again',
|
||||||
|
* `undefined` if the dialog is closed without the user making a choice.
|
||||||
|
*/
|
||||||
|
export async function showNeverAskAgainDialog(
|
||||||
|
message: string,
|
||||||
|
modal = true,
|
||||||
|
yesTitle = "Yes",
|
||||||
|
noTitle = "No",
|
||||||
|
neverAskAgainTitle = "No, and never ask me again",
|
||||||
|
): Promise<string | undefined> {
|
||||||
|
const yesItem = { title: yesTitle, isCloseAffordance: true };
|
||||||
|
const noItem = { title: noTitle, isCloseAffordance: false };
|
||||||
|
const neverAskAgainItem = {
|
||||||
|
title: neverAskAgainTitle,
|
||||||
|
isCloseAffordance: false,
|
||||||
|
};
|
||||||
|
const chosenItem = await window.showInformationMessage(
|
||||||
|
message,
|
||||||
|
{ modal },
|
||||||
|
yesItem,
|
||||||
|
noItem,
|
||||||
|
neverAskAgainItem,
|
||||||
|
);
|
||||||
|
|
||||||
|
return chosenItem?.title;
|
||||||
|
}
|
||||||
@@ -1,9 +1,7 @@
|
|||||||
import { Uri, window } from "vscode";
|
import { Uri, window } from "vscode";
|
||||||
import { AppCommandManager } from "../commands";
|
import { AppCommandManager } from "../commands";
|
||||||
import {
|
import { showAndLogExceptionWithTelemetry } from "../../helpers";
|
||||||
showAndLogExceptionWithTelemetry,
|
import { showBinaryChoiceDialog } from "./dialog";
|
||||||
showBinaryChoiceDialog,
|
|
||||||
} from "../../helpers";
|
|
||||||
import { redactableError } from "../../pure/errors";
|
import { redactableError } from "../../pure/errors";
|
||||||
import {
|
import {
|
||||||
asError,
|
asError,
|
||||||
|
|||||||
@@ -13,10 +13,8 @@ import {
|
|||||||
import { join } from "path";
|
import { join } from "path";
|
||||||
import { FullDatabaseOptions } from "./database-options";
|
import { FullDatabaseOptions } from "./database-options";
|
||||||
import { DatabaseItemImpl } from "./database-item-impl";
|
import { DatabaseItemImpl } from "./database-item-impl";
|
||||||
import {
|
import { showAndLogExceptionWithTelemetry } from "../../helpers";
|
||||||
showAndLogExceptionWithTelemetry,
|
import { showNeverAskAgainDialog } from "../../common/vscode/dialog";
|
||||||
showNeverAskAgainDialog,
|
|
||||||
} from "../../helpers";
|
|
||||||
import {
|
import {
|
||||||
getFirstWorkspaceFolder,
|
getFirstWorkspaceFolder,
|
||||||
isFolderAlreadyInWorkspace,
|
isFolderAlreadyInWorkspace,
|
||||||
|
|||||||
@@ -60,12 +60,14 @@ import {
|
|||||||
showAndLogExceptionWithTelemetry,
|
showAndLogExceptionWithTelemetry,
|
||||||
showAndLogInformationMessage,
|
showAndLogInformationMessage,
|
||||||
showAndLogWarningMessage,
|
showAndLogWarningMessage,
|
||||||
showBinaryChoiceDialog,
|
|
||||||
showInformationMessageWithAction,
|
|
||||||
tmpDir,
|
tmpDir,
|
||||||
tmpDirDisposal,
|
tmpDirDisposal,
|
||||||
prepareCodeTour,
|
prepareCodeTour,
|
||||||
} from "./helpers";
|
} from "./helpers";
|
||||||
|
import {
|
||||||
|
showBinaryChoiceDialog,
|
||||||
|
showInformationMessageWithAction,
|
||||||
|
} from "./common/vscode/dialog";
|
||||||
import {
|
import {
|
||||||
asError,
|
asError,
|
||||||
assertNever,
|
assertNever,
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { ensureDirSync, pathExists, ensureDir, writeFile } from "fs-extra";
|
import { ensureDirSync, pathExists, ensureDir, writeFile } from "fs-extra";
|
||||||
import { join } from "path";
|
import { join } from "path";
|
||||||
import { dirSync } from "tmp-promise";
|
import { dirSync } from "tmp-promise";
|
||||||
import { Uri, window as Window, workspace, env } from "vscode";
|
import { Uri, window as Window, workspace } from "vscode";
|
||||||
import { CodeQLCliServer } from "./codeql-cli/cli";
|
import { CodeQLCliServer } from "./codeql-cli/cli";
|
||||||
import { UserCancellationException } from "./common/vscode/progress";
|
import { UserCancellationException } from "./common/vscode/progress";
|
||||||
import { extLogger, OutputChannelLogger } from "./common";
|
import { extLogger, OutputChannelLogger } from "./common";
|
||||||
@@ -12,6 +12,7 @@ import { isQueryLanguage, QueryLanguage } from "./common/query-language";
|
|||||||
import { isCodespacesTemplate } from "./config";
|
import { isCodespacesTemplate } from "./config";
|
||||||
import { AppCommandManager } from "./common/commands";
|
import { AppCommandManager } from "./common/commands";
|
||||||
import { getOnDiskWorkspaceFolders } from "./common/vscode/workspace-folders";
|
import { getOnDiskWorkspaceFolders } from "./common/vscode/workspace-folders";
|
||||||
|
import { showBinaryChoiceDialog } from "./common/vscode/dialog";
|
||||||
|
|
||||||
// Shared temporary folder for the extension.
|
// Shared temporary folder for the extension.
|
||||||
export const tmpDir = dirSync({
|
export const tmpDir = dirSync({
|
||||||
@@ -139,140 +140,6 @@ async function internalShowAndLog(
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Opens a modal dialog for the user to make a yes/no choice.
|
|
||||||
*
|
|
||||||
* @param message The message to show.
|
|
||||||
* @param modal If true (the default), show a modal dialog box, otherwise dialog is non-modal and can
|
|
||||||
* be closed even if the user does not make a choice.
|
|
||||||
* @param yesTitle The text in the box indicating the affirmative choice.
|
|
||||||
* @param noTitle The text in the box indicating the negative choice.
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
* `true` if the user clicks 'Yes',
|
|
||||||
* `false` if the user clicks 'No' or cancels the dialog,
|
|
||||||
* `undefined` if the dialog is closed without the user making a choice.
|
|
||||||
*/
|
|
||||||
export async function showBinaryChoiceDialog(
|
|
||||||
message: string,
|
|
||||||
modal = true,
|
|
||||||
yesTitle = "Yes",
|
|
||||||
noTitle = "No",
|
|
||||||
): Promise<boolean | undefined> {
|
|
||||||
const yesItem = { title: yesTitle, isCloseAffordance: false };
|
|
||||||
const noItem = { title: noTitle, isCloseAffordance: true };
|
|
||||||
const chosenItem = await Window.showInformationMessage(
|
|
||||||
message,
|
|
||||||
{ modal },
|
|
||||||
yesItem,
|
|
||||||
noItem,
|
|
||||||
);
|
|
||||||
if (!chosenItem) {
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
return chosenItem?.title === yesItem.title;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Opens a modal dialog for the user to make a yes/no choice.
|
|
||||||
*
|
|
||||||
* @param message The message to show.
|
|
||||||
* @param modal If true (the default), show a modal dialog box, otherwise dialog is non-modal and can
|
|
||||||
* be closed even if the user does not make a choice.
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
* `true` if the user clicks 'Yes',
|
|
||||||
* `false` if the user clicks 'No' or cancels the dialog,
|
|
||||||
* `undefined` if the dialog is closed without the user making a choice.
|
|
||||||
*/
|
|
||||||
export async function showBinaryChoiceWithUrlDialog(
|
|
||||||
message: string,
|
|
||||||
url: string,
|
|
||||||
): Promise<boolean | undefined> {
|
|
||||||
const urlItem = { title: "More Information", isCloseAffordance: false };
|
|
||||||
const yesItem = { title: "Yes", isCloseAffordance: false };
|
|
||||||
const noItem = { title: "No", isCloseAffordance: true };
|
|
||||||
let chosenItem;
|
|
||||||
|
|
||||||
// Keep the dialog open as long as the user is clicking the 'more information' option.
|
|
||||||
// To prevent an infinite loop, if the user clicks 'more information' 5 times, close the dialog and return cancelled
|
|
||||||
let count = 0;
|
|
||||||
do {
|
|
||||||
chosenItem = await Window.showInformationMessage(
|
|
||||||
message,
|
|
||||||
{ modal: true },
|
|
||||||
urlItem,
|
|
||||||
yesItem,
|
|
||||||
noItem,
|
|
||||||
);
|
|
||||||
if (chosenItem === urlItem) {
|
|
||||||
await env.openExternal(Uri.parse(url, true));
|
|
||||||
}
|
|
||||||
count++;
|
|
||||||
} while (chosenItem === urlItem && count < 5);
|
|
||||||
|
|
||||||
if (!chosenItem || chosenItem.title === urlItem.title) {
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
return chosenItem.title === yesItem.title;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Show an information message with a customisable action.
|
|
||||||
* @param message The message to show.
|
|
||||||
* @param actionMessage The call to action message.
|
|
||||||
*
|
|
||||||
* @return `true` if the user clicks the action, `false` if the user cancels the dialog.
|
|
||||||
*/
|
|
||||||
export async function showInformationMessageWithAction(
|
|
||||||
message: string,
|
|
||||||
actionMessage: string,
|
|
||||||
): Promise<boolean> {
|
|
||||||
const actionItem = { title: actionMessage, isCloseAffordance: false };
|
|
||||||
const chosenItem = await Window.showInformationMessage(message, actionItem);
|
|
||||||
return chosenItem === actionItem;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Opens a modal dialog for the user to make a choice between yes/no/never be asked again.
|
|
||||||
*
|
|
||||||
* @param message The message to show.
|
|
||||||
* @param modal If true (the default), show a modal dialog box, otherwise dialog is non-modal and can
|
|
||||||
* be closed even if the user does not make a choice.
|
|
||||||
* @param yesTitle The text in the box indicating the affirmative choice.
|
|
||||||
* @param noTitle The text in the box indicating the negative choice.
|
|
||||||
* @param neverTitle The text in the box indicating the opt out choice.
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
* `Yes` if the user clicks 'Yes',
|
|
||||||
* `No` if the user clicks 'No' or cancels the dialog,
|
|
||||||
* `No, and never ask me again` if the user clicks 'No, and never ask me again',
|
|
||||||
* `undefined` if the dialog is closed without the user making a choice.
|
|
||||||
*/
|
|
||||||
export async function showNeverAskAgainDialog(
|
|
||||||
message: string,
|
|
||||||
modal = true,
|
|
||||||
yesTitle = "Yes",
|
|
||||||
noTitle = "No",
|
|
||||||
neverAskAgainTitle = "No, and never ask me again",
|
|
||||||
): Promise<string | undefined> {
|
|
||||||
const yesItem = { title: yesTitle, isCloseAffordance: true };
|
|
||||||
const noItem = { title: noTitle, isCloseAffordance: false };
|
|
||||||
const neverAskAgainItem = {
|
|
||||||
title: neverAskAgainTitle,
|
|
||||||
isCloseAffordance: false,
|
|
||||||
};
|
|
||||||
const chosenItem = await Window.showInformationMessage(
|
|
||||||
message,
|
|
||||||
{ modal },
|
|
||||||
yesItem,
|
|
||||||
noItem,
|
|
||||||
neverAskAgainItem,
|
|
||||||
);
|
|
||||||
|
|
||||||
return chosenItem?.title;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Check if the current workspace is the CodeTour and open the workspace folder.
|
/** Check if the current workspace is the CodeTour and open the workspace folder.
|
||||||
* Without this, we can't run the code tour correctly.
|
* Without this, we can't run the code tour correctly.
|
||||||
**/
|
**/
|
||||||
|
|||||||
@@ -21,8 +21,8 @@ import {
|
|||||||
findLanguage,
|
findLanguage,
|
||||||
showAndLogErrorMessage,
|
showAndLogErrorMessage,
|
||||||
showAndLogWarningMessage,
|
showAndLogWarningMessage,
|
||||||
showBinaryChoiceDialog,
|
|
||||||
} from "../helpers";
|
} from "../helpers";
|
||||||
|
import { showBinaryChoiceDialog } from "../common/vscode/dialog";
|
||||||
import { getOnDiskWorkspaceFolders } from "../common/vscode/workspace-folders";
|
import { getOnDiskWorkspaceFolders } from "../common/vscode/workspace-folders";
|
||||||
import { displayQuickQuery } from "./quick-query";
|
import { displayQuickQuery } from "./quick-query";
|
||||||
import { CoreCompletedQuery, QueryRunner } from "../query-server";
|
import { CoreCompletedQuery, QueryRunner } from "../query-server";
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import { CancellationToken, window as Window, workspace, Uri } from "vscode";
|
|||||||
import { LSPErrorCodes, ResponseError } from "vscode-languageclient";
|
import { LSPErrorCodes, ResponseError } from "vscode-languageclient";
|
||||||
import { CodeQLCliServer } from "../codeql-cli/cli";
|
import { CodeQLCliServer } from "../codeql-cli/cli";
|
||||||
import { DatabaseUI } from "../databases/local-databases-ui";
|
import { DatabaseUI } from "../databases/local-databases-ui";
|
||||||
import { showBinaryChoiceDialog } from "../helpers";
|
import { showBinaryChoiceDialog } from "../common/vscode/dialog";
|
||||||
import { getInitialQueryContents } from "./query-contents";
|
import { getInitialQueryContents } from "./query-contents";
|
||||||
import { getPrimaryDbscheme, getQlPackForDbscheme } from "../databases/qlpack";
|
import { getPrimaryDbscheme, getQlPackForDbscheme } from "../databases/qlpack";
|
||||||
import {
|
import {
|
||||||
|
|||||||
@@ -17,9 +17,11 @@ import {
|
|||||||
showAndLogErrorMessage,
|
showAndLogErrorMessage,
|
||||||
showAndLogInformationMessage,
|
showAndLogInformationMessage,
|
||||||
showAndLogWarningMessage,
|
showAndLogWarningMessage,
|
||||||
|
} from "../helpers";
|
||||||
|
import {
|
||||||
showBinaryChoiceDialog,
|
showBinaryChoiceDialog,
|
||||||
showInformationMessageWithAction,
|
showInformationMessageWithAction,
|
||||||
} from "../helpers";
|
} from "../common/vscode/dialog";
|
||||||
import { extLogger } from "../common";
|
import { extLogger } from "../common";
|
||||||
import { URLSearchParams } from "url";
|
import { URLSearchParams } from "url";
|
||||||
import { DisposableObject } from "../pure/disposable-object";
|
import { DisposableObject } from "../pure/disposable-object";
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ import {
|
|||||||
import * as appInsights from "applicationinsights";
|
import * as appInsights from "applicationinsights";
|
||||||
import { extLogger } from "./common";
|
import { extLogger } from "./common";
|
||||||
import { UserCancellationException } from "./common/vscode/progress";
|
import { UserCancellationException } from "./common/vscode/progress";
|
||||||
import { showBinaryChoiceWithUrlDialog } from "./helpers";
|
import { showBinaryChoiceWithUrlDialog } from "./common/vscode/dialog";
|
||||||
import { RedactableError } from "./pure/errors";
|
import { RedactableError } from "./pure/errors";
|
||||||
import { SemVer } from "semver";
|
import { SemVer } from "semver";
|
||||||
|
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import {
|
|||||||
UserCancellationException,
|
UserCancellationException,
|
||||||
withProgress,
|
withProgress,
|
||||||
} from "../common/vscode/progress";
|
} from "../common/vscode/progress";
|
||||||
import { showInformationMessageWithAction } from "../helpers";
|
import { showInformationMessageWithAction } from "../common/vscode/dialog";
|
||||||
import { extLogger } from "../common";
|
import { extLogger } from "../common";
|
||||||
import { createGist } from "./gh-api/gh-api-client";
|
import { createGist } from "./gh-api/gh-api-client";
|
||||||
import {
|
import {
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ import {
|
|||||||
} from "../../../src/common/vscode/archive-filesystem-provider";
|
} from "../../../src/common/vscode/archive-filesystem-provider";
|
||||||
import { testDisposeHandler } from "../test-dispose-handler";
|
import { testDisposeHandler } from "../test-dispose-handler";
|
||||||
import { QueryRunner } from "../../../src/query-server/query-runner";
|
import { QueryRunner } from "../../../src/query-server/query-runner";
|
||||||
import * as helpers from "../../../src/helpers";
|
import * as dialog from "../../../src/common/vscode/dialog";
|
||||||
import { Setting } from "../../../src/config";
|
import { Setting } from "../../../src/config";
|
||||||
import { QlPackGenerator } from "../../../src/qlpack-generator";
|
import { QlPackGenerator } from "../../../src/qlpack-generator";
|
||||||
import { mockedObject } from "../utils/mocking.helpers";
|
import { mockedObject } from "../utils/mocking.helpers";
|
||||||
@@ -45,7 +45,7 @@ describe("local databases", () => {
|
|||||||
let logSpy: jest.Mock<any, []>;
|
let logSpy: jest.Mock<any, []>;
|
||||||
|
|
||||||
let showNeverAskAgainDialogSpy: jest.SpiedFunction<
|
let showNeverAskAgainDialogSpy: jest.SpiedFunction<
|
||||||
typeof helpers.showNeverAskAgainDialog
|
typeof dialog.showNeverAskAgainDialog
|
||||||
>;
|
>;
|
||||||
|
|
||||||
let dir: tmp.DirResult;
|
let dir: tmp.DirResult;
|
||||||
@@ -64,7 +64,7 @@ describe("local databases", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
showNeverAskAgainDialogSpy = jest
|
showNeverAskAgainDialogSpy = jest
|
||||||
.spyOn(helpers, "showNeverAskAgainDialog")
|
.spyOn(dialog, "showNeverAskAgainDialog")
|
||||||
.mockResolvedValue("Yes");
|
.mockResolvedValue("Yes");
|
||||||
|
|
||||||
extensionContextStoragePath = dir.name;
|
extensionContextStoragePath = dir.name;
|
||||||
@@ -652,7 +652,7 @@ describe("local databases", () => {
|
|||||||
|
|
||||||
it("should return early if the user refuses help", async () => {
|
it("should return early if the user refuses help", async () => {
|
||||||
showNeverAskAgainDialogSpy = jest
|
showNeverAskAgainDialogSpy = jest
|
||||||
.spyOn(helpers, "showNeverAskAgainDialog")
|
.spyOn(dialog, "showNeverAskAgainDialog")
|
||||||
.mockResolvedValue("No");
|
.mockResolvedValue("No");
|
||||||
|
|
||||||
await (databaseManager as any).createSkeletonPacks(mockDbItem);
|
await (databaseManager as any).createSkeletonPacks(mockDbItem);
|
||||||
@@ -662,7 +662,7 @@ describe("local databases", () => {
|
|||||||
|
|
||||||
it("should return early and write choice to settings if user wants to never be asked again", async () => {
|
it("should return early and write choice to settings if user wants to never be asked again", async () => {
|
||||||
showNeverAskAgainDialogSpy = jest
|
showNeverAskAgainDialogSpy = jest
|
||||||
.spyOn(helpers, "showNeverAskAgainDialog")
|
.spyOn(dialog, "showNeverAskAgainDialog")
|
||||||
.mockResolvedValue("No, and never ask me again");
|
.mockResolvedValue("No, and never ask me again");
|
||||||
const updateValueSpy = jest.spyOn(Setting.prototype, "updateValue");
|
const updateValueSpy = jest.spyOn(Setting.prototype, "updateValue");
|
||||||
|
|
||||||
@@ -705,7 +705,7 @@ describe("local databases", () => {
|
|||||||
|
|
||||||
it("should exit early", async () => {
|
it("should exit early", async () => {
|
||||||
showNeverAskAgainDialogSpy = jest
|
showNeverAskAgainDialogSpy = jest
|
||||||
.spyOn(helpers, "showNeverAskAgainDialog")
|
.spyOn(dialog, "showNeverAskAgainDialog")
|
||||||
.mockResolvedValue("No");
|
.mockResolvedValue("No");
|
||||||
|
|
||||||
await (databaseManager as any).createSkeletonPacks(mockDbItem);
|
await (databaseManager as any).createSkeletonPacks(mockDbItem);
|
||||||
|
|||||||
@@ -0,0 +1,167 @@
|
|||||||
|
import { window } from "vscode";
|
||||||
|
import {
|
||||||
|
showBinaryChoiceDialog,
|
||||||
|
showBinaryChoiceWithUrlDialog,
|
||||||
|
showInformationMessageWithAction,
|
||||||
|
showNeverAskAgainDialog,
|
||||||
|
} from "../../../../../src/common/vscode/dialog";
|
||||||
|
|
||||||
|
describe("showBinaryChoiceDialog", () => {
|
||||||
|
let showInformationMessageSpy: jest.SpiedFunction<
|
||||||
|
typeof window.showInformationMessage
|
||||||
|
>;
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
showInformationMessageSpy = jest
|
||||||
|
.spyOn(window, "showInformationMessage")
|
||||||
|
.mockResolvedValue(undefined);
|
||||||
|
});
|
||||||
|
|
||||||
|
const resolveArg =
|
||||||
|
(index: number) =>
|
||||||
|
(...args: any[]) =>
|
||||||
|
Promise.resolve(args[index]);
|
||||||
|
|
||||||
|
it("should show a binary choice dialog and return `yes`", async () => {
|
||||||
|
// pretend user chooses 'yes'
|
||||||
|
showInformationMessageSpy.mockImplementationOnce(resolveArg(2));
|
||||||
|
const val = await showBinaryChoiceDialog("xxx");
|
||||||
|
expect(val).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should show a binary choice dialog and return `no`", async () => {
|
||||||
|
// pretend user chooses 'no'
|
||||||
|
showInformationMessageSpy.mockImplementationOnce(resolveArg(3));
|
||||||
|
const val = await showBinaryChoiceDialog("xxx");
|
||||||
|
expect(val).toBe(false);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("showInformationMessageWithAction", () => {
|
||||||
|
let showInformationMessageSpy: jest.SpiedFunction<
|
||||||
|
typeof window.showInformationMessage
|
||||||
|
>;
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
showInformationMessageSpy = jest
|
||||||
|
.spyOn(window, "showInformationMessage")
|
||||||
|
.mockResolvedValue(undefined);
|
||||||
|
});
|
||||||
|
|
||||||
|
const resolveArg =
|
||||||
|
(index: number) =>
|
||||||
|
(...args: any[]) =>
|
||||||
|
Promise.resolve(args[index]);
|
||||||
|
|
||||||
|
it("should show an info dialog and confirm the action", async () => {
|
||||||
|
// pretend user chooses to run action
|
||||||
|
showInformationMessageSpy.mockImplementationOnce(resolveArg(1));
|
||||||
|
const val = await showInformationMessageWithAction("xxx", "yyy");
|
||||||
|
expect(val).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should show an action dialog and avoid choosing the action", async () => {
|
||||||
|
// pretend user does not choose to run action
|
||||||
|
showInformationMessageSpy.mockResolvedValueOnce(undefined);
|
||||||
|
const val = await showInformationMessageWithAction("xxx", "yyy");
|
||||||
|
expect(val).toBe(false);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("showBinaryChoiceWithUrlDialog", () => {
|
||||||
|
let showInformationMessageSpy: jest.SpiedFunction<
|
||||||
|
typeof window.showInformationMessage
|
||||||
|
>;
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
showInformationMessageSpy = jest
|
||||||
|
.spyOn(window, "showInformationMessage")
|
||||||
|
.mockResolvedValue(undefined);
|
||||||
|
});
|
||||||
|
|
||||||
|
const resolveArg =
|
||||||
|
(index: number) =>
|
||||||
|
(...args: any[]) =>
|
||||||
|
Promise.resolve(args[index]);
|
||||||
|
|
||||||
|
it("should show a binary choice dialog with a url and return `yes`", async () => {
|
||||||
|
// pretend user clicks on the url twice and then clicks 'yes'
|
||||||
|
showInformationMessageSpy
|
||||||
|
.mockImplementation(resolveArg(2))
|
||||||
|
.mockImplementation(resolveArg(2))
|
||||||
|
.mockImplementation(resolveArg(3));
|
||||||
|
const val = await showBinaryChoiceWithUrlDialog("xxx", "invalid:url");
|
||||||
|
expect(val).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should show a binary choice dialog with a url and return `no`", async () => {
|
||||||
|
// pretend user clicks on the url twice and then clicks 'no'
|
||||||
|
showInformationMessageSpy
|
||||||
|
.mockImplementation(resolveArg(2))
|
||||||
|
.mockImplementation(resolveArg(2))
|
||||||
|
.mockImplementation(resolveArg(4));
|
||||||
|
const val = await showBinaryChoiceWithUrlDialog("xxx", "invalid:url");
|
||||||
|
expect(val).toBe(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should show a binary choice dialog and exit after clcking `more info` 5 times", async () => {
|
||||||
|
// pretend user clicks on the url twice and then clicks 'no'
|
||||||
|
showInformationMessageSpy
|
||||||
|
.mockImplementation(resolveArg(2))
|
||||||
|
.mockImplementation(resolveArg(2))
|
||||||
|
.mockImplementation(resolveArg(2))
|
||||||
|
.mockImplementation(resolveArg(2))
|
||||||
|
.mockImplementation(resolveArg(2));
|
||||||
|
const val = await showBinaryChoiceWithUrlDialog("xxx", "invalid:url");
|
||||||
|
// No choice was made
|
||||||
|
expect(val).toBeUndefined();
|
||||||
|
expect(showInformationMessageSpy).toHaveBeenCalledTimes(5);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("showNeverAskAgainDialog", () => {
|
||||||
|
let showInformationMessageSpy: jest.SpiedFunction<
|
||||||
|
typeof window.showInformationMessage
|
||||||
|
>;
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
showInformationMessageSpy = jest
|
||||||
|
.spyOn(window, "showInformationMessage")
|
||||||
|
.mockResolvedValue(undefined);
|
||||||
|
});
|
||||||
|
|
||||||
|
const resolveArg =
|
||||||
|
(index: number) =>
|
||||||
|
(...args: any[]) =>
|
||||||
|
Promise.resolve(args[index]);
|
||||||
|
|
||||||
|
const title =
|
||||||
|
"We've noticed you don't have a CodeQL pack available to analyze this database. Can we set up a query pack for you?";
|
||||||
|
|
||||||
|
it("should show a ternary choice dialog and return `Yes`", async () => {
|
||||||
|
// pretend user chooses 'Yes'
|
||||||
|
const yesItem = resolveArg(2);
|
||||||
|
showInformationMessageSpy.mockImplementationOnce(yesItem);
|
||||||
|
|
||||||
|
const answer = await showNeverAskAgainDialog(title);
|
||||||
|
expect(answer).toBe("Yes");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should show a ternary choice dialog and return `No`", async () => {
|
||||||
|
// pretend user chooses 'No'
|
||||||
|
const noItem = resolveArg(3);
|
||||||
|
showInformationMessageSpy.mockImplementationOnce(noItem);
|
||||||
|
|
||||||
|
const answer = await showNeverAskAgainDialog(title);
|
||||||
|
expect(answer).toBe("No");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should show a ternary choice dialog and return `No, and never ask me again`", async () => {
|
||||||
|
// pretend user chooses 'No, and never ask me again'
|
||||||
|
const neverAskAgainItem = resolveArg(4);
|
||||||
|
showInformationMessageSpy.mockImplementationOnce(neverAskAgainItem);
|
||||||
|
|
||||||
|
const answer = await showNeverAskAgainDialog(title);
|
||||||
|
expect(answer).toBe("No, and never ask me again");
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -3,13 +3,7 @@ import * as tmp from "tmp";
|
|||||||
import { join } from "path";
|
import { join } from "path";
|
||||||
import { writeFile, mkdir } from "fs-extra";
|
import { writeFile, mkdir } from "fs-extra";
|
||||||
|
|
||||||
import {
|
import { prepareCodeTour } from "../../../src/helpers";
|
||||||
prepareCodeTour,
|
|
||||||
showBinaryChoiceDialog,
|
|
||||||
showBinaryChoiceWithUrlDialog,
|
|
||||||
showInformationMessageWithAction,
|
|
||||||
showNeverAskAgainDialog,
|
|
||||||
} from "../../../src/helpers";
|
|
||||||
import { reportStreamProgress } from "../../../src/common/vscode/progress";
|
import { reportStreamProgress } from "../../../src/common/vscode/progress";
|
||||||
import { Setting } from "../../../src/config";
|
import { Setting } from "../../../src/config";
|
||||||
import { createMockCommandManager } from "../../__mocks__/commandsMock";
|
import { createMockCommandManager } from "../../__mocks__/commandsMock";
|
||||||
@@ -71,166 +65,6 @@ describe("helpers", () => {
|
|||||||
message: "My prefix (Size unknown)",
|
message: "My prefix (Size unknown)",
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("showBinaryChoiceDialog", () => {
|
|
||||||
let showInformationMessageSpy: jest.SpiedFunction<
|
|
||||||
typeof window.showInformationMessage
|
|
||||||
>;
|
|
||||||
|
|
||||||
beforeEach(() => {
|
|
||||||
showInformationMessageSpy = jest
|
|
||||||
.spyOn(window, "showInformationMessage")
|
|
||||||
.mockResolvedValue(undefined);
|
|
||||||
});
|
|
||||||
|
|
||||||
const resolveArg =
|
|
||||||
(index: number) =>
|
|
||||||
(...args: any[]) =>
|
|
||||||
Promise.resolve(args[index]);
|
|
||||||
|
|
||||||
it("should show a binary choice dialog and return `yes`", async () => {
|
|
||||||
// pretend user chooses 'yes'
|
|
||||||
showInformationMessageSpy.mockImplementationOnce(resolveArg(2));
|
|
||||||
const val = await showBinaryChoiceDialog("xxx");
|
|
||||||
expect(val).toBe(true);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should show a binary choice dialog and return `no`", async () => {
|
|
||||||
// pretend user chooses 'no'
|
|
||||||
showInformationMessageSpy.mockImplementationOnce(resolveArg(3));
|
|
||||||
const val = await showBinaryChoiceDialog("xxx");
|
|
||||||
expect(val).toBe(false);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe("showInformationMessageWithAction", () => {
|
|
||||||
let showInformationMessageSpy: jest.SpiedFunction<
|
|
||||||
typeof window.showInformationMessage
|
|
||||||
>;
|
|
||||||
|
|
||||||
beforeEach(() => {
|
|
||||||
showInformationMessageSpy = jest
|
|
||||||
.spyOn(window, "showInformationMessage")
|
|
||||||
.mockResolvedValue(undefined);
|
|
||||||
});
|
|
||||||
|
|
||||||
const resolveArg =
|
|
||||||
(index: number) =>
|
|
||||||
(...args: any[]) =>
|
|
||||||
Promise.resolve(args[index]);
|
|
||||||
|
|
||||||
it("should show an info dialog and confirm the action", async () => {
|
|
||||||
// pretend user chooses to run action
|
|
||||||
showInformationMessageSpy.mockImplementationOnce(resolveArg(1));
|
|
||||||
const val = await showInformationMessageWithAction("xxx", "yyy");
|
|
||||||
expect(val).toBe(true);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should show an action dialog and avoid choosing the action", async () => {
|
|
||||||
// pretend user does not choose to run action
|
|
||||||
showInformationMessageSpy.mockResolvedValueOnce(undefined);
|
|
||||||
const val = await showInformationMessageWithAction("xxx", "yyy");
|
|
||||||
expect(val).toBe(false);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe("showBinaryChoiceWithUrlDialog", () => {
|
|
||||||
let showInformationMessageSpy: jest.SpiedFunction<
|
|
||||||
typeof window.showInformationMessage
|
|
||||||
>;
|
|
||||||
|
|
||||||
beforeEach(() => {
|
|
||||||
showInformationMessageSpy = jest
|
|
||||||
.spyOn(window, "showInformationMessage")
|
|
||||||
.mockResolvedValue(undefined);
|
|
||||||
});
|
|
||||||
|
|
||||||
const resolveArg =
|
|
||||||
(index: number) =>
|
|
||||||
(...args: any[]) =>
|
|
||||||
Promise.resolve(args[index]);
|
|
||||||
|
|
||||||
it("should show a binary choice dialog with a url and return `yes`", async () => {
|
|
||||||
// pretend user clicks on the url twice and then clicks 'yes'
|
|
||||||
showInformationMessageSpy
|
|
||||||
.mockImplementation(resolveArg(2))
|
|
||||||
.mockImplementation(resolveArg(2))
|
|
||||||
.mockImplementation(resolveArg(3));
|
|
||||||
const val = await showBinaryChoiceWithUrlDialog("xxx", "invalid:url");
|
|
||||||
expect(val).toBe(true);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should show a binary choice dialog with a url and return `no`", async () => {
|
|
||||||
// pretend user clicks on the url twice and then clicks 'no'
|
|
||||||
showInformationMessageSpy
|
|
||||||
.mockImplementation(resolveArg(2))
|
|
||||||
.mockImplementation(resolveArg(2))
|
|
||||||
.mockImplementation(resolveArg(4));
|
|
||||||
const val = await showBinaryChoiceWithUrlDialog("xxx", "invalid:url");
|
|
||||||
expect(val).toBe(false);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should show a binary choice dialog and exit after clcking `more info` 5 times", async () => {
|
|
||||||
// pretend user clicks on the url twice and then clicks 'no'
|
|
||||||
showInformationMessageSpy
|
|
||||||
.mockImplementation(resolveArg(2))
|
|
||||||
.mockImplementation(resolveArg(2))
|
|
||||||
.mockImplementation(resolveArg(2))
|
|
||||||
.mockImplementation(resolveArg(2))
|
|
||||||
.mockImplementation(resolveArg(2));
|
|
||||||
const val = await showBinaryChoiceWithUrlDialog("xxx", "invalid:url");
|
|
||||||
// No choice was made
|
|
||||||
expect(val).toBeUndefined();
|
|
||||||
expect(showInformationMessageSpy).toHaveBeenCalledTimes(5);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe("showNeverAskAgainDialog", () => {
|
|
||||||
let showInformationMessageSpy: jest.SpiedFunction<
|
|
||||||
typeof window.showInformationMessage
|
|
||||||
>;
|
|
||||||
|
|
||||||
beforeEach(() => {
|
|
||||||
showInformationMessageSpy = jest
|
|
||||||
.spyOn(window, "showInformationMessage")
|
|
||||||
.mockResolvedValue(undefined);
|
|
||||||
});
|
|
||||||
|
|
||||||
const resolveArg =
|
|
||||||
(index: number) =>
|
|
||||||
(...args: any[]) =>
|
|
||||||
Promise.resolve(args[index]);
|
|
||||||
|
|
||||||
const title =
|
|
||||||
"We've noticed you don't have a CodeQL pack available to analyze this database. Can we set up a query pack for you?";
|
|
||||||
|
|
||||||
it("should show a ternary choice dialog and return `Yes`", async () => {
|
|
||||||
// pretend user chooses 'Yes'
|
|
||||||
const yesItem = resolveArg(2);
|
|
||||||
showInformationMessageSpy.mockImplementationOnce(yesItem);
|
|
||||||
|
|
||||||
const answer = await showNeverAskAgainDialog(title);
|
|
||||||
expect(answer).toBe("Yes");
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should show a ternary choice dialog and return `No`", async () => {
|
|
||||||
// pretend user chooses 'No'
|
|
||||||
const noItem = resolveArg(3);
|
|
||||||
showInformationMessageSpy.mockImplementationOnce(noItem);
|
|
||||||
|
|
||||||
const answer = await showNeverAskAgainDialog(title);
|
|
||||||
expect(answer).toBe("No");
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should show a ternary choice dialog and return `No, and never ask me again`", async () => {
|
|
||||||
// pretend user chooses 'No, and never ask me again'
|
|
||||||
const neverAskAgainItem = resolveArg(4);
|
|
||||||
showInformationMessageSpy.mockImplementationOnce(neverAskAgainItem);
|
|
||||||
|
|
||||||
const answer = await showNeverAskAgainDialog(title);
|
|
||||||
expect(answer).toBe("No, and never ask me again");
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("prepareCodeTour", () => {
|
describe("prepareCodeTour", () => {
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ import { createMockVariantAnalysisHistoryItem } from "../../../factories/query-h
|
|||||||
import { VariantAnalysisHistoryItem } from "../../../../src/query-history/variant-analysis-history-item";
|
import { VariantAnalysisHistoryItem } from "../../../../src/query-history/variant-analysis-history-item";
|
||||||
import { QueryStatus } from "../../../../src/query-status";
|
import { QueryStatus } from "../../../../src/query-status";
|
||||||
import { VariantAnalysisStatus } from "../../../../src/variant-analysis/shared/variant-analysis";
|
import { VariantAnalysisStatus } from "../../../../src/variant-analysis/shared/variant-analysis";
|
||||||
import * as helpers from "../../../../src/helpers";
|
import * as dialog from "../../../../src/common/vscode/dialog";
|
||||||
import { mockedQuickPickItem } from "../../utils/mocking.helpers";
|
import { mockedQuickPickItem } from "../../utils/mocking.helpers";
|
||||||
import { createMockQueryHistoryDirs } from "../../../factories/query-history/query-history-dirs";
|
import { createMockQueryHistoryDirs } from "../../../factories/query-history/query-history-dirs";
|
||||||
import { createMockApp } from "../../../__mocks__/appMock";
|
import { createMockApp } from "../../../__mocks__/appMock";
|
||||||
@@ -318,20 +318,20 @@ describe("QueryHistoryManager", () => {
|
|||||||
|
|
||||||
describe("when the item is a variant analysis", () => {
|
describe("when the item is a variant analysis", () => {
|
||||||
let showBinaryChoiceDialogSpy: jest.SpiedFunction<
|
let showBinaryChoiceDialogSpy: jest.SpiedFunction<
|
||||||
typeof helpers.showBinaryChoiceDialog
|
typeof dialog.showBinaryChoiceDialog
|
||||||
>;
|
>;
|
||||||
let showInformationMessageWithActionSpy: jest.SpiedFunction<
|
let showInformationMessageWithActionSpy: jest.SpiedFunction<
|
||||||
typeof helpers.showInformationMessageWithAction
|
typeof dialog.showInformationMessageWithAction
|
||||||
>;
|
>;
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
// Choose 'Yes' when asked "Are you sure?"
|
// Choose 'Yes' when asked "Are you sure?"
|
||||||
showBinaryChoiceDialogSpy = jest
|
showBinaryChoiceDialogSpy = jest
|
||||||
.spyOn(helpers, "showBinaryChoiceDialog")
|
.spyOn(dialog, "showBinaryChoiceDialog")
|
||||||
.mockResolvedValue(true);
|
.mockResolvedValue(true);
|
||||||
|
|
||||||
showInformationMessageWithActionSpy = jest.spyOn(
|
showInformationMessageWithActionSpy = jest.spyOn(
|
||||||
helpers,
|
dialog,
|
||||||
"showInformationMessageWithAction",
|
"showInformationMessageWithAction",
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user