Skip to content

Commit 5be4d3e

Browse files
committed
Add loading progress
1 parent 2ffe99d commit 5be4d3e

5 files changed

Lines changed: 49 additions & 15 deletions

File tree

web/src/lib/diff-viewer-multi-file.svelte.ts

Lines changed: 40 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ import { countOccurrences, type FileTreeNodeData, makeFileTree, type LazyPromise
2424
import { onDestroy, tick } from "svelte";
2525
import { type TreeNode, TreeState } from "$lib/components/tree/index.svelte";
2626
import { VList } from "virtua/svelte";
27-
import { Context, Debounced } from "runed";
27+
import { Context, Debounced, watch } from "runed";
2828
import { MediaQuery } from "svelte/reactivity";
2929
import { ProgressBarState } from "$lib/components/progress-bar/index.svelte";
3030

@@ -338,8 +338,7 @@ export class MultiFileDiffViewerState {
338338
activeSearchResult: ActiveSearchResult | null = $state(null);
339339
sidebarCollapsed = $state(false);
340340
diffMetadata: DiffMetadata | null = $state(null);
341-
loading: boolean = $state(false);
342-
readonly progressBar = $state(new ProgressBarState(null, 100));
341+
readonly loadingState: LoadingState = $state(new LoadingState());
343342

344343
readonly fileTreeFilterDebounced = new Debounced(() => this.fileTreeFilter, 500);
345344
readonly searchQueryDebounced = new Debounced(() => this.searchQuery, 500);
@@ -479,13 +478,12 @@ export class MultiFileDiffViewerState {
479478
}
480479

481480
async loadPatches(meta: () => Promise<DiffMetadata>, patches: () => Promise<AsyncGenerator<FileDetails, void>>) {
482-
if (this.loading) {
481+
if (this.loadingState.loading) {
483482
alert("Already loading patches, please wait.");
484483
return false;
485484
}
486485
try {
487-
this.progressBar.setSpinning();
488-
this.loading = true;
486+
this.loadingState.start();
489487
await tick();
490488
await animationFramePromise();
491489

@@ -501,8 +499,14 @@ export class MultiFileDiffViewerState {
501499

502500
const tempDetails: FileDetails[] = [];
503501
for await (const details of generator) {
502+
this.loadingState.loadedCount++;
503+
504504
// Pushing directly to the main array causes too many signals to update (lag)
505505
tempDetails.push(details);
506+
507+
// TODO this makes it load one patch per frame
508+
await tick();
509+
await animationFramePromise();
506510
}
507511
if (tempDetails.length === 0) {
508512
throw new Error("No valid patches found in the provided data.");
@@ -516,7 +520,7 @@ export class MultiFileDiffViewerState {
516520
alert("Failed to load patches: " + e);
517521
return false;
518522
} finally {
519-
this.loading = false;
523+
this.loadingState.done();
520524
}
521525
}
522526

@@ -527,7 +531,7 @@ export class MultiFileDiffViewerState {
527531
},
528532
async () => {
529533
const result = await resultPromise;
530-
return parseMultiFilePatchGithub(result.info, await result.response);
534+
return parseMultiFilePatchGithub(result.info, await result.response, this.loadingState);
531535
},
532536
);
533537
}
@@ -661,6 +665,34 @@ export class MultiFileDiffViewerState {
661665
}
662666
}
663667

668+
export class LoadingState {
669+
loading: boolean = $state(false);
670+
loadedCount: number = $state(0);
671+
totalCount: number | null = $state(0);
672+
readonly progressBar = $state(new ProgressBarState(null, 100));
673+
674+
constructor() {
675+
watch([() => this.loadedCount, () => this.totalCount], ([loadedCount, totalCount]) => {
676+
if (totalCount === null || totalCount <= 0) {
677+
this.progressBar.setSpinning();
678+
} else {
679+
this.progressBar.setProgress(loadedCount, totalCount);
680+
}
681+
});
682+
}
683+
684+
start() {
685+
this.loadedCount = 0;
686+
this.totalCount = null;
687+
this.progressBar.setSpinning();
688+
this.loading = true;
689+
}
690+
691+
done() {
692+
this.loading = false;
693+
}
694+
}
695+
664696
export type ActiveSearchResult = {
665697
file: FileDetails;
666698
idx: number;

web/src/lib/github.svelte.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { browser } from "$app/environment";
22
import type { components } from "@octokit/openapi-types";
33
import { parseMultiFilePatch, trimCommitHash } from "$lib/util";
4-
import { makeImageDetails } from "$lib/diff-viewer-multi-file.svelte";
4+
import { LoadingState, makeImageDetails } from "$lib/diff-viewer-multi-file.svelte";
55
import { PUBLIC_GITHUB_APP_NAME, PUBLIC_GITHUB_CLIENT_ID } from "$env/static/public";
66

77
export const GITHUB_USERNAME_KEY = "github_username";
@@ -139,8 +139,8 @@ export async function fetchGithubPRInfo(token: string | null, owner: string, rep
139139
}
140140
}
141141

142-
export function parseMultiFilePatchGithub(details: GithubDiff, patch: string) {
143-
return parseMultiFilePatch(patch, (from, to, status) => {
142+
export function parseMultiFilePatchGithub(details: GithubDiff, patch: string, loadingState: LoadingState) {
143+
return parseMultiFilePatch(patch, loadingState, (from, to, status) => {
144144
const token = getGithubToken();
145145
return makeImageDetails(
146146
from,

web/src/lib/util.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { type FileDetails, type ImageFileDetails, makeTextDetails } from "./diff-viewer-multi-file.svelte";
1+
import { type FileDetails, type ImageFileDetails, LoadingState, makeTextDetails } from "./diff-viewer-multi-file.svelte";
22
import type { FileStatus } from "./github.svelte";
33
import type { TreeNode } from "$lib/components/tree/index.svelte";
44
import type { BundledLanguage, SpecialLanguage } from "shiki";
@@ -146,9 +146,11 @@ function parseHeader(patch: string, fromFile: string, toFile: string): BasicHead
146146

147147
export function parseMultiFilePatch(
148148
patchContent: string,
149+
loadingState: LoadingState,
149150
imageFactory?: (fromFile: string, toFile: string, status: FileStatus) => ImageFileDetails | null,
150151
): AsyncGenerator<FileDetails> {
151152
const split = splitMultiFilePatch(patchContent);
153+
loadingState.totalCount = split.length;
152154
async function* detailsGenerator() {
153155
for (const [header, content] of split) {
154156
if (header.binary) {

web/src/routes/+page.svelte

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -138,9 +138,9 @@
138138
</SettingsPopover>
139139
{/snippet}
140140

141-
{#if viewer.loading}
141+
{#if viewer.loadingState.loading}
142142
<div class="absolute bottom-1/2 left-1/2 z-50 -translate-x-1/2 translate-y-1/2 rounded-full border bg-neutral p-2 shadow-md">
143-
<ProgressBar bind:state={viewer.progressBar} class="h-2 w-32" />
143+
<ProgressBar bind:state={viewer.loadingState.progressBar} class="h-2 w-32" />
144144
</div>
145145
{/if}
146146

web/src/routes/OpenDiffDialog.svelte

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -282,7 +282,7 @@
282282
return { type: "file", fileName: meta.name };
283283
},
284284
async () => {
285-
return parseMultiFilePatch(text);
285+
return parseMultiFilePatch(text, viewer.loadingState);
286286
},
287287
);
288288
if (!success) {

0 commit comments

Comments
 (0)