@@ -38,16 +38,20 @@ export function SessionQueuePanel(props: { queue: SessionQueueView; hidden?: boo
3838 ( next ) => {
3939 const prevLive = lastLive
4040 lastLive = next
41+
4142 if ( next . length === 0 ) return
4243
4344 // An in-place edit or reorder keeps the row count: a row whose ID it replaced swaps in place rather than closing,
4445 // while a row that was already closing keeps closing until its exit completes.
4546 const swap = next . length === prevLive . length && prevLive . length > 0
47+
4648 if ( ! swap && prevLive . length > 0 && ! props . hidden )
4749 next . forEach ( ( row ) => ! prevLive . some ( ( item ) => item . id === row . id ) && appearing . add ( row . id ) )
50+
4851 const kept = untrack ( shown ) . filter (
4952 ( row ) => ! swap || next . some ( ( item ) => item . id === row . id ) || ! prevLive . some ( ( item ) => item . id === row . id ) ,
5053 )
54+
5155 setShown ( keepLeaving ( kept , next ) )
5256 } ,
5357 { defer : true } ,
@@ -63,10 +67,14 @@ export function SessionQueuePanel(props: { queue: SessionQueueView; hidden?: boo
6367 stopCascade ?.( )
6468 stopCascade = undefined
6569 const step = queueStagger ( )
70+
6671 if ( ! now || was !== false || step <= 0 || prefersReducedMotion ( ) ) return
6772 queueMicrotask ( ( ) => {
6873 if ( ! open ( ) ) return
69- stopCascade = cascade ( [ ...listRef . querySelectorAll < HTMLElement > ( '[data-component="session-queue-row"]' ) ] , step )
74+ stopCascade = cascade (
75+ [ ...listRef . querySelectorAll < HTMLElement > ( '[data-component="session-queue-row"]' ) ] ,
76+ step ,
77+ )
7078 } )
7179 } ,
7280 { defer : true } ,
@@ -145,16 +153,16 @@ export function SessionQueuePanel(props: { queue: SessionQueueView; hidden?: boo
145153}
146154
147155function keepLeaving < T extends { id : string } > ( previous : T [ ] , next : T [ ] ) {
148- return previous . reduce (
149- ( rows , row , index ) => {
150- if ( rows . some ( ( item ) => item . id === row . id ) ) return rows
151- const before = previous . slice ( 0 , index ) . findLast ( ( item ) => rows . some ( ( entry ) => entry . id === item . id ) )
152- const at = before ? rows . findIndex ( ( item ) => item . id === before . id ) + 1 : 0
156+ const rows = [ ...next ]
153157
154- return [ ...rows . slice ( 0 , at ) , row , ...rows . slice ( at ) ]
155- } ,
156- [ ...next ] ,
157- )
158+ previous . forEach ( ( row , index ) => {
159+ if ( rows . some ( ( item ) => item . id === row . id ) ) return
160+ const before = previous . slice ( 0 , index ) . findLast ( ( item ) => rows . some ( ( entry ) => entry . id === item . id ) )
161+ const at = before ? rows . findIndex ( ( item ) => item . id === before . id ) + 1 : 0
162+ rows . splice ( at , 0 , row )
163+ } )
164+
165+ return rows
158166}
159167
160168function SessionQueueRow ( props : { queue : SessionQueueView ; id : string ; index : number } ) {
@@ -179,14 +187,16 @@ function SessionQueueRow(props: { queue: SessionQueueView; id: string; index: nu
179187 } ,
180188 } )
181189
190+ // Not keyed: the queue rebuilds every row object whenever it changes, and a keyed row would remount, tooltips and
191+ // all, each time a prompt is added or the server confirms one.
182192 return (
183- < Show when = { row ( ) } keyed >
193+ < Show when = { row ( ) } >
184194 { ( entry ) => (
185195 < div
186196 ref = { sortable . ref }
187197 data-component = { leaving ( ) ? undefined : "session-queue-row" }
188198 data-leaving = { leaving ( ) || undefined }
189- aria-busy = { leaving ( ) ? undefined : entry . pending }
199+ aria-busy = { leaving ( ) ? undefined : entry ( ) . pending }
190200 class = "group/queue-row mb-px flex h-8 shrink-0 items-center justify-between gap-2 rounded-md py-1 ps-0.5 pe-2"
191201 classList = { {
192202 "bg-v2-overlay-simple-overlay-hover" : editing ( ) ,
@@ -209,22 +219,22 @@ function SessionQueueRow(props: { queue: SessionQueueView; id: string; index: nu
209219 type = "button"
210220 data-action = "session-queue-edit"
211221 dir = "auto"
212- aria-disabled = { entry . pending }
222+ aria-disabled = { entry ( ) . pending }
213223 class = "max-w-full min-w-0 self-start truncate rounded-sm text-start text-[13px] font-[440] leading-[var(--line-height-compact)]"
214224 classList = { {
215- "text-v2-text-text-faint" : editing ( ) || entry . pending ,
216- "cursor-progress" : entry . pending ,
225+ "text-v2-text-text-faint" : editing ( ) || entry ( ) . pending ,
226+ "cursor-progress" : entry ( ) . pending ,
217227 "cursor-text text-v2-text-text-base hover:bg-v2-overlay-simple-overlay-hover" :
218- ! editing ( ) && ! entry . pending ,
228+ ! editing ( ) && ! entry ( ) . pending ,
219229 } }
220230 onClick = { ( ) => props . queue . edit ( props . id ) }
221231 >
222- { entry . text ||
223- ( entry . attachments ? language . plural ( "session.queue.attachments" , entry . attachments ) : "" ) }
232+ { entry ( ) . text ||
233+ ( entry ( ) . attachments ? language . plural ( "session.queue.attachments" , entry ( ) . attachments ) : "" ) }
224234 </ button >
225- < Show when = { entry . attachments && entry . text } >
235+ < Show when = { entry ( ) . attachments && entry ( ) . text } >
226236 < span class = "shrink-0 whitespace-nowrap text-[13px] font-[440] leading-[var(--line-height-compact)] text-v2-text-text-muted" >
227- { language . plural ( "session.queue.attachments" , entry . attachments ) }
237+ { language . plural ( "session.queue.attachments" , entry ( ) . attachments ) }
228238 </ span >
229239 </ Show >
230240 </ div >
@@ -234,14 +244,14 @@ function SessionQueueRow(props: { queue: SessionQueueView; id: string; index: nu
234244 class = "flex shrink-0 items-center gap-1.5"
235245 classList = { {
236246 "opacity-0 focus-within:opacity-100 group-hover/queue-row:opacity-100 [@media(hover:none)]:opacity-100" :
237- ! active ( ) && ! editing ( ) && ! entry . pending ,
247+ ! active ( ) && ! editing ( ) && ! entry ( ) . pending ,
238248 "pointer-events-none" : props . queue . busy ( ) || leaving ( ) ,
239249 } }
240250 >
241- < Show when = { entry . pending } >
251+ < Show when = { entry ( ) . pending } >
242252 < Loader class = "size-3.5 text-v2-text-text-faint" />
243253 </ Show >
244- < Show when = { ! editing ( ) && ! entry . pending } >
254+ < Show when = { ! editing ( ) && ! entry ( ) . pending } >
245255 < Tooltip
246256 placement = "top"
247257 inactive = { ! props . queue . working ( ) }
@@ -273,7 +283,7 @@ function SessionQueueRow(props: { queue: SessionQueueView; id: string; index: nu
273283 />
274284 </ Tooltip >
275285 </ Show >
276- < Show when = { ! entry . pending } >
286+ < Show when = { ! entry ( ) . pending } >
277287 < Tooltip placement = "top" value = { language . t ( "session.queue.remove" ) } >
278288 < IconButton
279289 data-action = "session-queue-remove"
0 commit comments