Skip to content

Commit 10a4056

Browse files
acartineclaude
andcommitted
fix(beats): show beat count during streaming, fix premature completion label
The progress bar now shows "Loading… 42 beats from 3/5 repos" during streaming instead of the misleading "All repositories loaded" that appeared when isComplete was set before isStreaming was cleared. Only shows "All repositories loaded" after the stream has fully ended. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent a27e4ae commit 10a4056

File tree

6 files changed

+44
-18
lines changed

6 files changed

+44
-18
lines changed

src/app/beats/__tests__/use-beats-query-streaming.test.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ function simulateStreamingFetch(
1919
let progress: StreamingProgress = {
2020
totalRepos: 0,
2121
loadedRepos: [],
22+
loadedBeatsCount: 0,
2223
isStreaming: false,
2324
isComplete: false,
2425
};
@@ -27,6 +28,7 @@ function simulateStreamingFetch(
2728
progress = {
2829
totalRepos: repoCount,
2930
loadedRepos: [],
31+
loadedBeatsCount: 0,
3032
isStreaming: true,
3133
isComplete: false,
3234
};
@@ -95,6 +97,7 @@ describe(
9597
const idle: StreamingProgress = {
9698
totalRepos: 0,
9799
loadedRepos: [],
100+
loadedBeatsCount: 0,
98101
isStreaming: false,
99102
isComplete: false,
100103
};

src/app/beats/__tests__/use-streaming-progress.test.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import type { StreamingProgress } from
1212
const EMPTY: StreamingProgress = {
1313
totalRepos: 0,
1414
loadedRepos: [],
15+
loadedBeatsCount: 0,
1516
isStreaming: false,
1617
isComplete: false,
1718
};
@@ -22,6 +23,7 @@ function applyStreamStart(
2223
return {
2324
totalRepos: total,
2425
loadedRepos: [],
26+
loadedBeatsCount: 0,
2527
isStreaming: true,
2628
isComplete: false,
2729
};
@@ -56,6 +58,7 @@ describe("streaming progress transitions", () => {
5658
expect(EMPTY).toEqual({
5759
totalRepos: 0,
5860
loadedRepos: [],
61+
loadedBeatsCount: 0,
5962
isStreaming: false,
6063
isComplete: false,
6164
});

src/app/beats/use-beats-query.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -199,7 +199,9 @@ interface StreamingFetchArgs {
199199
setQueryData: SetQueryData;
200200
getQueryData: () => QueryData | undefined;
201201
onStreamStart: (total: number) => void;
202-
onRepoLoaded: (repo: string) => void;
202+
onRepoLoaded: (
203+
repo: string, beatsCount: number,
204+
) => void;
203205
onStreamComplete: () => void;
204206
}
205207

@@ -268,7 +270,7 @@ async function fetchBeatsWithStreaming(
268270
data: [...prev, ...beats],
269271
};
270272
});
271-
onRepoLoaded(repo);
273+
onRepoLoaded(repo, beats.length);
272274
},
273275
}),
274276
() => ({

src/app/beats/use-streaming-progress.ts

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ export interface StreamingProgress {
99
totalRepos: number;
1010
/** Repo paths that have finished loading. */
1111
loadedRepos: string[];
12+
/** Running count of beats received so far. */
13+
loadedBeatsCount: number;
1214
/** True while the streaming fetch is in flight. */
1315
isStreaming: boolean;
1416
/** True once all repos have responded. */
@@ -18,14 +20,17 @@ export interface StreamingProgress {
1820
const EMPTY_PROGRESS: StreamingProgress = {
1921
totalRepos: 0,
2022
loadedRepos: [],
23+
loadedBeatsCount: 0,
2124
isStreaming: false,
2225
isComplete: false,
2326
};
2427

2528
export interface StreamingProgressHandle {
2629
progress: StreamingProgress;
2730
onStreamStart: (totalRepos: number) => void;
28-
onRepoLoaded: (repoPath: string) => void;
31+
onRepoLoaded: (
32+
repoPath: string, beatsCount: number,
33+
) => void;
2934
onStreamComplete: () => void;
3035
resetProgress: () => void;
3136
}
@@ -48,6 +53,7 @@ export function useStreamingProgress():
4853
setProgress({
4954
totalRepos,
5055
loadedRepos: [],
56+
loadedBeatsCount: 0,
5157
isStreaming: true,
5258
isComplete: false,
5359
});
@@ -56,16 +62,14 @@ export function useStreamingProgress():
5662
);
5763

5864
const onRepoLoaded = useCallback(
59-
(repoPath: string) => {
65+
(repoPath: string, beatsCount: number) => {
6066
setProgress((prev) => {
6167
const loaded = [...prev.loadedRepos, repoPath];
62-
const complete =
63-
loaded.length >= totalRef.current;
6468
return {
6569
...prev,
6670
loadedRepos: loaded,
67-
isComplete: complete,
68-
isStreaming: !complete,
71+
loadedBeatsCount:
72+
prev.loadedBeatsCount + beatsCount,
6973
};
7074
});
7175
},

src/components/__tests__/streaming-progress-bar.test.ts

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,15 @@ import type { StreamingProgress } from
88
*/
99

1010
function deriveLabel(p: StreamingProgress): string {
11-
if (p.isComplete) return "All repositories loaded";
12-
return `Loaded ${p.loadedRepos.length}`
13-
+ `/${p.totalRepos} repositories`;
11+
if (!p.isStreaming && p.isComplete) {
12+
return "All repositories loaded";
13+
}
14+
if (p.loadedBeatsCount > 0) {
15+
return `Loading\u2026 ${p.loadedBeatsCount} beats`
16+
+ ` from ${p.loadedRepos.length}`
17+
+ `/${p.totalRepos} repos`;
18+
}
19+
return `Loading ${p.totalRepos} repositories\u2026`;
1420
}
1521

1622
function derivePct(p: StreamingProgress): number {
@@ -32,32 +38,35 @@ describe("streaming progress bar logic", () => {
3238
const base: StreamingProgress = {
3339
totalRepos: 5,
3440
loadedRepos: [],
41+
loadedBeatsCount: 0,
3542
isStreaming: true,
3643
isComplete: false,
3744
};
3845

39-
it("shows 0/5 at start", () => {
46+
it("shows loading at start", () => {
4047
expect(derivePct(base)).toBe(0);
4148
expect(deriveLabel(base)).toBe(
42-
"Loaded 0/5 repositories",
49+
"Loading 5 repositories\u2026",
4350
);
4451
});
4552

46-
it("shows 60% at 3/5", () => {
53+
it("shows beat count at 3/5 repos", () => {
4754
const p = {
4855
...base,
4956
loadedRepos: ["/a", "/b", "/c"],
57+
loadedBeatsCount: 42,
5058
};
5159
expect(derivePct(p)).toBe(60);
5260
expect(deriveLabel(p)).toBe(
53-
"Loaded 3/5 repositories",
61+
"Loading\u2026 42 beats from 3/5 repos",
5462
);
5563
});
5664

5765
it("shows completion label", () => {
5866
const p: StreamingProgress = {
5967
totalRepos: 5,
6068
loadedRepos: ["/a", "/b", "/c", "/d", "/e"],
69+
loadedBeatsCount: 50,
6170
isStreaming: false,
6271
isComplete: true,
6372
};
@@ -93,6 +102,7 @@ describe("streaming progress bar logic", () => {
93102
const idle: StreamingProgress = {
94103
totalRepos: 0,
95104
loadedRepos: [],
105+
loadedBeatsCount: 0,
96106
isStreaming: false,
97107
isComplete: false,
98108
};
@@ -103,6 +113,7 @@ describe("streaming progress bar logic", () => {
103113
const empty: StreamingProgress = {
104114
totalRepos: 0,
105115
loadedRepos: [],
116+
loadedBeatsCount: 0,
106117
isStreaming: true,
107118
isComplete: false,
108119
};

src/components/streaming-progress-bar.tsx

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -54,10 +54,13 @@ export function StreamingProgressBar({
5454
)
5555
: 0;
5656

57-
const label = progress.isComplete
57+
const label = !progress.isStreaming && progress.isComplete
5858
? "All repositories loaded"
59-
: `Loaded ${progress.loadedRepos.length}`
60-
+ `/${progress.totalRepos} repositories`;
59+
: progress.loadedBeatsCount > 0
60+
? `Loading\u2026 ${progress.loadedBeatsCount} beats`
61+
+ ` from ${progress.loadedRepos.length}`
62+
+ `/${progress.totalRepos} repos`
63+
: `Loading ${progress.totalRepos} repositories\u2026`;
6164

6265
return (
6366
<div

0 commit comments

Comments
 (0)