mirror of
https://github.com/DRYTRIX/TimeTracker.git
synced 2026-01-05 11:09:55 -06:00
feat: add user favorite projects functionality with CSV export enhancements
Features: Add favorite projects feature allowing users to star/bookmark frequently used projects New UserFavoriteProject association model with user-project relationships Star icons in project list for one-click favorite toggling via AJAX Filter to display only favorite projects Per-user favorites with proper isolation and cascade delete behavior Activity logging for favorite/unfavorite actions Database: Add user_favorite_projects table with migration (023_add_user_favorite_projects.py) Foreign keys to users and projects with CASCADE delete Unique constraint preventing duplicate favorites Indexes on user_id and project_id for query optimization Models: User model: Add favorite_projects relationship with helper methods add_favorite_project() - add project to favorites remove_favorite_project() - remove from favorites is_project_favorite() - check favorite status get_favorite_projects() - retrieve favorites with status filter Project model: Add is_favorited_by() method and include favorite status in to_dict() Export UserFavoriteProject model in app/models/__init__.py Routes: Add /projects/<id>/favorite POST endpoint to favorite a project Add /projects/<id>/unfavorite POST endpoint to unfavorite a project Update /projects GET route to support favorites=true query parameter Fix status filtering to work correctly with favorites JOIN query Add /reports/export/form GET endpoint for enhanced CSV export form Templates: Update projects/list.html: Add favorites filter dropdown to filter form (5-column grid) Add star icon column with Font Awesome icons (filled/unfilled) Add JavaScript toggleFavorite() function for AJAX favorite toggling Improve hover states and transitions for better UX Pass favorite_project_ids and favorites_only to template Update reports/index.html: Update CSV export link to point to new export form Add icon and improve hover styling Reports: Enhance CSV export functionality with dedicated form page Add filter options for users, projects, clients, and date ranges Set default date range to last 30 days Import Client model and or_ operator for advanced filtering Testing: Comprehensive test suite in tests/test_favorite_projects.py (550+ lines) Model tests for UserFavoriteProject creation and validation User/Project method tests for favorite operations Route tests for favorite/unfavorite endpoints Filtering tests for favorites-only view Relationship tests for cascade delete behavior Smoke tests for complete workflows Coverage for edge cases and error handling Documentation: Add comprehensive feature documentation in docs/FAVORITE_PROJECTS_FEATURE.md User guide with step-by-step instructions Technical implementation details API documentation for new endpoints Migration guide and troubleshooting Performance and security considerations Template Cleanup: Remove duplicate templates from root templates/ directory Admin templates (dashboard, users, settings, OIDC debug, etc.) Client CRUD templates Error page templates Invoice templates Project templates Report templates Timer templates All templates now properly located in app/templates/ Breaking Changes: None - fully backward compatible Migration Required: Run alembic upgrade head to create user_favorite_projects table
This commit is contained in:
365
docs/FAVORITE_PROJECTS_FEATURE.md
Normal file
365
docs/FAVORITE_PROJECTS_FEATURE.md
Normal file
@@ -0,0 +1,365 @@
|
||||
# Favorite Projects Feature
|
||||
|
||||
## Overview
|
||||
|
||||
The Favorite Projects feature allows users to mark frequently used projects as favorites for quick access. This feature enhances user productivity by providing easy access to the projects they work with most often.
|
||||
|
||||
## Features
|
||||
|
||||
- **Star Icon**: Each project in the project list has a star icon that can be clicked to favorite/unfavorite
|
||||
- **Quick Filter**: Filter to show only favorite projects
|
||||
- **Per-User**: Each user has their own set of favorite projects
|
||||
- **Real-time Updates**: Favorite status updates immediately via AJAX
|
||||
- **Status Awareness**: Favorites work with all project statuses (active, inactive, archived)
|
||||
|
||||
## User Guide
|
||||
|
||||
### Marking a Project as Favorite
|
||||
|
||||
1. Navigate to the Projects list page (`/projects`)
|
||||
2. Find the project you want to favorite
|
||||
3. Click the star icon (☆) next to the project name
|
||||
4. The star will turn yellow/gold (★) indicating it's now a favorite
|
||||
|
||||
### Removing a Project from Favorites
|
||||
|
||||
1. Navigate to the Projects list page
|
||||
2. Find the favorited project (marked with a gold star ★)
|
||||
3. Click the star icon
|
||||
4. The star will become hollow (☆) indicating it's no longer a favorite
|
||||
|
||||
### Filtering by Favorites
|
||||
|
||||
1. Navigate to the Projects list page
|
||||
2. In the filters section, find the "Filter" dropdown
|
||||
3. Select "Favorites Only"
|
||||
4. Click "Filter"
|
||||
5. The list will show only your favorite projects
|
||||
|
||||
### Combining Filters
|
||||
|
||||
You can combine the favorites filter with other filters:
|
||||
- **Status Filter**: Show only active favorites, archived favorites, etc.
|
||||
- **Client Filter**: Show favorites for a specific client
|
||||
- **Search**: Search within your favorite projects
|
||||
|
||||
## Technical Implementation
|
||||
|
||||
### Database Schema
|
||||
|
||||
A new association table `user_favorite_projects` was created with the following structure:
|
||||
|
||||
```sql
|
||||
CREATE TABLE user_favorite_projects (
|
||||
id INTEGER PRIMARY KEY,
|
||||
user_id INTEGER NOT NULL,
|
||||
project_id INTEGER NOT NULL,
|
||||
created_at DATETIME NOT NULL,
|
||||
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE,
|
||||
FOREIGN KEY (project_id) REFERENCES projects(id) ON DELETE CASCADE,
|
||||
UNIQUE (user_id, project_id)
|
||||
);
|
||||
CREATE INDEX ix_user_favorite_projects_user_id ON user_favorite_projects(user_id);
|
||||
CREATE INDEX ix_user_favorite_projects_project_id ON user_favorite_projects(project_id);
|
||||
```
|
||||
|
||||
### Model Relationships
|
||||
|
||||
#### User Model
|
||||
|
||||
New methods added to `app/models/user.py`:
|
||||
|
||||
- `add_favorite_project(project)`: Add a project to favorites
|
||||
- `remove_favorite_project(project)`: Remove a project from favorites
|
||||
- `is_project_favorite(project)`: Check if a project is favorited
|
||||
- `get_favorite_projects(status='active')`: Get list of favorite projects
|
||||
|
||||
New relationship:
|
||||
```python
|
||||
favorite_projects = db.relationship('Project',
|
||||
secondary='user_favorite_projects',
|
||||
lazy='dynamic',
|
||||
backref=db.backref('favorited_by', lazy='dynamic'))
|
||||
```
|
||||
|
||||
#### Project Model
|
||||
|
||||
New method added to `app/models/project.py`:
|
||||
|
||||
- `is_favorited_by(user)`: Check if project is favorited by a specific user
|
||||
|
||||
Updated method:
|
||||
- `to_dict(user=None)`: Now includes `is_favorite` field when user is provided
|
||||
|
||||
### API Endpoints
|
||||
|
||||
#### POST /projects/<project_id>/favorite
|
||||
|
||||
Mark a project as favorite.
|
||||
|
||||
**Authentication**: Required
|
||||
**Method**: POST
|
||||
**Parameters**: None
|
||||
**Returns**: JSON response
|
||||
|
||||
**Example Request:**
|
||||
```bash
|
||||
curl -X POST https://timetracker.example.com/projects/123/favorite \
|
||||
-H "X-Requested-With: XMLHttpRequest" \
|
||||
-H "Cookie: session=..."
|
||||
```
|
||||
|
||||
**Example Response (Success):**
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"message": "Project added to favorites"
|
||||
}
|
||||
```
|
||||
|
||||
**Example Response (Error):**
|
||||
```json
|
||||
{
|
||||
"success": false,
|
||||
"message": "Project is already in favorites"
|
||||
}
|
||||
```
|
||||
|
||||
#### POST /projects/<project_id>/unfavorite
|
||||
|
||||
Remove a project from favorites.
|
||||
|
||||
**Authentication**: Required
|
||||
**Method**: POST
|
||||
**Parameters**: None
|
||||
**Returns**: JSON response
|
||||
|
||||
**Example Request:**
|
||||
```bash
|
||||
curl -X POST https://timetracker.example.com/projects/123/unfavorite \
|
||||
-H "X-Requested-With: XMLHttpRequest" \
|
||||
-H "Cookie: session=..."
|
||||
```
|
||||
|
||||
**Example Response (Success):**
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"message": "Project removed from favorites"
|
||||
}
|
||||
```
|
||||
|
||||
### Routes
|
||||
|
||||
#### GET /projects?favorites=true
|
||||
|
||||
List projects filtered by favorites.
|
||||
|
||||
**Authentication**: Required
|
||||
**Method**: GET
|
||||
**Parameters**:
|
||||
- `favorites`: "true" to show only favorites
|
||||
- `status`: Filter by status (active/inactive/archived)
|
||||
- `client`: Filter by client name
|
||||
- `search`: Search in project name/description
|
||||
|
||||
**Example:**
|
||||
```
|
||||
GET /projects?favorites=true&status=active
|
||||
```
|
||||
|
||||
### Frontend Implementation
|
||||
|
||||
#### JavaScript
|
||||
|
||||
The `toggleFavorite(projectId, button)` function handles the star icon clicks:
|
||||
|
||||
1. Performs optimistic UI update (changes star immediately)
|
||||
2. Sends AJAX POST request to favorite/unfavorite endpoint
|
||||
3. Reverts UI if request fails
|
||||
4. Shows success/error message
|
||||
|
||||
#### UI Components
|
||||
|
||||
- **Star Icon**: FontAwesome icons (`fas fa-star` for favorited, `far fa-star` for not favorited)
|
||||
- **Color Coding**: Yellow/gold for favorited, muted gray for not favorited
|
||||
- **Filter Dropdown**: Added "Favorites Only" option to the filters form
|
||||
|
||||
## Migration
|
||||
|
||||
### Running the Migration
|
||||
|
||||
To add the favorite projects table to an existing database:
|
||||
|
||||
```bash
|
||||
# Using Alembic
|
||||
alembic upgrade head
|
||||
|
||||
# Or using the migration management script
|
||||
python migrations/manage_migrations.py upgrade
|
||||
```
|
||||
|
||||
### Rollback
|
||||
|
||||
To rollback the favorite projects feature:
|
||||
|
||||
```bash
|
||||
alembic downgrade -1
|
||||
```
|
||||
|
||||
## Activity Logging
|
||||
|
||||
The following activities are logged:
|
||||
|
||||
- `project.favorited`: When a user adds a project to favorites
|
||||
- `project.unfavorited`: When a user removes a project from favorites
|
||||
|
||||
These activities can be viewed in:
|
||||
- User activity logs
|
||||
- System audit trail
|
||||
- Analytics dashboards (if enabled)
|
||||
|
||||
## Testing
|
||||
|
||||
Comprehensive test coverage is provided in `tests/test_favorite_projects.py`:
|
||||
|
||||
### Test Categories
|
||||
|
||||
1. **Model Tests**: Testing the `UserFavoriteProject` model
|
||||
2. **Method Tests**: Testing User and Project model methods
|
||||
3. **Route Tests**: Testing API endpoints
|
||||
4. **Filtering Tests**: Testing the favorites filter
|
||||
5. **Relationship Tests**: Testing cascade delete behavior
|
||||
6. **Smoke Tests**: End-to-end workflow tests
|
||||
|
||||
### Running Tests
|
||||
|
||||
```bash
|
||||
# Run all favorite projects tests
|
||||
pytest tests/test_favorite_projects.py -v
|
||||
|
||||
# Run specific test class
|
||||
pytest tests/test_favorite_projects.py::TestUserFavoriteProjectModel -v
|
||||
|
||||
# Run with coverage
|
||||
pytest tests/test_favorite_projects.py --cov=app.models --cov=app.routes -v
|
||||
```
|
||||
|
||||
## Performance Considerations
|
||||
|
||||
### Database Indexes
|
||||
|
||||
The feature includes indexes on both `user_id` and `project_id` columns in the `user_favorite_projects` table for optimal query performance.
|
||||
|
||||
### Query Optimization
|
||||
|
||||
- Favorites are loaded once per page load and stored in a set for O(1) lookup
|
||||
- The favorites filter uses an efficient JOIN query
|
||||
- Lazy loading is used for relationships to avoid N+1 queries
|
||||
|
||||
### Scalability
|
||||
|
||||
The feature is designed to scale:
|
||||
- Indexes ensure fast lookups even with thousands of projects
|
||||
- Per-user favorites don't impact other users
|
||||
- AJAX requests are lightweight (no page reloads)
|
||||
|
||||
## Security Considerations
|
||||
|
||||
- **Authentication Required**: All favorite endpoints require user login
|
||||
- **User Isolation**: Users can only manage their own favorites
|
||||
- **CSRF Protection**: All POST requests use CSRF tokens
|
||||
- **Input Validation**: Project IDs are validated before database operations
|
||||
- **Cascade Delete**: Favorites are automatically cleaned up when users/projects are deleted
|
||||
|
||||
## Browser Compatibility
|
||||
|
||||
The feature works in all modern browsers:
|
||||
- Chrome 90+
|
||||
- Firefox 88+
|
||||
- Safari 14+
|
||||
- Edge 90+
|
||||
|
||||
Required browser features:
|
||||
- Fetch API for AJAX requests
|
||||
- ES6 JavaScript (arrow functions, const/let)
|
||||
- CSS3 for animations
|
||||
|
||||
## Future Enhancements
|
||||
|
||||
Potential improvements for future versions:
|
||||
|
||||
1. **Favorite Count Badge**: Show number of favorites in summary cards
|
||||
2. **Recently Used**: Track and show recently accessed projects
|
||||
3. **Favorite Ordering**: Allow users to reorder their favorites
|
||||
4. **Quick Access Menu**: Add favorites to navigation menu
|
||||
5. **Keyboard Shortcuts**: Add keyboard shortcut to favorite/unfavorite
|
||||
6. **Bulk Favorite**: Select and favorite multiple projects at once
|
||||
7. **Favorites Dashboard**: Dedicated dashboard showing favorite project metrics
|
||||
8. **Export Favorites**: Export list of favorite projects
|
||||
9. **Favorite Teams**: Share favorite project lists with team members
|
||||
10. **Smart Favorites**: Auto-suggest favorites based on usage patterns
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Star Icon Not Appearing
|
||||
|
||||
**Symptom**: Star icon column is missing in project list
|
||||
|
||||
**Solution**:
|
||||
- Clear browser cache and reload
|
||||
- Verify template file is up to date
|
||||
- Check browser console for JavaScript errors
|
||||
|
||||
### Favorite Not Saving
|
||||
|
||||
**Symptom**: Clicking star doesn't persist the favorite
|
||||
|
||||
**Solution**:
|
||||
- Check browser console for network errors
|
||||
- Verify CSRF token is present in page
|
||||
- Check database migration was applied
|
||||
- Review server logs for errors
|
||||
|
||||
### Migration Fails
|
||||
|
||||
**Symptom**: Migration script fails to create table
|
||||
|
||||
**Solution**:
|
||||
- Check database user has CREATE TABLE permissions
|
||||
- Verify Alembic is up to date
|
||||
- Check for conflicting table names
|
||||
- Review migration logs for specific errors
|
||||
|
||||
## Support
|
||||
|
||||
For issues or questions about this feature:
|
||||
|
||||
1. Check the [FAQ](../README.md#faq) section
|
||||
2. Review the [test cases](../../tests/test_favorite_projects.py) for usage examples
|
||||
3. Check [GitHub Issues](https://github.com/yourusername/TimeTracker/issues)
|
||||
4. Contact the development team
|
||||
|
||||
## Changelog
|
||||
|
||||
### Version 1.0.0 (2025-10-23)
|
||||
|
||||
**Added:**
|
||||
- Initial implementation of favorite projects feature
|
||||
- Star icon for each project in project list
|
||||
- Favorites filter in projects page
|
||||
- User model methods for managing favorites
|
||||
- Project model methods for checking favorite status
|
||||
- API endpoints for favorite/unfavorite actions
|
||||
- Comprehensive test coverage
|
||||
- Documentation
|
||||
|
||||
**Database:**
|
||||
- Added `user_favorite_projects` table
|
||||
- Migration script: `023_add_user_favorite_projects.py`
|
||||
|
||||
**Security:**
|
||||
- CSRF protection on all favorite endpoints
|
||||
- User authentication required
|
||||
- Per-user favorite isolation
|
||||
|
||||
Reference in New Issue
Block a user