Skip to content

Commit 7414a77

Browse files
committed
Add progress notification to exporting results
This will add a progress notification to exporting results to give users feedback about what's happening. Unfortunately, we need to change some things in how we handle the actions on completion notifications since we want the progress notification to disappear when that notification shows. This results in us having to remove the `await` on the `showInformationMessageWithAction` calls.
1 parent fb154ab commit 7414a77

2 files changed

Lines changed: 102 additions & 14 deletions

File tree

extensions/ql-vscode/src/extension.ts

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1235,9 +1235,11 @@ async function activateWithInstalledDistribution(
12351235
);
12361236

12371237
ctx.subscriptions.push(
1238-
commandRunner(
1238+
commandRunnerWithProgress(
12391239
"codeQL.exportVariantAnalysisResults",
12401240
async (
1241+
progress: ProgressCallback,
1242+
token: CancellationToken,
12411243
variantAnalysisId: number,
12421244
filterSort?: RepositoriesFilterSortStateWithIds,
12431245
) => {
@@ -1246,8 +1248,14 @@ async function activateWithInstalledDistribution(
12461248
variantAnalysisManager,
12471249
variantAnalysisId,
12481250
filterSort,
1251+
progress,
1252+
token,
12491253
);
12501254
},
1255+
{
1256+
title: "Exporting variant analysis results",
1257+
cancellable: true,
1258+
},
12511259
),
12521260
);
12531261

extensions/ql-vscode/src/remote-queries/export-results.ts

Lines changed: 93 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,10 @@ import {
88
ExtensionContext,
99
workspace,
1010
ViewColumn,
11+
CancellationToken,
1112
} from "vscode";
1213
import { Credentials } from "../authentication";
13-
import { UserCancellationException } from "../commandRunner";
14+
import { ProgressCallback, UserCancellationException } from "../commandRunner";
1415
import { showInformationMessageWithAction } from "../helpers";
1516
import { extLogger } from "../common";
1617
import { QueryHistoryManager } from "../query-history";
@@ -131,6 +132,8 @@ export async function exportRemoteQueryAnalysisResults(
131132
);
132133
}
133134

