Skip to content

Commit ddddd2f

Browse files
authored
Merge pull request #2018 from github/koesie10/download-progress-indicator
Add download progress indicator for MRVA downloads
2 parents 5098382 + 7dd5b0a commit ddddd2f

File tree

5 files changed

+75
-9
lines changed

5 files changed

+75
-9
lines changed

extensions/ql-vscode/src/remote-queries/variant-analysis-manager.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ export class VariantAnalysisManager
6868
implements VariantAnalysisViewManager<VariantAnalysisView>
6969
{
7070
private static readonly REPO_STATES_FILENAME = "repo_states.json";
71-
private static readonly DOWNLOAD_PERCENTAGE_UPDATE_DELAY_MS = 3000;
71+
private static readonly DOWNLOAD_PERCENTAGE_UPDATE_DELAY_MS = 500;
7272

7373
private readonly _onVariantAnalysisAdded = this.push(
7474
new EventEmitter<VariantAnalysis>(),

extensions/ql-vscode/src/remote-queries/variant-analysis-results-manager.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,12 +90,18 @@ export class VariantAnalysisResultsManager extends DisposableObject {
9090
const zipFilePath = join(resultDirectory, "results.zip");
9191

9292
const response = await fetch(repoTask.artifactUrl);
93+
94+
let responseSize = parseInt(response.headers.get("content-length") || "0");
95+
if (responseSize === 0 && response.size > 0) {
96+
responseSize = response.size;
97+
}
98+
9399
let amountDownloaded = 0;
94100
for await (const chunk of response.body) {
95101
await appendFile(zipFilePath, Buffer.from(chunk));
96102
amountDownloaded += chunk.length;
97103
await onDownloadPercentageChanged(
98-
Math.floor((amountDownloaded / response.size) * 100),
104+
Math.floor((amountDownloaded / responseSize) * 100),
99105
);
100106
}
101107

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
import * as React from "react";
2+
import styled from "styled-components";
3+
4+
type Props = {
5+
percent: number;
6+
label?: string;
7+
};
8+
9+
const Circle = styled.div`
10+
width: 16px;
11+
height: 16px;
12+
`;
13+
14+
const Background = styled.circle`
15+
stroke: var(--vscode-editorWidget-background);
16+
fill: none;
17+
stroke-width: 2px;
18+
`;
19+
20+
const Determinate = styled.circle`
21+
stroke: var(--vscode-progressBar-background);
22+
fill: none;
23+
stroke-width: 2px;
24+
stroke-linecap: round;
25+
transform-origin: 50% 50%;
26+
transform: rotate(-90deg);
27+
transition: all 0.2s ease-in-out 0s;
28+
`;
29+
30+
const progressSegments = 44;
31+
32+
// This is a re-implementation of the FAST component progress ring
33+
// See https://github.com/microsoft/fast/blob/21c210f2164c5cf285cade1a328460c67e4b97e6/packages/web-components/fast-foundation/src/progress-ring/progress-ring.template.ts
34+
// Once the determinate progress ring is available in the VSCode webview UI toolkit, we should use that instead
35+
36+
export const DeterminateProgressRing = ({
37+
percent,
38+
label = "Loading...",
39+
}: Props) => (
40+
<Circle
41+
role="progressbar"
42+
aria-valuemin={0}
43+
aria-valuemax={100}
44+
aria-valuenow={percent}
45+
>
46+
<svg className="progress" viewBox="0 0 16 16">
47+
<Background cx="8px" cy="8px" r="7px" />
48+
<Determinate
49+
style={{
50+
strokeDasharray: `${
51+
(progressSegments * percent) / 100
52+
}px ${progressSegments}px`,
53+
}}
54+
cx="8px"
55+
cy="8px"
56+
r="7px"
57+
></Determinate>
58+
</svg>
59+
</Circle>
60+
);

extensions/ql-vscode/src/view/variant-analysis/RepoRow.tsx

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ import { AnalyzedRepoItemContent } from "./AnalyzedRepoItemContent";
2626
import StarCount from "../common/StarCount";
2727
import { LastUpdated } from "../common/LastUpdated";
2828
import { useTelemetryOnChange } from "../common/telemetry";
29+
import { DeterminateProgressRing } from "../common/DeterminateProgressRing";
2930

3031
// This will ensure that these icons have a className which we can use in the TitleContainer
3132
const ExpandCollapseCodicon = styled(Codicon)``;
@@ -284,12 +285,8 @@ export const RepoRow = ({
284285
</span>
285286
{downloadState?.downloadStatus ===
286287
VariantAnalysisScannedRepositoryDownloadStatus.InProgress && (
287-
<LoadingIcon
288-
label={
289-
downloadState.downloadPercentage !== undefined
290-
? `Downloading: ${downloadState.downloadPercentage}%`
291-
: "Downloading"
292-
}
288+
<DeterminateProgressRing
289+
percent={downloadState.downloadPercentage ?? 0}
293290
/>
294291
)}
295292
{downloadState?.downloadStatus ===

extensions/ql-vscode/test/vscode-tests/cli-integration/remote-queries/variant-analysis-results-manager.test.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -169,7 +169,10 @@ describe(VariantAnalysisResultsManager.name, () => {
169169
(url: RequestInfo, _init?: RequestInit) => {
170170
if (url === dummyRepoTask.artifactUrl) {
171171
const response = new Response(Readable.from(generateInParts()));
172-
response.size = fileContents.length;
172+
response.headers.set(
173+
"Content-Length",
174+
fileContents.length.toString(),
175+
);
173176
return Promise.resolve(response);
174177
}
175178
return Promise.reject(new Error("Unexpected artifact URL"));

0 commit comments

Comments
 (0)