Skip to content

Commit 77f84c6

Browse files
authored
Improve user experience when no database is selected (#3214)
1 parent d0a1275 commit 77f84c6

File tree

3 files changed

+138
-16
lines changed

3 files changed

+138
-16
lines changed

extensions/ql-vscode/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
## [UNRELEASED]
44

5+
- 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)
56
- Add a prompt for downloading a GitHub database when opening a GitHub repository. [#3138](https://github.com/github/vscode-codeql/pull/3138)
67
- Avoid showing a popup when hovering over source elements in database source files. [#3125](https://github.com/github/vscode-codeql/pull/3125)
78
- 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)

extensions/ql-vscode/src/databases/local-databases-ui.ts

Lines changed: 132 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import type {
55
ProviderResult,
66
TreeDataProvider,
77
CancellationToken,
8+
QuickPickItem,
89
} from "vscode";
910
import {
1011
EventEmitter,
@@ -28,7 +29,11 @@ import type {
2829
ProgressCallback,
2930
ProgressContext,
3031
} from "../common/vscode/progress";
31-
import { withInheritedProgress, withProgress } from "../common/vscode/progress";
32+
import {
33+
UserCancellationException,
34+
withInheritedProgress,
35+
withProgress,
36+
} from "../common/vscode/progress";
3237
import {
3338
isLikelyDatabaseRoot,
3439
isLikelyDbLanguageFolder,
@@ -52,7 +57,10 @@ import {
5257
createMultiSelectionCommand,
5358
createSingleSelectionCommand,
5459
} from "../common/vscode/selection-commands";
55-
import { tryGetQueryLanguage } from "../common/query-language";
60+
import {
61+
getLanguageDisplayName,
62+
tryGetQueryLanguage,
63+
} from "../common/query-language";
5664
import type { LanguageContextStore } from "../language-context-store";
5765

5866
enum SortOrder {
@@ -227,6 +235,18 @@ async function chooseDatabaseDir(byFolder: boolean): Promise<Uri | undefined> {
227235
return getFirst(chosen);
228236
}
229237

238+
interface DatabaseSelectionQuickPickItem extends QuickPickItem {
239+
databaseKind: "new" | "existing";
240+
}
241+
242+
export interface DatabaseQuickPickItem extends QuickPickItem {
243+
databaseItem: DatabaseItem;
244+
}
245+
246+
interface DatabaseImportQuickPickItems extends QuickPickItem {
247+
importType: "URL" | "github" | "archive" | "folder";
248+
}
249+
230250
export class DatabaseUI extends DisposableObject {
231251
private treeDataProvider: DatabaseTreeDataProvider;
232252

@@ -794,15 +814,122 @@ export class DatabaseUI extends DisposableObject {
794814
* notification if it tries to perform any long-running operations.
795815
*/
796816
private async getDatabaseItemInternal(
797-
progress: ProgressContext | undefined,
817+
progressContext: ProgressContext | undefined,
798818
): Promise<DatabaseItem | undefined> {
799819
if (this.databaseManager.currentDatabaseItem === undefined) {
800-
await this.chooseAndSetDatabase(false, progress);
820+
progressContext?.progress({
821+
maxStep: 2,
822+
step: 1,
823+
message: "Choosing database",
824+
});
825+
await this.promptForDatabase();
801826
}
802-
803827
return this.databaseManager.currentDatabaseItem;
804828
}
805829

830+
private async promptForDatabase(): Promise<void> {
831+
const quickPickItems: DatabaseSelectionQuickPickItem[] = [
832+
{
833+
label: "$(database) Existing database",
834+
detail: "Select an existing database from your workspace",
835+
alwaysShow: true,
836+
databaseKind: "existing",
837+
},
838+
{
839+
label: "$(arrow-down) New database",
840+
detail: "Import a new database from the cloud or your local machine",
841+
alwaysShow: true,
842+
databaseKind: "new",
843+
},
844+
];
845+
const selectedOption =
846+
await window.showQuickPick<DatabaseSelectionQuickPickItem>(
847+
quickPickItems,
848+
{
849+
placeHolder: "Select an option",
850+
ignoreFocusOut: true,
851+
},
852+
);
853+
854+
if (!selectedOption) {
855+
throw new UserCancellationException("No database selected", true);
856+
}
857+
858+
if (selectedOption.databaseKind === "existing") {
859+
await this.selectExistingDatabase();
860+
} else if (selectedOption.databaseKind === "new") {
861+
await this.importNewDatabase();
862+
}
863+
}
864+
865+
private async selectExistingDatabase() {
866+
const dbItems: DatabaseQuickPickItem[] =
867+
this.databaseManager.databaseItems.map((dbItem) => ({
868+
label: dbItem.name,
869+
description: getLanguageDisplayName(dbItem.language),
870+
databaseItem: dbItem,
871+
}));
872+
873+
const selectedDatabase = await window.showQuickPick(dbItems, {
874+
placeHolder: "Select a database",
875+
ignoreFocusOut: true,
876+
});
877+
878+
if (!selectedDatabase) {
879+
throw new UserCancellationException("No database selected", true);
880+
}
881+
882+
await this.databaseManager.setCurrentDatabaseItem(
883+
selectedDatabase.databaseItem,
884+
);
885+
}
886+
887+
private async importNewDatabase() {
888+
const importOptions: DatabaseImportQuickPickItems[] = [
889+
{
890+
label: "$(github) GitHub",
891+
detail: "Import a database from a GitHub repository",
892+
alwaysShow: true,
893+
importType: "github",
894+
},
895+
{
896+
label: "$(link) URL",
897+
detail: "Import a database archive or folder from a remote URL",
898+
alwaysShow: true,
899+
importType: "URL",
900+
},
901+
{
902+
label: "$(file-zip) Archive",
903+
detail: "Import a database from a local ZIP archive",
904+
alwaysShow: true,
905+
importType: "archive",
906+
},
907+
{
908+
label: "$(folder) Folder",
909+
detail: "Import a database from a local folder",
910+
alwaysShow: true,
911+
importType: "folder",
912+
},
913+
];
914+
const selectedImportOption =
915+
await window.showQuickPick<DatabaseImportQuickPickItems>(importOptions, {
916+
placeHolder: "Import a database from...",
917+
ignoreFocusOut: true,
918+
});
919+
if (!selectedImportOption) {
920+
throw new UserCancellationException("No database selected", true);
921+
}
922+
if (selectedImportOption.importType === "github") {
923+
await this.handleChooseDatabaseGithub();
924+
} else if (selectedImportOption.importType === "URL") {
925+
await this.handleChooseDatabaseInternet();
926+
} else if (selectedImportOption.importType === "archive") {
927+
await this.handleChooseDatabaseArchive();
928+
} else if (selectedImportOption.importType === "folder") {
929+
await this.handleChooseDatabaseFolder();
930+
}
931+
}
932+
806933
/**
807934
* Ask the user for a database directory. Returns the chosen database, or `undefined` if the
808935
* operation was canceled.

extensions/ql-vscode/src/local-queries/local-queries.ts

Lines changed: 5 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,7 @@ import type {
33
ProgressUpdate,
44
} from "../common/vscode/progress";
55
import { withProgress } from "../common/vscode/progress";
6-
import type {
7-
CancellationToken,
8-
QuickPickItem,
9-
Range,
10-
TabInputText,
11-
} from "vscode";
6+
import type { CancellationToken, Range, TabInputText } from "vscode";
127
import { CancellationTokenSource, Uri, window } from "vscode";
138
import {
149
TeeLogger,
@@ -23,7 +18,10 @@ import { getOnDiskWorkspaceFolders } from "../common/vscode/workspace-folders";
2318
import { displayQuickQuery } from "./quick-query";
2419
import type { CoreCompletedQuery, QueryRunner } from "../query-server";
2520
import type { QueryHistoryManager } from "../query-history/query-history-manager";
26-
import type { DatabaseUI } from "../databases/local-databases-ui";
21+
import type {
22+
DatabaseQuickPickItem,
23+
DatabaseUI,
24+
} from "../databases/local-databases-ui";
2725
import type { ResultsView } from "./results-view";
2826
import type {
2927
DatabaseItem,
@@ -55,10 +53,6 @@ import { tryGetQueryLanguage } from "../common/query-language";
5553
import type { LanguageContextStore } from "../language-context-store";
5654
import type { ExtensionApp } from "../common/vscode/vscode-app";
5755

58-
interface DatabaseQuickPickItem extends QuickPickItem {
59-
databaseItem: DatabaseItem;
60-
}
61-
6256
export enum QuickEvalType {
6357
None,
6458
QuickEval,

0 commit comments

Comments
 (0)