From 0ac135539b4cb205da7b60c6c6cec110f33e74cc Mon Sep 17 00:00:00 2001 From: Hector Ros Date: Tue, 20 Jan 2026 02:10:19 +0100 Subject: [PATCH] Improve UI: hierarchical navigation + task deletion - Add delete button to tasks with confirmation - Restructure Dashboard: select Project first, then view its Tasks - Remove global Tasks tab, tasks are now scoped to project - Add back button from project view to projects list - Pre-select project when creating task from project view - Make project cards clickable - Better UX with clear navigation flow Co-Authored-By: Claude Sonnet 4.5 (1M context) --- src/components/CreateTaskModal.tsx | 12 ++- src/components/ProjectList.tsx | 9 +- src/components/TaskList.tsx | 34 +++++++- src/pages/Dashboard.tsx | 130 +++++++++++++++++------------ 4 files changed, 125 insertions(+), 60 deletions(-) diff --git a/src/components/CreateTaskModal.tsx b/src/components/CreateTaskModal.tsx index 508a77e..22dfded 100644 --- a/src/components/CreateTaskModal.tsx +++ b/src/components/CreateTaskModal.tsx @@ -7,15 +7,23 @@ interface CreateTaskModalProps { onClose: () => void onCreated: () => void projects: Project[] + selectedProjectId?: string } -export default function CreateTaskModal({ isOpen, onClose, onCreated, projects }: CreateTaskModalProps) { +export default function CreateTaskModal({ isOpen, onClose, onCreated, projects, selectedProjectId }: CreateTaskModalProps) { const [formData, setFormData] = useState({ - projectId: '', + projectId: selectedProjectId || '', title: '', description: '', priority: 'medium', }) + + // Update projectId when selectedProjectId changes + React.useEffect(() => { + if (selectedProjectId) { + setFormData((prev) => ({ ...prev, projectId: selectedProjectId })) + } + }, [selectedProjectId]) const [loading, setLoading] = useState(false) const [error, setError] = useState('') diff --git a/src/components/ProjectList.tsx b/src/components/ProjectList.tsx index 6345012..f6ee60b 100644 --- a/src/components/ProjectList.tsx +++ b/src/components/ProjectList.tsx @@ -4,9 +4,10 @@ import type { Project } from '../types' interface ProjectListProps { projects: Project[] onRefresh: () => void + onSelectProject: (project: Project) => void } -export default function ProjectList({ projects, onRefresh }: ProjectListProps) { +export default function ProjectList({ projects, onRefresh, onSelectProject }: ProjectListProps) { const getStatusColor = (status: string) => { switch (status) { case 'active': @@ -31,7 +32,11 @@ export default function ProjectList({ projects, onRefresh }: ProjectListProps) { return (
{projects.map((project) => ( -
+
onSelectProject(project)} + >

{project.name}

diff --git a/src/components/TaskList.tsx b/src/components/TaskList.tsx index 515a9f4..df678d7 100644 --- a/src/components/TaskList.tsx +++ b/src/components/TaskList.tsx @@ -1,4 +1,5 @@ -import React from 'react' +import React, { useState } from 'react' +import apiClient from '../api/client' import type { Task } from '../types' interface TaskListProps { @@ -7,6 +8,23 @@ interface TaskListProps { } export default function TaskList({ tasks, onRefresh }: TaskListProps) { + const [deleting, setDeleting] = useState(null) + + const handleDelete = async (taskId: string) => { + if (!confirm('Are you sure you want to delete this task?')) return + + setDeleting(taskId) + try { + await apiClient.delete(`/tasks/${taskId}`) + onRefresh() + } catch (error) { + console.error('Failed to delete task:', error) + alert('Failed to delete task') + } finally { + setDeleting(null) + } + } + const getStateColor = (state: string) => { switch (state) { case 'backlog': @@ -54,8 +72,18 @@ export default function TaskList({ tasks, onRefresh }: TaskListProps) { return (
{tasks.map((task) => ( -
-
+
+ +

{task.title}

diff --git a/src/pages/Dashboard.tsx b/src/pages/Dashboard.tsx index be6a15e..d7798dc 100644 --- a/src/pages/Dashboard.tsx +++ b/src/pages/Dashboard.tsx @@ -13,10 +13,16 @@ export default function Dashboard() { const [tasks, setTasks] = useState([]) const [agents, setAgents] = useState([]) const [loading, setLoading] = useState(true) - const [activeTab, setActiveTab] = useState<'projects' | 'tasks' | 'agents'>('projects') + const [selectedProject, setSelectedProject] = useState(null) + const [view, setView] = useState<'projects' | 'agents'>('projects') const [showProjectModal, setShowProjectModal] = useState(false) const [showTaskModal, setShowTaskModal] = useState(false) + // Filter tasks for selected project + const filteredTasks = selectedProject + ? tasks.filter((t) => t.projectId === selectedProject.id) + : [] + useEffect(() => { loadData() // Refresh data every 10 seconds @@ -54,68 +60,85 @@ export default function Dashboard() {
-

AiWorker Dashboard

-

Manage your AI agents and development tasks

+ {selectedProject ? ( +
+ +

{selectedProject.name}

+

{selectedProject.description || 'Project tasks and details'}

+
+ ) : ( +
+

AiWorker Dashboard

+

Manage your AI agents and development tasks

+
+ )}
- - + {selectedProject ? ( + + ) : ( + + )}
- {/* Tabs */} -
- -
+ {/* Navigation */} + {!selectedProject && ( +
+ +
+ )} {/* Content */}
- {activeTab === 'projects' && } - {activeTab === 'tasks' && } - {activeTab === 'agents' && } + {selectedProject ? ( + + ) : view === 'projects' ? ( + + ) : ( + + )}
@@ -130,6 +153,7 @@ export default function Dashboard() { onClose={() => setShowTaskModal(false)} onCreated={loadData} projects={projects} + selectedProjectId={selectedProject?.id} />
)