authorgravatar for julius0216@outlook.comJulius Marminge <julius0216@outlook.com> 2026-03-02 11:05:39-08:00
committergravatar for jmarminge@gmail.comJulius Marminge <jmarminge@gmail.com> 2026-03-02 13:13:19-08:00
logafcd824ae9ca93672fda317562e0076ce8918c89
treefc9b116492b5a9625dde277e2c5eceee8550d887
parentf84f2797383fc6e586bb6e5d5b2eb18631152fb1

fix(web): resolve post-rebase selector/store regressions

Remove duplicate selector declarations introduced during rebase and restore the streamlined AppStore shape so Zustand selector usage remains consistent. Restore Sidebar cleanup semantics and pure store test assertions so lint/typecheck stay green after rebasing. Made-with: Cursor

5 files changed, 7 insertions(+), 46 deletions(-)

apps/web/src/components/BranchToolbar.tsx-7
......@@ -48,13 +48,6 @@ export default function BranchToolbar({
4848 const setThreadBranchAction = useStore((store) => store.setThreadBranch);
4949 const setThreadErrorAction = useStore((store) => store.setError);
5050 const draftThread = useComposerDraftStore((store) => store.getDraftThread(threadId));
51 const serverThread = useStore((state) =>
52 state.threads.find((thread) => thread.id === threadId),
53 );
54 const activeProjectId = serverThread?.projectId ?? draftThread?.projectId ?? null;
55 const activeProject = useStore((state) =>
56 activeProjectId ? state.projects.find((project) => project.id === activeProjectId) : undefined,
57 );
5851 const setDraftThreadContext = useComposerDraftStore((store) => store.setDraftThreadContext);
5952 const queryClient = useQueryClient();
6053
apps/web/src/components/ChatView.tsx-10
......@@ -475,15 +475,6 @@ export default function ChatView({ threadId }: ChatViewProps) {
475475 const clearDraftThread = useComposerDraftStore((store) => store.clearDraftThread);
476476 const setDraftThreadContext = useComposerDraftStore((store) => store.setDraftThreadContext);
477477 const draftThread = useComposerDraftStore((store) => store.draftThreadsByThreadId[threadId] ?? null);
478 const serverThread = useStore((state) =>
479 state.threads.find((thread) => thread.id === threadId),
480 );
481 const fallbackDraftProjectId = draftThread?.projectId ?? null;
482 const fallbackDraftProject = useStore((state) =>
483 fallbackDraftProjectId
484 ? state.projects.find((project) => project.id === fallbackDraftProjectId)
485 : undefined,
486 );
487478 const promptRef = useRef(prompt);
488479 const [isDragOverComposer, setIsDragOverComposer] = useState(false);
489480 const [expandedImage, setExpandedImage] = useState<ExpandedImagePreview | null>(null);
......@@ -1714,7 +1705,6 @@ export default function ChatView({ threadId }: ChatViewProps) {
17141705 splitTerminal,
17151706 keybindings,
17161707 onToggleDiff,
1717 setThreadTerminalOpen,
17181708 toggleTerminalVisibility,
17191709 ]);
17201710
apps/web/src/components/Sidebar.tsx+4-3
......@@ -470,10 +470,11 @@ export default function Sidebar() {
470470 await handleNewThread(projectId).catch(() => undefined);
471471 }
472472 }
473 } finally {
474 setIsAddingProject(false);
475 setNewCwd("");
476 setAddingProject(false);
473477 }
474 setIsAddingProject(false);
475 setNewCwd("");
476 setAddingProject(false);
477478 },
478479 [focusMostRecentThreadForProject, handleNewThread, isAddingProject, projects],
479480 );
apps/web/src/store.test.ts+3-3
......@@ -1,5 +1,5 @@
11import { ProjectId, ThreadId, TurnId } from "@t3tools/contracts";
2import { beforeEach, describe, expect, it } from "vitest";
2import { describe, expect, it } from "vitest";
33
44import { markThreadUnread, type AppState } from "./store";
55import type { Thread } from "./types";
......@@ -61,7 +61,7 @@ describe("store pure functions", () => {
6161
6262 const next = markThreadUnread(initialState, ThreadId.makeUnsafe("thread-1"));
6363
64 const updatedThread = useStore.getState().threads[0];
64 const updatedThread = next.threads[0];
6565 expect(updatedThread).toBeDefined();
6666 expect(updatedThread?.lastVisitedAt).toBe("2026-02-25T12:29:59.999Z");
6767 expect(Date.parse(updatedThread?.lastVisitedAt ?? "")).toBeLessThan(
......@@ -79,6 +79,6 @@ describe("store pure functions", () => {
7979
8080 const next = markThreadUnread(initialState, ThreadId.makeUnsafe("thread-1"));
8181
82 expect(useStore.getState().threads[0]?.lastVisitedAt).toBe("2026-02-25T12:35:00.000Z");
82 expect(next).toEqual(initialState);
8383 });
8484});
apps/web/src/store.ts-23
......@@ -25,29 +25,6 @@ export interface AppState {
2525 runtimeMode: RuntimeMode;
2626}
2727
28interface AppStore extends AppState {
29 syncServerReadModel: (readModel: OrchestrationReadModel) => void;
30 markThreadVisited: (threadId: ThreadId, visitedAt?: string) => void;
31 markThreadUnread: (threadId: ThreadId) => void;
32 toggleProject: (projectId: Project["id"]) => void;
33 setThreadTerminalActivity: (
34 threadId: ThreadId,
35 terminalId: string,
36 hasRunningSubprocess: boolean,
37 ) => void;
38 setProjectExpanded: (projectId: Project["id"], expanded: boolean) => void;
39 toggleThreadTerminal: (threadId: ThreadId) => void;
40 setThreadTerminalOpen: (threadId: ThreadId, open: boolean) => void;
41 setThreadTerminalHeight: (threadId: ThreadId, height: number) => void;
42 splitThreadTerminal: (threadId: ThreadId, terminalId: string) => void;
43 newThreadTerminal: (threadId: ThreadId, terminalId: string) => void;
44 setThreadActiveTerminal: (threadId: ThreadId, terminalId: string) => void;
45 closeThreadTerminal: (threadId: ThreadId, terminalId: string) => void;
46 setThreadError: (threadId: ThreadId, error: string | null) => void;
47 setThreadBranch: (threadId: ThreadId, branch: string | null, worktreePath: string | null) => void;
48 setRuntimeMode: (mode: RuntimeMode) => void;
49}
50
5128const PERSISTED_STATE_KEY = "t3code:renderer-state:v7";
5229const LEGACY_PERSISTED_STATE_KEYS = [
5330 "t3code:renderer-state:v6",