Skip to content

Conversation

@connermo
Copy link

@connermo connermo commented Sep 2, 2025

Summary

This PR implements comprehensive log clearing functionality for both chat and completion conversations. The implementation supports both bulk deletion (all logs) and selective deletion (specific conversation IDs).

Key Features:

  • Backend API endpoints for clearing chat/completion conversations
  • Frontend UI with "Clear All" and "Clear Selected" functionality
  • Multi-select checkboxes with confirmation dialogs

Technical Implementation:

  • Cascading deletion across database tables (conversations, messages, annotations, variables)
  • Background file cleanup with Celery tasks
  • Comprehensive localStorage clearing mechanism
  • SWR cache invalidation and cross-tab synchronization

Resolve #24626

Screenshots

Default shows "Clear All Logs" button only:

image

"Clear Selected" button shows when conversations are selected:

image

Confirmation dialog shows before execution:

image

Checklist

  • This change requires a documentation update, included: https://github.com/langgenius/dify-docs
  • I understand that this PR may be closed in case there was no previous discussion or issues. (This doesn't apply to typos!)
  • I've added a test for each change that was introduced, and I tried as much as possible to make a single atomic change.
  • I've updated the documentation accordingly.
  • I ran dev/reformat(backend) and cd web && npx lint-staged(frontend) to appease the lint gods

Additional Notes

Files Modified:

  • api/controllers/console/app/conversation.py - New DELETE endpoints
  • api/tasks/clean_uploaded_files_task.py - Background file cleanup task
  • web/app/components/app/log/filter.tsx - Clear buttons and confirmations
  • web/app/components/app/log/list.tsx - Multi-select functionality
  • web/app/components/app/log/index.tsx - Selection state management
  • web/service/log.ts - Enhanced clearing with 404 prevention
  • web/app/components/base/chat/chat-with-history/hooks.tsx - Error handling

Testing Completed:

  • Bulk deletion flow with explore page navigation
  • Selective deletion with remaining conversation accessibility
  • Error recovery scenarios (cross-tab conversation deletion)
  • localStorage synchronization across browser tabs

Conner Mo and others added 3 commits August 28, 2025 14:01
This PR introduces selective deletion capabilities for conversation logs, allowing users to delete specific conversations instead of only being able to clear all logs at once.

## Changes Made

### Backend API Updates
- Enhanced DELETE endpoints in `api/controllers/console/app/conversation.py` to support selective deletion
- Added `conversation_ids` parameter support for both chat and completion conversations
- Maintained backward compatibility with existing "clear all" functionality
- Added proper cleanup of related data (messages, files, annotations, etc.)

### Frontend UI Improvements
- Added multi-selection checkboxes to log list interface
- Implemented "Select All" functionality with proper state management
- Enhanced filter component with "Clear Selected" button alongside existing "Clear All"
- Added confirmation dialogs for both selective and full deletion operations
- Fixed checkbox event handling to prevent conflicts with row clicks

### Internationalization
- Added bilingual support (English/Chinese) for new UI elements
- Included appropriate success/error messages for selective operations

## Key Features
- **Multi-Selection**: Users can select individual conversations or use "Select All"
- **Confirmation Dialogs**: Separate confirmations for clearing all vs clearing selected items
- **Progress Feedback**: Loading states and success/error notifications
- **Data Integrity**: Proper cleanup of associated files, messages, and metadata
- **Backward Compatible**: Existing "Clear All" functionality remains unchanged

## Technical Details
- Used React state management for selection tracking
- Implemented proper event propagation handling for checkboxes
- Enhanced API service layer with optional conversation ID parameters
- Added comprehensive error handling and user feedback

Fixes user pain point of having to delete all logs when only wanting to remove specific conversations.
Following community feedback (@crazywoola), this refactors the delete functionality:

## Changes Made

### Service Layer Implementation
- Added `ConversationService.clear_conversations()` method
- Moved complex deletion logic from controllers to service layer
- Added proper user validation and conversation ownership checks
- Integrated with Celery task queue for async processing

### Celery Task Implementation
- Created `clear_conversation_task.py` with batch processing
- Handles large datasets efficiently with configurable batch sizes
- Includes proper error handling and retry mechanisms
- Comprehensive cleanup of files, messages, annotations, and related data
- Progress tracking and detailed logging

### Controller Refactoring
- Simplified DELETE endpoints to use service layer
- Maintained backward compatibility with existing API
- Added task tracking information in response
- Proper error handling and user permissions

## Benefits
- **Scalability**: Large datasets processed asynchronously
- **Reliability**: Celery tasks with retry mechanisms
- **Maintainability**: Clean separation of concerns
- **Monitoring**: Progress tracking and detailed logging
- **Performance**: Batch processing prevents memory issues

## Technical Details
- Uses SQLAlchemy batch operations for efficiency
- Proper transaction management with session handling
- File cleanup integrated with storage layer
- Comprehensive error handling for missing tables/data

This addresses the architectural concern while maintaining all existing functionality.
- Fixed localStorage clearing mechanism to prevent 404 errors on explore pages
- Added comprehensive error handling for conversation rename operations
- Resolved merge conflicts and maintained clean code formatting
- Enhanced conversation deletion to clear all conversation IDs to prevent app ID mismatches
- Added proper error handling when conversations are deleted before rename operations complete
- Fixed code style issues (line length, logging format, variable declaration order)

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <[email protected]>
@dosubot dosubot bot added size:XXL This PR changes 1000+ lines, ignoring generated files. 💪 enhancement New feature or request labels Sep 2, 2025
@connermo connermo changed the title Feat/selective log deletion Feat/complete and selective log deletion Sep 2, 2025
@connermo connermo changed the title Feat/complete and selective log deletion Feat/Bulk and selective log deletion Sep 2, 2025
- Resolved import conflicts in conversation.py and conversation_service.py
- Maintained clear logs functionality with error prevention
- Updated dependencies and imports to match upstream changes
@crazywoola crazywoola self-assigned this Sep 3, 2025
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull Request Overview

This PR implements comprehensive log clearing functionality for both chat and completion conversations, supporting bulk deletion (all logs) and selective deletion (specific conversation IDs).

  • Backend API endpoints for clearing chat/completion conversations with cascading deletion across database tables
  • Frontend UI with "Clear All" and "Clear Selected" functionality including multi-select checkboxes and confirmation dialogs
  • Background file cleanup with Celery tasks and comprehensive localStorage clearing mechanism with SWR cache invalidation

Reviewed Changes

Copilot reviewed 11 out of 11 changed files in this pull request and generated 6 comments.

Show a summary per file
File Description
web/service/log.ts Added API functions for clearing conversations with localStorage and SWR cache management
web/i18n/zh-Hans/app-log.ts Added Chinese translations for clear functionality
web/i18n/en-US/app-log.ts Added English translations for clear functionality
web/app/components/base/chat/chat-with-history/hooks.tsx Added error handling for deleted conversations and storage event listeners
web/app/components/app/log/list.tsx Added multi-select checkboxes and selection state management
web/app/components/app/log/index.tsx Added selection state management and prop passing
web/app/components/app/log/filter.tsx Added clear buttons, confirmation dialogs, and clearing logic
api/tasks/clear_conversation_task.py New Celery task for batch conversation deletion
api/tasks/clean_uploaded_files_task.py New task for asynchronous file cleanup
api/services/conversation_service.py Added clear conversations service method with error handling
api/controllers/console/app/conversation.py Added DELETE endpoints for chat and completion conversations

Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.

Conner Mo added 2 commits September 4, 2025 22:46
- Extract localStorage clearing logic into shared utility function (web/utils/localStorage.ts)
- Add accessibility improvements with aria-labels for checkboxes
- Improve exception handling with specific exception types (OperationalError, ProgrammingError)
- Add comprehensive error logging for better debugging
- Enhanced user permission validation with security logging

This addresses the main feedback points from the PR review:
- Code duplication reduction
- Better error handling and debugging
- Improved accessibility for screen readers
- Enhanced security measures
@connermo connermo force-pushed the feat/selective-log-deletion branch from f918b3a to 8518150 Compare September 4, 2025 14:47
Conner Mo and others added 3 commits September 4, 2025 22:50
- Change clearConversationIds to only clear specific app IDs by default
- Add clearRelated option for handling related app IDs (app.id vs installedApp.id)
- Add forceGlobalClear option for backwards compatibility (disabled by default)
- Provide specialized functions for common use cases:
  - clearConversationIdsWithMapping() for log<->explore app ID mapping
  - smartClearConversationIds() for intelligent related ID detection
- Update service calls to use safer, app-specific clearing
- Add comprehensive logging to track what gets cleared

This addresses the feedback: 'This code clears ALL conversation IDs from
localStorage regardless of the app being cleared. This is overly aggressive
and could affect other apps conversation states.'

The new approach:
- Default: Only clear the specific app ID provided
- Optional: Clear related app IDs when explicitly specified
- Safeguard: Prevent accidental clearing of unrelated apps
- Update import path from '@/config' to '@/app/components/base/chat/constants'
- This resolves the build error: 'CONVERSATION_ID_INFO' is not exported from '@/config'

The constant is properly defined in the chat constants file, matching other
similar imports throughout the codebase.
@crazywoola
Copy link
Member

@connermo Hello there are some conflicts in the CI pipeline.

autofix-ci bot and others added 3 commits September 12, 2025 02:13
…nflicts

- Change from complex string parsing with action="append" to simple list type
- Remove unnecessary parameter validation and conversion logic
- Streamline conversation_ids handling for better maintainability
- Resolve merge conflicts in conversation.py imports
- Add Account import from models to resolve merge conflict
- Merge imports from both feat/selective-log-deletion and main branches
- Keep all necessary model imports for selective deletion functionality
@connermo
Copy link
Author

@connermo Hello there are some conflicts in the CI pipeline.

Conflicts resolved. Please have a check. Thanks.

@crazywoola
Copy link
Member

/gemini review

Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request adds bulk and selective log deletion capabilities. The frontend implementation is well-done, featuring a clean UI, robust state management, and cross-tab synchronization. However, the backend implementation has several critical issues. There are two separate deletion mechanisms, and the one currently in use is synchronous, inefficient (contains N+1 queries), and has a critical bug that prevents file cleanup from working correctly. My review provides detailed feedback on fixing these backend issues, refactoring duplicated code, and recommends consolidating the logic to use the more robust asynchronous task-based approach that was also partially implemented.

asukaminato0721 and others added 5 commits October 20, 2025 03:49
…sues

This commit addresses all critical issues identified in PR review:

**1. Fixed File Cleanup Bug**
- File cleanup now happens BEFORE database deletion in Celery task
- Prevents orphaned files in storage by retrieving upload metadata before DB deletion
- File: api/tasks/clear_conversation_task.py

**2. Eliminated Code Duplication (282 lines → 80 lines)**
- Removed duplicate ~140-line deletion methods in CompletionConversationApi and ChatConversationApi
- Both endpoints now delegate to ConversationService.clear_conversations()
- Single source of truth for deletion logic in Celery task
- File: api/controllers/console/app/conversation.py

**3. Resolved N+1 Query Problem**
- Implemented batch processing (1000 records per batch)
- Use single IN clause queries instead of loops
- Significantly improved performance for large datasets
- File: api/tasks/clear_conversation_task.py

**4. Improved Exception Handling**
- Replaced broad 'except Exception' with specific exception types
- OSError for storage failures, DatabaseError for DB issues
- OperationalError for missing tables, MaxRetriesExceededError for Celery
- Better error logging with context
- Files: api/tasks/clear_conversation_task.py, api/tasks/clean_uploaded_files_task.py

**5. Fixed Mode Filtering**
- Properly handles all chat modes: chat, agent-chat, advanced-chat
- Completion mode filtering remains unchanged
- File: api/tasks/clear_conversation_task.py:75-80

**6. Code Quality**
- Removed unused imports from controller
- All tests pass (1,918 unit tests)
- Linting passes (make lint)
- Type checking passes (make type-check)

**Changes:**
- Modified: api/controllers/console/app/conversation.py (-282 lines)
- Modified: api/tasks/clear_conversation_task.py (+42 lines)
- Modified: api/tasks/clean_uploaded_files_task.py (-1 line)

**Breaking Changes:** None - API interface remains the same, returns 202 (queued) instead of 200
Resolved conflicts in web/app/components/app/log/list.tsx:
- Kept checkbox selection functionality from feature branch
- Adopted type-safe AppStoreState from upstream
- Merged activeConversationId usage from upstream
- Removed unused handleRowClick function (click handlers moved inline)
- Combined both feature sets successfully
Removed handleRowClick that was no longer used after merge.
Click handlers are now inline in the table rows.
Copy link
Member

@laipz8200 laipz8200 left a comment

Choose a reason for hiding this comment

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

Hi @connermo, is there any mechanism to prevent users from submitting this deletion task multiple times? If not, it might cause confusion and result in multiple redundant tasks being added to the queue.

This commit fixes critical issues with the log clearing functionality:

Backend fixes:
- Fixed DELETE request body parsing with proper default values
- Added conversation queue routing for Celery tasks
- Ensured proper handling of empty conversation_ids array

Frontend fixes:
- Fixed DELETE request body handling in HTTP client
- Improved SWR cache invalidation with correct key matching
- Added proactive conversation ID validation to prevent 404 errors
- Simplified error handling and removed debug logging

Key improvements:
- Request body now always sent for DELETE (empty array vs undefined)
- Multi-layer cache clearing (log list, explore apps, conversation data)
- Auto-cleanup of stale conversation IDs from localStorage
- Error handling for deleted conversations with 404 recovery

All changes pass lint and type-check validation.
…istic UI updates

This commit addresses the reviewer's concern about duplicate task submissions
by implementing a multi-layered prevention strategy.

## Backend improvements:

1. **Redis-based task deduplication**
   - Added Redis lock mechanism in ConversationService.clear_conversations()
   - Lock key format: `clear_conversations:{app_id}:{mode}[:{conversation_ids_hash}]`
   - Lock expires in 10 minutes, preventing stale locks
   - Returns 409 Conflict if clearing task already in progress

2. **New exception handling**
   - Added ConversationClearInProgressError exception
   - Controllers return 409 status with clear error message
   - Lock is automatically released on task completion or max retries

3. **Celery task improvements**
   - Task accepts lock_key parameter for cleanup
   - Releases lock on successful completion
   - Releases lock after max retries to prevent deadlock

## Frontend improvements:

1. **Optimistic UI updates**
   - List immediately cleared from UI when user clicks "Clear All"
   - For selective deletion, removed items are filtered out instantly
   - Prevents user confusion and repeat submissions

2. **Improved user experience**
   - No need to wait for backend processing to see results
   - Clear visual feedback that operation started
   - Backend revalidation happens after optimistic update

## How it works:

1. User clicks "Clear All" → List immediately disappears (optimistic update)
2. Frontend sends DELETE request → Backend checks Redis lock
3. If lock exists → Return 409 error (task already running)
4. If no lock → Acquire lock and queue Celery task
5. Celery task processes deletion in background
6. Task releases lock when done or after max retries
7. Frontend revalidates data after request completes

This prevents duplicate tasks even in edge cases like:
- Cross-tab submissions
- Slow network + multiple clicks
- Page refresh during operation
@connermo connermo force-pushed the feat/selective-log-deletion branch from a51b033 to 8da334c Compare November 3, 2025 10:04
The global SWR config disables revalidateOnFocus, causing the log list
to never refresh automatically. This creates poor UX where users must
manually refresh to see new conversations.

This commit overrides the global config for log list endpoints to enable:
- revalidateOnFocus: automatically refresh when user returns to the tab
- revalidateOnReconnect: refresh when network reconnects

This improves UX without breaking existing functionality or adding
unnecessary polling.
When users delete conversations (all or selected), the UI now updates
immediately instead of waiting for the async Celery task to complete.

Changes:
- Added handleOptimisticDelete in index.tsx to update SWR cache instantly
- Modified filter.tsx to call optimistic update before API request
- Items are removed from UI immediately on delete action
- Background revalidation still occurs to sync with backend
- On error, revalidation restores correct state

This provides instant feedback and better UX for deletion operations.
Previously, the log list only refreshed on browser focus events,
not on in-app navigation. When users chat on the configuration page
and then navigate to the logs page, the list wouldn't update.

This commit adds a useEffect hook that monitors pathname changes
and triggers data revalidation when the user navigates to /logs.

Changes:
- Import useEffect and use usePathname hook
- Add effect to call mutate() when pathname includes '/logs'
- Ensures fresh data when users navigate from chat/config to logs

Now the log list automatically refreshes when users switch to the
logs page from anywhere in the app.
When users delete conversations from the logs page and navigate to
the configuration/chat page, the conversation list in the sidebar
wasn't refreshing, showing stale deleted conversations.

This commit adds pathname monitoring to the chat-with-history hook
to automatically refresh both pinned and regular conversation lists
when users navigate to the configuration page.

Changes:
- Import usePathname from next/navigation
- Add pathname to hook dependencies
- Add useEffect to call mutate when pathname includes '/configuration'
- Refreshes both pinned and regular conversation data

This ensures the conversation sidebar always shows current data
after deletions from the logs page.
@connermo
Copy link
Author

connermo commented Nov 3, 2025

Hi @connermo, is there any mechanism to prevent users from submitting this deletion task multiple times? If not, it might cause confusion and result in multiple redundant tasks being added to the queue.

Yes, you are right. The new implementation fixed the problem:
Backend Protection (Redis-based locking):

  1. Redis Lock Mechanism - When a deletion request is received, the backend acquires a Redis lock with key format:
    clear_conversations:{app_id}:{mode}[:{conversation_ids_hash}]
  2. Lock Expiration - The lock expires after 10 minutes to prevent stale locks
  3. 409 Conflict Response - If a deletion task is already in progress (lock exists), the API returns a 409 Conflict status with a clear error message
  4. Automatic Lock Release - The Celery task releases the lock when:
    - Task completes successfully
    - Task reaches max retries (to prevent deadlock)

Frontend Protection (Optimistic UI):

  1. Immediate UI Update - When the user clicks "Clear" or "Clear Selected", the items are immediately removed from the UI
  2. Button State - The delete buttons are disabled (isClearing state) during the operation
  3. Visual Feedback - Users see immediate results, preventing them from clicking again

How it prevents duplicates:

Scenario 1: User clicks multiple times rapidly

  • First click: Immediately removes items from UI + starts backend request
  • Second click: Button is disabled (isClearing=true), click ignored

Scenario 2: User submits from different tabs

  • First tab: Acquires Redis lock, processes deletion
  • Second tab: Gets 409 Conflict, backend rejects the duplicate request

Scenario 3: Slow network + impatient user

  • Items disappear immediately (optimistic update)
  • User has no reason to click again since the list is already clear
  • Backend processes asynchronously

The code for this is in commit 8da334c - you can see the Redis lock implementation in api/services/conversation_service.py and the optimistic UI updates in the frontend filter/index components.

The previous implementation only handled pathname changes, which didn't
work reliably when users deleted conversations from the logs page and
navigated back to the configuration page in the same browser tab.

This commit implements a dual notification system:

1. **Same-tab communication**: Uses CustomEvent to immediately notify
   the configuration page when conversations are deleted

2. **Cross-tab communication**: Uses localStorage + storage event to
   sync deletions across different browser tabs/windows

Changes:
- filter.tsx: Dispatch both CustomEvent and localStorage update
- hooks.tsx: Listen to both conversationsCleared event and storage event
- Ensures conversation lists refresh immediately after deletion
- Works in both same-tab navigation and multi-tab scenarios

Now when users delete conversations from logs and switch to the
configuration page, the conversation sidebar updates immediately.
Adds a reusable conversation sync system that automatically refreshes
conversation lists across pages when conversations are modified.

New utility:
- utils/conversation-sync.ts: Universal notification system for any
  conversation list changes (delete, create, rename, pin/unpin)

Implementation:
- Uses localStorage timestamp-based sync
- Supports same-tab navigation via visibilitychange event
- Supports cross-tab sync via storage event
- Prevents 404 errors by clearing current conversation ID on updates

Changes:
- filter.tsx: Call notifyConversationListUpdate() after deletion
- hooks.tsx: Listen for conversation updates and refresh lists
- Initialize lastCheckedTimeRef to 0 to catch updates on mount

This generic approach can be extended to:
- New conversation creation
- Conversation renaming
- Pin/unpin operations
- Any conversation list modifications
@connermo connermo requested a review from laipz8200 November 3, 2025 16:03
Resolved conflicts in web/app/components/app/log/index.tsx:
- Kept useEffect and usePathname imports for route-based refresh
- Merged List component props (selectedItems from feature branch)
- Adopted EmptyElement API change (appDetail prop from upstream)

All features preserved while integrating upstream changes.
@crazywoola
Copy link
Member

Sorry for the late reply, but there are some conflicts, could you resolve them and push it again?

connermo and others added 3 commits November 24, 2025 14:21
Resolved conflicts in:
- web/app/components/app/log/list.tsx: Updated to use AppModeEnum constants while preserving bulk selection functionality
- web/i18n/en-US/app-log.ts: Merged selection-related and trigger-related i18n keys
- web/i18n/zh-Hans/app-log.ts: Merged Chinese translations for both features
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

💪 enhancement New feature or request size:XXL This PR changes 1000+ lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Bulk Clear All Conversation Logs

4 participants