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({...@@ -48,13 +48,6 @@ export default function BranchToolbar({
48 const setThreadBranchAction = useStore((store) => store.setThreadBranch);48 const setThreadBranchAction = useStore((store) => store.setThreadBranch);
49 const setThreadErrorAction = useStore((store) => store.setError);49 const setThreadErrorAction = useStore((store) => store.setError);
50 const draftThread = useComposerDraftStore((store) => store.getDraftThread(threadId));50 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 );
58 const setDraftThreadContext = useComposerDraftStore((store) => store.setDraftThreadContext);51 const setDraftThreadContext = useComposerDraftStore((store) => store.setDraftThreadContext);
59 const queryClient = useQueryClient();52 const queryClient = useQueryClient();
6053
apps/web/src/components/ChatView.tsx-10
...@@ -475,15 +475,6 @@ export default function ChatView({ threadId }: ChatViewProps) {...@@ -475,15 +475,6 @@ export default function ChatView({ threadId }: ChatViewProps) {
475 const clearDraftThread = useComposerDraftStore((store) => store.clearDraftThread);475 const clearDraftThread = useComposerDraftStore((store) => store.clearDraftThread);
476 const setDraftThreadContext = useComposerDraftStore((store) => store.setDraftThreadContext);476 const setDraftThreadContext = useComposerDraftStore((store) => store.setDraftThreadContext);
477 const draftThread = useComposerDraftStore((store) => store.draftThreadsByThreadId[threadId] ?? null);477 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 );
487 const promptRef = useRef(prompt);478 const promptRef = useRef(prompt);
488 const [isDragOverComposer, setIsDragOverComposer] = useState(false);479 const [isDragOverComposer, setIsDragOverComposer] = useState(false);
489 const [expandedImage, setExpandedImage] = useState<ExpandedImagePreview | null>(null);480 const [expandedImage, setExpandedImage] = useState<ExpandedImagePreview | null>(null);
...@@ -1714,7 +1705,6 @@ export default function ChatView({ threadId }: ChatViewProps) {...@@ -1714,7 +1705,6 @@ export default function ChatView({ threadId }: ChatViewProps) {
1714 splitTerminal,1705 splitTerminal,
1715 keybindings,1706 keybindings,
1716 onToggleDiff,1707 onToggleDiff,
1717 setThreadTerminalOpen,
1718 toggleTerminalVisibility,1708 toggleTerminalVisibility,
1719 ]);1709 ]);
17201710
apps/web/src/components/Sidebar.tsx+4-3
...@@ -470,10 +470,11 @@ export default function Sidebar() {...@@ -470,10 +470,11 @@ export default function Sidebar() {
470 await handleNewThread(projectId).catch(() => undefined);470 await handleNewThread(projectId).catch(() => undefined);
471 }471 }
472 }472 }
473 } finally {
474 setIsAddingProject(false);
475 setNewCwd("");
476 setAddingProject(false);
473 }477 }
474 setIsAddingProject(false);
475 setNewCwd("");
476 setAddingProject(false);
477 },478 },
478 [focusMostRecentThreadForProject, handleNewThread, isAddingProject, projects],479 [focusMostRecentThreadForProject, handleNewThread, isAddingProject, projects],
479 );480 );
apps/web/src/store.test.ts+3-3
...@@ -1,5 +1,5 @@...@@ -1,5 +1,5 @@
1import { ProjectId, ThreadId, TurnId } from "@t3tools/contracts";1import { ProjectId, ThreadId, TurnId } from "@t3tools/contracts";
2import { beforeEach, describe, expect, it } from "vitest";2import { describe, expect, it } from "vitest";
33
4import { markThreadUnread, type AppState } from "./store";4import { markThreadUnread, type AppState } from "./store";
5import type { Thread } from "./types";5import type { Thread } from "./types";
...@@ -61,7 +61,7 @@ describe("store pure functions", () => {...@@ -61,7 +61,7 @@ describe("store pure functions", () => {
6161
62 const next = markThreadUnread(initialState, ThreadId.makeUnsafe("thread-1"));62 const next = markThreadUnread(initialState, ThreadId.makeUnsafe("thread-1"));
6363
64 const updatedThread = useStore.getState().threads[0];64 const updatedThread = next.threads[0];
65 expect(updatedThread).toBeDefined();65 expect(updatedThread).toBeDefined();
66 expect(updatedThread?.lastVisitedAt).toBe("2026-02-25T12:29:59.999Z");66 expect(updatedThread?.lastVisitedAt).toBe("2026-02-25T12:29:59.999Z");
67 expect(Date.parse(updatedThread?.lastVisitedAt ?? "")).toBeLessThan(67 expect(Date.parse(updatedThread?.lastVisitedAt ?? "")).toBeLessThan(
...@@ -79,6 +79,6 @@ describe("store pure functions", () => {...@@ -79,6 +79,6 @@ describe("store pure functions", () => {
7979
80 const next = markThreadUnread(initialState, ThreadId.makeUnsafe("thread-1"));80 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);
83 });83 });
84});84});
apps/web/src/store.ts-23
...@@ -25,29 +25,6 @@ export interface AppState {...@@ -25,29 +25,6 @@ export interface AppState {
25 runtimeMode: RuntimeMode;25 runtimeMode: RuntimeMode;
26}26}
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
51const PERSISTED_STATE_KEY = "t3code:renderer-state:v7";28const PERSISTED_STATE_KEY = "t3code:renderer-state:v7";
52const LEGACY_PERSISTED_STATE_KEYS = [29const LEGACY_PERSISTED_STATE_KEYS = [
53 "t3code:renderer-state:v6",30 "t3code:renderer-state:v6",