Skip to content

Conversation

@Aayushgoyal00
Copy link

@Aayushgoyal00 Aayushgoyal00 commented Nov 12, 2025

Description

This PR adds conversation deletion functionality to allow users to remove unwanted or old chats from their chat history sidebar. The implementation includes a delete button for each conversation, a confirmation modal to prevent accidental deletions, and proper loading states during the deletion process.

Fixes #75

Key Changes:

  • Delete Button: Added a trash icon button beside each conversation item in the sidebar that triggers the deletion flow
  • Confirmation Modal: Implemented a modal that prompts users with "Are you sure you want to delete this conversation? This action cannot be undone." to prevent accidental deletions
  • Database Integration: Added deleteConversation function in useChatHistoryData hook that permanently removes conversations and associated messages from the database
  • Loading States: Added loading state management to prevent multiple deletion attempts and provide user feedback during the deletion process
  • Error Handling: Implemented proper error handling with user-friendly error messages
  • Real-time UI Updates: The sidebar immediately reflects changes after successful deletion

Implementation Details:

  • Modified apps/client/app/(main)/chat-history.tsx to add UI components and deletion logic
  • Extended apps/client/hooks/useChatHistoryData.ts with database deletion functionality
  • Used Ionicons trash-outline icon for the delete button
  • Styled modal and buttons for consistent UI experience

Type of Change

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • Documentation update
  • Release (version bump)

Release

Is this a release? No

Testing

  • Tested deletion of multiple conversations to ensure they are permanently removed from the database
  • Verified the confirmation modal appears before deletion and properly cancels when dismissed
  • Tested loading states to ensure users cannot trigger multiple deletions simultaneously
  • Confirmed UI updates immediately after successful deletion without page refresh
  • Tested error handling for failed deletion attempts
  • Verified that deleted conversations do not reappear after app refresh/reload

Checklist

  • My code follows the project's style guidelines
  • I have performed a self-review of my own code
  • I have commented my code, particularly in hard-to-understand areas
  • My changes generate no new warnings or errors
  • I have added tests that prove my fix is effective or that my feature works
  • New and existing tests pass locally with my changes
  • If releasing, I have verified the version number is correct and follows semantic versioning

- Implemented deleteConversation function to remove conversations and their messages from the database.
- Added UI elements for deleting conversations, including a confirmation modal.
- Enhanced chat history screen to handle conversation deletion and update state accordingly.
- Updated styles for new modal and delete button interactions.
- Changed the delete button style to use a new class for modal interactions.
- Removed the color specification from the trash icon for a cleaner look.
- Adjusted padding and margin for the delete button to improve layout consistency.
- Added loading state management for conversation deletion to prevent multiple submissions.
- Updated UI to reflect the loading state on delete button and cancel action.
- Improved error handling and user feedback during the deletion process.
@vercel
Copy link

vercel bot commented Nov 12, 2025

@Aayushgoyal00 is attempting to deploy a commit to the dark Team on Vercel.

A member of the Team first needs to authorize it.

@edgarpavlovsky
Copy link
Member

this is awesome! great and easy feature add that definitely belongs in mallory

one of the things i'm thinking about here - that i don't think we have a solution for yet, so we're kind of guinea pigging in this PR, is the right way to solve for the design piece of open source contributions. we're pretty design oriented and i'd love for mallory to continue to be cohesive on that front.

here's what i'm thinking on this PR specifically:

  1. Delete Button: let's find a clean, minimal way to show the trash functionality. i'm thinking:
    a. show the trash can on hover over a given conversation near the date:

    [New conversation ...................... 🗑️] Saturday
    

    b. now or in the future, we can convert the 🗑️ to the three vertical dots typically used to signify "more" - although i'm not sure what more we'd need

  2. Confirmation Modal: i'm a bit wary of modals - i've found them to be less stable in RN - but open to keeping it this way if it feels good.

  3. Database Integration: in a production application that isn't just an open source case study, i'd avoid true deletion in the database and mark the conversation as hidden or something similar. there's other things we want messages for too - Mallory's memory functionality fetching content, for example. can we apply something similar here? happy to do with an is_visible flag in the conversations table that is true by default - maybe the most straightforward thing here

need to take a closer look at:

  • loading states
  • error handling
  • real-time ui updates

but thought i'd drop these initial comments for now

@edgarpavlovsky
Copy link
Member

realized we're talking about another chat-history feature in #90 and was thinking: the three buttons with an additional dropdown feel kind of eh

i feel like icons for actions next to the date would feel nicer

[New conversation ...................... ✏️ .🗑️] Saturday

something like that

Aayushgoyal00 and others added 2 commits November 14, 2025 17:11
…ory UI

- Added `is_visible` column to the conversations table to support soft deletion.
- Updated conversation loading logic to filter out soft-deleted conversations.
- Modified the delete functionality to soft delete conversations instead of permanently removing them.
- Enhanced chat history UI to show delete action on hover for web users, improving user experience.
- Refactored styles for better layout and interaction consistency.
@Aayushgoyal00
Copy link
Author

Aayushgoyal00 commented Nov 14, 2025

✅ Changes Made

1. Soft Deletion with is_visible Flag

  • Added database migration to create is_visible column (defaults to true)
  • Modified deleteConversation to set is_visible = false instead of hard deleting
  • Updated all queries to filter out soft-deleted conversations with .neq('is_visible', false)
  • Created index on is_visible for performance

