feat(KB-502): add dashboard multi-project UX with overview, drill-down, and setup wizard

- Add Project Overview page with responsive grid and health metrics

- Add Project selector dropdown for quick context switching

- Add Project drill-down with back navigation to overview

- Add Setup wizard with auto-detection and manual entry flows

- Add Global activity feed with project attribution badges

- Add Project health polling (active tasks, agents, completion counts)

- Add Empty states and loading skeletons for better UX

- Add Keyboard navigation support (arrow keys, enter, escape)

- Add LocalStorage persistence for wizard state and view preferences
This commit is contained in:
gsxdsm
2026-04-01 08:04:02 -07:00
parent 360af7d863
commit d8a591bd7f
7 changed files with 1015 additions and 215 deletions

View File

@@ -43,6 +43,10 @@ function truncatePath(path: string, maxLength: number = 40): string {
return `${start}...${end}`;
}
/**
* Compare two sets of ProjectCardProps for memo equality.
* Checks project properties and health metrics to determine if re-render is needed.
*/
function areProjectCardPropsEqual(previous: ProjectCardProps, next: ProjectCardProps): boolean {
if (previous.project.id !== next.project.id) return false;
if (previous.project.status !== next.project.status) return false;
@@ -66,6 +70,28 @@ function areProjectCardPropsEqual(previous: ProjectCardProps, next: ProjectCardP
);
}
/**
* Individual project card component showing project status, health metrics, and actions.
*
* Displays:
* - Project name and truncated path
* - Status badge (active, paused, errored, initializing)
* - Health metrics: active tasks, running agents, completed tasks
* - Last activity timestamp
* - Action buttons: Open, Pause/Resume, Remove
*
* @example
* ```tsx
* <ProjectCard
* project={registeredProject}
* health={projectHealth}
* onSelect={(p) => setCurrentProject(p)}
* onPause={(p) => pauseProject(p.id)}
* onResume={(p) => resumeProject(p.id)}
* onRemove={(p) => unregisterProject(p.id)}
* />
* ```
*/
function ProjectCardInner({
project,
health,