6767.empty-state p {font-size : 13px }
6868.hidden {display : none!important }
6969.result-timestamp {font-size : 10px ;color : var (--text2 );opacity : .5 }
70+ .result-metadata {margin-top : 8px ;border-top : 1px solid var (--border );padding-top : 8px }
71+ .result-metadata summary {font-size : 11px ;color : var (--text2 );cursor : pointer;user-select : none}
72+ .result-metadata pre {margin-top : 6px ;font-size : 11px ;color : var (--text2 );background : var (--surface2 );padding : 8px ;border-radius : 6px ;overflow-x : auto;font-family : var (--mono );line-height : 1.5 ;white-space : pre-wrap;word-break : break-word}
7073</ style >
7174</ head >
7275< body >
@@ -145,6 +148,7 @@ <h1>Moss <span>Playground</span></h1>
145148let indexes = [ ] ;
146149let currentIndex = null ;
147150let requestId = 0 ;
151+ let searchAbort = null ;
148152
149153const $ = id => document . getElementById ( id ) ;
150154const select = $ ( 'index-select' ) ;
@@ -244,6 +248,8 @@ <h1>Moss <span>Playground</span></h1>
244248
245249 const loadReqId = ++ requestId ;
246250 if ( searchTimeout ) clearTimeout ( searchTimeout ) ;
251+ if ( searchAbort ) searchAbort . abort ( ) ;
252+ searchAbort = null ;
247253 select . disabled = true ;
248254
249255 loadBtn . disabled = true ;
@@ -337,6 +343,18 @@ <h1>Moss <span>Playground</span></h1>
337343 textDiv . textContent = doc . text ;
338344 item . appendChild ( textDiv ) ;
339345
346+ if ( doc . metadata && typeof doc . metadata === 'object' && Object . keys ( doc . metadata ) . length > 0 ) {
347+ const details = document . createElement ( 'details' ) ;
348+ details . className = 'result-metadata' ;
349+ const summary = document . createElement ( 'summary' ) ;
350+ summary . textContent = 'Metadata' ;
351+ details . appendChild ( summary ) ;
352+ const pre = document . createElement ( 'pre' ) ;
353+ pre . textContent = JSON . stringify ( doc . metadata , null , 2 ) ;
354+ details . appendChild ( pre ) ;
355+ item . appendChild ( details ) ;
356+ }
357+
340358 results . appendChild ( item ) ;
341359 } ) ;
342360}
@@ -355,6 +373,10 @@ <h1>Moss <span>Playground</span></h1>
355373
356374 const query = searchInput . value . trim ( ) ;
357375 if ( ! query ) {
376+ if ( searchTimeout ) clearTimeout ( searchTimeout ) ;
377+ if ( searchAbort ) searchAbort . abort ( ) ;
378+ searchAbort = null ;
379+ ++ requestId ;
358380 results . innerHTML = '' ;
359381 const empty = document . createElement ( 'div' ) ;
360382 empty . className = 'empty-state' ;
@@ -363,13 +385,17 @@ <h1>Moss <span>Playground</span></h1>
363385 return ;
364386 }
365387
366- const parsedTopK = parseInt ( topkInput . value , 10 ) ;
367- const topK = Number . isNaN ( parsedTopK ) ? 5 : parsedTopK ;
388+ const rawTopK = topkInput . value . trim ( ) ;
389+ const parsedTopK = Number ( rawTopK ) ;
390+ const topK = rawTopK === '' || Number . isNaN ( parsedTopK ) ? 5 : parsedTopK ;
368391 const parsedAlpha = parseFloat ( alphaSlider . value ) ;
369392 const alpha = Number . isNaN ( parsedAlpha ) ? 0.5 : parsedAlpha ;
370393
371394 if ( searchTimeout ) clearTimeout ( searchTimeout ) ;
372395 const thisRequestId = ++ requestId ;
396+ if ( searchAbort ) searchAbort . abort ( ) ;
397+ searchAbort = new AbortController ( ) ;
398+ const thisAbort = searchAbort ;
373399 const idx = currentIndex ;
374400 searchTimeout = setTimeout ( async ( ) => {
375401 const placeholder = results . querySelector ( '.empty-state' ) ;
@@ -379,17 +405,18 @@ <h1>Moss <span>Playground</span></h1>
379405 const res = await apiFetch ( '/api/query' , {
380406 method : 'POST' ,
381407 headers : { 'Content-Type' : 'application/json' } ,
382- body : JSON . stringify ( { name : idx , query, topK, alpha } ) ,
408+ signal : thisAbort . signal ,
409+ body : JSON . stringify ( { name : idx , query, topK, alpha, requestId : thisRequestId } ) ,
383410 } ) ;
384411 if ( ! res . ok ) {
385412 const err = await res . json ( ) ;
386413 throw new Error ( err . error || 'Query failed' ) ;
387414 }
388415 const searchResults = await res . json ( ) ;
389- if ( thisRequestId !== requestId ) return ;
416+ if ( thisRequestId !== requestId || thisAbort . signal . aborted ) return ;
390417 renderResults ( searchResults ) ;
391418 } catch ( e ) {
392- if ( thisRequestId !== requestId ) return ;
419+ if ( thisRequestId !== requestId || thisAbort . signal . aborted ) return ;
393420 console . error ( 'Query failed:' , e ) ;
394421 results . innerHTML = `<div class="status-box status-error">Query failed: ${ escapeHtml ( e . message || e ) } </div>` ;
395422 }
@@ -399,6 +426,8 @@ <h1>Moss <span>Playground</span></h1>
399426select . addEventListener ( 'change' , ( ) => {
400427 ++ requestId ;
401428 if ( searchTimeout ) clearTimeout ( searchTimeout ) ;
429+ if ( searchAbort ) searchAbort . abort ( ) ;
430+ searchAbort = null ;
402431 results . innerHTML = '' ;
403432 const empty = document . createElement ( 'div' ) ;
404433 empty . className = 'empty-state' ;
0 commit comments