2. Improved UI/UX Design

  • Delete icon now appears on hover (web) or always visible (mobile)
  • Positioned delete icon inline with the date on the right side: [New conversation ...................... 🗑️ Today]

3. Confirmation Modal - Kept Intentionally

I've kept the confirmation modal for an important UX reason:

  • Prevents accidental deletions - The delete icon is small and could be clicked by mistake
  • Provides clear feedback - Users understand the action is permanent from their perspective
  • As you mentioned, you were "open to keeping it this way if it feels good" - I believe it adds a necessary safety layer

Database Migration Required

Before merging, please run this migration on your Supabase instance:

-- Add is_visible column to conversations table for soft deletion
ALTER TABLE conversations 
ADD COLUMN IF NOT EXISTS is_visible BOOLEAN DEFAULT true;

-- Create index for performance when filtering visible conversations
CREATE INDEX IF NOT EXISTS idx_conversations_is_visible ON conversations(is_visible);

-- Update any existing conversations to be visible
UPDATE conversations SET is_visible = true WHERE is_visible IS NULL;

Benefits of This Implementation

  1. Data Preservation: Conversations are never truly deleted, preserving data for Mallory's memory functionality
  2. Clean Design: Minimal interface with actions shown only on hover, maintaining design cohesion
  3. Future-proof: Easy to add "restore deleted conversations" feature later if needed
  4. Performance: Indexed column ensures fast query performance even with many soft-deleted records

Testing Checklist

I've tested:

  • ✅ Hover behavior on desktop browsers
  • ✅ Confirmation modal flow
  • ✅ UI updates immediately after deletion
  • ✅ Deleted conversations don't reappear on refresh
  • ✅ Loading states during deletion

The implementation is ready for review. Let me know if you'd like any adjustments!

Copy link

@vercel vercel bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Additional Suggestion:

The handleConversationUpdate function doesn't check if a conversation has been soft-deleted (is_visible: false), which could cause soft-deleted conversations to be updated or displayed incorrectly when real-time events are received.

View Details
📝 Patch Details
diff --git a/apps/client/hooks/useChatHistoryData.ts b/apps/client/hooks/useChatHistoryData.ts
index e3a94c3..95209fa 100644
--- a/apps/client/hooks/useChatHistoryData.ts
+++ b/apps/client/hooks/useChatHistoryData.ts
@@ -178,9 +178,9 @@ export function useChatHistoryData(userId?: string) {
     console.log('📝 [HANDLE INSERT] newRecord.token_ca:', newRecord.token_ca);
     console.log('📝 [HANDLE INSERT] GLOBAL_TOKEN_ID:', GLOBAL_TOKEN_ID);
     
-    // Only add global conversations
-    if (newRecord.token_ca !== GLOBAL_TOKEN_ID) {
-      console.log('⚠️ [HANDLE INSERT] Skipping - not a global conversation');
+    // Only add global conversations that are visible (not soft-deleted)
+    if (newRecord.token_ca !== GLOBAL_TOKEN_ID || newRecord.is_visible === false) {
+      console.log('⚠️ [HANDLE INSERT] Skipping - not a global conversation or soft-deleted');
       return;
     }
     
@@ -208,6 +208,23 @@ export function useChatHistoryData(userId?: string) {
   }, []);
 
   const handleConversationUpdate = useCallback((newRecord: any) => {
+    if (newRecord.is_visible === false) {
+      // Remove soft-deleted conversations instead of updating them
+      setConversations(prev => {
+        const updated = prev.filter(conv => conv.id !== newRecord.id);
+        cache.conversations = updated;
+        return updated;
+      });
+      setAllMessages(prev => {
+        const updated = { ...prev };
+        delete updated[newRecord.id];
+        cache.allMessages = updated;
+        return updated;
+      });
+      console.log('✅ [useChatHistoryData] Removed soft-deleted conversation:', newRecord.id);
+      return;
+    }
+    
     setConversations(prev => {
       const updated = prev.map(conv => 
         conv.id === newRecord.id 
@@ -399,4 +416,3 @@ export function getCachedMessagesForConversation(conversationId: string): any[]
   if (!cache.allMessages || !conversationId) return null;
   return cache.allMessages[conversationId] || null;
 }
-

Analysis

Real-time handlers ignore is_visible flag allowing soft-deleted conversations to persist

What fails: handleConversationUpdate() and handleConversationInsert() in useChatHistoryData.ts don't check is_visible field, causing soft-deleted conversations to remain visible when real-time UPDATE/INSERT events are received

How to reproduce:

# Multi-client scenario:
# 1. Client A has conversation in local state
# 2. Client B soft-deletes conversation (sets is_visible: false)  
# 3. Client A receives UPDATE event with is_visible: false
# 4. handleConversationUpdate processes it without checking is_visible
# 5. Soft-deleted conversation remains in Client A's state

Result: Soft-deleted conversations remain visible to other clients and can be incorrectly updated instead of removed

Expected: Conversations with is_visible: false should be filtered out or removed from local state, consistent with initial query filter at line 85: .neq('is_visible', false)

Evidence: Supabase real-time docs confirm UPDATE events are sent when columns change, including is_visible field changes

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add option to delete a conversation

2 participants