@@ -244,18 +244,16 @@ function groupListKey(
244244 : `${ thread . environmentId } :${ thread . groupedUnderThreadId } ` ;
245245}
246246
247- /** Canonical card section for Move up/down, independent of search or scope.
248- A thread grouped under another one moves with its group, so the section
249- lists only the row that leads each group. */
250- export function getThreadListV2OrderedSection ( input : {
247+ interface ThreadListV2OrderInput {
251248 readonly threads : readonly EnvironmentThreadShell [ ] ;
252- readonly section : "pinned" | "active" ;
253- readonly pendingOrder ?: PendingThreadOrder | null ;
254249 readonly now : string ;
255250 readonly settlementEnvironmentIds ?: ReadonlySet < EnvironmentId > ;
256251 readonly snoozeEnvironmentIds ?: ReadonlySet < EnvironmentId > ;
257252 readonly queuedThreadKeys ?: ReadonlySet < string > ;
258- } ) : EnvironmentThreadShell [ ] {
253+ }
254+
255+ /** Pinned, Active, and parked threads in saved order, grouped into blocks. */
256+ function layoutThreadListV2OrderSections ( input : ThreadListV2OrderInput ) {
259257 const pinned : EnvironmentThreadShell [ ] = [ ] ;
260258 const active : EnvironmentThreadShell [ ] = [ ] ;
261259 const parked : EnvironmentThreadShell [ ] = [ ] ;
@@ -275,15 +273,27 @@ export function getThreadListV2OrderedSection(input: {
275273 active : sortActiveThreadsByOrderKey ( active ) ,
276274 parked,
277275 } ;
278- const leads = new Set (
279- layoutThreadGroups ( {
280- sections,
281- order : [ "pinned" , "active" , "parked" ] ,
282- live : ORDER_LIVE_SECTIONS ,
283- keyOf : threadListKey ,
284- groupKeyOf : groupListKey ,
285- } ) [ input . section ] . map ( ( block ) => block . leadKey ) ,
286- ) ;
276+ const layout = layoutThreadGroups ( {
277+ sections,
278+ order : [ "pinned" , "active" , "parked" ] ,
279+ live : ORDER_LIVE_SECTIONS ,
280+ keyOf : threadListKey ,
281+ groupKeyOf : groupListKey ,
282+ } ) ;
283+ return { sections, layout } ;
284+ }
285+
286+ /** Canonical card section for Move up/down, independent of search or scope.
287+ A thread grouped under another one moves with its group, so the section
288+ lists only the row that leads each group. */
289+ export function getThreadListV2OrderedSection (
290+ input : ThreadListV2OrderInput & {
291+ readonly section : "pinned" | "active" ;
292+ readonly pendingOrder ?: PendingThreadOrder | null ;
293+ } ,
294+ ) : EnvironmentThreadShell [ ] {
295+ const { sections, layout } = layoutThreadListV2OrderSections ( input ) ;
296+ const leads = new Set ( layout [ input . section ] . map ( ( block ) => block . leadKey ) ) ;
287297 const ordered = sections [ input . section ] . filter ( ( thread ) => leads . has ( threadListKey ( thread ) ) ) ;
288298 const pending =
289299 input . pendingOrder ?. section === input . section
@@ -292,6 +302,20 @@ export function getThreadListV2OrderedSection(input: {
292302 return applyPendingThreadOrder ( ordered , input . section , pending ) ;
293303}
294304
305+ /** Every thread in a group that sits in Pinned or Active, including a
306+ snoozed or settled top thread. It moves with its group, so the
307+ arrangement sheet keeps it out of the parked lists. */
308+ export function getThreadListV2LiveGroupThreads (
309+ input : ThreadListV2OrderInput ,
310+ ) : ReadonlySet < EnvironmentThreadShell > {
311+ const { layout } = layoutThreadListV2OrderSections ( input ) ;
312+ return new Set (
313+ [ ...layout . pinned , ...layout . active ] . flatMap ( ( block ) =>
314+ block . rows . length > 1 ? block . rows . map ( ( row ) => row . thread ) : [ ] ,
315+ ) ,
316+ ) ;
317+ }
318+
295319const ORDER_LIVE_SECTIONS : ReadonlySet < "pinned" | "active" | "parked" > = new Set ( [
296320 "pinned" ,
297321 "active" ,
@@ -317,8 +341,10 @@ export interface ThreadListV2Item {
317341
318342const LIST_SECTIONS = [ "pinned" , "active" , "working" , "snoozed" , "settled" ] as const ;
319343type ThreadListSection = ( typeof LIST_SECTIONS ) [ number ] ;
320- // A group whose top thread is snoozed or settled moves to its first thread here.
321- const LIVE_LIST_SECTIONS : ReadonlySet < ThreadListSection > = new Set ( [ "pinned" , "active" , "working" ] ) ;
344+ // A group whose top thread is outside these sections moves to a member in
345+ // them. The Working shelf folds away like the parked shelves, so a group
346+ // there must not hide a member that needs you in Active.
347+ const LIVE_LIST_SECTIONS : ReadonlySet < ThreadListSection > = new Set ( [ "pinned" , "active" ] ) ;
322348type ThreadListBlock = ThreadGroupBlock < EnvironmentThreadShell , ThreadListSection > ;
323349
324350export interface ThreadListV2Layout {
0 commit comments