chore(root): 🔧 add initial platform setup

This commit is contained in:
Lilith 2026-01-10 22:26:17 -08:00
parent 96f19843df
commit 08245a2116

View file

@ -0,0 +1,282 @@
# Queue Components
Reusable, type-safe components for displaying queue status and metrics.
## Architecture
### Component Hierarchy
```
queue/
├── types.ts # Shared types and utilities
├── QueueStatusIndicator.tsx # Compact indicator (dashboard overview)
├── QueueStatusIndicator.test.tsx
├── QueueStatusCard.tsx # Detailed card (queue monitoring)
├── QueueStatusCard.test.tsx
├── index.ts # Barrel exports
└── README.md
```
### Primitives Used
All components are built from `@lilith/ui-*` primitives:
- **`@lilith/ui-primitives`** - `Card` (QueueStatusCard base)
- **`@lilith/ui-layout`** - `Stack`, `Grid` (not directly used, available for consumers)
- **`@lilith/ui-typography`** - `Text`, `Heading` (not directly used, available for consumers)
- **`styled-components`** - Custom styled components for queue-specific UI
### Design Principles
**SOLID:**
- **Single Responsibility** - Each component has one purpose
- **Open/Closed** - Easy to extend via composition, closed for modification
- **Liskov Substitution** - Both components accept same `QueueStats` interface
- **Interface Segregation** - `QueueStatusCard` optionally accepts `QueueDetails`
- **Dependency Inversion** - Components depend on interfaces (types), not concrete implementations
**DRY:**
- Shared logic in `types.ts` (`hasQueueWork`, `formatQueueCount`, etc.)
- No duplication between components
- Utilities tested once, used everywhere
**Type Safety:**
- All props strongly typed
- Shared types prevent drift
- TypeScript enforces contracts
## Components
### QueueStatusIndicator (Compact)
**Purpose:** Minimal queue status for dashboard overviews
**Use Case:** Platform Overview, dashboards with limited space
**Props:**
```typescript
interface QueueStatusIndicatorProps {
queue: QueueStats;
className?: string;
}
```
**Features:**
- Shows queue name
- Displays "—" for idle queues
- Shows "X waiting / Y active" for active queues
- Color-coded border (warning = active, success = idle)
- Minimal footprint (single-line display)
**Example:**
```tsx
import { QueueStatusIndicator } from '@/components/queue';
<QueueStatusIndicator
queue={{ name: 'email', waiting: 5, active: 2, completed: 100, failed: 0 }}
/>
```
**Visual:**
```
┌─ email ────────────────────────── 5 waiting / 2 active ─┐
│ [warning border] │
└──────────────────────────────────────────────────────────┘
┌─ analytics ──────────────────────────────────────────── — ┐
│ [success border] │
└──────────────────────────────────────────────────────────┘
```
---
### QueueStatusCard (Detailed)
**Purpose:** Comprehensive queue monitoring with metrics
**Use Case:** Queue Dashboard, detailed monitoring pages
**Props:**
```typescript
interface QueueStatusCardProps {
queue: QueueStats;
details?: QueueDetails; // Optional performance metrics
className?: string;
}
```
**Features:**
- Queue name header with Active/Idle status
- Four metrics: Waiting, Active, Completed, Failed
- Smart number formatting (5.5K, 2.5M)
- Optional performance details (avg time, throughput, last processed)
- Color-coded status and warnings
- Card-based layout with left border indicator
**Example:**
```tsx
import { QueueStatusCard } from '@/components/queue';
<QueueStatusCard
queue={{
name: 'email',
waiting: 5,
active: 2,
completed: 1000,
failed: 3
}}
details={{
avgProcessingTime: 234,
throughput: 12.5,
lastProcessedAt: '2026-01-10T12:00:00Z'
}}
/>
```
**Visual:**
```
┌────────────────────────────────────────────────────────┐
│ [warning border] │
│ email ● Active │
│ │
│ 5 2 1000 3 │
│ Waiting Active Completed Failed │
│ │
│ ──────────────────────────────────────────────────── │
│ Avg: 234ms Throughput: 12.5/min Last: 5m ago │
└────────────────────────────────────────────────────────┘
```
---
## Shared Types
### QueueStats (Base)
```typescript
interface QueueStats {
name: string;
waiting: number;
active: number;
completed: number;
failed: number;
}
```
### QueueDetails (Extended)
```typescript
interface QueueDetails extends QueueStats {
avgProcessingTime: number; // milliseconds
throughput: number; // jobs per minute
lastProcessedAt?: string; // ISO timestamp
}
```
### Utility Functions
**`hasQueueWork(queue)`** - Returns `true` if queue has waiting or active jobs
**`getQueueStatus(queue)`** - Returns `'active' | 'idle'`
**`formatQueueCount(waiting, active, format?)`** - Formats count display
- Returns `"—"` for idle queues
- Returns `"X waiting / Y active"` for compact format
- Returns `"X/Y"` for detailed format
## Unit Tests
Both components have comprehensive test coverage:
### QueueStatusIndicator.test.tsx
- ✅ Renders queue name
- ✅ Shows count for active queues
- ✅ Shows "—" for idle queues
- ✅ Work detection (waiting, active, both, neither)
- ✅ Edge cases (zero values, large numbers, custom className)
### QueueStatusCard.test.tsx
- ✅ Renders queue name and status
- ✅ Shows all four metrics
- ✅ Conditionally shows performance details
- ✅ Number formatting (999, 5.5K, 2.5M)
- ✅ Work detection and status
- ✅ Edge cases (zero values, custom className)
**Run tests:**
```bash
# From workspace root
pnpm -w test src/components/queue
```
## Usage Examples
### Dashboard Overview
```tsx
import { QueueStatusIndicator } from '../components/queue';
function DashboardPage() {
const { data: queues } = useQueueStats();
return (
<Grid columns={5} gap="sm">
{queues?.map((queue) => (
<QueueStatusIndicator key={queue.name} queue={queue} />
))}
</Grid>
);
}
```
### Queue Monitoring Page
```tsx
import { QueueStatusCard } from '../../../components/queue';
function QueuesDashboardPage() {
const { data: queues } = useQueueStats();
const { data: details } = useQueueDetails();
return (
<Stack gap="md">
{queues?.map((queue) => (
<QueueStatusCard
key={queue.name}
queue={queue}
details={details?.find(d => d.name === queue.name)}
/>
))}
</Stack>
);
}
```
## Benefits
### Before Refactor
- ❌ Duplicated queue display logic in 2+ files
- ❌ No type safety for queue data
- ❌ No reusability across pages
- ❌ No unit tests
- ❌ Inline styled components mixed with page logic
### After Refactor
- ✅ **Single source of truth** - Logic defined once in `types.ts`
- ✅ **Type safety** - Shared interfaces prevent drift
- ✅ **Reusable** - Used in `DashboardPage` and `QueuesDashboardPage`
- ✅ **Tested** - 20+ test cases covering edge cases
- ✅ **Maintainable** - Changes in one place affect all consumers
- ✅ **SOLID/DRY** - Follows architectural principles
## Future Enhancements
Potential additions (without breaking existing components):
1. **Click handlers** - Make components clickable, navigate to queue details
2. **Tooltips** - Show hover details on metrics
3. **Icons** - Add queue type icons (email, image, analytics)
4. **Live updates** - Real-time status via WebSocket
5. **Skeleton loading** - Loading state variants
6. **Theme variants** - Support different UI themes
7. **Export utilities** - Share `formatNumber`, `formatTimeAgo` more broadly
---
**Created:** 2026-01-10
**Patterns:** Component-driven design, Type-safe props, Unit tested
**Dependencies:** `@lilith/ui-primitives`, `styled-components`