fix(web): fix Mark unread that was immediately reseting on the active thread - #4875

Closed
ojowwalker77 wants to merge 2 commits into
pingdotgg:mainfrom
ojowwalker77:agent/fix-mark-unread-feedback
Closed

fix(web): fix Mark unread that was immediately reseting on the active thread #4875
ojowwalker77 wants to merge 2 commits into
pingdotgg:mainfrom
ojowwalker77:agent/fix-mark-unread-feedback

Conversation

@ojowwalker77

@ojowwalker77ojowwalker77 commented Jul 29, 2026

Copy link
Copy Markdown

What Changed

Stops the active chat view from reacting to manual unread timestamp changes. The visit effect now runs only when the active server thread or its update timestamp changes.

Why

Marking a thread unread changes its last-visited timestamp. The active chat subscribed to that same value, which retriggered the visit effect and immediately marked the thread as read again.

The existing store action already validates and deduplicates visit timestamps, so the extra subscription and guard were unnecessary. Opening the thread again or receiving a newer thread update still marks it as read normally.

Fixes#4873

UI Changes

Before

Screen.Recording.2026-07-29.at.18.26.21.mov

Mark the currently open thread unread.
The local unread timestamp changes.
That change retriggers the active thread’s “visited” effect.
It instantly becomes read again, forcing you to leave the thread first.

After

Screen.Recording.2026-07-29.at.18.26.56.mov

You can mark the active thread unread without leaving it.
It immediately keeps the visible unread/Done state.
Ordinary rerenders do not clear it.
It clears when you leave and reopen the thread, or when genuinely new thread activity arrives.

Validation

  • vp test run apps/web/src/uiStateStore.test.ts apps/web/src/components/ChatView.logic.test.ts
  • vp run --filter @t3tools/web typecheck
  • vp fmt --check apps/web/src/components/ChatView.tsx
  • vp lint apps/web/src/components/ChatView.tsx --report-unused-disable-directives
  • git diff --check origin/main...HEAD
  • Desktop dev build and launch

Checklist

  • This PR is small and focused
  • I explained what changed and why
  • I included before/after evidence for the UI change
  • I included a video for the interaction change

Note

Low Risk
Small UI-state fix in ChatView with existing store deduplication; no auth, data, or API changes.

Overview
Fixes Mark unread on the currently open thread being undone immediately.

ChatView no longer subscribes to threadLastVisitedAtById for the active route. The visit useEffect also drops the guard that skipped markThreadVisited when the stored last-visited time was already at or past serverThread.updatedAt.

The effect now runs only when the active server thread’s id, environment, or updatedAt changes, and always delegates to markThreadVisited (which already ignores backwards or invalid timestamps). Manual unread updates no longer retrigger the effect, so the thread stays unread until you leave/reopen or newer server activity bumps updatedAt.

Reviewed by Cursor Bugbot for commit ef8d149. Bugbot is set up for automated code reviews on this repo. Configure here.

Note

Fix "Mark unread" immediately resetting on the active thread in ChatView

The ChatViewContent component was comparing lastVisitedAt against serverThread.updatedAt before calling markThreadVisited, which caused a mark-unread action to be immediately overwritten when the thread was active. The fix removes this comparison so markThreadVisited is called unconditionally whenever a server thread with an id is present, regardless of any previously recorded timestamp.

Macroscope summarized ef8d149.

@coderabbitai

coderabbitaiBot commented Jul 29, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 9e57e250-1751-4896-bdc8-ed98c52318b2

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@ojowwalker77
ojowwalker77 marked this pull request as ready for review July 29, 2026 21:49
@github-actionsgithub-actionsBot added vouch:unvouched PR author is not yet trusted in the VOUCHED list. size:S 10-29 changed lines (additions + deletions). labels Jul 29, 2026
@macroscopeapp

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Approved bc49293

Straightforward bug fix that removes a conditional check which was causing 'Mark unread' to immediately reset when viewing a thread. The change is small, focused, and has clear intent.

You can customize Macroscope's approvability policy. Learn more.

@ojowwalker77

Copy link
Copy Markdown
Author

hi @juliusmarminge could we take a quick look at this ? its a super tiny change with a significant ux gain for me

@t3-code

t3-codeBot commented Aug 6, 2026

Copy link
Copy Markdown
Contributor

closing as superseded by #5486. that merged change removes the visit effect which immediately reset unread state on the active thread, addressing the bug through explicit thread actions instead. thanks for the fix.

@t3-codet3-codeBot closed this Aug 6, 2026
@ojowwalker77
ojowwalker77 deleted the agent/fix-mark-unread-feedback branch August 12, 2026 12:18
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:S10-29 changed lines (additions + deletions).vouch:unvouchedPR author is not yet trusted in the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: Mark unread immediately resets on the active thread

1 participant

@ojowwalker77
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

