From 0b0dae3adefbef87ebd6e890dc730b76255f6782 Mon Sep 17 00:00:00 2001 From: jeheskielSunloy77 Date: Fri, 13 Mar 2026 22:37:27 +0700 Subject: [PATCH] fix(sidebar): use first message time for thread recency Sidebar thread timestamps were based on thread.createdAt, which measures when the thread shell was created rather than when the conversation actually started. In practice that made draft or pre-created threads look older or newer than the underlying conversation, and it caused the visible timestamp to communicate a different concept than users infer from the sidebar. Use the first message createdAt as the sidebar timestamp source, with a fallback to thread.createdAt when a thread has no messages yet. Apply the same derived timestamp to thread ordering and recent-thread focus so the label and sort order stay aligned. This keeps empty threads stable while making active threads reflect real conversation start time instead of internal object creation time. --- apps/web/src/components/Sidebar.tsx | 28 +++++++++++++++++++++++++--- 1 file changed, 25 insertions(+), 3 deletions(-) diff --git a/apps/web/src/components/Sidebar.tsx b/apps/web/src/components/Sidebar.tsx index 1b43eb4c1..8b358d60d 100644 --- a/apps/web/src/components/Sidebar.tsx +++ b/apps/web/src/components/Sidebar.tsx @@ -104,6 +104,25 @@ function formatRelativeTime(iso: string): string { return `${Math.floor(hours / 24)}d ago`; } +function getThreadSidebarTimestamp(thread: Thread): string { + if (thread.messages.length === 0) { + return thread.createdAt; + } + + let earliestTimestamp = thread.messages[0]?.createdAt ?? thread.createdAt; + let earliestTime = new Date(earliestTimestamp).getTime(); + + for (const message of thread.messages) { + const messageTime = new Date(message.createdAt).getTime(); + if (messageTime < earliestTime) { + earliestTimestamp = message.createdAt; + earliestTime = messageTime; + } + } + + return earliestTimestamp; +} + interface TerminalStatusIndicator { label: "Terminal process running"; colorClass: string; @@ -386,7 +405,9 @@ export default function Sidebar() { const latestThread = threads .filter((thread) => thread.projectId === projectId) .toSorted((a, b) => { - const byDate = new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime(); + const byDate = + new Date(getThreadSidebarTimestamp(b)).getTime() - + new Date(getThreadSidebarTimestamp(a)).getTime(); if (byDate !== 0) return byDate; return b.id.localeCompare(a.id); })[0]; @@ -1297,7 +1318,8 @@ export default function Sidebar() { .filter((thread) => thread.projectId === project.id) .toSorted((a, b) => { const byDate = - new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime(); + new Date(getThreadSidebarTimestamp(b)).getTime() - + new Date(getThreadSidebarTimestamp(a)).getTime(); if (byDate !== 0) return byDate; return b.id.localeCompare(a.id); }); @@ -1551,7 +1573,7 @@ export default function Sidebar() { : "text-muted-foreground/40" }`} > - {formatRelativeTime(thread.createdAt)} + {formatRelativeTime(getThreadSidebarTimestamp(thread))}