Improve user experience when no database is selected (#3214)

This commit is contained in:
Shati Patel
2024-01-11 09:41:44 +00:00
committed by GitHub
parent d0a12753d8
commit 77f84c6ca9
3 changed files with 138 additions and 16 deletions

View File

@@ -2,6 +2,7 @@
## [UNRELEASED]
- If you run a query without having selected a database, we show a more intuitive prompt to help you select a database. [#3214](https://github.com/github/vscode-codeql/pull/3214)
- Add a prompt for downloading a GitHub database when opening a GitHub repository. [#3138](https://github.com/github/vscode-codeql/pull/3138)
- Avoid showing a popup when hovering over source elements in database source files. [#3125](https://github.com/github/vscode-codeql/pull/3125)
- Add comparison of alerts when comparing query results. This allows viewing path explanations for differences in alerts. [#3113](https://github.com/github/vscode-codeql/pull/3113)

View File

@@ -5,6 +5,7 @@ import type {
ProviderResult,
TreeDataProvider,
CancellationToken,
QuickPickItem,
} from "vscode";
import {
EventEmitter,
@@ -28,7 +29,11 @@ import type {
ProgressCallback,
ProgressContext,
} from "../common/vscode/progress";
import { withInheritedProgress, withProgress } from "../common/vscode/progress";
import {
UserCancellationException,
withInheritedProgress,
withProgress,
} from "../common/vscode/progress";
import {
isLikelyDatabaseRoot,
isLikelyDbLanguageFolder,
@@ -52,7 +57,10 @@ import {
createMultiSelectionCommand,
createSingleSelectionCommand,
} from "../common/vscode/selection-commands";
import { tryGetQueryLanguage } from "../common/query-language";
import {
getLanguageDisplayName,
tryGetQueryLanguage,
} from "../common/query-language";
import type { LanguageContextStore } from "../language-context-store";
enum SortOrder {
@@ -227,6 +235,18 @@ async function chooseDatabaseDir(byFolder: boolean): Promise<Uri | undefined> {
return getFirst(chosen);
}
interface DatabaseSelectionQuickPickItem extends QuickPickItem {
databaseKind: "new" | "existing";
}
export interface DatabaseQuickPickItem extends QuickPickItem {
databaseItem: DatabaseItem;
}
interface DatabaseImportQuickPickItems extends QuickPickItem {
importType: "URL" | "github" | "archive" | "folder";
}
export class DatabaseUI extends DisposableObject {
private treeDataProvider: DatabaseTreeDataProvider;
@@ -794,13 +814,120 @@ export class DatabaseUI extends DisposableObject {
* notification if it tries to perform any long-running operations.
*/
private async getDatabaseItemInternal(
progress: ProgressContext | undefined,
progressContext: ProgressContext | undefined,
): Promise<DatabaseItem | undefined> {
if (this.databaseManager.currentDatabaseItem === undefined) {
await this.chooseAndSetDatabase(false, progress);
progressContext?.progress({
maxStep: 2,
step: 1,
message: "Choosing database",
});
await this.promptForDatabase();
}
return this.databaseManager.currentDatabaseItem;
}
private async promptForDatabase(): Promise<void> {
const quickPickItems: DatabaseSelectionQuickPickItem[] = [
{
label: "$(database) Existing database",
detail: "Select an existing database from your workspace",
alwaysShow: true,
databaseKind: "existing",
},
{
label: "$(arrow-down) New database",
detail: "Import a new database from the cloud or your local machine",
alwaysShow: true,
databaseKind: "new",
},
];
const selectedOption =
await window.showQuickPick<DatabaseSelectionQuickPickItem>(
quickPickItems,
{
placeHolder: "Select an option",
ignoreFocusOut: true,
},
);
if (!selectedOption) {
throw new UserCancellationException("No database selected", true);
}
return this.databaseManager.currentDatabaseItem;
if (selectedOption.databaseKind === "existing") {
await this.selectExistingDatabase();
} else if (selectedOption.databaseKind === "new") {
await this.importNewDatabase();
}
}
private async selectExistingDatabase() {
const dbItems: DatabaseQuickPickItem[] =
this.databaseManager.databaseItems.map((dbItem) => ({
label: dbItem.name,
description: getLanguageDisplayName(dbItem.language),
databaseItem: dbItem,
}));
const selectedDatabase = await window.showQuickPick(dbItems, {
placeHolder: "Select a database",
ignoreFocusOut: true,
});
if (!selectedDatabase) {
throw new UserCancellationException("No database selected", true);
}
await this.databaseManager.setCurrentDatabaseItem(
selectedDatabase.databaseItem,
);
}
private async importNewDatabase() {
const importOptions: DatabaseImportQuickPickItems[] = [
{
label: "$(github) GitHub",
detail: "Import a database from a GitHub repository",
alwaysShow: true,
importType: "github",
},
{
label: "$(link) URL",
detail: "Import a database archive or folder from a remote URL",
alwaysShow: true,
importType: "URL",
},
{
label: "$(file-zip) Archive",
detail: "Import a database from a local ZIP archive",
alwaysShow: true,
importType: "archive",
},
{
label: "$(folder) Folder",
detail: "Import a database from a local folder",
alwaysShow: true,
importType: "folder",
},
];
const selectedImportOption =
await window.showQuickPick<DatabaseImportQuickPickItems>(importOptions, {
placeHolder: "Import a database from...",
ignoreFocusOut: true,
});
if (!selectedImportOption) {
throw new UserCancellationException("No database selected", true);
}
if (selectedImportOption.importType === "github") {
await this.handleChooseDatabaseGithub();
} else if (selectedImportOption.importType === "URL") {
await this.handleChooseDatabaseInternet();
} else if (selectedImportOption.importType === "archive") {
await this.handleChooseDatabaseArchive();
} else if (selectedImportOption.importType === "folder") {
await this.handleChooseDatabaseFolder();
}
}
/**

View File

@@ -3,12 +3,7 @@ import type {
ProgressUpdate,
} from "../common/vscode/progress";
import { withProgress } from "../common/vscode/progress";
import type {
CancellationToken,
QuickPickItem,
Range,
TabInputText,
} from "vscode";
import type { CancellationToken, Range, TabInputText } from "vscode";
import { CancellationTokenSource, Uri, window } from "vscode";
import {
TeeLogger,
@@ -23,7 +18,10 @@ import { getOnDiskWorkspaceFolders } from "../common/vscode/workspace-folders";
import { displayQuickQuery } from "./quick-query";
import type { CoreCompletedQuery, QueryRunner } from "../query-server";
import type { QueryHistoryManager } from "../query-history/query-history-manager";
import type { DatabaseUI } from "../databases/local-databases-ui";
import type {
DatabaseQuickPickItem,
DatabaseUI,
} from "../databases/local-databases-ui";
import type { ResultsView } from "./results-view";
import type {
DatabaseItem,
@@ -55,10 +53,6 @@ import { tryGetQueryLanguage } from "../common/query-language";
import type { LanguageContextStore } from "../language-context-store";
import type { ExtensionApp } from "../common/vscode/vscode-app";
interface DatabaseQuickPickItem extends QuickPickItem {
databaseItem: DatabaseItem;
}
export enum QuickEvalType {
None,
QuickEval,