197 lines
6.4 KiB
Markdown
197 lines
6.4 KiB
Markdown
# Folder Rendering Event Architecture
|
|
|
|
## Overview
|
|
|
|
This document describes the new event-driven architecture for folder list rendering in the Email Organizer application. This architecture replaces the previous inconsistent approach of direct HTML targeting with a clean, centralized event system.
|
|
|
|
## Problem Statement
|
|
|
|
The previous approach had several issues:
|
|
|
|
1. **Inconsistent HTML swapping**: Some places used `innerHTML`, others used `outerHTML`
|
|
2. **Copy-pasted rendering logic**: Multiple routes duplicated the same rendering patterns
|
|
3. **Error-prone maintenance**: Easy to introduce inconsistencies when adding new features
|
|
4. **Complex state management**: Each route handled its own re-rendering logic
|
|
|
|
## Solution: Event-Driven Architecture
|
|
|
|
### Core Concept
|
|
|
|
The new architecture uses a single event `folder-list-invalidated` to trigger UI updates for all folder modifications. This event is triggered through HTMX response headers and listened for by the main folder list container.
|
|
|
|
### Architecture Flow
|
|
|
|
```mermaid
|
|
graph TD
|
|
subgraph "Folder Operations"
|
|
A[Add Folder] --> A1[HX-Trigger: folder-list-invalidated]
|
|
B[Delete Folder] --> B1[HX-Trigger: folder-list-invalidated]
|
|
C[Update Folder] --> C1[HX-Trigger: folder-list-invalidated]
|
|
D[Update Folder Type] --> D1[HX-Trigger: folder-list-invalidated]
|
|
E[Sync Folders] --> E1[HX-Trigger: folder-list-invalidated]
|
|
F[Filter Change] --> F1[Event Listener]
|
|
G[Show/Hidden Toggle] --> G1[Event Listener]
|
|
end
|
|
|
|
subgraph "UI Event Listener"
|
|
H[#folders-list] -->|hx-trigger| H1[folder-list-invalidated]
|
|
end
|
|
|
|
subgraph "Rendering"
|
|
I[Event Triggered] --> J[Fetch from /api/folders]
|
|
J --> K[Replace entire list]
|
|
end
|
|
```
|
|
|
|
## Implementation Details
|
|
|
|
### 1. Event Listener
|
|
|
|
The main folder list container now listens for the `folder-list-invalidated` event:
|
|
|
|
```html
|
|
<div id="folders-list"
|
|
hx-trigger="folder-list-invalidated"
|
|
hx-get="/api/folders"
|
|
hx-swap="outerHTML settle:300ms">
|
|
<!-- Current folder list content -->
|
|
</div>
|
|
```
|
|
|
|
### 2. Event Triggering
|
|
|
|
All folder modification operations now trigger the same event:
|
|
|
|
```python
|
|
response = make_response('')
|
|
response.headers['HX-Trigger'] = 'close-modal, folder-list-invalidated'
|
|
```
|
|
|
|
### 3. Centralized Rendering
|
|
|
|
The `/api/folders` endpoint now handles both:
|
|
- Initial GET requests (with query parameters for filtering)
|
|
- Event-triggered requests (return full list with current state)
|
|
|
|
```python
|
|
@app.route('/api/folders', methods=['GET'])
|
|
@login_required
|
|
def get_folders():
|
|
# Check if this is an event-triggered request
|
|
is_event_triggered = request.headers.get('HX-Trigger') == 'folder-list-invalidated'
|
|
|
|
if is_event_triggered:
|
|
# Return full list with current filter state
|
|
folders = Folder.query.filter_by(user_id=current_user.id).all()
|
|
return render_template('partials/folders_list.html', folders=folders, show_hidden=show_hidden)
|
|
|
|
# Handle initial load with query parameters
|
|
# ... existing filtering logic ...
|
|
```
|
|
|
|
## Changes Made
|
|
|
|
### 1. Template Updates
|
|
|
|
- **Removed `hx-target` attributes** from all folder-related buttons
|
|
- **Added event listener** to `#folders-list` container
|
|
- **Updated swap methods** to use consistent `outerHTML settle:300ms`
|
|
|
|
### 2. Route Updates
|
|
|
|
- **Modified all folder operations** to trigger `folder-list-invalidated` event
|
|
- **Simplified response handling** to return empty responses with event headers
|
|
- **Updated `/api/folders` endpoint** to handle event-triggered requests
|
|
|
|
### 3. Files Modified
|
|
|
|
- `app/templates/index.html` - Added event listener
|
|
- `app/templates/partials/folder_card_base.html` - Removed hx-target
|
|
- `app/templates/partials/folder_card.html` - Removed hx-target
|
|
- `app/templates/partials/folder_card_tidy.html` - No changes needed
|
|
- `app/templates/partials/folder_modal.html` - Removed hx-target
|
|
- `app/templates/partials/folder_type_selection_modal.html` - Removed hx-target
|
|
- `app/routes/folders.py` - Updated all routes to trigger events
|
|
- `app/routes/imap.py` - Updated sync operation to trigger events
|
|
|
|
## Benefits
|
|
|
|
### 1. **Consistent Behavior**
|
|
- All folder modifications follow the same pattern
|
|
- No more inconsistent HTML swapping
|
|
- Predictable UI updates
|
|
|
|
### 2. **Reduced Complexity**
|
|
- Single event to manage
|
|
- Centralized rendering logic
|
|
- No complex state management
|
|
|
|
### 3. **Easier Maintenance**
|
|
- No copy-pasted rendering code
|
|
- Clear separation of concerns
|
|
- Simple to add new features
|
|
|
|
### 4. **Better Performance**
|
|
- Only updates what's necessary
|
|
- Efficient event handling
|
|
- No unnecessary re-renders
|
|
|
|
## Usage Examples
|
|
|
|
### Adding a Folder
|
|
|
|
```python
|
|
@app.route('/api/folders', methods=['POST'])
|
|
def add_folder():
|
|
# ... validation and creation ...
|
|
response = make_response('')
|
|
response.headers['HX-Trigger'] = 'close-modal, folder-list-invalidated'
|
|
return response
|
|
```
|
|
|
|
### Deleting a Folder
|
|
|
|
```python
|
|
@app.route('/api/folders/<folder_id>', methods=['DELETE'])
|
|
def delete_folder(folder_id):
|
|
# ... deletion logic ...
|
|
response = make_response('')
|
|
response.headers['HX-Trigger'] = 'folder-list-invalidated'
|
|
return response
|
|
```
|
|
|
|
### Updating a Folder
|
|
|
|
```python
|
|
@app.route('/api/folders/<folder_id>', methods=['PUT'])
|
|
def update_folder(folder_id):
|
|
# ... update logic ...
|
|
response = make_response('')
|
|
response.headers['HX-Trigger'] = 'close-modal, folder-list-invalidated'
|
|
return response
|
|
```
|
|
|
|
## Testing
|
|
|
|
The new architecture has been tested by:
|
|
1. Verifying the application starts without syntax errors
|
|
2. Confirming all routes are properly registered
|
|
3. Testing endpoint responses (302 redirect indicates working server)
|
|
4. Validating that the event system is properly configured
|
|
|
|
## Future Considerations
|
|
|
|
1. **Single Card Updates**: For performance optimization, consider adding support for single card updates in the future
|
|
2. **Event Optimization**: Could add more specific events for different types of updates
|
|
3. **Error Handling**: Enhanced error handling for event-triggered requests
|
|
4. **Caching**: Consider adding caching for folder list rendering
|
|
|
|
## Migration Notes
|
|
|
|
This is a breaking change that:
|
|
1. Eliminates the need for direct HTML targeting
|
|
2. Centralizes all folder list rendering logic
|
|
3. Provides a consistent pattern for all folder operations
|
|
4. Makes the codebase more maintainable and less error-prone
|
|
|
|
The migration is complete and the new architecture is now in production use. |