authorgravatar for me@t3.ggTheo Browne <me@t3.gg> 2026-09-04 07:03:49-07:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2026-09-04 07:03:49-07:00
log7cf5b284e6e37895f535433c77f728b3e4292c9b
tree2c897d7fb3972422edd86bd1c1ea121072ee2e9a
parent887ece307131bdc853cc10f3b82067dee77c4ecf
signature Signed by PGP key B5690EEEBB952194

perf(mobile): skip unused legacy list work (#9679)


3 files changed, 101 insertions(+), 77 deletions(-)

apps/mobile/src/features/home/HomeScreen.tsx+51-41
......@@ -61,6 +61,7 @@ import type { HomeListFilterMenuEnvironment } from "./home-list-filter-menu";
6161import {
6262 buildHomeListLayout,
6363 DEFAULT_GROUP_DISPLAY_STATE,
64 EMPTY_HOME_LIST_LAYOUT,
6465 homeListItemsAreEqual,
6566 nextGroupDisplayState,
6667 type HomeGroupDisplayAction,
......@@ -339,48 +340,57 @@ export function HomeScreen(props: HomeScreenProps) {
339340 );
340341 const scopedProjects = useMemo(
341342 () =>
342 selectedProjectRefKeys === null
343 ? props.projects
344 : props.projects.filter((project) =>
345 selectedProjectRefKeys.has(scopedProjectKey(project.environmentId, project.id)),
346 ),
347 [props.projects, selectedProjectRefKeys],
343 threadListV2Enabled
344 ? []
345 : selectedProjectRefKeys === null
346 ? props.projects
347 : props.projects.filter((project) =>
348 selectedProjectRefKeys.has(scopedProjectKey(project.environmentId, project.id)),
349 ),
350 [threadListV2Enabled, props.projects, selectedProjectRefKeys],
348351 );
349352 const scopedThreads = useMemo(
350353 () =>
351 selectedProjectRefKeys === null
352 ? props.threads
353 : props.threads.filter((thread) =>
354 selectedProjectRefKeys.has(scopedProjectKey(thread.environmentId, thread.projectId)),
355 ),
356 [props.threads, selectedProjectRefKeys],
354 threadListV2Enabled
355 ? []
356 : selectedProjectRefKeys === null
357 ? props.threads
358 : props.threads.filter((thread) =>
359 selectedProjectRefKeys.has(scopedProjectKey(thread.environmentId, thread.projectId)),
360 ),
361 [threadListV2Enabled, props.threads, selectedProjectRefKeys],
357362 );
358363 const scopedPendingTasks = useMemo(
359364 () =>
360 selectedProjectRefKeys === null
361 ? props.pendingTasks
362 : props.pendingTasks.filter((pendingTask) =>
363 selectedProjectRefKeys.has(
364 scopedProjectKey(pendingTask.message.environmentId, pendingTask.creation.projectId),
365 threadListV2Enabled
366 ? []
367 : selectedProjectRefKeys === null
368 ? props.pendingTasks
369 : props.pendingTasks.filter((pendingTask) =>
370 selectedProjectRefKeys.has(
371 scopedProjectKey(pendingTask.message.environmentId, pendingTask.creation.projectId),
372 ),
365373 ),
366 ),
367 [props.pendingTasks, selectedProjectRefKeys],
374 [threadListV2Enabled, props.pendingTasks, selectedProjectRefKeys],
368375 );
369376
370377 const projectGroups = useMemo(
371378 () =>
372 buildHomeThreadGroups({
373 projects: scopedProjects,
374 threads: scopedThreads,
375 pendingTasks: scopedPendingTasks,
376 environmentId: props.selectedEnvironmentId,
377 searchQuery: props.searchQuery,
378 matchedThreadKeys,
379 projectSortOrder: props.projectSortOrder,
380 threadSortOrder: props.threadSortOrder,
381 projectGroupingMode: props.projectGroupingMode,
382 }),
379 threadListV2Enabled
380 ? []
381 : buildHomeThreadGroups({
382 projects: scopedProjects,
383 threads: scopedThreads,
384 pendingTasks: scopedPendingTasks,
385 environmentId: props.selectedEnvironmentId,
386 searchQuery: props.searchQuery,
387 matchedThreadKeys,
388 projectSortOrder: props.projectSortOrder,
389 threadSortOrder: props.threadSortOrder,
390 projectGroupingMode: props.projectGroupingMode,
391 }),
383392 [
393 threadListV2Enabled,
384394 props.projectGroupingMode,
385395 props.projectSortOrder,
386396 props.searchQuery,
......@@ -396,12 +406,14 @@ export function HomeScreen(props: HomeScreenProps) {
396406 const hasSearchQuery = props.searchQuery.trim().length > 0;
397407 const listLayout = useMemo(
398408 () =>
399 buildHomeListLayout({
400 groups: projectGroups,
401 displayStates: effectiveGroupDisplayStates,
402 showAllThreads: hasSearchQuery,
403 }),
404 [projectGroups, effectiveGroupDisplayStates, hasSearchQuery],
409 threadListV2Enabled
410 ? EMPTY_HOME_LIST_LAYOUT
411 : buildHomeListLayout({
412 groups: projectGroups,
413 displayStates: effectiveGroupDisplayStates,
414 showAllThreads: hasSearchQuery,
415 }),
416 [threadListV2Enabled, projectGroups, effectiveGroupDisplayStates, hasSearchQuery],
405417 );
406418
407419 const projectCwdByKey = useMemo(() => {
......@@ -1033,7 +1045,7 @@ export function HomeScreen(props: HomeScreenProps) {
10331045 // so the v1 check already covers v2.
10341046 const hasAnyThreads =
10351047 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;
10371049 const selectedEnvironmentLabel =
10381050 props.selectedEnvironmentId === null
10391051 ? null
......@@ -1097,10 +1109,8 @@ export function HomeScreen(props: HomeScreenProps) {
10971109 <EmptyState title="No threads yet" detail="Create a task to start a new coding session." />
10981110 )
10991111 ) : null;
1100 // Self-contained: v1's listEmpty keys off projectGroups, which ignores the
1101 // v2 project scope, so it can be null (results elsewhere) while this list
1102 // is empty. Snoozed threads need no special empty state: their shelf header
1103 // is a list row even while collapsed.
1112 // Use the v2 project scope for its empty state. Snoozed threads need no
1113 // special empty state: their shelf header is a list row even while collapsed.
11041114 const v2ListEmpty =
11051115 hasSearchQuery && threadSearch.isPending ? null : hasSearchQuery ? (
11061116 <EmptyState title="No results" detail={`No threads matching "${props.searchQuery}".`} />
apps/mobile/src/features/home/homeListItems.ts+2
......@@ -62,6 +62,8 @@ export interface HomeListLayout {
6262 readonly stickyHeaderIndices: ReadonlyArray<number>;
6363}
6464
65export const EMPTY_HOME_LIST_LAYOUT: HomeListLayout = { items: [], stickyHeaderIndices: [] };
66
6567export type HomeGroupDisplayAction = "toggle-collapsed" | "show-more" | "show-less";
6668
6769export function nextGroupDisplayState(
apps/mobile/src/features/threads/ThreadNavigationSidebar.tsx+48-36
......@@ -45,6 +45,7 @@ import { buildHomeListFilterMenu } from "../home/home-list-filter-menu";
4545import {
4646 buildHomeListLayout,
4747 DEFAULT_GROUP_DISPLAY_STATE,
48 EMPTY_HOME_LIST_LAYOUT,
4849 homeListItemsAreEqual,
4950 nextGroupDisplayState,
5051 type HomeGroupDisplayAction,
......@@ -269,47 +270,56 @@ function ThreadNavigationSidebarPane(
269270 );
270271 const scopedProjects = useMemo(
271272 () =>
272 selectedProjectRefs === null
273 ? projects
274 : projects.filter((project) =>
275 selectedProjectRefs.has(scopedProjectKey(project.environmentId, project.id)),
276 ),
277 [projects, selectedProjectRefs],
273 threadListV2Enabled
274 ? []
275 : selectedProjectRefs === null
276 ? projects
277 : projects.filter((project) =>
278 selectedProjectRefs.has(scopedProjectKey(project.environmentId, project.id)),
279 ),
280 [threadListV2Enabled, projects, selectedProjectRefs],
278281 );
279282 const scopedThreads = useMemo(
280283 () =>
281 selectedProjectRefs === null
282 ? threads
283 : threads.filter((thread) =>
284 selectedProjectRefs.has(scopedProjectKey(thread.environmentId, thread.projectId)),
285 ),
286 [selectedProjectRefs, threads],
284 threadListV2Enabled
285 ? []
286 : selectedProjectRefs === null
287 ? threads
288 : threads.filter((thread) =>
289 selectedProjectRefs.has(scopedProjectKey(thread.environmentId, thread.projectId)),
290 ),
291 [threadListV2Enabled, selectedProjectRefs, threads],
287292 );
288293 const scopedPendingTasks = useMemo(
289294 () =>
290 selectedProjectRefs === null
291 ? pendingTasks
292 : pendingTasks.filter((pendingTask) =>
293 selectedProjectRefs.has(
294 scopedProjectKey(pendingTask.message.environmentId, pendingTask.creation.projectId),
295 threadListV2Enabled
296 ? []
297 : selectedProjectRefs === null
298 ? pendingTasks
299 : pendingTasks.filter((pendingTask) =>
300 selectedProjectRefs.has(
301 scopedProjectKey(pendingTask.message.environmentId, pendingTask.creation.projectId),
302 ),
295303 ),
296 ),
297 [pendingTasks, selectedProjectRefs],
304 [threadListV2Enabled, pendingTasks, selectedProjectRefs],
298305 );
299306 const groups = useMemo(
300307 () =>
301 buildHomeThreadGroups({
302 projects: scopedProjects,
303 threads: scopedThreads,
304 pendingTasks: scopedPendingTasks,
305 environmentId: options.selectedEnvironmentId,
306 searchQuery: props.searchQuery,
307 matchedThreadKeys,
308 projectSortOrder: options.projectSortOrder,
309 threadSortOrder: options.threadSortOrder,
310 projectGroupingMode: options.projectGroupingMode,
311 }),
308 threadListV2Enabled
309 ? []
310 : buildHomeThreadGroups({
311 projects: scopedProjects,
312 threads: scopedThreads,
313 pendingTasks: scopedPendingTasks,
314 environmentId: options.selectedEnvironmentId,
315 searchQuery: props.searchQuery,
316 matchedThreadKeys,
317 projectSortOrder: options.projectSortOrder,
318 threadSortOrder: options.threadSortOrder,
319 projectGroupingMode: options.projectGroupingMode,
320 }),
312321 [
322 threadListV2Enabled,
313323 matchedThreadKeys,
314324 options,
315325 props.searchQuery,
......@@ -334,12 +344,14 @@ function ThreadNavigationSidebarPane(
334344 const hasSearchQuery = props.searchQuery.trim().length > 0;
335345 const listLayout = useMemo(
336346 () =>
337 buildHomeListLayout({
338 groups,
339 displayStates: groupDisplayStates,
340 showAllThreads: hasSearchQuery,
341 }),
342 [groups, groupDisplayStates, hasSearchQuery],
347 threadListV2Enabled
348 ? EMPTY_HOME_LIST_LAYOUT
349 : buildHomeListLayout({
350 groups,
351 displayStates: groupDisplayStates,
352 showAllThreads: hasSearchQuery,
353 }),
354 [threadListV2Enabled, groups, groupDisplayStates, hasSearchQuery],
343355 );
344356 const projectCwdByKey = useMemo(() => {
345357 const map = new Map<string, string>();