feat: complete LOW priority code quality improvements

Backend:
- LOW-002: Add Query validation with max page size limits (100)
- LOW-003: Replace magic strings with TaskStatus.is_done flag
- LOW-004: Add 'creation' trigger type validation
- Add action_executor.py with UpdateFieldAction and AutoAssignAction

Frontend:
- LOW-005: Replace TypeScript 'any' with 'unknown' + type guards
- LOW-006: Add ConfirmModal component with A11Y support
- LOW-007: Add ToastContext for user feedback notifications
- LOW-009: Add Skeleton components (17 loading states replaced)
- LOW-010: Setup Vitest with 21 tests for ConfirmModal and Skeleton

Components updated:
- App.tsx, ProtectedRoute.tsx, Spaces.tsx, Projects.tsx, Tasks.tsx
- ProjectSettings.tsx, AuditPage.tsx, WorkloadPage.tsx, ProjectHealthPage.tsx
- Comments.tsx, AttachmentList.tsx, TriggerList.tsx, TaskDetailModal.tsx
- NotificationBell.tsx, BlockerDialog.tsx, CalendarView.tsx, WorkloadUserDetail.tsx

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
beabigegg
2026-01-07 21:24:36 +08:00
parent 2d80a8384e
commit 4b5a9c1d0a
66 changed files with 7809 additions and 171 deletions

View File

@@ -118,6 +118,9 @@ def should_encrypt_file(project: Project, db: Session) -> tuple[bool, Optional[E
Returns:
Tuple of (should_encrypt, encryption_key)
Raises:
HTTPException: If project is confidential but encryption is not available
"""
# Only encrypt for confidential projects
if project.security_level != "confidential":
@@ -125,11 +128,14 @@ def should_encrypt_file(project: Project, db: Session) -> tuple[bool, Optional[E
# Check if encryption is available
if not encryption_service.is_encryption_available():
logger.warning(
logger.error(
f"Project {project.id} is confidential but encryption is not configured. "
"Files will be stored unencrypted."
"Rejecting file upload to maintain security."
)
raise HTTPException(
status_code=400,
detail="Confidential project requires encryption. Please configure ENCRYPTION_MASTER_KEY environment variable."
)
return False, None
# Get active encryption key
active_key = db.query(EncryptionKey).filter(
@@ -137,11 +143,14 @@ def should_encrypt_file(project: Project, db: Session) -> tuple[bool, Optional[E
).first()
if not active_key:
logger.warning(
logger.error(
f"Project {project.id} is confidential but no active encryption key exists. "
"Files will be stored unencrypted. Create a key using /api/admin/encryption-keys/rotate"
"Rejecting file upload to maintain security."
)
raise HTTPException(
status_code=400,
detail="Confidential project requires encryption. Please create an active encryption key first."
)
return False, None
return True, active_key