fix(web): fix Mark unread that was immediately reseting on the active thread - #4875

Closed
ojowwalker77 wants to merge 2 commits into
pingdotgg:mainfrom
ojowwalker77:agent/fix-mark-unread-feedback
Closed

fix(web): fix Mark unread that was immediately reseting on the active thread #4875
ojowwalker77 wants to merge 2 commits into
pingdotgg:mainfrom
ojowwalker77:agent/fix-mark-unread-feedback

Conversation

@ojowwalker77

@ojowwalker77ojowwalker77 commented Jul 29, 2026

Copy link
Copy Markdown

What Changed

Stops the active chat view from reacting to manual unread timestamp changes. The visit effect now runs only when the active server thread or its update timestamp changes.

Why

Marking a thread unread changes its last-visited timestamp. The active chat subscribed to that same value, which retriggered the visit effect and immediately marked the thread as read again.

The existing store action already validates and deduplicates visit timestamps, so the extra subscription and guard were unnecessary. Opening the thread again or receiving a newer thread update still marks it as read normally.

Fixes#4873

UI Changes

Before

Screen.Recording.2026-07-29.at.18.26.21.mov

Mark the currently open thread unread.
The local unread timestamp changes.
That change retriggers the active thread’s “visited” effect.
It instantly becomes read again, forcing you to leave the thread first.

After

Screen.Recording.2026-07-29.at.18.26.56.mov

You can mark the active thread unread without leaving it.
It immediately keeps the visible unread/Done state.
Ordinary rerenders do not clear it.
It clears when you leave and reopen the thread, or when genuinely new thread activity arrives.

Validation

  • vp test run apps/web/src/uiStateStore.test.ts apps/web/src/components/ChatView.logic.test.ts
  • vp run --filter @t3tools/web typecheck
  • vp fmt --check apps/web/src/components/ChatView.tsx
  • vp lint apps/web/src/components/ChatView.tsx --report-unused-disable-directives
  • git diff --check origin/main...HEAD
  • Desktop dev build and launch

Checklist

  • This PR is small and focused
  • I explained what changed and why
  • I included before/after evidence for the UI change
  • I included a video for the interaction change

Note

Low Risk
Small UI-state fix in ChatView with existing store deduplication; no auth, data, or API changes.

Overview
Fixes Mark unread on the currently open thread being undone immediately.

ChatView no longer subscribes to threadLastVisitedAtById for the active route. The visit useEffect also drops the guard that skipped markThreadVisited when the stored last-visited time was already at or past serverThread.updatedAt.

The effect now runs only when the active server thread’s id, environment, or updatedAt changes, and always delegates to markThreadVisited (which already ignores backwards or invalid timestamps). Manual unread updates no longer retrigger the effect, so the thread stays unread until you leave/reopen or newer server activity bumps updatedAt.

Reviewed by Cursor Bugbot for commit ef8d149. Bugbot is set up for automated code reviews on this repo. Configure here.

Note

Fix "Mark unread" immediately resetting on the active thread in ChatView

The ChatViewContent component was comparing lastVisitedAt against serverThread.updatedAt before calling markThreadVisited, which caused a mark-unread action to be immediately overwritten when the thread was active. The fix removes this comparison so markThreadVisited is called unconditionally whenever a server thread with an id is present, regardless of any previously recorded timestamp.

Macroscope summarized ef8d149.

@coderabbitai

coderabbitaiBot commented Jul 29, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 9e57e250-1751-4896-bdc8-ed98c52318b2

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@ojowwalker77
ojowwalker77 marked this pull request as ready for review July 29, 2026 21:49
@github-actionsgithub-actionsBot added vouch:unvouched PR author is not yet trusted in the VOUCHED list. size:S 10-29 changed lines (additions + deletions). labels Jul 29, 2026
@macroscopeapp

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Approved bc49293

Straightforward bug fix that removes a conditional check which was causing 'Mark unread' to immediately reset when viewing a thread. The change is small, focused, and has clear intent.

You can customize Macroscope's approvability policy. Learn more.

@ojowwalker77

Copy link
Copy Markdown
Author

hi @juliusmarminge could we take a quick look at this ? its a super tiny change with a significant ux gain for me

@t3-code

t3-codeBot commented Aug 6, 2026

Copy link
Copy Markdown
Contributor

closing as superseded by #5486. that merged change removes the visit effect which immediately reset unread state on the active thread, addressing the bug through explicit thread actions instead. thanks for the fix.

@t3-codet3-codeBot closed this Aug 6, 2026
@ojowwalker77
ojowwalker77 deleted the agent/fix-mark-unread-feedback branch August 12, 2026 12:18
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:S10-29 changed lines (additions + deletions).vouch:unvouchedPR author is not yet trusted in the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: Mark unread immediately resets on the active thread

1 participant

@ojowwalker77
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

