Skip to content

Commit 08e5181

Browse files
committed
Fix unpinned items being re-pinned on next server sync
Toggle functions now store false instead of deleting keys, and syncProjects/syncThreads unconditionally store pinned state for all items. This prevents the nullish coalescing fallback from reaching stale persisted sets and re-pinning items that the user explicitly unpinned.
1 parent d32da3c commit 08e5181

File tree

2 files changed

+8
-9
lines changed

2 files changed

+8
-9
lines changed

apps/web/src/uiStateStore.test.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,7 @@ describe("uiStateStore pure functions", () => {
136136
]);
137137

138138
expect(next.projectPinnedById).toEqual({
139+
[oldProject1]: false,
139140
[recreatedProject2]: true,
140141
});
141142
});
@@ -232,7 +233,7 @@ describe("uiStateStore pure functions", () => {
232233

233234
const unpinned = toggleProjectPinned(pinned, project1);
234235

235-
expect(unpinned.projectPinnedById).toEqual({});
236+
expect(unpinned.projectPinnedById).toEqual({ [project1]: false });
236237
});
237238

238239
it("toggleThreadPinned adds and removes pinned state", () => {
@@ -243,7 +244,7 @@ describe("uiStateStore pure functions", () => {
243244

244245
const unpinned = toggleThreadPinned(pinned, thread1);
245246

246-
expect(unpinned.threadPinnedById).toEqual({});
247+
expect(unpinned.threadPinnedById).toEqual({ [thread1]: false });
247248
});
248249

249250
it("clearThreadUi removes visit state for deleted threads", () => {

apps/web/src/uiStateStore.ts

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -211,9 +211,7 @@ export function syncProjects(state: UiState, projects: readonly SyncProjectInput
211211
(previousProjectIdForCwd ? previousPinnedById[previousProjectIdForCwd] : undefined) ??
212212
persistedPinnedProjectCwds.has(project.cwd);
213213
nextExpandedById[project.id] = expanded;
214-
if (pinned) {
215-
nextPinnedById[project.id] = true;
216-
}
214+
nextPinnedById[project.id] = pinned;
217215
return {
218216
id: project.id,
219217
cwd: project.cwd,
@@ -307,8 +305,8 @@ export function syncThreads(state: UiState, threads: readonly SyncThreadInput[])
307305
) {
308306
nextThreadLastVisitedAtById[thread.id] = thread.seedVisitedAt;
309307
}
310-
if (nextThreadPinnedById[thread.id] === undefined && persistedPinnedThreadIds.has(thread.id)) {
311-
nextThreadPinnedById[thread.id] = true;
308+
if (nextThreadPinnedById[thread.id] === undefined) {
309+
nextThreadPinnedById[thread.id] = persistedPinnedThreadIds.has(thread.id);
312310
}
313311
}
314312
if (
@@ -388,7 +386,7 @@ export function clearThreadUi(state: UiState, threadId: ThreadId): UiState {
388386
export function toggleThreadPinned(state: UiState, threadId: ThreadId): UiState {
389387
const nextThreadPinnedById = { ...state.threadPinnedById };
390388
if (nextThreadPinnedById[threadId]) {
391-
delete nextThreadPinnedById[threadId];
389+
nextThreadPinnedById[threadId] = false;
392390
} else {
393391
nextThreadPinnedById[threadId] = true;
394392
}
@@ -457,7 +455,7 @@ export function reorderProjects(
457455
export function toggleProjectPinned(state: UiState, projectId: ProjectId): UiState {
458456
const nextProjectPinnedById = { ...state.projectPinnedById };
459457
if (nextProjectPinnedById[projectId]) {
460-
delete nextProjectPinnedById[projectId];
458+
nextProjectPinnedById[projectId] = false;
461459
} else {
462460
nextProjectPinnedById[projectId] = true;
463461
}

0 commit comments

Comments
 (0)