authorgravatar for julius0216@outlook.comJulius Marminge <julius0216@outlook.com> 2026-09-05 01:20:54-07:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2026-09-05 01:20:54-07:00
log5cb696595cd66bb00e03fa5f91d9cd4273949f5b
tree398379bd86b5da3773b85e1c123e8c4a8ac87a67
parent83a2897ed6c400b3679a37920e964d829094bd43
signature Signed by PGP key B5690EEEBB952194

refactor(web): remove unused sidebar selectors (#10034)


2 files changed, 0 insertions(+), 226 deletions(-)

apps/web/src/components/Sidebar.logic.test.ts-144
......@@ -9,11 +9,9 @@ import {
99 createThreadJumpHintVisibilityController,
1010 filterSidebarProjectScopeItems,
1111 getSidebarThreadIdsToPrewarm,
12 getVisibleSidebarThreadIds,
1312 resolveAdjacentThreadId,
1413 reduceSidebarProjectScopeMenuState,
1514 getFallbackThreadIdAfterDelete,
16 getVisibleThreadsForProject,
1715 getProjectSortTimestamp,
1816 hasUnseenCompletion,
1917 isContextMenuPointerDown,
......@@ -27,7 +25,6 @@ import {
2725 resolveWorkingStartedAt,
2826 searchSidebarThreadsByTitle,
2927 formatWorkingDurationLabel,
30 shouldNavigateAfterProjectRemoval,
3128 shouldClearThreadSelectionOnMouseDown,
3229 shouldRecedeSidebarThread,
3330 sortLogicalProjectsForSidebar,
......@@ -84,56 +81,6 @@ describe("animatePinnedLayoutChanges", () => {
8481 });
8582});
8683
87describe("shouldNavigateAfterProjectRemoval", () => {
88 const projectThreads = [{ environmentId: "environment-local", id: "thread-1" }];
89
90 it("navigates away from a draft route owned by the removed project", () => {
91 expect(
92 shouldNavigateAfterProjectRemoval({
93 routeTarget: { kind: "draft", draftId: "draft-1" as never },
94 projectThreads,
95 projectDraftId: "draft-1",
96 }),
97 ).toBe(true);
98 });
99
100 it("does not navigate away from a different draft route", () => {
101 expect(
102 shouldNavigateAfterProjectRemoval({
103 routeTarget: { kind: "draft", draftId: "draft-2" as never },
104 projectThreads,
105 projectDraftId: "draft-1",
106 }),
107 ).toBe(false);
108 });
109
110 it("navigates away from a server thread owned by the removed project", () => {
111 expect(
112 shouldNavigateAfterProjectRemoval({
113 routeTarget: {
114 kind: "server",
115 threadRef: {
116 environmentId: EnvironmentId.make("environment-local"),
117 threadId: ThreadId.make("thread-1"),
118 },
119 },
120 projectThreads,
121 projectDraftId: null,
122 }),
123 ).toBe(true);
124 });
125
126 it("does not navigate from an unrelated route", () => {
127 expect(
128 shouldNavigateAfterProjectRemoval({
129 routeTarget: null,
130 projectThreads,
131 projectDraftId: null,
132 }),
133 ).toBe(false);
134 });
135});
136
13784describe("archiveSelectedThreadEntries", () => {
13885 const entries = [{ threadKey: "one" }, { threadKey: "two" }, { threadKey: "three" }] as const;
13986 const success = { _tag: "Success" } as const;
......@@ -644,46 +591,6 @@ describe("resolveAdjacentThreadId", () => {
644591 });
645592});
646593
647describe("getVisibleSidebarThreadIds", () => {
648 it("returns only the rendered visible thread order across projects", () => {
649 expect(
650 getVisibleSidebarThreadIds([
651 {
652 renderedThreadIds: [
653 ThreadId.make("thread-12"),
654 ThreadId.make("thread-11"),
655 ThreadId.make("thread-10"),
656 ],
657 },
658 {
659 renderedThreadIds: [ThreadId.make("thread-8"), ThreadId.make("thread-6")],
660 },
661 ]),
662 ).toEqual([
663 ThreadId.make("thread-12"),
664 ThreadId.make("thread-11"),
665 ThreadId.make("thread-10"),
666 ThreadId.make("thread-8"),
667 ThreadId.make("thread-6"),
668 ]);
669 });
670
671 it("skips threads from collapsed projects whose thread panels are not shown", () => {
672 expect(
673 getVisibleSidebarThreadIds([
674 {
675 shouldShowThreadPanel: false,
676 renderedThreadIds: [ThreadId.make("thread-hidden-2"), ThreadId.make("thread-hidden-1")],
677 },
678 {
679 shouldShowThreadPanel: true,
680 renderedThreadIds: [ThreadId.make("thread-12"), ThreadId.make("thread-11")],
681 },
682 ]),
683 ).toEqual([ThreadId.make("thread-12"), ThreadId.make("thread-11")]);
684 });
685});
686
687594describe("isContextMenuPointerDown", () => {
688595 it("treats secondary-button presses as context menu gestures on all platforms", () => {
689596 expect(
......@@ -1362,57 +1269,6 @@ describe("resolveProjectStatusIndicator", () => {
13621269 });
13631270});
13641271
1365describe("getVisibleThreadsForProject", () => {
1366 it("includes the active thread even when it falls below the folded preview", () => {
1367 const threads = Array.from({ length: 8 }, (_, index) =>
1368 makeThread({
1369 id: ThreadId.make(`thread-${index + 1}`),
1370 title: `Thread ${index + 1}`,
1371 }),
1372 );
1373
1374 const result = getVisibleThreadsForProject({
1375 threads,
1376 activeThreadId: ThreadId.make("thread-8"),
1377 isThreadListExpanded: false,
1378 previewLimit: 6,
1379 });
1380
1381 expect(result.hasHiddenThreads).toBe(true);
1382 expect(result.visibleThreads.map((thread) => thread.id)).toEqual([
1383 ThreadId.make("thread-1"),
1384 ThreadId.make("thread-2"),
1385 ThreadId.make("thread-3"),
1386 ThreadId.make("thread-4"),
1387 ThreadId.make("thread-5"),
1388 ThreadId.make("thread-6"),
1389 ThreadId.make("thread-8"),
1390 ]);
1391 expect(result.hiddenThreads.map((thread) => thread.id)).toEqual([ThreadId.make("thread-7")]);
1392 });
1393
1394 it("returns all threads when the list is expanded", () => {
1395 const threads = Array.from({ length: 8 }, (_, index) =>
1396 makeThread({
1397 id: ThreadId.make(`thread-${index + 1}`),
1398 }),
1399 );
1400
1401 const result = getVisibleThreadsForProject({
1402 threads,
1403 activeThreadId: ThreadId.make("thread-8"),
1404 isThreadListExpanded: true,
1405 previewLimit: 6,
1406 });
1407
1408 expect(result.hasHiddenThreads).toBe(true);
1409 expect(result.visibleThreads.map((thread) => thread.id)).toEqual(
1410 threads.map((thread) => thread.id),
1411 );
1412 expect(result.hiddenThreads).toEqual([]);
1413 });
1414});
1415
14161272function makeProject(overrides: Partial<Project> = {}): Project {
14171273 const { defaultModelSelection, ...rest } = overrides;
14181274 return {
apps/web/src/components/Sidebar.logic.ts-82
......@@ -12,7 +12,6 @@ import {
1212 type ThreadSortInput,
1313} from "../lib/threadSort";
1414import type { SidebarThreadSummary, Thread } from "../types";
15import type { ThreadRouteTarget } from "../threadRoutes";
1615import { cn } from "../lib/utils";
1716import { isLatestTurnSettled } from "../session-logic";
1817
......@@ -407,17 +406,6 @@ export function orderItemsByPreferredIds<TItem, TId>(input: {
407406 return [...ordered, ...remaining];
408407}
409408
410export function getVisibleSidebarThreadIds<TThreadId>(
411 renderedProjects: readonly {
412 shouldShowThreadPanel?: boolean;
413 renderedThreadIds: readonly TThreadId[];
414 }[],
415): TThreadId[] {
416 return renderedProjects.flatMap((renderedProject) =>
417 renderedProject.shouldShowThreadPanel === false ? [] : renderedProject.renderedThreadIds,
418 );
419}
420
421409export function getSidebarThreadIdsToPrewarm<TThreadId>(
422410 visibleThreadIds: readonly TThreadId[],
423411 limit = SIDEBAR_THREAD_PREWARM_LIMIT,
......@@ -452,28 +440,6 @@ export function resolveAdjacentThreadId<T>(input: {
452440 return currentIndex < threadIds.length - 1 ? (threadIds[currentIndex + 1] ?? null) : null;
453441}
454442
455export function shouldNavigateAfterProjectRemoval(input: {
456 routeTarget: ThreadRouteTarget | null;
457 projectThreads: readonly {
458 environmentId: string;
459 id: string;
460 }[];
461 projectDraftId: string | null;
462}): boolean {
463 const { projectDraftId, projectThreads, routeTarget } = input;
464 if (routeTarget?.kind === "draft") {
465 return projectDraftId === routeTarget.draftId;
466 }
467 if (routeTarget?.kind !== "server") {
468 return false;
469 }
470 return projectThreads.some(
471 (thread) =>
472 thread.environmentId === routeTarget.threadRef.environmentId &&
473 thread.id === routeTarget.threadRef.threadId,
474 );
475}
476
477443export function isContextMenuPointerDown(input: {
478444 button: number;
479445 ctrlKey: boolean;
......@@ -838,54 +804,6 @@ export function resolveProjectStatusIndicator(
838804 return highestPriorityStatus;
839805}
840806
841export function getVisibleThreadsForProject<T extends Pick<Thread, "id">>(input: {
842 threads: readonly T[];
843 activeThreadId: T["id"] | undefined;
844 isThreadListExpanded: boolean;
845 previewLimit: number;
846}): {
847 hasHiddenThreads: boolean;
848 visibleThreads: T[];
849 hiddenThreads: T[];
850} {
851 const { activeThreadId, isThreadListExpanded, previewLimit, threads } = input;
852 const hasHiddenThreads = threads.length > previewLimit;
853
854 if (!hasHiddenThreads || isThreadListExpanded) {
855 return {
856 hasHiddenThreads,
857 hiddenThreads: [],
858 visibleThreads: [...threads],
859 };
860 }
861
862 const previewThreads = threads.slice(0, previewLimit);
863 if (!activeThreadId || previewThreads.some((thread) => thread.id === activeThreadId)) {
864 return {
865 hasHiddenThreads: true,
866 hiddenThreads: threads.slice(previewLimit),
867 visibleThreads: previewThreads,
868 };
869 }
870
871 const activeThread = threads.find((thread) => thread.id === activeThreadId);
872 if (!activeThread) {
873 return {
874 hasHiddenThreads: true,
875 hiddenThreads: threads.slice(previewLimit),
876 visibleThreads: previewThreads,
877 };
878 }
879
880 const visibleThreadIds = new Set([...previewThreads, activeThread].map((thread) => thread.id));
881
882 return {
883 hasHiddenThreads: true,
884 hiddenThreads: threads.filter((thread) => !visibleThreadIds.has(thread.id)),
885 visibleThreads: threads.filter((thread) => visibleThreadIds.has(thread.id)),
886 };
887}
888
889807export function getFallbackThreadIdAfterDelete<
890808 T extends Pick<Thread, "id" | "projectId" | "createdAt" | "updatedAt"> & ThreadSortInput,
891809>(input: {