feat(store): integrate task management reducers into the store
- Added taskManagementReducer, groupingReducer, and selectionReducer to the Redux store. - Organized imports and store configuration for better clarity and maintainability.
This commit is contained in:
429
docs/enhanced-task-management-technical-guide.md
Normal file
429
docs/enhanced-task-management-technical-guide.md
Normal file
@@ -0,0 +1,429 @@
|
||||
# Enhanced Task Management: Technical Guide
|
||||
|
||||
## Overview
|
||||
The Enhanced Task Management system is a comprehensive React-based interface built on top of WorkLenz's existing task infrastructure. It provides a modern, grouped view with drag-and-drop functionality, bulk operations, and responsive design.
|
||||
|
||||
## Architecture
|
||||
|
||||
### Component Structure
|
||||
```
|
||||
src/components/task-management/
|
||||
├── TaskListBoard.tsx # Main container with DnD context
|
||||
├── TaskGroup.tsx # Individual group with collapse/expand
|
||||
├── TaskRow.tsx # Task display with rich metadata
|
||||
├── GroupingSelector.tsx # Grouping method switcher
|
||||
└── BulkActionBar.tsx # Bulk operations toolbar
|
||||
```
|
||||
|
||||
### Integration Points
|
||||
The system integrates with existing WorkLenz infrastructure:
|
||||
|
||||
- **Redux Store:** Uses `tasks.slice.ts` for state management
|
||||
- **Types:** Leverages existing TypeScript interfaces
|
||||
- **API Services:** Works with existing task API endpoints
|
||||
- **WebSocket:** Supports real-time updates via existing socket system
|
||||
|
||||
## Core Components
|
||||
|
||||
### TaskListBoard.tsx
|
||||
Main orchestrator component that provides:
|
||||
|
||||
- **DnD Context:** @dnd-kit drag-and-drop functionality
|
||||
- **State Management:** Redux integration for task data
|
||||
- **Event Handling:** Drag events and bulk operations
|
||||
- **Layout Structure:** Header controls and group container
|
||||
|
||||
#### Key Props
|
||||
```typescript
|
||||
interface TaskListBoardProps {
|
||||
projectId: string; // Required: Project identifier
|
||||
className?: string; // Optional: Additional CSS classes
|
||||
}
|
||||
```
|
||||
|
||||
#### Redux Selectors Used
|
||||
```typescript
|
||||
const {
|
||||
taskGroups, // ITaskListGroup[] - Grouped task data
|
||||
loadingGroups, // boolean - Loading state
|
||||
error, // string | null - Error state
|
||||
groupBy, // IGroupBy - Current grouping method
|
||||
search, // string | null - Search filter
|
||||
archived, // boolean - Show archived tasks
|
||||
} = useSelector((state: RootState) => state.taskReducer);
|
||||
```
|
||||
|
||||
### TaskGroup.tsx
|
||||
Renders individual task groups with:
|
||||
|
||||
- **Collapsible Headers:** Expand/collapse functionality
|
||||
- **Progress Indicators:** Visual completion progress
|
||||
- **Drop Zones:** Accept dropped tasks from other groups
|
||||
- **Group Statistics:** Task counts and completion rates
|
||||
|
||||
#### Key Props
|
||||
```typescript
|
||||
interface TaskGroupProps {
|
||||
group: ITaskListGroup; // Group data with tasks
|
||||
projectId: string; // Project context
|
||||
currentGrouping: IGroupBy; // Current grouping mode
|
||||
selectedTaskIds: string[]; // Selected task IDs
|
||||
onAddTask?: (groupId: string) => void;
|
||||
onToggleCollapse?: (groupId: string) => void;
|
||||
}
|
||||
```
|
||||
|
||||
### TaskRow.tsx
|
||||
Individual task display featuring:
|
||||
|
||||
- **Rich Metadata:** Progress, assignees, labels, due dates
|
||||
- **Drag Handles:** Sortable within and between groups
|
||||
- **Selection:** Multi-select with checkboxes
|
||||
- **Subtask Support:** Expandable hierarchy display
|
||||
|
||||
#### Key Props
|
||||
```typescript
|
||||
interface TaskRowProps {
|
||||
task: IProjectTask; // Task data
|
||||
projectId: string; // Project context
|
||||
groupId: string; // Parent group ID
|
||||
currentGrouping: IGroupBy; // Current grouping mode
|
||||
isSelected: boolean; // Selection state
|
||||
isDragOverlay?: boolean; // Drag overlay rendering
|
||||
index?: number; // Position in group
|
||||
onSelect?: (taskId: string, selected: boolean) => void;
|
||||
onToggleSubtasks?: (taskId: string) => void;
|
||||
}
|
||||
```
|
||||
|
||||
## State Management
|
||||
|
||||
### Redux Integration
|
||||
The system uses existing WorkLenz Redux patterns:
|
||||
|
||||
```typescript
|
||||
// Primary slice used
|
||||
import {
|
||||
fetchTaskGroups, // Async thunk for loading data
|
||||
reorderTasks, // Update task order/group
|
||||
setGroup, // Change grouping method
|
||||
updateTaskStatus, // Update individual task status
|
||||
updateTaskPriority, // Update individual task priority
|
||||
// ... other existing actions
|
||||
} from '@/features/tasks/tasks.slice';
|
||||
```
|
||||
|
||||
### Data Flow
|
||||
1. **Component Mount:** `TaskListBoard` dispatches `fetchTaskGroups(projectId)`
|
||||
2. **Group Changes:** `setGroup(newGroupBy)` triggers data reorganization
|
||||
3. **Drag Operations:** `reorderTasks()` updates task positions and properties
|
||||
4. **Real-time Updates:** WebSocket events update Redux state automatically
|
||||
|
||||
## Drag and Drop Implementation
|
||||
|
||||
### DnD Kit Integration
|
||||
Uses @dnd-kit for modern, accessible drag-and-drop:
|
||||
|
||||
```typescript
|
||||
// Sensors for different input methods
|
||||
const sensors = useSensors(
|
||||
useSensor(PointerSensor, {
|
||||
activationConstraint: { distance: 8 }
|
||||
}),
|
||||
useSensor(KeyboardSensor, {
|
||||
coordinateGetter: sortableKeyboardCoordinates
|
||||
})
|
||||
);
|
||||
```
|
||||
|
||||
### Drag Event Handling
|
||||
```typescript
|
||||
const handleDragEnd = (event: DragEndEvent) => {
|
||||
const { active, over } = event;
|
||||
|
||||
// Determine source and target
|
||||
const sourceGroup = findTaskGroup(active.id);
|
||||
const targetGroup = findTargetGroup(over?.id);
|
||||
|
||||
// Update task arrays and dispatch changes
|
||||
dispatch(reorderTasks({
|
||||
activeGroupId: sourceGroup.id,
|
||||
overGroupId: targetGroup.id,
|
||||
fromIndex: sourceIndex,
|
||||
toIndex: targetIndex,
|
||||
task: movedTask,
|
||||
updatedSourceTasks,
|
||||
updatedTargetTasks,
|
||||
}));
|
||||
};
|
||||
```
|
||||
|
||||
### Smart Property Updates
|
||||
When tasks are moved between groups, properties update automatically:
|
||||
|
||||
- **Status Grouping:** Moving to "Done" group sets task status to "done"
|
||||
- **Priority Grouping:** Moving to "High" group sets task priority to "high"
|
||||
- **Phase Grouping:** Moving to "Testing" group sets task phase to "testing"
|
||||
|
||||
## Bulk Operations
|
||||
|
||||
### Selection State Management
|
||||
```typescript
|
||||
// Local state for task selection
|
||||
const [selectedTaskIds, setSelectedTaskIds] = useState<string[]>([]);
|
||||
|
||||
// Selection handlers
|
||||
const handleTaskSelect = (taskId: string, selected: boolean) => {
|
||||
if (selected) {
|
||||
setSelectedTaskIds(prev => [...prev, taskId]);
|
||||
} else {
|
||||
setSelectedTaskIds(prev => prev.filter(id => id !== taskId));
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
### Context-Aware Actions
|
||||
Bulk actions adapt to current grouping:
|
||||
|
||||
```typescript
|
||||
// Only show status changes when not grouped by status
|
||||
{currentGrouping !== 'status' && (
|
||||
<Dropdown overlay={statusMenu}>
|
||||
<Button>Change Status</Button>
|
||||
</Dropdown>
|
||||
)}
|
||||
```
|
||||
|
||||
## Performance Optimizations
|
||||
|
||||
### Memoized Selectors
|
||||
```typescript
|
||||
// Expensive group calculations are memoized
|
||||
const taskGroups = useMemo(() => {
|
||||
return createGroupsFromTasks(tasks, currentGrouping);
|
||||
}, [tasks, currentGrouping]);
|
||||
```
|
||||
|
||||
### Virtual Scrolling Ready
|
||||
For large datasets, the system is prepared for react-window integration:
|
||||
|
||||
```typescript
|
||||
// Large group detection
|
||||
const shouldVirtualize = group.tasks.length > 100;
|
||||
|
||||
return shouldVirtualize ? (
|
||||
<VirtualizedTaskList tasks={group.tasks} />
|
||||
) : (
|
||||
<StandardTaskList tasks={group.tasks} />
|
||||
);
|
||||
```
|
||||
|
||||
### Optimistic Updates
|
||||
UI updates immediately while API calls process in background:
|
||||
|
||||
```typescript
|
||||
// Immediate UI update
|
||||
dispatch(updateTaskStatusOptimistically(taskId, newStatus));
|
||||
|
||||
// API call with rollback on error
|
||||
try {
|
||||
await updateTaskStatus(taskId, newStatus);
|
||||
} catch (error) {
|
||||
dispatch(rollbackTaskStatusUpdate(taskId));
|
||||
}
|
||||
```
|
||||
|
||||
## Responsive Design
|
||||
|
||||
### Breakpoint Strategy
|
||||
```css
|
||||
/* Mobile-first responsive design */
|
||||
.task-row {
|
||||
padding: 12px;
|
||||
}
|
||||
|
||||
@media (min-width: 768px) {
|
||||
.task-row {
|
||||
padding: 16px;
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 1024px) {
|
||||
.task-row {
|
||||
padding: 20px;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Progressive Enhancement
|
||||
- **Mobile:** Essential information only
|
||||
- **Tablet:** Additional metadata visible
|
||||
- **Desktop:** Full feature set with optimal layout
|
||||
|
||||
## Accessibility
|
||||
|
||||
### ARIA Implementation
|
||||
```typescript
|
||||
// Proper ARIA labels for screen readers
|
||||
<div
|
||||
role="button"
|
||||
aria-label={`Move task ${task.name}`}
|
||||
tabIndex={0}
|
||||
{...dragHandleProps}
|
||||
>
|
||||
<DragOutlined />
|
||||
</div>
|
||||
```
|
||||
|
||||
### Keyboard Navigation
|
||||
- **Tab:** Navigate between elements
|
||||
- **Space:** Select/deselect tasks
|
||||
- **Enter:** Activate buttons
|
||||
- **Arrows:** Navigate sortable lists with keyboard sensor
|
||||
|
||||
### Focus Management
|
||||
```typescript
|
||||
// Maintain focus during dynamic updates
|
||||
useEffect(() => {
|
||||
if (shouldFocusTask) {
|
||||
taskRef.current?.focus();
|
||||
}
|
||||
}, [taskGroups]);
|
||||
```
|
||||
|
||||
## WebSocket Integration
|
||||
|
||||
### Real-time Updates
|
||||
The system subscribes to existing WorkLenz WebSocket events:
|
||||
|
||||
```typescript
|
||||
// Socket event handlers (existing WorkLenz patterns)
|
||||
socket.on('TASK_STATUS_CHANGED', (data) => {
|
||||
dispatch(updateTaskStatus(data));
|
||||
});
|
||||
|
||||
socket.on('TASK_PROGRESS_UPDATED', (data) => {
|
||||
dispatch(updateTaskProgress(data));
|
||||
});
|
||||
```
|
||||
|
||||
### Live Collaboration
|
||||
- Multiple users can work simultaneously
|
||||
- Changes appear in real-time
|
||||
- Conflict resolution through server-side validation
|
||||
|
||||
## API Integration
|
||||
|
||||
### Existing Endpoints Used
|
||||
```typescript
|
||||
// Uses existing WorkLenz API services
|
||||
import { tasksApiService } from '@/api/tasks/tasks.api.service';
|
||||
|
||||
// Task data fetching
|
||||
tasksApiService.getTaskList(config);
|
||||
|
||||
// Task updates
|
||||
tasksApiService.updateTask(taskId, changes);
|
||||
|
||||
// Bulk operations
|
||||
tasksApiService.bulkUpdateTasks(taskIds, changes);
|
||||
```
|
||||
|
||||
### Error Handling
|
||||
```typescript
|
||||
try {
|
||||
await dispatch(fetchTaskGroups(projectId));
|
||||
} catch (error) {
|
||||
// Display user-friendly error message
|
||||
message.error('Failed to load tasks. Please try again.');
|
||||
logger.error('Task loading error:', error);
|
||||
}
|
||||
```
|
||||
|
||||
## Testing Strategy
|
||||
|
||||
### Component Testing
|
||||
```typescript
|
||||
// Example test structure
|
||||
describe('TaskListBoard', () => {
|
||||
it('should render task groups correctly', () => {
|
||||
const mockTasks = generateMockTasks(10);
|
||||
render(<TaskListBoard projectId="test-project" />);
|
||||
|
||||
expect(screen.getByText('Tasks (10)')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('should handle drag and drop operations', async () => {
|
||||
// Test drag and drop functionality
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
### Integration Testing
|
||||
- Redux state management
|
||||
- API service integration
|
||||
- WebSocket event handling
|
||||
- Drag and drop operations
|
||||
|
||||
## Development Guidelines
|
||||
|
||||
### Code Organization
|
||||
- Follow existing WorkLenz patterns
|
||||
- Use TypeScript strictly
|
||||
- Implement proper error boundaries
|
||||
- Maintain accessibility standards
|
||||
|
||||
### Performance Considerations
|
||||
- Memoize expensive calculations
|
||||
- Implement virtual scrolling for large datasets
|
||||
- Debounce user input operations
|
||||
- Optimize re-render cycles
|
||||
|
||||
### Styling Standards
|
||||
- Use existing Ant Design components
|
||||
- Follow WorkLenz design system
|
||||
- Implement responsive breakpoints
|
||||
- Maintain dark mode compatibility
|
||||
|
||||
## Future Enhancements
|
||||
|
||||
### Planned Features
|
||||
- Custom column integration
|
||||
- Advanced filtering capabilities
|
||||
- Kanban board view
|
||||
- Enhanced time tracking
|
||||
- Task templates
|
||||
|
||||
### Extension Points
|
||||
The system is designed for easy extension:
|
||||
|
||||
```typescript
|
||||
// Plugin architecture ready
|
||||
interface TaskViewPlugin {
|
||||
name: string;
|
||||
component: React.ComponentType;
|
||||
supportedGroupings: IGroupBy[];
|
||||
}
|
||||
|
||||
const plugins: TaskViewPlugin[] = [
|
||||
{ name: 'kanban', component: KanbanView, supportedGroupings: ['status'] },
|
||||
{ name: 'timeline', component: TimelineView, supportedGroupings: ['phase'] },
|
||||
];
|
||||
```
|
||||
|
||||
## Deployment Considerations
|
||||
|
||||
### Bundle Size
|
||||
- Tree-shake unused dependencies
|
||||
- Code-split large components
|
||||
- Optimize asset loading
|
||||
|
||||
### Browser Compatibility
|
||||
- Modern browsers (ES2020+)
|
||||
- Graceful degradation for older browsers
|
||||
- Progressive enhancement approach
|
||||
|
||||
### Performance Monitoring
|
||||
- Track component render times
|
||||
- Monitor API response times
|
||||
- Measure user interaction latency
|
||||
Reference in New Issue
Block a user