fix(web): fix Mark unread that was immediately reseting on the active thread - #4875

Closed
ojowwalker77 wants to merge 2 commits into
pingdotgg:mainfrom
ojowwalker77:agent/fix-mark-unread-feedback
Closed

fix(web): fix Mark unread that was immediately reseting on the active thread #4875
ojowwalker77 wants to merge 2 commits into
pingdotgg:mainfrom
ojowwalker77:agent/fix-mark-unread-feedback

Conversation

@ojowwalker77

@ojowwalker77ojowwalker77 commented Jul 29, 2026

Copy link
Copy Markdown

What Changed

Stops the active chat view from reacting to manual unread timestamp changes. The visit effect now runs only when the active server thread or its update timestamp changes.

Why

Marking a thread unread changes its last-visited timestamp. The active chat subscribed to that same value, which retriggered the visit effect and immediately marked the thread as read again.

The existing store action already validates and deduplicates visit timestamps, so the extra subscription and guard were unnecessary. Opening the thread again or receiving a newer thread update still marks it as read normally.

Fixes#4873

UI Changes

Before

Screen.Recording.2026-07-29.at.18.26.21.mov

Mark the currently open thread unread.
The local unread timestamp changes.
That change retriggers the active thread’s “visited” effect.
It instantly becomes read again, forcing you to leave the thread first.

After

Screen.Recording.2026-07-29.at.18.26.56.mov

You can mark the active thread unread without leaving it.
It immediately keeps the visible unread/Done state.
Ordinary rerenders do not clear it.
It clears when you leave and reopen the thread, or when genuinely new thread activity arrives.

Validation

  • vp test run apps/web/src/uiStateStore.test.ts apps/web/src/components/ChatView.logic.test.ts
  • vp run --filter @t3tools/web typecheck
  • vp fmt --check apps/web/src/components/ChatView.tsx
  • vp lint apps/web/src/components/ChatView.tsx --report-unused-disable-directives
  • git diff --check origin/main...HEAD
  • Desktop dev build and launch

Checklist

  • This PR is small and focused
  • I explained what changed and why
  • I included before/after evidence for the UI change
  • I included a video for the interaction change

Note

Low Risk
Small UI-state fix in ChatView with existing store deduplication; no auth, data, or API changes.

Overview
Fixes Mark unread on the currently open thread being undone immediately.

ChatView no longer subscribes to threadLastVisitedAtById for the active route. The visit useEffect also drops the guard that skipped markThreadVisited when the stored last-visited time was already at or past serverThread.updatedAt.

The effect now runs only when the active server thread’s id, environment, or updatedAt changes, and always delegates to markThreadVisited (which already ignores backwards or invalid timestamps). Manual unread updates no longer retrigger the effect, so the thread stays unread until you leave/reopen or newer server activity bumps updatedAt.

Reviewed by Cursor Bugbot for commit ef8d149. Bugbot is set up for automated code reviews on this repo. Configure here.

Note

Fix "Mark unread" immediately resetting on the active thread in ChatView

The ChatViewContent component was comparing lastVisitedAt against serverThread.updatedAt before calling markThreadVisited, which caused a mark-unread action to be immediately overwritten when the thread was active. The fix removes this comparison so markThreadVisited is called unconditionally whenever a server thread with an id is present, regardless of any previously recorded timestamp.

Macroscope summarized ef8d149.

@coderabbitai

coderabbitaiBot commented Jul 29, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 9e57e250-1751-4896-bdc8-ed98c52318b2

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@ojowwalker77
ojowwalker77 marked this pull request as ready for review July 29, 2026 21:49
@github-actionsgithub-actionsBot added vouch:unvouched PR author is not yet trusted in the VOUCHED list. size:S 10-29 changed lines (additions + deletions). labels Jul 29, 2026
@macroscopeapp

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Approved bc49293

Straightforward bug fix that removes a conditional check which was causing 'Mark unread' to immediately reset when viewing a thread. The change is small, focused, and has clear intent.

You can customize Macroscope's approvability policy. Learn more.

@ojowwalker77

Copy link
Copy Markdown
Author

hi @juliusmarminge could we take a quick look at this ? its a super tiny change with a significant ux gain for me

@t3-code

t3-codeBot commented Aug 6, 2026

Copy link
Copy Markdown
Contributor

closing as superseded by #5486. that merged change removes the visit effect which immediately reset unread state on the active thread, addressing the bug through explicit thread actions instead. thanks for the fix.

@t3-codet3-codeBot closed this Aug 6, 2026
@ojowwalker77
ojowwalker77 deleted the agent/fix-mark-unread-feedback branch August 12, 2026 12:18
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:S10-29 changed lines (additions + deletions).vouch:unvouchedPR author is not yet trusted in the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: Mark unread immediately resets on the active thread

1 participant

@ojowwalker77
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

