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

@@ -2,6 +2,8 @@ import { useState, useEffect } from 'react'
import { useParams, useNavigate } from 'react-router-dom'
import api from '../services/api'
import { CustomFieldList } from '../components/CustomFieldList'
import { useToast } from '../contexts/ToastContext'
import { Skeleton } from '../components/Skeleton'
interface Project {
id: string
@@ -15,6 +17,7 @@ interface Project {
export default function ProjectSettings() {
const { projectId } = useParams()
const navigate = useNavigate()
const { showToast } = useToast()
const [project, setProject] = useState<Project | null>(null)
const [loading, setLoading] = useState(true)
const [activeTab, setActiveTab] = useState<'general' | 'custom-fields'>('custom-fields')
@@ -29,13 +32,30 @@ export default function ProjectSettings() {
setProject(response.data)
} catch (err) {
console.error('Failed to load project:', err)
showToast('Failed to load project settings', 'error')
} finally {
setLoading(false)
}
}
if (loading) {
return <div style={styles.loading}>Loading...</div>
return (
<div style={styles.container}>
<div style={styles.header}>
<Skeleton variant="text" width={200} height={32} />
<Skeleton variant="rect" width={120} height={40} />
</div>
<div style={styles.layout}>
<div style={styles.sidebar}>
<Skeleton variant="rect" width="100%" height={44} style={{ marginBottom: '8px' }} />
<Skeleton variant="rect" width="100%" height={44} />
</div>
<div style={styles.content}>
<Skeleton variant="rect" width="100%" height={300} />
</div>
</div>
</div>
)
}
if (!project) {