| ... | @@ -61,6 +61,7 @@ import type { HomeListFilterMenuEnvironment } from "./home-list-filter-menu"; | ... | @@ -61,6 +61,7 @@ import type { HomeListFilterMenuEnvironment } from "./home-list-filter-menu"; |
| 61 | import { | 61 | import { |
| 62 | buildHomeListLayout, | 62 | buildHomeListLayout, |
| 63 | DEFAULT_GROUP_DISPLAY_STATE, | 63 | DEFAULT_GROUP_DISPLAY_STATE, |
| | 64 | EMPTY_HOME_LIST_LAYOUT, |
| 64 | homeListItemsAreEqual, | 65 | homeListItemsAreEqual, |
| 65 | nextGroupDisplayState, | 66 | nextGroupDisplayState, |
| 66 | type HomeGroupDisplayAction, | 67 | type HomeGroupDisplayAction, |
| ... | @@ -339,48 +340,57 @@ export function HomeScreen(props: HomeScreenProps) { | ... | @@ -339,48 +340,57 @@ export function HomeScreen(props: HomeScreenProps) { |
| 339 | ); | 340 | ); |
| 340 | const scopedProjects = useMemo( | 341 | const scopedProjects = useMemo( |
| 341 | () => | 342 | () => |
| 342 | selectedProjectRefKeys === null | 343 | threadListV2Enabled |
| 343 | ? props.projects | 344 | ? [] |
| 344 | : props.projects.filter((project) => | 345 | : selectedProjectRefKeys === null |
| 345 | selectedProjectRefKeys.has(scopedProjectKey(project.environmentId, project.id)), | 346 | ? props.projects |
| 346 | ), | 347 | : props.projects.filter((project) => |
| 347 | [props.projects, selectedProjectRefKeys], | 348 | selectedProjectRefKeys.has(scopedProjectKey(project.environmentId, project.id)), |
| | 349 | ), |
| | 350 | [threadListV2Enabled, props.projects, selectedProjectRefKeys], |
| 348 | ); | 351 | ); |
| 349 | const scopedThreads = useMemo( | 352 | const scopedThreads = useMemo( |
| 350 | () => | 353 | () => |
| 351 | selectedProjectRefKeys === null | 354 | threadListV2Enabled |
| 352 | ? props.threads | 355 | ? [] |
| 353 | : props.threads.filter((thread) => | 356 | : selectedProjectRefKeys === null |
| 354 | selectedProjectRefKeys.has(scopedProjectKey(thread.environmentId, thread.projectId)), | 357 | ? props.threads |
| 355 | ), | 358 | : props.threads.filter((thread) => |
| 356 | [props.threads, selectedProjectRefKeys], | 359 | selectedProjectRefKeys.has(scopedProjectKey(thread.environmentId, thread.projectId)), |
| | 360 | ), |
| | 361 | [threadListV2Enabled, props.threads, selectedProjectRefKeys], |
| 357 | ); | 362 | ); |
| 358 | const scopedPendingTasks = useMemo( | 363 | const scopedPendingTasks = useMemo( |
| 359 | () => | 364 | () => |
| 360 | selectedProjectRefKeys === null | 365 | threadListV2Enabled |
| 361 | ? props.pendingTasks | 366 | ? [] |
| 362 | : props.pendingTasks.filter((pendingTask) => | 367 | : selectedProjectRefKeys === null |
| 363 | selectedProjectRefKeys.has( | 368 | ? props.pendingTasks |
| 364 | scopedProjectKey(pendingTask.message.environmentId, pendingTask.creation.projectId), | 369 | : props.pendingTasks.filter((pendingTask) => |
| | 370 | selectedProjectRefKeys.has( |
| | 371 | scopedProjectKey(pendingTask.message.environmentId, pendingTask.creation.projectId), |
| | 372 | ), |
| 365 | ), | 373 | ), |
| 366 | ), | 374 | [threadListV2Enabled, props.pendingTasks, selectedProjectRefKeys], |
| 367 | [props.pendingTasks, selectedProjectRefKeys], | | |
| 368 | ); | 375 | ); |
| 369 | | 376 | |
| 370 | const projectGroups = useMemo( | 377 | const projectGroups = useMemo( |
| 371 | () => | 378 | () => |
| 372 | buildHomeThreadGroups({ | 379 | threadListV2Enabled |
| 373 | projects: scopedProjects, | 380 | ? [] |
| 374 | threads: scopedThreads, | 381 | : buildHomeThreadGroups({ |
| 375 | pendingTasks: scopedPendingTasks, | 382 | projects: scopedProjects, |
| 376 | environmentId: props.selectedEnvironmentId, | 383 | threads: scopedThreads, |
| 377 | searchQuery: props.searchQuery, | 384 | pendingTasks: scopedPendingTasks, |
| 378 | matchedThreadKeys, | 385 | environmentId: props.selectedEnvironmentId, |
| 379 | projectSortOrder: props.projectSortOrder, | 386 | searchQuery: props.searchQuery, |
| 380 | threadSortOrder: props.threadSortOrder, | 387 | matchedThreadKeys, |
| 381 | projectGroupingMode: props.projectGroupingMode, | 388 | projectSortOrder: props.projectSortOrder, |
| 382 | }), | 389 | threadSortOrder: props.threadSortOrder, |
| | 390 | projectGroupingMode: props.projectGroupingMode, |
| | 391 | }), |
| 383 | [ | 392 | [ |
| | 393 | threadListV2Enabled, |
| 384 | props.projectGroupingMode, | 394 | props.projectGroupingMode, |
| 385 | props.projectSortOrder, | 395 | props.projectSortOrder, |
| 386 | props.searchQuery, | 396 | props.searchQuery, |
| ... | @@ -396,12 +406,14 @@ export function HomeScreen(props: HomeScreenProps) { | ... | @@ -396,12 +406,14 @@ export function HomeScreen(props: HomeScreenProps) { |
| 396 | const hasSearchQuery = props.searchQuery.trim().length > 0; | 406 | const hasSearchQuery = props.searchQuery.trim().length > 0; |
| 397 | const listLayout = useMemo( | 407 | const listLayout = useMemo( |
| 398 | () => | 408 | () => |
| 399 | buildHomeListLayout({ | 409 | threadListV2Enabled |
| 400 | groups: projectGroups, | 410 | ? EMPTY_HOME_LIST_LAYOUT |
| 401 | displayStates: effectiveGroupDisplayStates, | 411 | : buildHomeListLayout({ |
| 402 | showAllThreads: hasSearchQuery, | 412 | groups: projectGroups, |
| 403 | }), | 413 | displayStates: effectiveGroupDisplayStates, |
| 404 | [projectGroups, effectiveGroupDisplayStates, hasSearchQuery], | 414 | showAllThreads: hasSearchQuery, |
| | 415 | }), |
| | 416 | [threadListV2Enabled, projectGroups, effectiveGroupDisplayStates, hasSearchQuery], |
| 405 | ); | 417 | ); |
| 406 | | 418 | |
| 407 | const projectCwdByKey = useMemo(() => { | 419 | const projectCwdByKey = useMemo(() => { |
| ... | @@ -1033,7 +1045,7 @@ export function HomeScreen(props: HomeScreenProps) { | ... | @@ -1033,7 +1045,7 @@ export function HomeScreen(props: HomeScreenProps) { |
| 1033 | // so the v1 check already covers v2. | 1045 | // so the v1 check already covers v2. |
| 1034 | const hasAnyThreads = | 1046 | const hasAnyThreads = |
| 1035 | props.threads.some((thread) => thread.archivedAt === null) || props.pendingTasks.length > 0; | 1047 | props.threads.some((thread) => thread.archivedAt === null) || props.pendingTasks.length > 0; |
| 1036 | const hasResults = projectGroups.length > 0; | 1048 | const hasResults = threadListV2Enabled ? threadListV2Items.length > 0 : projectGroups.length > 0; |
| 1037 | const selectedEnvironmentLabel = | 1049 | const selectedEnvironmentLabel = |
| 1038 | props.selectedEnvironmentId === null | 1050 | props.selectedEnvironmentId === null |
| 1039 | ? null | 1051 | ? null |
| ... | @@ -1097,10 +1109,8 @@ export function HomeScreen(props: HomeScreenProps) { | ... | @@ -1097,10 +1109,8 @@ export function HomeScreen(props: HomeScreenProps) { |
| 1097 | <EmptyState title="No threads yet" detail="Create a task to start a new coding session." /> | 1109 | <EmptyState title="No threads yet" detail="Create a task to start a new coding session." /> |
| 1098 | ) | 1110 | ) |
| 1099 | ) : null; | 1111 | ) : null; |
| 1100 | // Self-contained: v1's listEmpty keys off projectGroups, which ignores the | 1112 | // Use the v2 project scope for its empty state. Snoozed threads need no |
| 1101 | // v2 project scope, so it can be null (results elsewhere) while this list | 1113 | // special empty state: their shelf header is a list row even while collapsed. |
| 1102 | // is empty. Snoozed threads need no special empty state: their shelf header | | |
| 1103 | // is a list row even while collapsed. | | |
| 1104 | const v2ListEmpty = | 1114 | const v2ListEmpty = |
| 1105 | hasSearchQuery && threadSearch.isPending ? null : hasSearchQuery ? ( | 1115 | hasSearchQuery && threadSearch.isPending ? null : hasSearchQuery ? ( |
| 1106 | <EmptyState title="No results" detail={`No threads matching "${props.searchQuery}".`} /> | 1116 | <EmptyState title="No results" detail={`No threads matching "${props.searchQuery}".`} /> |