Add comprehensive development roadmap via GitHub Issues

Created 10 detailed GitHub issues covering:
- Project activation and management UI (#1-2)
- Worker node coordination and visualization (#3-4)
- Automated GitHub repository scanning (#5)
- Intelligent model-to-issue matching (#6)
- Multi-model task execution system (#7)
- N8N workflow integration (#8)
- Hive-Bzzz P2P bridge (#9)
- Peer assistance protocol (#10)

Each issue includes detailed specifications, acceptance criteria,
technical implementation notes, and dependency mapping.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
anthonyrawlins
2025-07-12 19:41:01 +10:00
parent 9a6a06da89
commit e89f2f4b7b
4980 changed files with 1501266 additions and 57 deletions

View File

@@ -0,0 +1,566 @@
import type { Meta, StoryObj } from '@storybook/react';
import DataTable, { Column } from './DataTable';
import { Badge } from './badge';
import { Button } from './button';
/**
* DataTable component for Hive UI
*
* A powerful and flexible data table component with sorting, filtering, searching, and pagination.
* Perfect for displaying agent lists, task queues, and workflow executions.
*/
const meta = {
title: 'UI Components/DataTable',
component: DataTable,
parameters: {
layout: 'padded',
docs: {
description: {
component: `
The DataTable component is a comprehensive solution for displaying tabular data in the Hive application.
It provides powerful features for data manipulation and user interaction.
## Features
- **Sorting**: Click column headers to sort data ascending/descending
- **Filtering**: Column-specific filters with text, select, and numeric options
- **Searching**: Global search across all visible columns
- **Pagination**: Built-in pagination with configurable page sizes
- **Custom Rendering**: Custom cell renderers for complex content
- **Row Actions**: Clickable rows with custom action handlers
- **Loading States**: Built-in loading indicator
- **Responsive**: Horizontal scrolling on smaller screens
## Column Configuration
\`\`\`tsx
const columns: Column<Agent>[] = [
{
key: 'id',
header: 'ID',
sortable: true,
filterable: true,
width: 'w-32'
},
{
key: 'status',
header: 'Status',
sortable: true,
filterable: true,
filterType: 'select',
filterOptions: [
{ label: 'Available', value: 'available' },
{ label: 'Busy', value: 'busy' },
{ label: 'Offline', value: 'offline' }
],
render: (agent, value) => (
<Badge variant={getStatusVariant(value)}>{value}</Badge>
)
}
];
\`\`\`
## Usage
\`\`\`tsx
import DataTable from '@/components/ui/DataTable';
<DataTable
data={agents}
columns={columns}
searchable={true}
pageSize={10}
onRowClick={(agent) => navigate(\`/agents/\${agent.id}\`)}
/>
\`\`\`
`,
},
},
},
tags: ['autodocs'],
argTypes: {
data: {
control: false,
description: 'Array of data objects to display',
},
columns: {
control: false,
description: 'Column configuration array',
},
searchable: {
control: 'boolean',
description: 'Enable global search functionality',
},
searchPlaceholder: {
control: 'text',
description: 'Placeholder text for search input',
},
pageSize: {
control: 'number',
description: 'Number of rows per page',
},
loading: {
control: 'boolean',
description: 'Show loading state',
},
emptyMessage: {
control: 'text',
description: 'Message displayed when no data is available',
},
onRowClick: {
action: 'row-clicked',
description: 'Handler for row click events',
},
},
} satisfies Meta<typeof DataTable>;
export default meta;
type Story = StoryObj<typeof meta>;
// Sample data for stories
interface Agent {
id: string;
name: string;
model: string;
status: 'available' | 'busy' | 'offline';
current_tasks: number;
max_concurrent: number;
specialization: string;
last_heartbeat: string;
utilization: number;
}
const sampleAgents: Agent[] = [
{
id: 'walnut-codellama',
name: 'Walnut CodeLlama',
model: 'codellama:34b',
status: 'available',
current_tasks: 2,
max_concurrent: 4,
specialization: 'kernel_dev',
last_heartbeat: '2024-01-15T10:30:00Z',
utilization: 0.5,
},
{
id: 'oak-gemma',
name: 'Oak Gemma',
model: 'gemma:7b',
status: 'busy',
current_tasks: 3,
max_concurrent: 3,
specialization: 'tester',
last_heartbeat: '2024-01-15T10:29:45Z',
utilization: 1.0,
},
{
id: 'ironwood-llama',
name: 'Ironwood Llama',
model: 'llama2:13b',
status: 'offline',
current_tasks: 0,
max_concurrent: 2,
specialization: 'docs_writer',
last_heartbeat: '2024-01-15T09:15:22Z',
utilization: 0.0,
},
{
id: 'pine-mistral',
name: 'Pine Mistral',
model: 'mistral:7b',
status: 'available',
current_tasks: 1,
max_concurrent: 4,
specialization: 'general_ai',
last_heartbeat: '2024-01-15T10:29:58Z',
utilization: 0.25,
},
{
id: 'birch-phi',
name: 'Birch Phi',
model: 'phi:3b',
status: 'busy',
current_tasks: 2,
max_concurrent: 2,
specialization: 'profiler',
last_heartbeat: '2024-01-15T10:30:12Z',
utilization: 1.0,
},
];
const getStatusVariant = (status: string) => {
switch (status) {
case 'available': return 'success';
case 'busy': return 'warning';
case 'offline': return 'destructive';
default: return 'secondary';
}
};
const agentColumns: Column<Agent>[] = [
{
key: 'id',
header: 'Agent ID',
sortable: true,
filterable: true,
width: 'w-40',
},
{
key: 'name',
header: 'Name',
sortable: true,
filterable: true,
},
{
key: 'model',
header: 'Model',
sortable: true,
filterable: true,
filterType: 'select',
filterOptions: [
{ label: 'CodeLlama 34B', value: 'codellama:34b' },
{ label: 'Gemma 7B', value: 'gemma:7b' },
{ label: 'Llama2 13B', value: 'llama2:13b' },
{ label: 'Mistral 7B', value: 'mistral:7b' },
{ label: 'Phi 3B', value: 'phi:3b' },
],
},
{
key: 'status',
header: 'Status',
sortable: true,
filterable: true,
filterType: 'select',
filterOptions: [
{ label: 'Available', value: 'available' },
{ label: 'Busy', value: 'busy' },
{ label: 'Offline', value: 'offline' },
],
render: (agent, value) => (
<Badge variant={getStatusVariant(value) as any}>
{value.charAt(0).toUpperCase() + value.slice(1)}
</Badge>
),
},
{
key: 'current_tasks',
header: 'Tasks',
sortable: true,
filterable: true,
filterType: 'number',
render: (agent) => `${agent.current_tasks} / ${agent.max_concurrent}`,
},
{
key: 'specialization',
header: 'Specialization',
sortable: true,
filterable: true,
filterType: 'select',
filterOptions: [
{ label: 'Kernel Development', value: 'kernel_dev' },
{ label: 'Testing', value: 'tester' },
{ label: 'Documentation', value: 'docs_writer' },
{ label: 'General AI', value: 'general_ai' },
{ label: 'Profiler', value: 'profiler' },
],
},
{
key: 'utilization',
header: 'Utilization',
sortable: true,
render: (agent) => {
const percentage = Math.round(agent.utilization * 100);
return (
<div className="flex items-center space-x-2">
<div className="w-16 bg-gray-200 rounded-full h-2">
<div
className={`h-2 rounded-full ${
percentage >= 80 ? 'bg-red-500' : percentage >= 50 ? 'bg-yellow-500' : 'bg-green-500'
}`}
style={{ width: `${percentage}%` }}
/>
</div>
<span className="text-sm">{percentage}%</span>
</div>
);
},
},
];
/**
* Basic agent data table
*/
export const Default: Story = {
args: {
data: sampleAgents,
columns: agentColumns,
searchable: true,
pageSize: 10,
loading: false,
},
};
/**
* Loading state
*/
export const Loading: Story = {
args: {
data: [],
columns: agentColumns,
loading: true,
},
};
/**
* Empty state
*/
export const Empty: Story = {
args: {
data: [],
columns: agentColumns,
loading: false,
emptyMessage: 'No agents found. Register some agents to get started.',
},
};
/**
* Small page size for pagination demo
*/
export const WithPagination: Story = {
args: {
data: [...sampleAgents, ...sampleAgents, ...sampleAgents], // 15 items
columns: agentColumns,
pageSize: 3,
searchable: true,
},
};
/**
* Simple task data table
*/
export const TaskTable: Story = {
render: () => {
interface Task {
id: string;
type: string;
priority: number;
status: string;
assigned_agent: string;
created_at: string;
progress: number;
}
const tasks: Task[] = [
{
id: 'task-001',
type: 'code_analysis',
priority: 1,
status: 'in_progress',
assigned_agent: 'walnut-codellama',
created_at: '2024-01-15T10:00:00Z',
progress: 75,
},
{
id: 'task-002',
type: 'testing',
priority: 2,
status: 'completed',
assigned_agent: 'oak-gemma',
created_at: '2024-01-15T09:30:00Z',
progress: 100,
},
{
id: 'task-003',
type: 'documentation',
priority: 3,
status: 'pending',
assigned_agent: null,
created_at: '2024-01-15T10:15:00Z',
progress: 0,
},
];
const taskColumns: Column<Task>[] = [
{
key: 'id',
header: 'Task ID',
sortable: true,
filterable: true,
},
{
key: 'type',
header: 'Type',
sortable: true,
filterable: true,
filterType: 'select',
filterOptions: [
{ label: 'Code Analysis', value: 'code_analysis' },
{ label: 'Testing', value: 'testing' },
{ label: 'Documentation', value: 'documentation' },
],
},
{
key: 'priority',
header: 'Priority',
sortable: true,
filterable: true,
filterType: 'select',
filterOptions: [
{ label: 'Critical (1)', value: 1 },
{ label: 'High (2)', value: 2 },
{ label: 'Medium (3)', value: 3 },
],
render: (task) => {
const priority = task.priority;
const variant = priority === 1 ? 'destructive' : priority === 2 ? 'warning' : 'default';
const label = priority === 1 ? 'Critical' : priority === 2 ? 'High' : 'Medium';
return <Badge variant={variant as any}>{label}</Badge>;
},
},
{
key: 'status',
header: 'Status',
sortable: true,
filterable: true,
filterType: 'select',
filterOptions: [
{ label: 'Pending', value: 'pending' },
{ label: 'In Progress', value: 'in_progress' },
{ label: 'Completed', value: 'completed' },
],
render: (task, value) => {
const variant = value === 'completed' ? 'success' : value === 'in_progress' ? 'warning' : 'secondary';
return <Badge variant={variant as any}>{value.replace('_', ' ')}</Badge>;
},
},
{
key: 'assigned_agent',
header: 'Agent',
sortable: true,
filterable: true,
render: (task, value) => value || <span className="text-gray-400">Unassigned</span>,
},
{
key: 'progress',
header: 'Progress',
sortable: true,
render: (task) => (
<div className="flex items-center space-x-2">
<div className="w-16 bg-gray-200 rounded-full h-2">
<div
className="bg-blue-500 h-2 rounded-full"
style={{ width: `${task.progress}%` }}
/>
</div>
<span className="text-sm">{task.progress}%</span>
</div>
),
},
];
return (
<DataTable
data={tasks}
columns={taskColumns}
searchable={true}
pageSize={10}
emptyMessage="No tasks available"
/>
);
},
parameters: {
docs: {
description: {
story: 'Example task management table with custom rendering and status badges',
},
},
},
};
/**
* Interactive table with row actions
*/
export const WithRowActions: Story = {
render: () => {
const handleRowClick = (agent: Agent) => {
alert(`Clicked on agent: ${agent.name}`);
};
const columnsWithActions: Column<Agent>[] = [
...agentColumns,
{
key: 'actions',
header: 'Actions',
render: (agent) => (
<div className="flex space-x-2" onClick={(e) => e.stopPropagation()}>
<Button size="sm" variant="outline">
View
</Button>
<Button size="sm" variant="default">
Assign
</Button>
</div>
),
},
];
return (
<DataTable
data={sampleAgents}
columns={columnsWithActions}
searchable={true}
onRowClick={handleRowClick}
pageSize={5}
/>
);
},
parameters: {
docs: {
description: {
story: 'Table with clickable rows and action buttons in cells',
},
},
},
};
/**
* Minimal table without search and filters
*/
export const Minimal: Story = {
render: () => {
const minimalColumns: Column<Agent>[] = [
{
key: 'name',
header: 'Agent Name',
},
{
key: 'status',
header: 'Status',
render: (agent, value) => (
<Badge variant={getStatusVariant(value) as any}>
{value.charAt(0).toUpperCase() + value.slice(1)}
</Badge>
),
},
{
key: 'current_tasks',
header: 'Active Tasks',
render: (agent) => `${agent.current_tasks} / ${agent.max_concurrent}`,
},
];
return (
<DataTable
data={sampleAgents}
columns={minimalColumns}
searchable={false}
pageSize={10}
className="border-0 shadow-none"
/>
);
},
parameters: {
docs: {
description: {
story: 'Simplified table without search, filters, or advanced features',
},
},
},
};

View File

@@ -0,0 +1,258 @@
import type { Meta, StoryObj } from '@storybook/react';
import { Badge } from './badge';
/**
* Badge component for Hive UI
*
* A small status indicator component used to display labels, statuses, and categories.
* Perfect for showing agent statuses, task priorities, and workflow states.
*/
const meta = {
title: 'UI Components/Badge',
component: Badge,
parameters: {
layout: 'centered',
docs: {
description: {
component: `
The Badge component is used to display small labels and status indicators throughout the Hive application.
It's commonly used for showing agent statuses, task priorities, and other categorical information.
## Features
- Multiple color variants for different semantic meanings
- Consistent sizing and typography
- Rounded pill design for modern appearance
- Customizable through className prop
## Usage
\`\`\`tsx
import { Badge } from '@/components/ui/badge';
<Badge variant="success">Online</Badge>
<Badge variant="warning">Busy</Badge>
<Badge variant="destructive">Offline</Badge>
\`\`\`
## Semantic Meanings
- **default**: Primary information or neutral status
- **secondary**: Less important or secondary information
- **success**: Positive status (available, completed, healthy)
- **warning**: Attention needed (busy, pending, degraded)
- **destructive**: Negative status (error, failed, offline)
- **outline**: Minimal emphasis or placeholder
`,
},
},
},
tags: ['autodocs'],
argTypes: {
variant: {
control: 'select',
options: ['default', 'secondary', 'destructive', 'outline', 'success', 'warning'],
description: 'Visual variant of the badge',
},
className: {
control: 'text',
description: 'Additional CSS classes',
},
children: {
control: 'text',
description: 'Badge content',
},
},
} satisfies Meta<typeof Badge>;
export default meta;
type Story = StoryObj<typeof meta>;
/**
* Default blue badge
*/
export const Default: Story = {
args: {
children: 'Default',
variant: 'default',
},
};
/**
* Secondary gray badge
*/
export const Secondary: Story = {
args: {
children: 'Secondary',
variant: 'secondary',
},
};
/**
* Success green badge
*/
export const Success: Story = {
args: {
children: 'Available',
variant: 'success',
},
};
/**
* Warning yellow badge
*/
export const Warning: Story = {
args: {
children: 'Busy',
variant: 'warning',
},
};
/**
* Destructive red badge
*/
export const Destructive: Story = {
args: {
children: 'Offline',
variant: 'destructive',
},
};
/**
* Outline variant
*/
export const Outline: Story = {
args: {
children: 'Outline',
variant: 'outline',
},
};
/**
* All variants showcase
*/
export const AllVariants: Story = {
render: () => (
<div className="flex flex-wrap gap-2">
<Badge variant="default">Default</Badge>
<Badge variant="secondary">Secondary</Badge>
<Badge variant="success">Success</Badge>
<Badge variant="warning">Warning</Badge>
<Badge variant="destructive">Destructive</Badge>
<Badge variant="outline">Outline</Badge>
</div>
),
parameters: {
docs: {
description: {
story: 'All available badge variants displayed together',
},
},
},
};
/**
* Agent status badges as used in Hive
*/
export const AgentStatuses: Story = {
render: () => (
<div className="flex flex-wrap gap-2">
<Badge variant="success">Available</Badge>
<Badge variant="warning">Busy</Badge>
<Badge variant="destructive">Offline</Badge>
<Badge variant="secondary">Maintenance</Badge>
<Badge variant="default">Connected</Badge>
</div>
),
parameters: {
docs: {
description: {
story: 'Common agent status badges used throughout the Hive application',
},
},
},
};
/**
* Task priority badges
*/
export const TaskPriorities: Story = {
render: () => (
<div className="flex flex-wrap gap-2">
<Badge variant="destructive">Critical</Badge>
<Badge variant="warning">High</Badge>
<Badge variant="default">Medium</Badge>
<Badge variant="secondary">Low</Badge>
<Badge variant="outline">Background</Badge>
</div>
),
parameters: {
docs: {
description: {
story: 'Task priority badges with semantic color coding',
},
},
},
};
/**
* Task status badges
*/
export const TaskStatuses: Story = {
render: () => (
<div className="flex flex-wrap gap-2">
<Badge variant="secondary">Pending</Badge>
<Badge variant="warning">In Progress</Badge>
<Badge variant="success">Completed</Badge>
<Badge variant="destructive">Failed</Badge>
<Badge variant="outline">Cancelled</Badge>
</div>
),
parameters: {
docs: {
description: {
story: 'Task execution status badges used in task management',
},
},
},
};
/**
* Workflow status badges
*/
export const WorkflowStatuses: Story = {
render: () => (
<div className="flex flex-wrap gap-2">
<Badge variant="success">Active</Badge>
<Badge variant="warning">Running</Badge>
<Badge variant="secondary">Paused</Badge>
<Badge variant="destructive">Failed</Badge>
<Badge variant="outline">Draft</Badge>
</div>
),
parameters: {
docs: {
description: {
story: 'Workflow status badges used in workflow management',
},
},
},
};
/**
* Custom styled badges
*/
export const CustomStyling: Story = {
render: () => (
<div className="flex flex-wrap gap-2">
<Badge variant="default" className="text-lg px-4 py-1">Large Badge</Badge>
<Badge variant="success" className="uppercase tracking-wider">Success</Badge>
<Badge variant="warning" className="animate-pulse">Flashing</Badge>
<Badge variant="outline" className="border-dashed border-2">Dashed Border</Badge>
</div>
),
parameters: {
docs: {
description: {
story: 'Examples of custom styling applied to badges using the className prop',
},
},
},
};

View File

@@ -2,7 +2,7 @@ import React from 'react';
interface BadgeProps {
className?: string;
variant?: 'default' | 'secondary' | 'destructive' | 'outline';
variant?: 'default' | 'secondary' | 'destructive' | 'outline' | 'success' | 'warning';
children: React.ReactNode;
}
@@ -15,7 +15,9 @@ export const Badge: React.FC<BadgeProps> = ({
default: 'bg-blue-600 text-white',
secondary: 'bg-gray-100 text-gray-900',
destructive: 'bg-red-600 text-white',
outline: 'border border-gray-300 bg-white'
outline: 'border border-gray-300 bg-white',
success: 'bg-green-600 text-white',
warning: 'bg-yellow-600 text-white'
};
return (

View File

@@ -0,0 +1,241 @@
import type { Meta, StoryObj } from '@storybook/react';
import { Button } from './button';
/**
* Button component for Hive UI
*
* A versatile button component with multiple variants, sizes, and states.
* Supports all standard button functionality with consistent styling.
*/
const meta = {
title: 'UI Components/Button',
component: Button,
parameters: {
layout: 'centered',
docs: {
description: {
component: `
The Button component is a fundamental UI element used throughout the Hive application.
It provides consistent styling and behavior across different contexts.
## Features
- Multiple visual variants (default, destructive, outline, secondary, ghost)
- Different sizes (small, default, large)
- Disabled state support
- Loading state (future enhancement)
- Icon support (via children)
- Full accessibility support
## Usage
\`\`\`tsx
import { Button } from '@/components/ui/button';
<Button variant="default" size="default" onClick={handleClick}>
Click me
</Button>
\`\`\`
`,
},
},
},
tags: ['autodocs'],
argTypes: {
variant: {
control: 'select',
options: ['default', 'destructive', 'outline', 'secondary', 'ghost'],
description: 'Visual variant of the button',
},
size: {
control: 'select',
options: ['sm', 'default', 'lg'],
description: 'Size of the button',
},
disabled: {
control: 'boolean',
description: 'Whether the button is disabled',
},
type: {
control: 'select',
options: ['button', 'submit', 'reset'],
description: 'HTML button type',
},
children: {
control: 'text',
description: 'Button content',
},
onClick: {
action: 'clicked',
description: 'Click event handler',
},
},
args: {
onClick: () => console.log('Button clicked'),
},
} satisfies Meta<typeof Button>;
export default meta;
type Story = StoryObj<typeof meta>;
/**
* Default button style with primary blue color
*/
export const Default: Story = {
args: {
children: 'Default Button',
variant: 'default',
size: 'default',
},
};
/**
* Destructive variant for dangerous actions like deletion
*/
export const Destructive: Story = {
args: {
children: 'Delete Item',
variant: 'destructive',
size: 'default',
},
};
/**
* Outline variant for secondary actions
*/
export const Outline: Story = {
args: {
children: 'Outline Button',
variant: 'outline',
size: 'default',
},
};
/**
* Secondary variant for less important actions
*/
export const Secondary: Story = {
args: {
children: 'Secondary Button',
variant: 'secondary',
size: 'default',
},
};
/**
* Ghost variant for minimal styling
*/
export const Ghost: Story = {
args: {
children: 'Ghost Button',
variant: 'ghost',
size: 'default',
},
};
/**
* Small size variant
*/
export const Small: Story = {
args: {
children: 'Small Button',
variant: 'default',
size: 'sm',
},
};
/**
* Large size variant
*/
export const Large: Story = {
args: {
children: 'Large Button',
variant: 'default',
size: 'lg',
},
};
/**
* Disabled state
*/
export const Disabled: Story = {
args: {
children: 'Disabled Button',
variant: 'default',
size: 'default',
disabled: true,
},
};
/**
* All variants showcase
*/
export const AllVariants: Story = {
render: () => (
<div className="flex flex-wrap gap-4">
<Button variant="default">Default</Button>
<Button variant="destructive">Destructive</Button>
<Button variant="outline">Outline</Button>
<Button variant="secondary">Secondary</Button>
<Button variant="ghost">Ghost</Button>
</div>
),
parameters: {
docs: {
description: {
story: 'Showcase of all button variants side by side',
},
},
},
};
/**
* All sizes showcase
*/
export const AllSizes: Story = {
render: () => (
<div className="flex items-center gap-4">
<Button size="sm">Small</Button>
<Button size="default">Default</Button>
<Button size="lg">Large</Button>
</div>
),
parameters: {
docs: {
description: {
story: 'Showcase of all button sizes side by side',
},
},
},
};
/**
* Common Hive use cases
*/
export const HiveUseCases: Story = {
render: () => (
<div className="flex flex-col gap-4 max-w-md">
<div className="flex gap-2">
<Button variant="default">Create Agent</Button>
<Button variant="outline">View Details</Button>
</div>
<div className="flex gap-2">
<Button variant="default">Execute Task</Button>
<Button variant="secondary">Cancel</Button>
</div>
<div className="flex gap-2">
<Button variant="default">Deploy Workflow</Button>
<Button variant="destructive">Stop Execution</Button>
</div>
<div className="flex gap-2">
<Button variant="outline">Export Logs</Button>
<Button variant="ghost">Refresh</Button>
</div>
</div>
),
parameters: {
docs: {
description: {
story: 'Common button combinations used throughout the Hive application',
},
},
},
};

View File

@@ -0,0 +1,340 @@
import type { Meta, StoryObj } from '@storybook/react';
import { Card, CardHeader, CardTitle, CardDescription, CardContent } from './card';
import { Button } from './button';
import { Badge } from './badge';
/**
* Card component system for Hive UI
*
* A flexible card component system that provides a container for content.
* Includes header, title, description, and content sections.
*/
const meta = {
title: 'UI Components/Card',
component: Card,
parameters: {
layout: 'centered',
docs: {
description: {
component: `
The Card component system provides a structured way to display content in containers.
It's composed of several sub-components that work together to create consistent layouts.
## Components
- **Card**: Main container component
- **CardHeader**: Header section for titles and descriptions
- **CardTitle**: Primary title text
- **CardDescription**: Subtitle or description text
- **CardContent**: Main content area
## Features
- Consistent styling across the application
- Flexible composition with sub-components
- Responsive design support
- Shadow and border styling
- Customizable through className props
## Usage
\`\`\`tsx
import { Card, CardHeader, CardTitle, CardDescription, CardContent } from '@/components/ui/card';
<Card>
<CardHeader>
<CardTitle>Card Title</CardTitle>
<CardDescription>Card description goes here</CardDescription>
</CardHeader>
<CardContent>
<p>Card content goes here</p>
</CardContent>
</Card>
\`\`\`
`,
},
},
},
tags: ['autodocs'],
argTypes: {
className: {
control: 'text',
description: 'Additional CSS classes',
},
children: {
control: false,
description: 'Card content',
},
},
} satisfies Meta<typeof Card>;
export default meta;
type Story = StoryObj<typeof meta>;
/**
* Basic card with title and content
*/
export const Default: Story = {
render: () => (
<Card className="w-80">
<CardHeader>
<CardTitle>Default Card</CardTitle>
<CardDescription>
This is a basic card component with a title and description.
</CardDescription>
</CardHeader>
<CardContent>
<p>This is the main content area of the card where you can put any content.</p>
</CardContent>
</Card>
),
};
/**
* Card with only content, no header
*/
export const ContentOnly: Story = {
render: () => (
<Card className="w-80">
<CardContent>
<p>This card contains only content without a header section.</p>
</CardContent>
</Card>
),
};
/**
* Agent status card as used in Hive
*/
export const AgentStatusCard: Story = {
render: () => (
<Card className="w-96">
<CardHeader>
<div className="flex items-center justify-between">
<div>
<CardTitle>walnut-codellama</CardTitle>
<CardDescription>Code analysis specialist agent</CardDescription>
</div>
<Badge variant="success">Available</Badge>
</div>
</CardHeader>
<CardContent>
<div className="space-y-3">
<div className="flex justify-between text-sm">
<span className="text-gray-600">Model:</span>
<span>codellama:34b</span>
</div>
<div className="flex justify-between text-sm">
<span className="text-gray-600">Active Tasks:</span>
<span>2 / 4</span>
</div>
<div className="flex justify-between text-sm">
<span className="text-gray-600">Utilization:</span>
<span>50%</span>
</div>
<div className="flex gap-2 mt-4">
<Button size="sm" variant="outline">View Details</Button>
<Button size="sm" variant="default">Assign Task</Button>
</div>
</div>
</CardContent>
</Card>
),
parameters: {
docs: {
description: {
story: 'Example of how cards are used to display agent information in the Hive dashboard',
},
},
},
};
/**
* Task execution card as used in Hive
*/
export const TaskCard: Story = {
render: () => (
<Card className="w-96">
<CardHeader>
<div className="flex items-center justify-between">
<div>
<CardTitle>Code Analysis Task</CardTitle>
<CardDescription>task-abc123 5 minutes ago</CardDescription>
</div>
<Badge variant="warning">In Progress</Badge>
</div>
</CardHeader>
<CardContent>
<div className="space-y-3">
<div className="flex justify-between text-sm">
<span className="text-gray-600">Assigned Agent:</span>
<span>walnut-codellama</span>
</div>
<div className="flex justify-between text-sm">
<span className="text-gray-600">Priority:</span>
<span>High</span>
</div>
<div className="flex justify-between text-sm">
<span className="text-gray-600">Progress:</span>
<span>75%</span>
</div>
<div className="w-full bg-gray-200 rounded-full h-2 mt-2">
<div className="bg-blue-600 h-2 rounded-full" style={{ width: '75%' }}></div>
</div>
<div className="flex gap-2 mt-4">
<Button size="sm" variant="outline">View Logs</Button>
<Button size="sm" variant="destructive">Cancel</Button>
</div>
</div>
</CardContent>
</Card>
),
parameters: {
docs: {
description: {
story: 'Example of how cards are used to display task information in the Hive dashboard',
},
},
},
};
/**
* Workflow card as used in Hive
*/
export const WorkflowCard: Story = {
render: () => (
<Card className="w-96">
<CardHeader>
<div className="flex items-center justify-between">
<div>
<CardTitle>Code Review Pipeline</CardTitle>
<CardDescription>Automated code review and testing workflow</CardDescription>
</div>
<Badge variant="success">Active</Badge>
</div>
</CardHeader>
<CardContent>
<div className="space-y-3">
<div className="flex justify-between text-sm">
<span className="text-gray-600">Steps:</span>
<span>4</span>
</div>
<div className="flex justify-between text-sm">
<span className="text-gray-600">Success Rate:</span>
<span>92.5%</span>
</div>
<div className="flex justify-between text-sm">
<span className="text-gray-600">Last Run:</span>
<span>2 hours ago</span>
</div>
<div className="flex justify-between text-sm">
<span className="text-gray-600">Executions:</span>
<span>25</span>
</div>
<div className="flex gap-2 mt-4">
<Button size="sm" variant="default">Execute</Button>
<Button size="sm" variant="outline">Edit</Button>
</div>
</div>
</CardContent>
</Card>
),
parameters: {
docs: {
description: {
story: 'Example of how cards are used to display workflow information in the Hive dashboard',
},
},
},
};
/**
* System metrics card
*/
export const MetricsCard: Story = {
render: () => (
<Card className="w-80">
<CardHeader>
<CardTitle>System Metrics</CardTitle>
<CardDescription>Real-time cluster performance</CardDescription>
</CardHeader>
<CardContent>
<div className="grid grid-cols-2 gap-4">
<div className="text-center">
<div className="text-2xl font-bold text-blue-600">12</div>
<div className="text-sm text-gray-600">Active Agents</div>
</div>
<div className="text-center">
<div className="text-2xl font-bold text-green-600">8</div>
<div className="text-sm text-gray-600">Running Tasks</div>
</div>
<div className="text-center">
<div className="text-2xl font-bold text-purple-600">3</div>
<div className="text-sm text-gray-600">Workflows</div>
</div>
<div className="text-center">
<div className="text-2xl font-bold text-orange-600">98.5%</div>
<div className="text-sm text-gray-600">Uptime</div>
</div>
</div>
</CardContent>
</Card>
),
parameters: {
docs: {
description: {
story: 'Example of a metrics card showing system statistics',
},
},
},
};
/**
* Card grid layout example
*/
export const CardGrid: Story = {
render: () => (
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4 max-w-6xl">
<Card>
<CardHeader>
<CardTitle>Agent 1</CardTitle>
<CardDescription>Available</CardDescription>
</CardHeader>
<CardContent>
<p>Active tasks: 2/4</p>
</CardContent>
</Card>
<Card>
<CardHeader>
<CardTitle>Agent 2</CardTitle>
<CardDescription>Busy</CardDescription>
</CardHeader>
<CardContent>
<p>Active tasks: 4/4</p>
</CardContent>
</Card>
<Card>
<CardHeader>
<CardTitle>Agent 3</CardTitle>
<CardDescription>Available</CardDescription>
</CardHeader>
<CardContent>
<p>Active tasks: 1/4</p>
</CardContent>
</Card>
<Card>
<CardHeader>
<CardTitle>Agent 4</CardTitle>
<CardDescription>Offline</CardDescription>
</CardHeader>
<CardContent>
<p>Active tasks: 0/4</p>
</CardContent>
</Card>
</div>
),
parameters: {
docs: {
description: {
story: 'Example of cards arranged in a responsive grid layout',
},
},
},
};

View File

@@ -0,0 +1,423 @@
import type { Meta, StoryObj } from '@storybook/react';
import { Input } from './input';
import { Label } from './label';
import { Button } from './button';
/**
* Input component for Hive UI
*
* A versatile input component for forms and user input throughout the Hive application.
* Supports various input types with consistent styling and behavior.
*/
const meta = {
title: 'UI Components/Input',
component: Input,
parameters: {
layout: 'centered',
docs: {
description: {
component: `
The Input component provides consistent styling and behavior for form inputs across the Hive application.
It supports all standard HTML input types with enhanced styling and focus states.
## Features
- Consistent styling across all input types
- Built-in focus and disabled states
- File upload support with custom styling
- Form validation integration
- Responsive design
- Accessibility support
## Usage
\`\`\`tsx
import { Input } from '@/components/ui/input';
<Input
type="text"
placeholder="Enter agent name"
value={agentName}
onChange={(e) => setAgentName(e.target.value)}
required
/>
\`\`\`
## Input Types
- **text**: General text input
- **email**: Email address input with validation
- **password**: Password input with hidden text
- **number**: Numeric input with step controls
- **search**: Search input with enhanced styling
- **url**: URL input with validation
- **tel**: Telephone number input
- **file**: File upload input
`,
},
},
},
tags: ['autodocs'],
argTypes: {
type: {
control: 'select',
options: ['text', 'email', 'password', 'number', 'search', 'url', 'tel', 'file'],
description: 'HTML input type',
},
placeholder: {
control: 'text',
description: 'Placeholder text',
},
value: {
control: 'text',
description: 'Input value',
},
disabled: {
control: 'boolean',
description: 'Whether the input is disabled',
},
required: {
control: 'boolean',
description: 'Whether the input is required',
},
className: {
control: 'text',
description: 'Additional CSS classes',
},
onChange: {
action: 'changed',
description: 'Change event handler',
},
},
args: {
onChange: (e: any) => console.log('Input changed:', e.target.value),
},
} satisfies Meta<typeof Input>;
export default meta;
type Story = StoryObj<typeof meta>;
/**
* Default text input
*/
export const Default: Story = {
args: {
type: 'text',
placeholder: 'Enter text...',
},
};
/**
* Email input with validation
*/
export const Email: Story = {
args: {
type: 'email',
placeholder: 'Enter email address',
},
};
/**
* Password input
*/
export const Password: Story = {
args: {
type: 'password',
placeholder: 'Enter password',
},
};
/**
* Number input
*/
export const Number: Story = {
args: {
type: 'number',
placeholder: 'Enter number',
},
};
/**
* Search input
*/
export const Search: Story = {
args: {
type: 'search',
placeholder: 'Search agents...',
},
};
/**
* File input
*/
export const File: Story = {
args: {
type: 'file',
},
};
/**
* Disabled state
*/
export const Disabled: Story = {
args: {
type: 'text',
placeholder: 'Disabled input',
disabled: true,
value: 'Cannot edit this value',
},
};
/**
* Required input
*/
export const Required: Story = {
args: {
type: 'text',
placeholder: 'Required field',
required: true,
},
};
/**
* Input with label (form example)
*/
export const WithLabel: Story = {
render: () => (
<div className="space-y-2">
<Label htmlFor="agent-name">Agent Name</Label>
<Input
id="agent-name"
name="agentName"
type="text"
placeholder="e.g., walnut-codellama"
required
/>
</div>
),
parameters: {
docs: {
description: {
story: 'Input component used with a label in a form context',
},
},
},
};
/**
* Form example with multiple inputs
*/
export const FormExample: Story = {
render: () => (
<div className="space-y-4 w-80">
<div className="space-y-2">
<Label htmlFor="agent-id">Agent ID</Label>
<Input
id="agent-id"
name="agentId"
type="text"
placeholder="unique-agent-id"
required
/>
</div>
<div className="space-y-2">
<Label htmlFor="endpoint">Endpoint URL</Label>
<Input
id="endpoint"
name="endpoint"
type="url"
placeholder="http://hostname:port"
required
/>
</div>
<div className="space-y-2">
<Label htmlFor="model">Model Name</Label>
<Input
id="model"
name="model"
type="text"
placeholder="codellama:34b"
required
/>
</div>
<div className="space-y-2">
<Label htmlFor="max-concurrent">Max Concurrent Tasks</Label>
<Input
id="max-concurrent"
name="maxConcurrent"
type="number"
placeholder="4"
min="1"
max="10"
required
/>
</div>
<div className="flex gap-2">
<Button variant="default" className="flex-1">Register Agent</Button>
<Button variant="outline" className="flex-1">Cancel</Button>
</div>
</div>
),
parameters: {
docs: {
description: {
story: 'Complete form example showing agent registration with multiple input types',
},
},
},
};
/**
* Search and filter inputs
*/
export const SearchAndFilter: Story = {
render: () => (
<div className="space-y-4 w-96">
<div className="space-y-2">
<Label htmlFor="search-agents">Search Agents</Label>
<Input
id="search-agents"
type="search"
placeholder="Search by name, model, or status..."
/>
</div>
<div className="grid grid-cols-2 gap-4">
<div className="space-y-2">
<Label htmlFor="min-tasks">Min Tasks</Label>
<Input
id="min-tasks"
type="number"
placeholder="0"
min="0"
/>
</div>
<div className="space-y-2">
<Label htmlFor="max-tasks">Max Tasks</Label>
<Input
id="max-tasks"
type="number"
placeholder="10"
min="0"
/>
</div>
</div>
<Button variant="default" className="w-full">Apply Filters</Button>
</div>
),
parameters: {
docs: {
description: {
story: 'Input components used for search and filtering functionality',
},
},
},
};
/**
* All input types showcase
*/
export const AllTypes: Story = {
render: () => (
<div className="grid grid-cols-1 md:grid-cols-2 gap-4 w-full max-w-4xl">
<div className="space-y-2">
<Label>Text Input</Label>
<Input type="text" placeholder="Text input" />
</div>
<div className="space-y-2">
<Label>Email Input</Label>
<Input type="email" placeholder="email@example.com" />
</div>
<div className="space-y-2">
<Label>Password Input</Label>
<Input type="password" placeholder="Password" />
</div>
<div className="space-y-2">
<Label>Number Input</Label>
<Input type="number" placeholder="123" />
</div>
<div className="space-y-2">
<Label>Search Input</Label>
<Input type="search" placeholder="Search..." />
</div>
<div className="space-y-2">
<Label>URL Input</Label>
<Input type="url" placeholder="https://example.com" />
</div>
<div className="space-y-2">
<Label>Tel Input</Label>
<Input type="tel" placeholder="+1 (555) 123-4567" />
</div>
<div className="space-y-2">
<Label>File Input</Label>
<Input type="file" />
</div>
</div>
),
parameters: {
docs: {
description: {
story: 'Showcase of all supported input types',
},
},
},
};
/**
* Validation states example
*/
export const ValidationStates: Story = {
render: () => (
<div className="space-y-4 w-80">
<div className="space-y-2">
<Label htmlFor="valid-input">Valid Input</Label>
<Input
id="valid-input"
type="text"
value="valid-agent-name"
className="border-green-500 focus-visible:ring-green-500"
/>
<p className="text-sm text-green-600"> Agent name is available</p>
</div>
<div className="space-y-2">
<Label htmlFor="error-input">Error Input</Label>
<Input
id="error-input"
type="text"
value="invalid name!"
className="border-red-500 focus-visible:ring-red-500"
/>
<p className="text-sm text-red-600"> Agent name contains invalid characters</p>
</div>
<div className="space-y-2">
<Label htmlFor="warning-input">Warning Input</Label>
<Input
id="warning-input"
type="text"
value="existing-agent"
className="border-yellow-500 focus-visible:ring-yellow-500"
/>
<p className="text-sm text-yellow-600"> Similar agent name already exists</p>
</div>
</div>
),
parameters: {
docs: {
description: {
story: 'Examples of input validation states with custom styling',
},
},
},
};