fix(web): keep sidebar unread dots in sync across browser tabs - #978
Conversation
🦋 Changeset detectedLatest commit: 9cbf1ca The changes in this PR will be included in the next version bump. This PR includes changesets to release 1 package
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
commit: |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: f46d15d7c4
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
| window.addEventListener('storage', (event) => { | ||
| if (event.key === STORAGE_KEYS.unread) { | ||
| rawState.unreadBySession = loadUnread(); |
There was a problem hiding this comment.
Keep active sessions from being re-marked unread
When this tab is currently viewing session X, another tab where X is in the background can still receive X's idle event and write { X: true } to kimi-web.unread; this storage listener then blindly adopts that value, so the tab that is already displaying X shows an unread dot and can persist it until the user re-selects the row. Filter/clear rawState.activeSessionId when applying cross-tab unread state so a session that is open in this tab cannot be re-marked unread by another tab's view of it.
Useful? React with 👍 / 👎.
f46d15d to
6fa4e29
Compare
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 6fa4e29abe
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
| if (active) { | ||
| delete latest[active]; | ||
| } |
There was a problem hiding this comment.
Clear persisted unread state for the active session
When tab A is already viewing session X and tab B records X as unread because it is in the background there, this handler only removes X from tab A's in-memory copy. The localStorage value remains { X: true }, so tab B and any future reload still show an unread dot even though X was visible in tab A, leaving the cross-tab state out of sync for the active-session case. Persisting a false change before deleting the active key would propagate the clear to the other tabs.
Useful? React with 👍 / 👎.
6fa4e29 to
e3b98dd
Compare
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: e3b98ddb2b
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
| if (active && latest[active]) { | ||
| saveUnread({ [active]: false }); |
There was a problem hiding this comment.
Avoid clearing unread from hidden tabs
When the same session is selected in a background tab, this storage handler clears the newly persisted unread bit for every tab, even if the tab that has the session selected is not visible. For example, with hidden Tab A on session S and visible Tab B on session T, when S finishes in the background Tab B writes S as unread, then hidden Tab A receives the storage event and immediately saveUnread({ [active]: false }), causing Tab B to remove the sidebar dot before the user sees it. This should only clear globally when the tab is actually visible/viewing the session, or it should leave the unread bit intact for other tabs.
Useful? React with 👍 / 👎.
e3b98dd to
9cbf1ca
Compare
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 9cbf1cab61
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
| active && | ||
| latest[active] && | ||
| typeof document !== 'undefined' && | ||
| document.visibilityState === 'visible' |
There was a problem hiding this comment.
Clear active unread when hidden tab becomes visible
When a tab has session S selected but is hidden, another tab can mark S unread; this branch skips the clear because visibilityState is hidden, then stores S in rawState.unreadBySession. I couldn't find a later visibility-change clear in this composable, so when the tab is shown again the session is already on screen but its sidebar dot and persisted unread flag remain until the user re-selects it, leaving the cross-tab unread state stale for the active session.
Useful? React with 👍 / 👎.
9cbf1ca to
d66ade8
Compare
|
Codex Review: Didn't find any major issues. Delightful! Reviewed commit: ℹ️ About Codex in GitHubCodex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
If Codex has suggestions, it will comment; otherwise it will react with 👍. When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback". |
Related Issue
N/A — follow-up to #977.
Problem
Each browser tab keeps its own in-memory
unreadBySessionmap, and the oldsaveUnreadToStoragewrote the whole map back tolocalStoragein one shot. A clear in one tab could be overwritten by another tab's stale map:{B: true, C: true}in memory.{C: true}(B cleared).{B: true, C: true, D: true}back.There was also no cross-tab sync, so clearing a dot in one tab never updated the others.
What changed
saveUnreadnow takes a partial set of changes and merges them onto the latest stored value, so a tab only touches the sessions it actually changed.storageevent listener adopts another tab's value as soon as it writes the unread key, keeping every tab's in-memory map in sync.lib/storage.tsand added unit tests for the merge behavior.Checklist
gen-changesetsskill, or this PR needs no changeset.gen-docsskill, or this PR needs no doc update.