135+
const MAX_VARIANT_ANALYSIS_EXPORT_PROGRESS_STEPS = 2;
136+
134137
/**
135138
* Exports the results of the given or currently-selected remote query.
136139
* The user is prompted to select the export format.
@@ -139,7 +142,9 @@ export async function exportVariantAnalysisResults(
139142
ctx: ExtensionContext,
140143
variantAnalysisManager: VariantAnalysisManager,
141144
variantAnalysisId: number,
142-
filterSort?: RepositoriesFilterSortStateWithIds,
145+
filterSort: RepositoriesFilterSortStateWithIds | undefined,
146+
progress: ProgressCallback,
147+
token: CancellationToken,
143148
): Promise<void> {
144149
const variantAnalysis = await variantAnalysisManager.getVariantAnalysis(
145150
variantAnalysisId,
@@ -153,15 +158,29 @@ export async function exportVariantAnalysisResults(
153158
);
154159
}
155160

161+
if (token.isCancellationRequested) {
162+
throw new UserCancellationException("Cancelled");
163+
}
164+
156165
void extLogger.log(
157166
`Exporting variant analysis results for variant analysis with id ${variantAnalysis.id}`,
158167
);
159168

169+
progress({
170+
maxStep: MAX_VARIANT_ANALYSIS_EXPORT_PROGRESS_STEPS,
171+
step: 0,
172+
message: "Determining export format",
173+
});
174+
160175
const exportFormat = await determineExportFormat();
161176
if (!exportFormat) {
162177
return;
163178
}
164179

180+
if (token.isCancellationRequested) {
181+
throw new UserCancellationException("Cancelled");
182+
}
183+
165184
async function* getAnalysesResults(): AsyncGenerator<
166185
[VariantAnalysisScannedRepository, VariantAnalysisScannedRepositoryResult]
167186
> {
@@ -223,6 +242,8 @@ export async function exportVariantAnalysisResults(
223242
variantAnalysis,
224243
getAnalysesResults(),
225244
exportFormat,
245+
progress,
246+
token,
226247
);
227248
}
228249

@@ -234,7 +255,19 @@ export async function exportVariantAnalysisAnalysisResults(
234255
[VariantAnalysisScannedRepository, VariantAnalysisScannedRepositoryResult]
235256
>,
236257
exportFormat: "gist" | "local",
258+
progress: ProgressCallback,
259+
token: CancellationToken,
237260
) {
261+
if (token.isCancellationRequested) {
262+
throw new UserCancellationException("Cancelled");
263+
}
264+
265+
progress({
266+
maxStep: MAX_VARIANT_ANALYSIS_EXPORT_PROGRESS_STEPS,
267+
step: 1,
268+
message: "Generating Markdown files",
269+
});
270+
238271
const description = buildVariantAnalysisGistDescription(variantAnalysis);
239272
const markdownFiles = await generateVariantAnalysisMarkdown(
240273
variantAnalysis,
@@ -248,6 +281,8 @@ export async function exportVariantAnalysisAnalysisResults(
248281
description,
249282
markdownFiles,
250283
exportFormat,
284+
progress,
285+
token,
251286
);
252287
}
253288

@@ -290,21 +325,44 @@ export async function exportResults(
290325
description: string,
291326
markdownFiles: MarkdownFile[],
292327
exportFormat: "gist" | "local",
328+
progress?: ProgressCallback,
329+
token?: CancellationToken,
293330
) {
331+
if (token?.isCancellationRequested) {
332+
throw new UserCancellationException("Cancelled");
333+
}
334+
294335
if (exportFormat === "gist") {
295-
await exportToGist(ctx, description, markdownFiles);
336+
await exportToGist(ctx, description, markdownFiles, progress, token);
296337
} else if (exportFormat === "local") {
297-
await exportToLocalMarkdown(exportedResultsPath, markdownFiles);
338+
await exportToLocalMarkdown(
339+
exportedResultsPath,
340+
markdownFiles,
341+
progress,
342+
token,
343+
);
298344
}
299345
}
300346

301347
export async function exportToGist(
302348
ctx: ExtensionContext,
303349
description: string,
304350
markdownFiles: MarkdownFile[],
351+
progress?: ProgressCallback,
352+
token?: CancellationToken,
305353
) {
354+
progress?.({
355+
maxStep: MAX_VARIANT_ANALYSIS_EXPORT_PROGRESS_STEPS,
356+
step: 2,
357+
message: "Creating Gist",
358+
});
359+
306360
const credentials = await Credentials.initialize(ctx);
307361

362+
if (token?.isCancellationRequested) {
363+
throw new UserCancellationException("Cancelled");
364+
}
365+
308366
// Convert markdownFiles to the appropriate format for uploading to gist
309367
const gistFiles = markdownFiles.reduce((acc, cur) => {
310368
acc[`${cur.fileName}.md`] = { content: cur.content.join("\n") };
@@ -313,13 +371,17 @@ export async function exportToGist(
313371

314372
const gistUrl = await createGist(credentials, description, gistFiles);
315373
if (gistUrl) {
316-
const shouldOpenGist = await showInformationMessageWithAction(
374+
// This needs to use .then to ensure we aren't keeping the progress notification open. We shouldn't await the
375+
// "Open gist" button click.
376+
void showInformationMessageWithAction(
317377
"Variant analysis results exported to gist.",
318378
"Open gist",
319-
);
320-
if (shouldOpenGist) {
321-
await commands.executeCommand("vscode.open", Uri.parse(gistUrl));
322-
}
379+
).then((shouldOpenGist) => {
380+
if (!shouldOpenGist) {
381+
return;
382+
}
383+
return commands.executeCommand("vscode.open", Uri.parse(gistUrl));
384+
});
323385
}
324386
}
325387

@@ -369,20 +431,38 @@ const buildVariantAnalysisGistDescription = (
369431
async function exportToLocalMarkdown(
370432
exportedResultsPath: string,
371433
markdownFiles: MarkdownFile[],
434+
progress?: ProgressCallback,
435+
token?: CancellationToken,
372436
) {
437+
if (token?.isCancellationRequested) {
438+
throw new UserCancellationException("Cancelled");
439+
}
440+
441+
progress?.({
442+
maxStep: MAX_VARIANT_ANALYSIS_EXPORT_PROGRESS_STEPS,
443+
step: 2,
444+
message: "Creating local Markdown files",
445+
});
446+
373447
await ensureDir(exportedResultsPath);
374448
for (const markdownFile of markdownFiles) {
375449
const filePath = join(exportedResultsPath, `${markdownFile.fileName}.md`);
376450
await writeFile(filePath, markdownFile.content.join("\n"), "utf8");
377451
}
378-
const shouldOpenExportedResults = await showInformationMessageWithAction(
452+
453+
// This needs to use .then to ensure we aren't keeping the progress notification open. We shouldn't await the
454+
// "Open exported results" button click.
455+
void showInformationMessageWithAction(
379456
`Variant analysis results exported to \"${exportedResultsPath}\".`,
380457
"Open exported results",
381-
);
382-
if (shouldOpenExportedResults) {
458+
).then(async (shouldOpenExportedResults) => {
459+
if (!shouldOpenExportedResults) {
460+
return;
461+
}
462+
383463
const summaryFilePath = join(exportedResultsPath, "_summary.md");
384464
const summaryFile = await workspace.openTextDocument(summaryFilePath);
385465
await window.showTextDocument(summaryFile, ViewColumn.One);
386466
await commands.executeCommand("revealFileInOS", Uri.file(summaryFilePath));
387-
}
467+
});
388468
}

0 commit comments

Comments
 (0)