BOC v1.0: RS256 auth, Ledger integration, Prometheus metrics, CI/CD, backup
This commit is contained in:
@@ -0,0 +1,207 @@
|
||||
import { Card, CardHeader } from '@/components/ui/Card'
|
||||
import { Badge } from '@/components/ui/Badge'
|
||||
import { Button } from '@/components/ui/Button'
|
||||
import {
|
||||
Zap,
|
||||
Plus,
|
||||
Play,
|
||||
Pause,
|
||||
CheckCircle2,
|
||||
GitBranch,
|
||||
Mail,
|
||||
MessageSquare,
|
||||
FileText,
|
||||
UserPlus,
|
||||
} from 'lucide-react'
|
||||
|
||||
const workflows = [
|
||||
{
|
||||
id: '1',
|
||||
name: 'New Lead Notification',
|
||||
description: 'Send Slack notification when a new lead is created',
|
||||
status: 'active' as const,
|
||||
trigger: 'Lead Created',
|
||||
actions: ['Send Email', 'Slack Message'],
|
||||
lastRun: '2 min ago',
|
||||
runs: 1240,
|
||||
},
|
||||
{
|
||||
id: '2',
|
||||
name: 'Invoice Reminder',
|
||||
description: 'Send reminder 3 days before invoice due date',
|
||||
status: 'active' as const,
|
||||
trigger: 'Schedule',
|
||||
actions: ['Send Email'],
|
||||
lastRun: '1 hour ago',
|
||||
runs: 856,
|
||||
},
|
||||
{
|
||||
id: '3',
|
||||
name: 'Customer Onboarding',
|
||||
description: 'Welcome email series for new customers',
|
||||
status: 'active' as const,
|
||||
trigger: 'Customer Created',
|
||||
actions: ['Send Email', 'Create Task', 'Add to CRM'],
|
||||
lastRun: '15 min ago',
|
||||
runs: 342,
|
||||
},
|
||||
{
|
||||
id: '4',
|
||||
name: 'Deal Stage Alert',
|
||||
description: 'Notify sales team when deal reaches negotiation',
|
||||
status: 'paused' as const,
|
||||
trigger: 'Deal Updated',
|
||||
actions: ['Send Email', 'Slack Message'],
|
||||
lastRun: '3 days ago',
|
||||
runs: 89,
|
||||
},
|
||||
{
|
||||
id: '5',
|
||||
name: 'Employee Offboarding',
|
||||
description: 'Automated offboarding checklist',
|
||||
status: 'active' as const,
|
||||
trigger: 'Employee Terminated',
|
||||
actions: ['Create Task', 'Send Email', 'Update HR'],
|
||||
lastRun: '1 week ago',
|
||||
runs: 12,
|
||||
},
|
||||
]
|
||||
|
||||
const actionIcons: Record<string, React.ReactNode> = {
|
||||
'Send Email': <Mail size={12} />,
|
||||
'Slack Message': <MessageSquare size={12} />,
|
||||
'Create Task': <FileText size={12} />,
|
||||
'Add to CRM': <UserPlus size={12} />,
|
||||
'Update HR': <UserPlus size={12} />,
|
||||
}
|
||||
|
||||
export function AutomationPage() {
|
||||
const activeWorkflows = workflows.filter((w) => w.status === 'active').length
|
||||
const totalRuns = workflows.reduce((sum, w) => sum + w.runs, 0)
|
||||
|
||||
return (
|
||||
<div className="space-y-8">
|
||||
{/* Page Header */}
|
||||
<div className="flex flex-col sm:flex-row sm:items-center justify-between gap-4">
|
||||
<div>
|
||||
<h1 className="text-xl font-semibold text-text-primary">Automation</h1>
|
||||
<p className="text-sm text-text-secondary mt-0.5">Workflows and automated tasks</p>
|
||||
</div>
|
||||
<Button icon={<Plus size={16} />}>New Workflow</Button>
|
||||
</div>
|
||||
|
||||
{/* Quick Stats */}
|
||||
<div className="grid grid-cols-2 lg:grid-cols-4 gap-5">
|
||||
<Card padding="md">
|
||||
<div className="flex items-center gap-3">
|
||||
<div className="w-10 h-10 rounded-xl bg-primary-light flex items-center justify-center text-primary">
|
||||
<Zap size={18} />
|
||||
</div>
|
||||
<div>
|
||||
<p className="text-2xl font-semibold text-text-primary">{workflows.length}</p>
|
||||
<p className="text-xs text-text-secondary">Workflows</p>
|
||||
</div>
|
||||
</div>
|
||||
</Card>
|
||||
<Card padding="md">
|
||||
<div className="flex items-center gap-3">
|
||||
<div className="w-10 h-10 rounded-xl bg-success-light flex items-center justify-center text-success">
|
||||
<Play size={18} />
|
||||
</div>
|
||||
<div>
|
||||
<p className="text-2xl font-semibold text-text-primary">{activeWorkflows}</p>
|
||||
<p className="text-xs text-text-secondary">Active</p>
|
||||
</div>
|
||||
</div>
|
||||
</Card>
|
||||
<Card padding="md">
|
||||
<div className="flex items-center gap-3">
|
||||
<div className="w-10 h-10 rounded-xl bg-warning-light flex items-center justify-center text-warning">
|
||||
<Pause size={18} />
|
||||
</div>
|
||||
<div>
|
||||
<p className="text-2xl font-semibold text-text-primary">{workflows.length - activeWorkflows}</p>
|
||||
<p className="text-xs text-text-secondary">Paused</p>
|
||||
</div>
|
||||
</div>
|
||||
</Card>
|
||||
<Card padding="md">
|
||||
<div className="flex items-center gap-3">
|
||||
<div className="w-10 h-10 rounded-xl bg-primary-light flex items-center justify-center text-primary">
|
||||
<CheckCircle2 size={18} />
|
||||
</div>
|
||||
<div>
|
||||
<p className="text-2xl font-semibold text-text-primary">{totalRuns.toLocaleString()}</p>
|
||||
<p className="text-xs text-text-secondary">Total Runs</p>
|
||||
</div>
|
||||
</div>
|
||||
</Card>
|
||||
</div>
|
||||
|
||||
{/* Workflows */}
|
||||
<Card>
|
||||
<CardHeader title="Workflows" subtitle="Automated processes and triggers" />
|
||||
<div className="space-y-3">
|
||||
{workflows.map((workflow) => (
|
||||
<div
|
||||
key={workflow.id}
|
||||
className="flex items-center justify-between p-4 rounded-xl bg-bg/50 hover:bg-bg transition-colors"
|
||||
>
|
||||
<div className="flex items-center gap-4">
|
||||
<div className={`w-10 h-10 rounded-xl flex items-center justify-center ${
|
||||
workflow.status === 'active' ? 'bg-success-light text-success' : 'bg-warning-light text-warning'
|
||||
}`}>
|
||||
{workflow.status === 'active' ? <Play size={18} /> : <Pause size={18} />}
|
||||
</div>
|
||||
<div>
|
||||
<div className="flex items-center gap-2">
|
||||
<span className="font-medium text-text-primary">{workflow.name}</span>
|
||||
<Badge
|
||||
variant={workflow.status === 'active' ? 'success' : 'warning'}
|
||||
size="sm"
|
||||
>
|
||||
{workflow.status}
|
||||
</Badge>
|
||||
</div>
|
||||
<p className="text-xs text-text-secondary mt-0.5">{workflow.description}</p>
|
||||
<div className="flex items-center gap-3 mt-2">
|
||||
<div className="flex items-center gap-1.5">
|
||||
<GitBranch size={12} className="text-text-secondary/60" />
|
||||
<span className="text-[11px] text-text-secondary">{workflow.trigger}</span>
|
||||
</div>
|
||||
<div className="flex items-center gap-1">
|
||||
{workflow.actions.map((action, i) => (
|
||||
<span
|
||||
key={i}
|
||||
className="inline-flex items-center gap-1 px-1.5 py-0.5 bg-bg rounded text-[10px] text-text-secondary"
|
||||
>
|
||||
{actionIcons[action]}
|
||||
{action}
|
||||
</span>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex items-center gap-6 text-right">
|
||||
<div>
|
||||
<p className="text-sm font-medium text-text-primary">{workflow.runs.toLocaleString()}</p>
|
||||
<p className="text-[11px] text-text-secondary">runs</p>
|
||||
</div>
|
||||
<div>
|
||||
<p className="text-sm font-medium text-text-primary">{workflow.lastRun}</p>
|
||||
<p className="text-[11px] text-text-secondary">last run</p>
|
||||
</div>
|
||||
<div className="flex items-center">
|
||||
<div className="w-9 h-5 rounded-full bg-success/20 relative cursor-pointer">
|
||||
<div className="absolute right-0.5 top-0.5 w-4 h-4 rounded-full bg-success" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</Card>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user