fix(web): fix Mark unread that was immediately reseting on the active thread - #4875

Closed
ojowwalker77 wants to merge 2 commits into
pingdotgg:mainfrom
ojowwalker77:agent/fix-mark-unread-feedback
Closed

fix(web): fix Mark unread that was immediately reseting on the active thread #4875
ojowwalker77 wants to merge 2 commits into
pingdotgg:mainfrom
ojowwalker77:agent/fix-mark-unread-feedback

Conversation

@ojowwalker77

@ojowwalker77ojowwalker77 commented Jul 29, 2026

Copy link
Copy Markdown

What Changed

Stops the active chat view from reacting to manual unread timestamp changes. The visit effect now runs only when the active server thread or its update timestamp changes.

Why

Marking a thread unread changes its last-visited timestamp. The active chat subscribed to that same value, which retriggered the visit effect and immediately marked the thread as read again.

The existing store action already validates and deduplicates visit timestamps, so the extra subscription and guard were unnecessary. Opening the thread again or receiving a newer thread update still marks it as read normally.

Fixes#4873

UI Changes

Before

Screen.Recording.2026-07-29.at.18.26.21.mov

Mark the currently open thread unread.
The local unread timestamp changes.
That change retriggers the active thread’s “visited” effect.
It instantly becomes read again, forcing you to leave the thread first.

After

Screen.Recording.2026-07-29.at.18.26.56.mov

You can mark the active thread unread without leaving it.
It immediately keeps the visible unread/Done state.
Ordinary rerenders do not clear it.
It clears when you leave and reopen the thread, or when genuinely new thread activity arrives.

Validation

  • vp test run apps/web/src/uiStateStore.test.ts apps/web/src/components/ChatView.logic.test.ts
  • vp run --filter @t3tools/web typecheck
  • vp fmt --check apps/web/src/components/ChatView.tsx
  • vp lint apps/web/src/components/ChatView.tsx --report-unused-disable-directives
  • git diff --check origin/main...HEAD
  • Desktop dev build and launch

Checklist

  • This PR is small and focused
  • I explained what changed and why
  • I included before/after evidence for the UI change
  • I included a video for the interaction change

Note

Low Risk
Small UI-state fix in ChatView with existing store deduplication; no auth, data, or API changes.

Overview
Fixes Mark unread on the currently open thread being undone immediately.

ChatView no longer subscribes to threadLastVisitedAtById for the active route. The visit useEffect also drops the guard that skipped markThreadVisited when the stored last-visited time was already at or past serverThread.updatedAt.

The effect now runs only when the active server thread’s id, environment, or updatedAt changes, and always delegates to markThreadVisited (which already ignores backwards or invalid timestamps). Manual unread updates no longer retrigger the effect, so the thread stays unread until you leave/reopen or newer server activity bumps updatedAt.

Reviewed by Cursor Bugbot for commit ef8d149. Bugbot is set up for automated code reviews on this repo. Configure here.

Note

Fix "Mark unread" immediately resetting on the active thread in ChatView

The ChatViewContent component was comparing lastVisitedAt against serverThread.updatedAt before calling markThreadVisited, which caused a mark-unread action to be immediately overwritten when the thread was active. The fix removes this comparison so markThreadVisited is called unconditionally whenever a server thread with an id is present, regardless of any previously recorded timestamp.

Macroscope summarized ef8d149.

@coderabbitai

coderabbitaiBot commented Jul 29, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 9e57e250-1751-4896-bdc8-ed98c52318b2

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@ojowwalker77
ojowwalker77 marked this pull request as ready for review July 29, 2026 21:49
@github-actionsgithub-actionsBot added vouch:unvouched PR author is not yet trusted in the VOUCHED list. size:S 10-29 changed lines (additions + deletions). labels Jul 29, 2026
@macroscopeapp

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Approved bc49293

Straightforward bug fix that removes a conditional check which was causing 'Mark unread' to immediately reset when viewing a thread. The change is small, focused, and has clear intent.

You can customize Macroscope's approvability policy. Learn more.

@ojowwalker77

Copy link
Copy Markdown
Author

hi @juliusmarminge could we take a quick look at this ? its a super tiny change with a significant ux gain for me

@t3-code

t3-codeBot commented Aug 6, 2026

Copy link
Copy Markdown
Contributor

closing as superseded by #5486. that merged change removes the visit effect which immediately reset unread state on the active thread, addressing the bug through explicit thread actions instead. thanks for the fix.

@t3-codet3-codeBot closed this Aug 6, 2026
@ojowwalker77
ojowwalker77 deleted the agent/fix-mark-unread-feedback branch August 12, 2026 12:18
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:S10-29 changed lines (additions + deletions).vouch:unvouchedPR author is not yet trusted in the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: Mark unread immediately resets on the active thread

1 participant

@ojowwalker77
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

