Implement the main dashboard / projects list page for Syndarix as the landing page after login. The implementation includes: Dashboard Components: - QuickStats: Overview cards showing active projects, agents, issues, approvals - ProjectsSection: Grid/list view with filtering and sorting controls - ProjectCardGrid: Rich project cards for grid view - ProjectRowList: Compact rows for list view - ActivityFeed: Real-time activity sidebar with connection status - PerformanceCard: Performance metrics display - EmptyState: Call-to-action for new users - ProjectStatusBadge: Status indicator with icons - ComplexityIndicator: Visual complexity dots - ProgressBar: Accessible progress bar component Features: - Projects grid/list view with view mode toggle - Filter by status (all, active, paused, completed, archived) - Sort by recent, name, progress, or issues - Quick stats overview with counts - Real-time activity feed sidebar with live/reconnecting status - Performance metrics card - Create project button linking to wizard - Responsive layout for mobile/desktop - Loading skeleton states - Empty state for new users API Integration: - useProjects hook for fetching projects (mock data until backend ready) - useDashboardStats hook for statistics - TanStack Query for caching and data fetching Testing: - 37 unit tests covering all dashboard components - E2E test suite for dashboard functionality - Accessibility tests (keyboard nav, aria attributes, heading hierarchy) Technical: - TypeScript strict mode compliance - ESLint passing - WCAG AA accessibility compliance - Mobile-first responsive design - Dark mode support via semantic tokens - Follows design system guidelines
80 lines
1.5 KiB
TypeScript
80 lines
1.5 KiB
TypeScript
/**
|
|
* Agent Status Indicator
|
|
*
|
|
* Visual indicator for agent status (idle, working, error, etc.)
|
|
*/
|
|
|
|
'use client';
|
|
|
|
import { cn } from '@/lib/utils';
|
|
import type { AgentStatus } from './types';
|
|
|
|
const statusConfig: Record<AgentStatus, { color: string; label: string }> = {
|
|
idle: {
|
|
color: 'bg-yellow-500',
|
|
label: 'Idle',
|
|
},
|
|
active: {
|
|
color: 'bg-green-500',
|
|
label: 'Active',
|
|
},
|
|
working: {
|
|
color: 'bg-green-500 animate-pulse',
|
|
label: 'Working',
|
|
},
|
|
pending: {
|
|
color: 'bg-gray-400',
|
|
label: 'Pending',
|
|
},
|
|
error: {
|
|
color: 'bg-red-500',
|
|
label: 'Error',
|
|
},
|
|
terminated: {
|
|
color: 'bg-gray-600',
|
|
label: 'Terminated',
|
|
},
|
|
};
|
|
|
|
interface AgentStatusIndicatorProps {
|
|
status: AgentStatus;
|
|
size?: 'sm' | 'md' | 'lg';
|
|
showLabel?: boolean;
|
|
className?: string;
|
|
}
|
|
|
|
export function AgentStatusIndicator({
|
|
status,
|
|
size = 'sm',
|
|
showLabel = false,
|
|
className,
|
|
}: AgentStatusIndicatorProps) {
|
|
const config = statusConfig[status] || statusConfig.pending;
|
|
|
|
const sizeClasses = {
|
|
sm: 'h-2 w-2',
|
|
md: 'h-3 w-3',
|
|
lg: 'h-4 w-4',
|
|
};
|
|
|
|
return (
|
|
<span
|
|
className={cn('inline-flex items-center gap-1.5', className)}
|
|
role="status"
|
|
aria-label={`Status: ${config.label}`}
|
|
>
|
|
<span
|
|
className={cn(
|
|
'inline-block rounded-full',
|
|
sizeClasses[size],
|
|
config.color
|
|
)}
|
|
aria-hidden="true"
|
|
/>
|
|
{showLabel && (
|
|
<span className="text-xs text-muted-foreground">{config.label}</span>
|
|
)}
|
|
</span>
|
|
);
|
|
}
|