Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions apps/web/src/browserHistoryStore.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,19 @@ describe("useBrowserHistoryStore", () => {
).toBe("New");
});

it("keeps another thread's newer title when this thread's unchanged tab is re-sent", () => {
const otherThreadRef = { ...threadRef, threadId: ThreadId.make("thread-2") };
const store = useBrowserHistoryStore.getState();
store.registerThreadProject(threadRef, "proj-a");
store.registerThreadProject(otherThreadRef, "proj-a");
recordVisitForThread(threadRef, "http://a.test/", 1);
settle("http://a.test/", "Old", "tab_a", threadRef);
settle("http://a.test/", "New", "tab_a", otherThreadRef);
// A resize or a list reconcile replaces the session without a new page load.
settle("http://a.test/", "Old", "tab_a", threadRef);
expect(useBrowserHistoryStore.getState().byProjectKey["proj-a"]?.[0]?.title).toBe("New");
});

it("keeps another thread's newer title when this thread revisits the same url", () => {
const otherThreadRef = { ...threadRef, threadId: ThreadId.make("thread-2") };
const store = useBrowserHistoryStore.getState();
Expand Down
15 changes: 10 additions & 5 deletions apps/web/src/browserHistoryStore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -336,10 +336,9 @@ export function recordVisitForThread(ref: ScopedThreadRef, url: string, at?: num
}

/**
* Titles only update entries already in history, so they apply on settle and on
* visit. History is shared across a project's threads and settled sessions stay
* retained, so a visit only fills untitled entries: replaying this thread's
* older settle would clobber a newer title. Settles apply what just changed.
* History is shared across a project's threads and settled sessions are retained,
* so replaying an old settle would clobber another thread's newer title. Visits
* only fill untitled entries; settles apply only pages that loaded or retitled.
*/
function recordPreviewTitles(
ref: ScopedThreadRef,
Expand Down Expand Up @@ -368,9 +367,15 @@ function recordPreviewTitles(
"urls" in only
? new Set(only.urls.map(titleKey).filter((key) => key !== null && !titled.has(key)))
: null;
// Resizes and list reconciles replace a session without loading a new page.
const settledAgain = (session: PreviewSessionSnapshot, previous?: PreviewSessionSnapshot) =>
previous?.navStatus._tag === "Success" &&
session.navStatus._tag === "Success" &&
previous.navStatus.url === session.navStatus.url &&
previous.navStatus.title === session.navStatus.title;
const include = (session: PreviewSessionSnapshot, url: string) =>
"changedSince" in only
? only.changedSince[session.tabId] !== session
? !settledAgain(session, only.changedSince[session.tabId])
: (visitKeys?.has(titleKey(url)) ?? false);
// Tabs can share a URL; applying oldest first lets the newest settle win.
const sessions = Object.values(preview.sessions).toSorted((a, b) =>
Expand Down
Loading