fix(web): fix Mark unread that was immediately reseting on the active thread - #4875

Closed
ojowwalker77 wants to merge 2 commits into
pingdotgg:mainfrom
ojowwalker77:agent/fix-mark-unread-feedback
Closed

fix(web): fix Mark unread that was immediately reseting on the active thread #4875
ojowwalker77 wants to merge 2 commits into
pingdotgg:mainfrom
ojowwalker77:agent/fix-mark-unread-feedback

Conversation

@ojowwalker77

@ojowwalker77ojowwalker77 commented Jul 29, 2026

Copy link
Copy Markdown

What Changed

Stops the active chat view from reacting to manual unread timestamp changes. The visit effect now runs only when the active server thread or its update timestamp changes.

Why

Marking a thread unread changes its last-visited timestamp. The active chat subscribed to that same value, which retriggered the visit effect and immediately marked the thread as read again.

The existing store action already validates and deduplicates visit timestamps, so the extra subscription and guard were unnecessary. Opening the thread again or receiving a newer thread update still marks it as read normally.

Fixes#4873

UI Changes

Before

Screen.Recording.2026-07-29.at.18.26.21.mov

Mark the currently open thread unread.
The local unread timestamp changes.
That change retriggers the active thread’s “visited” effect.
It instantly becomes read again, forcing you to leave the thread first.

After

Screen.Recording.2026-07-29.at.18.26.56.mov

You can mark the active thread unread without leaving it.
It immediately keeps the visible unread/Done state.
Ordinary rerenders do not clear it.
It clears when you leave and reopen the thread, or when genuinely new thread activity arrives.

Validation

  • vp test run apps/web/src/uiStateStore.test.ts apps/web/src/components/ChatView.logic.test.ts
  • vp run --filter @t3tools/web typecheck
  • vp fmt --check apps/web/src/components/ChatView.tsx
  • vp lint apps/web/src/components/ChatView.tsx --report-unused-disable-directives
  • git diff --check origin/main...HEAD
  • Desktop dev build and launch

Checklist

  • This PR is small and focused
  • I explained what changed and why
  • I included before/after evidence for the UI change
  • I included a video for the interaction change

Note

Low Risk
Small UI-state fix in ChatView with existing store deduplication; no auth, data, or API changes.

Overview
Fixes Mark unread on the currently open thread being undone immediately.

ChatView no longer subscribes to threadLastVisitedAtById for the active route. The visit useEffect also drops the guard that skipped markThreadVisited when the stored last-visited time was already at or past serverThread.updatedAt.

The effect now runs only when the active server thread’s id, environment, or updatedAt changes, and always delegates to markThreadVisited (which already ignores backwards or invalid timestamps). Manual unread updates no longer retrigger the effect, so the thread stays unread until you leave/reopen or newer server activity bumps updatedAt.

Reviewed by Cursor Bugbot for commit ef8d149. Bugbot is set up for automated code reviews on this repo. Configure here.

Note

Fix "Mark unread" immediately resetting on the active thread in ChatView

The ChatViewContent component was comparing lastVisitedAt against serverThread.updatedAt before calling markThreadVisited, which caused a mark-unread action to be immediately overwritten when the thread was active. The fix removes this comparison so markThreadVisited is called unconditionally whenever a server thread with an id is present, regardless of any previously recorded timestamp.

Macroscope summarized ef8d149.

@coderabbitai

coderabbitaiBot commented Jul 29, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 9e57e250-1751-4896-bdc8-ed98c52318b2

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@ojowwalker77
ojowwalker77 marked this pull request as ready for review July 29, 2026 21:49
@github-actionsgithub-actionsBot added vouch:unvouched PR author is not yet trusted in the VOUCHED list. size:S 10-29 changed lines (additions + deletions). labels Jul 29, 2026
@macroscopeapp

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Approved bc49293

Straightforward bug fix that removes a conditional check which was causing 'Mark unread' to immediately reset when viewing a thread. The change is small, focused, and has clear intent.

You can customize Macroscope's approvability policy. Learn more.

@ojowwalker77

Copy link
Copy Markdown
Author

hi @juliusmarminge could we take a quick look at this ? its a super tiny change with a significant ux gain for me

@t3-code

t3-codeBot commented Aug 6, 2026

Copy link
Copy Markdown
Contributor

closing as superseded by #5486. that merged change removes the visit effect which immediately reset unread state on the active thread, addressing the bug through explicit thread actions instead. thanks for the fix.

@t3-codet3-codeBot closed this Aug 6, 2026
@ojowwalker77
ojowwalker77 deleted the agent/fix-mark-unread-feedback branch August 12, 2026 12:18
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:S10-29 changed lines (additions + deletions).vouch:unvouchedPR author is not yet trusted in the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: Mark unread immediately resets on the active thread

1 participant

@ojowwalker77
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

