@@ -6,9 +6,12 @@ import type {MultipartChunk} from '../../store/reducers/multipart/multipart';
66import { useLazyStreamMultipartQuery } from '../../store/reducers/multipart/multipart' ;
77
88const ANIMATION_DURATION = 300 ;
9+ const TOTAL_EXPECTED_CHUNKS = 9999 ;
10+ const GRID_SIZE = 50 ; // Number of squares per row
911
1012export function MultipartTest ( ) {
1113 const [ receivedChunks , setReceivedChunks ] = React . useState < MultipartChunk [ ] > ( [ ] ) ;
14+ const [ receivedCounters , setReceivedCounters ] = React . useState < Set < number > > ( new Set ( ) ) ;
1215
1316 const handleChunk = React . useCallback ( ( chunk : MultipartChunk ) => {
1417 console . log ( 'handleChunk called in component:' , chunk ) ;
@@ -19,8 +22,59 @@ export function MultipartTest() {
1922 // Sort by part_number in descending order to show newest first
2023 return newChunks ;
2124 } ) ;
25+ setReceivedCounters ( ( prev ) => {
26+ const counter = chunk . content ?. Counter || 0 ;
27+ return new Set ( [ ...prev , counter ] ) ;
28+ } ) ;
2229 } , [ ] ) ;
2330
31+ const getMissingCounters = React . useCallback ( ( ) => {
32+ const missing : number [ ] = [ ] ;
33+ for ( let i = 1 ; i <= TOTAL_EXPECTED_CHUNKS ; i ++ ) {
34+ if ( ! receivedCounters . has ( i ) ) {
35+ missing . push ( i ) ;
36+ }
37+ }
38+ return missing ;
39+ } , [ receivedCounters ] ) ;
40+
41+ const renderProgressGrid = React . useCallback ( ( ) => {
42+ const cells = [ ] ;
43+ for ( let i = 1 ; i <= TOTAL_EXPECTED_CHUNKS ; i ++ ) {
44+ const isReceived = receivedCounters . has ( i ) ;
45+ cells . push (
46+ < div
47+ key = { i }
48+ style = { {
49+ width : '8px' ,
50+ height : '8px' ,
51+ backgroundColor : isReceived
52+ ? 'var(--g-color-success)'
53+ : 'var(--g-color-base-generic)' ,
54+ margin : '1px' ,
55+ transition : 'background-color 0.3s ease' ,
56+ } }
57+ title = { `Counter: ${ i } ` }
58+ /> ,
59+ ) ;
60+ }
61+ return (
62+ < div
63+ style = { {
64+ display : 'grid' ,
65+ gridTemplateColumns : `repeat(${ GRID_SIZE } , 8px)` ,
66+ gap : '1px' ,
67+ padding : '16px' ,
68+ backgroundColor : 'var(--g-color-base-generic-hover)' ,
69+ borderRadius : '8px' ,
70+ marginBottom : '24px' ,
71+ } }
72+ >
73+ { cells }
74+ </ div >
75+ ) ;
76+ } , [ receivedCounters ] ) ;
77+
2478 const [ trigger , { error, isLoading} ] = useLazyStreamMultipartQuery ( ) ;
2579 const requestRef = React . useRef < ReturnType < typeof trigger > | null > ( null ) ;
2680
@@ -84,11 +138,40 @@ export function MultipartTest() {
84138 fontSize : '14px' ,
85139 } }
86140 >
87- Received: { receivedChunks . length } chunks
141+ Received: { receivedChunks . length } chunks (
142+ { Math . round ( ( receivedCounters . size / TOTAL_EXPECTED_CHUNKS ) * 100 ) } %)
88143 </ span >
89144 ) }
90145 </ div >
91146
147+ { renderProgressGrid ( ) }
148+
149+ { receivedChunks . length > 0 && (
150+ < div
151+ style = { {
152+ marginBottom : '24px' ,
153+ padding : '12px' ,
154+ backgroundColor : 'var(--g-color-base-generic)' ,
155+ borderRadius : '6px' ,
156+ fontSize : '14px' ,
157+ } }
158+ >
159+ < div style = { { marginBottom : '8px' , fontWeight : 500 } } > Progress Analysis:</ div >
160+ < div > Total Expected: { TOTAL_EXPECTED_CHUNKS } </ div >
161+ < div > Received: { receivedCounters . size } </ div >
162+ < div > Missing: { TOTAL_EXPECTED_CHUNKS - receivedCounters . size } </ div >
163+ { receivedCounters . size < TOTAL_EXPECTED_CHUNKS && (
164+ < div style = { { marginTop : '8px' } } >
165+ < div style = { { marginBottom : '4px' } } > First 10 missing counters:</ div >
166+ < div style = { { color : 'var(--g-color-text-secondary)' } } >
167+ { getMissingCounters ( ) . slice ( 0 , 10 ) . join ( ', ' ) }
168+ { getMissingCounters ( ) . length > 10 ? '...' : '' }
169+ </ div >
170+ </ div >
171+ ) }
172+ </ div >
173+ ) }
174+
92175 { Boolean ( error ) && (
93176 < div
94177 style = { {
0 commit comments