feat(ui): Nested task slots in worker dashboard
Backend: - Add active_tasks array to GET /worker-registry/workers response - Include task details: role, dispensary, running_seconds, progress Frontend: - Show nested task list under each worker with duration - Display empty slots when worker has capacity - Update pod visualization to show 3 task slot nodes - Active slots pulse blue, empty slots gray - Hover for task details (dispensary, duration, progress) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -430,9 +430,59 @@ router.get('/workers', async (req: Request, res: Response) => {
|
||||
FROM worker_registry
|
||||
`);
|
||||
|
||||
// Get active tasks for all workers (for nested task view)
|
||||
const { rows: activeTasks } = await pool.query(`
|
||||
SELECT
|
||||
t.worker_id,
|
||||
t.id as task_id,
|
||||
t.role,
|
||||
t.status as task_status,
|
||||
t.started_at,
|
||||
t.progress,
|
||||
t.progress_message,
|
||||
EXTRACT(EPOCH FROM (NOW() - t.started_at))::int as running_seconds,
|
||||
d.id as dispensary_id,
|
||||
d.name as dispensary_name,
|
||||
d.city as dispensary_city,
|
||||
d.state as dispensary_state
|
||||
FROM worker_tasks t
|
||||
LEFT JOIN dispensaries d ON t.dispensary_id = d.id
|
||||
WHERE t.status IN ('running', 'claimed')
|
||||
ORDER BY t.worker_id, t.started_at
|
||||
`);
|
||||
|
||||
// Group tasks by worker_id
|
||||
const tasksByWorker: Record<string, any[]> = {};
|
||||
for (const task of activeTasks) {
|
||||
if (!tasksByWorker[task.worker_id]) {
|
||||
tasksByWorker[task.worker_id] = [];
|
||||
}
|
||||
tasksByWorker[task.worker_id].push({
|
||||
task_id: task.task_id,
|
||||
role: task.role,
|
||||
status: task.task_status,
|
||||
started_at: task.started_at,
|
||||
running_seconds: task.running_seconds,
|
||||
progress: task.progress,
|
||||
progress_message: task.progress_message,
|
||||
dispensary: task.dispensary_name ? {
|
||||
id: task.dispensary_id,
|
||||
name: task.dispensary_name,
|
||||
city: task.dispensary_city,
|
||||
state: task.dispensary_state,
|
||||
} : null,
|
||||
});
|
||||
}
|
||||
|
||||
// Attach tasks to each worker
|
||||
const workersWithTasks = rows.map((worker: any) => ({
|
||||
...worker,
|
||||
active_tasks: tasksByWorker[worker.worker_id] || [],
|
||||
}));
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
workers: rows,
|
||||
workers: workersWithTasks,
|
||||
summary: summary[0]
|
||||
});
|
||||
} catch (error: any) {
|
||||
|
||||
Reference in New Issue
Block a user