fix(web): fix Mark unread that was immediately reseting on the active thread - #4875

Closed
ojowwalker77 wants to merge 2 commits into
pingdotgg:mainfrom
ojowwalker77:agent/fix-mark-unread-feedback
Closed

fix(web): fix Mark unread that was immediately reseting on the active thread #4875
ojowwalker77 wants to merge 2 commits into
pingdotgg:mainfrom
ojowwalker77:agent/fix-mark-unread-feedback

Conversation

@ojowwalker77

@ojowwalker77ojowwalker77 commented Jul 29, 2026

Copy link
Copy Markdown

What Changed

Stops the active chat view from reacting to manual unread timestamp changes. The visit effect now runs only when the active server thread or its update timestamp changes.

Why

Marking a thread unread changes its last-visited timestamp. The active chat subscribed to that same value, which retriggered the visit effect and immediately marked the thread as read again.

The existing store action already validates and deduplicates visit timestamps, so the extra subscription and guard were unnecessary. Opening the thread again or receiving a newer thread update still marks it as read normally.

Fixes#4873

UI Changes

Before

Screen.Recording.2026-07-29.at.18.26.21.mov

Mark the currently open thread unread.
The local unread timestamp changes.
That change retriggers the active thread’s “visited” effect.
It instantly becomes read again, forcing you to leave the thread first.

After

Screen.Recording.2026-07-29.at.18.26.56.mov

You can mark the active thread unread without leaving it.
It immediately keeps the visible unread/Done state.
Ordinary rerenders do not clear it.
It clears when you leave and reopen the thread, or when genuinely new thread activity arrives.

Validation

  • vp test run apps/web/src/uiStateStore.test.ts apps/web/src/components/ChatView.logic.test.ts
  • vp run --filter @t3tools/web typecheck
  • vp fmt --check apps/web/src/components/ChatView.tsx
  • vp lint apps/web/src/components/ChatView.tsx --report-unused-disable-directives
  • git diff --check origin/main...HEAD
  • Desktop dev build and launch

Checklist

  • This PR is small and focused
  • I explained what changed and why
  • I included before/after evidence for the UI change
  • I included a video for the interaction change

Note

Low Risk
Small UI-state fix in ChatView with existing store deduplication; no auth, data, or API changes.

Overview
Fixes Mark unread on the currently open thread being undone immediately.

ChatView no longer subscribes to threadLastVisitedAtById for the active route. The visit useEffect also drops the guard that skipped markThreadVisited when the stored last-visited time was already at or past serverThread.updatedAt.

The effect now runs only when the active server thread’s id, environment, or updatedAt changes, and always delegates to markThreadVisited (which already ignores backwards or invalid timestamps). Manual unread updates no longer retrigger the effect, so the thread stays unread until you leave/reopen or newer server activity bumps updatedAt.

Reviewed by Cursor Bugbot for commit ef8d149. Bugbot is set up for automated code reviews on this repo. Configure here.

Note

Fix "Mark unread" immediately resetting on the active thread in ChatView

The ChatViewContent component was comparing lastVisitedAt against serverThread.updatedAt before calling markThreadVisited, which caused a mark-unread action to be immediately overwritten when the thread was active. The fix removes this comparison so markThreadVisited is called unconditionally whenever a server thread with an id is present, regardless of any previously recorded timestamp.

Macroscope summarized ef8d149.

@coderabbitai

coderabbitaiBot commented Jul 29, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 9e57e250-1751-4896-bdc8-ed98c52318b2

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@ojowwalker77
ojowwalker77 marked this pull request as ready for review July 29, 2026 21:49
@github-actionsgithub-actionsBot added vouch:unvouched PR author is not yet trusted in the VOUCHED list. size:S 10-29 changed lines (additions + deletions). labels Jul 29, 2026
@macroscopeapp

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Approved bc49293

Straightforward bug fix that removes a conditional check which was causing 'Mark unread' to immediately reset when viewing a thread. The change is small, focused, and has clear intent.

You can customize Macroscope's approvability policy. Learn more.

@ojowwalker77

Copy link
Copy Markdown
Author

hi @juliusmarminge could we take a quick look at this ? its a super tiny change with a significant ux gain for me

@t3-code

t3-codeBot commented Aug 6, 2026

Copy link
Copy Markdown
Contributor

closing as superseded by #5486. that merged change removes the visit effect which immediately reset unread state on the active thread, addressing the bug through explicit thread actions instead. thanks for the fix.

@t3-codet3-codeBot closed this Aug 6, 2026
@ojowwalker77
ojowwalker77 deleted the agent/fix-mark-unread-feedback branch August 12, 2026 12:18
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:S10-29 changed lines (additions + deletions).vouch:unvouchedPR author is not yet trusted in the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: Mark unread immediately resets on the active thread

1 participant

@ojowwalker77
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

