-
Notifications
You must be signed in to change notification settings - Fork 233
fix: show & sort conversations by latest message time #946
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
fix: show & sort conversations by latest message time #946
Conversation
…MessageAt fallback) so replies display now/1m and match sorting
@notcodesid is attempting to deploy a commit to the Antiwork Team on Vercel. A member of the Team first needs to authorize it. |
WalkthroughUpdates conversation timestamp handling across DB search, serialization, API mapping, and UI so lists use the latest message/activity time. Adds a lateral join to fetch recent message data, exposes latestMessageAt in payloads, updates ordering fallbacks, and adjusts UI labels to "Last activity". Changes
Sequence Diagram(s)sequenceDiagram
participant UI as UI (List/Widget)
participant API as GET /api/chat/conversations
participant Search as searchConversations()
participant DB as Database
UI->>API: Request conversations
API->>Search: Fetch conversations with recent_message lateral join
Search->>DB: Query (COALESCE lastMessageAt, recent_message.created_at, createdAt)
DB-->>Search: Rows including lastMessageAt, recent_message.*
Search-->>API: Conversations with recentMessageAt/Text
API->>API: Compute latestMessageAt = lastMessageAt ?? recentMessageAt ?? createdAt
API-->>UI: Serialized conversations (latestMessageAt)
UI->>UI: Render timestamp from latestMessageAt (fallbacks)
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Assessment against linked issues
Out-of-scope changesNo out-of-scope changes found. Possibly related PRs
Suggested reviewers
Poem
Tip 🔌 Remote MCP (Model Context Protocol) integration is now available!Pro plan users can now connect to remote MCP servers from the Integrations page. Connect with popular remote MCPs such as Notion and Linear to add more context to your reviews and chats. 📜 Recent review detailsConfiguration used: CodeRabbit UI 💡 Knowledge Base configuration:
You can enable these sources in your CodeRabbit configuration. 📒 Files selected for processing (1)
🚧 Files skipped from review as they are similar to previous changes (1)
✨ Finishing Touches
🧪 Generate unit tests
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. 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
SupportNeed help? Create a ticket on our support page for assistance with any issues or questions. CodeRabbit Commands (Invoked using PR/Issue comments)Type Other keywords and placeholders
CodeRabbit Configuration File (
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
🧹 Nitpick comments (5)
lib/data/conversation.ts (1)
237-239
: Align latestMessageAt semantics with the rest of the PR (fallback to createdAt).Elsewhere (search query + widget API), latestMessageAt falls back to createdAt. Serializing only lastMessageAt here can leave latestMessageAt null for legacy rows (pre-backfill) and during transitional states. Consider aligning to avoid nulls and keep UI logic simpler.
- latestMessageAt: conversation.lastMessageAt ?? null, + // Keep consistent with list/search and widget API semantics + latestMessageAt: conversation.lastMessageAt ?? conversation.createdAt,app/(dashboard)/[category]/list/conversationListItem.tsx (2)
17-17
: Remove the any-cast; add a typed recentMessageAt to ListItem.Avoids unsafe casts and improves maintainability. The list query already supplies recentMessageAt; reflect it in the type and use it directly.
-type ListItem = ConversationListItemType & { isNew?: boolean }; +type ListItem = ConversationListItemType & { + isNew?: boolean; + // Provided by the lateral join in the list query (Date on server-rendered lists) + recentMessageAt?: Date | string | null; +};
136-141
: Follow-up to typing fix: use the typed recentMessageAt instead of any.After adding recentMessageAt to ListItem, remove the any-cast.
- // recentMessageAt comes from the lateral join in the list query - (conversation as any).recentMessageAt ?? + // recentMessageAt comes from the lateral join in the list query + conversation.recentMessageAt ??lib/data/conversation/search.ts (2)
151-160
: Ordering by last activity: logic looks right; mind the performance of the lateral join.The COALESCE chain matches the desired behavior. Since this relies on a LATERAL subquery, ensure indexes exist to keep it fast at scale:
- conversation_messages (conversation_id, created_at DESC) covering index to speed up ORDER BY created_at LIMIT 1
- conversations (last_message_at) index already exists (good)
- conversations (created_at) index already exists (good)
If the first index is missing, consider adding:
CREATE INDEX CONCURRENTLY IF NOT EXISTS conversation_messages_conversation_id_created_at_idx ON conversation_messages (conversation_id, created_at DESC);
204-215
: Be robust to driver-returned types when parsing recent_message_createdAt.Depending on the PG driver config, recent_message_createdAt may already be a Date. Guard against double-parsing/locale strings.
- recentMessageAt: recent_message_createdAt ? new Date(recent_message_createdAt) : null, + recentMessageAt: recent_message_createdAt + ? recent_message_createdAt instanceof Date + ? recent_message_createdAt + : new Date(recent_message_createdAt) + : null,
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
💡 Knowledge Base configuration:
- MCP integration is disabled by default for public repositories
- Jira integration is disabled by default for public repositories
- Linear integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
📒 Files selected for processing (5)
app/(dashboard)/[category]/list/conversationListItem.tsx
(1 hunks)app/api/chat/conversations/route.ts
(1 hunks)components/widget/PreviousConversations.tsx
(2 hunks)lib/data/conversation.ts
(1 hunks)lib/data/conversation/search.ts
(1 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
**/*.tsx
📄 CodeRabbit Inference Engine (.cursorrules)
Name component files in lowerCamelCase, e.g. conversationList.tsx
Files:
app/(dashboard)/[category]/list/conversationListItem.tsx
components/widget/PreviousConversations.tsx
🧬 Code Graph Analysis (1)
lib/data/conversation/search.ts (1)
db/schema/conversations.ts (1)
conversations
(12-78)
🔇 Additional comments (6)
app/(dashboard)/[category]/list/conversationListItem.tsx (1)
134-143
: Good fallback chain for “Last activity” and label update.The priority order and copy change match the PR intent. No functional concerns here.
app/api/chat/conversations/route.ts (1)
56-68
: Confirm ConversationsResult includes latestMessageAt.You’re returning latestMessageAt in each conversation. Ensure @helperai/client’s ConversationsResult type has this field; otherwise TypeScript will flag excess properties on the nested conversation literals.
Would you confirm the published client type includes:
- latestMessageAt?: string | null
If not, either update the client package type or introduce a local response type that augments the client one for widget use.
components/widget/PreviousConversations.tsx (2)
13-15
: Type extension looks correct and backward-compatible.Adding latestMessageAt as optional cleanly supports the new server field while preserving compatibility if absent.
131-131
: Good fallback to createdAt when latestMessageAt is missing.This matches the documented behavior for brand-new threads (no replies yet).
lib/data/conversation/search.ts (2)
171-179
: Expose recent_message.created_at/text via lateral join: solid approach.Pulling fields via a lateral join is a good fit here and keeps the main list query cohesive.
182-193
: Confirm role filter for “recent_message” excludes AI messages by design.You’ve limited the recent_message lateral join to ["user", "staff"]. That means:
- Ordering prefers lastMessageAt (any role) first
- Else falls back to last human/staff message time
This could bump threads due to AI assistant messages (via lastMessageAt) even when no human/staff activity occurred. If that’s intended, great. If not, consider aligning both sources to the same role set.
Would you like to exclude AI assistant activity from lastMessageAt updates and/or from ordering consistently?
…add typed recentMessageAt on list item to avoid any
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
🧹 Nitpick comments (2)
app/(dashboard)/[category]/list/conversationListItem.tsx (2)
138-138
: Avoid any-cast; use typed recentMessageAt from the local ListItem typeYou already augmented the local ListItem type with recentMessageAt; there’s no need to cast to any here. This preserves type safety and avoids masking future regressions.
Apply this diff:
- // recentMessageAt comes from the lateral join in the list query - (conversation as any).recentMessageAt ?? + // recentMessageAt comes from the lateral join in the list query + conversation.recentMessageAt ??
17-17
: Widen recentMessageAt type to allow both ISO string and Date; aligns with upstream payloadsData from the API/join often serializes as ISO strings. Make this string | Date | null to match reality and keep the HumanizedTime input flexible.
Apply this diff:
-type ListItem = ConversationListItemType & { isNew?: boolean; recentMessageAt?: Date | null }; +type ListItem = ConversationListItemType & { isNew?: boolean; recentMessageAt?: string | Date | null };
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
💡 Knowledge Base configuration:
- MCP integration is disabled by default for public repositories
- Jira integration is disabled by default for public repositories
- Linear integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
📒 Files selected for processing (1)
app/(dashboard)/[category]/list/conversationListItem.tsx
(2 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
**/*.tsx
📄 CodeRabbit Inference Engine (.cursorrules)
Name component files in lowerCamelCase, e.g. conversationList.tsx
Files:
app/(dashboard)/[category]/list/conversationListItem.tsx
🔇 Additional comments (2)
app/(dashboard)/[category]/list/conversationListItem.tsx (2)
142-142
: Label change to “Last activity on” — LGTMMatches the product copy and the PR’s goal to emphasize recent activity.
134-143
: No action required: HumanizedTime supports string | Date inputsHumanizedTimeProps declares
time: string | Date
, so it safely handles both ISO strings and Date objects. All current usages (ISO strings via.toISOString()
, Date instances from tRPC deserialization) are compatible.
…ast; widen recentMessageAt type to string | Date | null
fix: show & sort conversations by latest message time (closes #899)
Summary
Use the latest message time for both display and ordering in conversation lists.
UI uses
latestMessageAt ?? createdAt
. Closed conversations still sort byclosedAt
.Demo
demo.mov
User impact
How to test
createdAt
.closedAt
.Notes
pnpm db:backfill-last-message-at
.Closes #899
Summary by CodeRabbit