fix(web): fix Mark unread that was immediately reseting on the active thread - #4875

Closed
ojowwalker77 wants to merge 2 commits into
pingdotgg:mainfrom
ojowwalker77:agent/fix-mark-unread-feedback
Closed

fix(web): fix Mark unread that was immediately reseting on the active thread #4875
ojowwalker77 wants to merge 2 commits into
pingdotgg:mainfrom
ojowwalker77:agent/fix-mark-unread-feedback

Conversation

@ojowwalker77

@ojowwalker77ojowwalker77 commented Jul 29, 2026

Copy link
Copy Markdown

What Changed

Stops the active chat view from reacting to manual unread timestamp changes. The visit effect now runs only when the active server thread or its update timestamp changes.

Why

Marking a thread unread changes its last-visited timestamp. The active chat subscribed to that same value, which retriggered the visit effect and immediately marked the thread as read again.

The existing store action already validates and deduplicates visit timestamps, so the extra subscription and guard were unnecessary. Opening the thread again or receiving a newer thread update still marks it as read normally.

Fixes#4873

UI Changes

Before

Screen.Recording.2026-07-29.at.18.26.21.mov

Mark the currently open thread unread.
The local unread timestamp changes.
That change retriggers the active thread’s “visited” effect.
It instantly becomes read again, forcing you to leave the thread first.

After

Screen.Recording.2026-07-29.at.18.26.56.mov

You can mark the active thread unread without leaving it.
It immediately keeps the visible unread/Done state.
Ordinary rerenders do not clear it.
It clears when you leave and reopen the thread, or when genuinely new thread activity arrives.

Validation

  • vp test run apps/web/src/uiStateStore.test.ts apps/web/src/components/ChatView.logic.test.ts
  • vp run --filter @t3tools/web typecheck
  • vp fmt --check apps/web/src/components/ChatView.tsx
  • vp lint apps/web/src/components/ChatView.tsx --report-unused-disable-directives
  • git diff --check origin/main...HEAD
  • Desktop dev build and launch

Checklist

  • This PR is small and focused
  • I explained what changed and why
  • I included before/after evidence for the UI change
  • I included a video for the interaction change

Note

Low Risk
Small UI-state fix in ChatView with existing store deduplication; no auth, data, or API changes.

Overview
Fixes Mark unread on the currently open thread being undone immediately.

ChatView no longer subscribes to threadLastVisitedAtById for the active route. The visit useEffect also drops the guard that skipped markThreadVisited when the stored last-visited time was already at or past serverThread.updatedAt.

The effect now runs only when the active server thread’s id, environment, or updatedAt changes, and always delegates to markThreadVisited (which already ignores backwards or invalid timestamps). Manual unread updates no longer retrigger the effect, so the thread stays unread until you leave/reopen or newer server activity bumps updatedAt.

Reviewed by Cursor Bugbot for commit ef8d149. Bugbot is set up for automated code reviews on this repo. Configure here.

Note

Fix "Mark unread" immediately resetting on the active thread in ChatView

The ChatViewContent component was comparing lastVisitedAt against serverThread.updatedAt before calling markThreadVisited, which caused a mark-unread action to be immediately overwritten when the thread was active. The fix removes this comparison so markThreadVisited is called unconditionally whenever a server thread with an id is present, regardless of any previously recorded timestamp.

Macroscope summarized ef8d149.

@coderabbitai

coderabbitaiBot commented Jul 29, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 9e57e250-1751-4896-bdc8-ed98c52318b2

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@ojowwalker77
ojowwalker77 marked this pull request as ready for review July 29, 2026 21:49
@github-actionsgithub-actionsBot added vouch:unvouched PR author is not yet trusted in the VOUCHED list. size:S 10-29 changed lines (additions + deletions). labels Jul 29, 2026
@macroscopeapp

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Approved bc49293

Straightforward bug fix that removes a conditional check which was causing 'Mark unread' to immediately reset when viewing a thread. The change is small, focused, and has clear intent.

You can customize Macroscope's approvability policy. Learn more.

@ojowwalker77

Copy link
Copy Markdown
Author

hi @juliusmarminge could we take a quick look at this ? its a super tiny change with a significant ux gain for me

@t3-code

t3-codeBot commented Aug 6, 2026

Copy link
Copy Markdown
Contributor

closing as superseded by #5486. that merged change removes the visit effect which immediately reset unread state on the active thread, addressing the bug through explicit thread actions instead. thanks for the fix.

@t3-codet3-codeBot closed this Aug 6, 2026
@ojowwalker77
ojowwalker77 deleted the agent/fix-mark-unread-feedback branch August 12, 2026 12:18
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:S10-29 changed lines (additions + deletions).vouch:unvouchedPR author is not yet trusted in the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: Mark unread immediately resets on the active thread

1 participant

@ojowwalker77
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

fix(web): fix Mark unread that was immediately reseting on the active thread - #4875

Closed
ojowwalker77 wants to merge 2 commits into
pingdotgg:mainfrom
ojowwalker77:agent/fix-mark-unread-feedback
Closed

fix(web): fix Mark unread that was immediately reseting on the active thread #4875
ojowwalker77 wants to merge 2 commits into
pingdotgg:mainfrom
ojowwalker77:agent/fix-mark-unread-feedback

Conversation

@ojowwalker77

@ojowwalker77ojowwalker77 commented Jul 29, 2026

Copy link
Copy Markdown

What Changed

Stops the active chat view from reacting to manual unread timestamp changes. The visit effect now runs only when the active server thread or its update timestamp changes.

Why

Marking a thread unread changes its last-visited timestamp. The active chat subscribed to that same value, which retriggered the visit effect and immediately marked the thread as read again.

The existing store action already validates and deduplicates visit timestamps, so the extra subscription and guard were unnecessary. Opening the thread again or receiving a newer thread update still marks it as read normally.

Fixes#4873

UI Changes

Before

Screen.Recording.2026-07-29.at.18.26.21.mov

Mark the currently open thread unread.
The local unread timestamp changes.
That change retriggers the active thread’s “visited” effect.
It instantly becomes read again, forcing you to leave the thread first.

After

Screen.Recording.2026-07-29.at.18.26.56.mov

You can mark the active thread unread without leaving it.
It immediately keeps the visible unread/Done state.
Ordinary rerenders do not clear it.
It clears when you leave and reopen the thread, or when genuinely new thread activity arrives.

Validation

  • vp test run apps/web/src/uiStateStore.test.ts apps/web/src/components/ChatView.logic.test.ts
  • vp run --filter @t3tools/web typecheck
  • vp fmt --check apps/web/src/components/ChatView.tsx
  • vp lint apps/web/src/components/ChatView.tsx --report-unused-disable-directives
  • git diff --check origin/main...HEAD
  • Desktop dev build and launch

Checklist

  • This PR is small and focused
  • I explained what changed and why
  • I included before/after evidence for the UI change
  • I included a video for the interaction change

Note

Low Risk
Small UI-state fix in ChatView with existing store deduplication; no auth, data, or API changes.

Overview
Fixes Mark unread on the currently open thread being undone immediately.

ChatView no longer subscribes to threadLastVisitedAtById for the active route. The visit useEffect also drops the guard that skipped markThreadVisited when the stored last-visited time was already at or past serverThread.updatedAt.

The effect now runs only when the active server thread’s id, environment, or updatedAt changes, and always delegates to markThreadVisited (which already ignores backwards or invalid timestamps). Manual unread updates no longer retrigger the effect, so the thread stays unread until you leave/reopen or newer server activity bumps updatedAt.

Reviewed by Cursor Bugbot for commit ef8d149. Bugbot is set up for automated code reviews on this repo. Configure here.

Note

Fix "Mark unread" immediately resetting on the active thread in ChatView

The ChatViewContent component was comparing lastVisitedAt against serverThread.updatedAt before calling markThreadVisited, which caused a mark-unread action to be immediately overwritten when the thread was active. The fix removes this comparison so markThreadVisited is called unconditionally whenever a server thread with an id is present, regardless of any previously recorded timestamp.

Macroscope summarized ef8d149.

@coderabbitai

coderabbitaiBot commented Jul 29, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 9e57e250-1751-4896-bdc8-ed98c52318b2

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@ojowwalker77
ojowwalker77 marked this pull request as ready for review July 29, 2026 21:49
@github-actionsgithub-actionsBot added vouch:unvouched PR author is not yet trusted in the VOUCHED list. size:S 10-29 changed lines (additions + deletions). labels Jul 29, 2026
@macroscopeapp

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Approved bc49293

Straightforward bug fix that removes a conditional check which was causing 'Mark unread' to immediately reset when viewing a thread. The change is small, focused, and has clear intent.

You can customize Macroscope's approvability policy. Learn more.

@ojowwalker77

Copy link
Copy Markdown
Author

hi @juliusmarminge could we take a quick look at this ? its a super tiny change with a significant ux gain for me

@t3-code

t3-codeBot commented Aug 6, 2026

Copy link
Copy Markdown
Contributor

closing as superseded by #5486. that merged change removes the visit effect which immediately reset unread state on the active thread, addressing the bug through explicit thread actions instead. thanks for the fix.

@t3-codet3-codeBot closed this Aug 6, 2026
@ojowwalker77
ojowwalker77 deleted the agent/fix-mark-unread-feedback branch August 12, 2026 12:18
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:S10-29 changed lines (additions + deletions).vouch:unvouchedPR author is not yet trusted in the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: Mark unread immediately resets on the active thread

1 participant

@ojowwalker77