mirror of
https://github.com/block/buzz.git
synced 2026-10-27 04:30:52 +00:00
103 lines
3.0 KiB
TypeScript
103 lines
3.0 KiB
TypeScript
import { Clock, MoreHorizontal, Play, Trash2, Zap } from "lucide-react";
|
|
|
|
import type { Workflow } from "@/shared/api/types";
|
|
import { Button } from "@/shared/ui/button";
|
|
import {
|
|
DropdownMenu,
|
|
DropdownMenuContent,
|
|
DropdownMenuItem,
|
|
DropdownMenuTrigger,
|
|
} from "@/shared/ui/dropdown-menu";
|
|
|
|
type WorkflowCardProps = {
|
|
workflow: Workflow;
|
|
channelName?: string;
|
|
onSelect: (workflowId: string) => void;
|
|
onTrigger: (workflowId: string) => void;
|
|
onDelete: (workflowId: string) => void;
|
|
};
|
|
|
|
function StatusBadge({ status }: { status: Workflow["status"] }) {
|
|
const colors = {
|
|
active: "bg-green-500/15 text-green-500",
|
|
disabled: "bg-muted text-muted-foreground",
|
|
archived: "bg-amber-500/15 text-amber-500",
|
|
};
|
|
|
|
return (
|
|
<span
|
|
className={`inline-flex items-center rounded-full px-2 py-0.5 text-[10px] font-medium ${colors[status]}`}
|
|
>
|
|
{status}
|
|
</span>
|
|
);
|
|
}
|
|
|
|
export function WorkflowCard({
|
|
workflow,
|
|
channelName,
|
|
onSelect,
|
|
onTrigger,
|
|
onDelete,
|
|
}: WorkflowCardProps) {
|
|
return (
|
|
<div
|
|
className="relative w-full rounded-lg border bg-card p-3 text-left transition-colors hover:bg-muted/50"
|
|
data-testid={`workflow-card-${workflow.id}`}
|
|
>
|
|
<button
|
|
className="absolute inset-0 rounded-lg"
|
|
onClick={() => onSelect(workflow.id)}
|
|
type="button"
|
|
>
|
|
<span className="sr-only">View {workflow.name}</span>
|
|
</button>
|
|
|
|
<div className="flex items-start justify-between">
|
|
<div className="min-w-0 flex-1">
|
|
<div className="flex items-center gap-2">
|
|
<Zap className="h-4 w-4 shrink-0 text-amber-500" />
|
|
<span className="truncate text-sm font-medium">
|
|
{workflow.name}
|
|
</span>
|
|
<StatusBadge status={workflow.status} />
|
|
</div>
|
|
<div className="mt-1.5 flex items-center gap-3 pl-6 text-[11px] text-muted-foreground">
|
|
{channelName ? <span>{channelName}</span> : null}
|
|
<span className="flex items-center gap-1">
|
|
<Clock className="h-3 w-3" />
|
|
{new Date(workflow.updatedAt * 1000).toLocaleDateString()}
|
|
</span>
|
|
</div>
|
|
</div>
|
|
|
|
<DropdownMenu>
|
|
<DropdownMenuTrigger asChild>
|
|
<Button
|
|
aria-label="Workflow actions"
|
|
className="relative z-10 h-7 w-7 shrink-0"
|
|
size="icon"
|
|
variant="ghost"
|
|
>
|
|
<MoreHorizontal className="h-4 w-4" />
|
|
</Button>
|
|
</DropdownMenuTrigger>
|
|
<DropdownMenuContent align="end">
|
|
<DropdownMenuItem onClick={() => onTrigger(workflow.id)}>
|
|
<Play className="mr-2 h-4 w-4" />
|
|
Trigger
|
|
</DropdownMenuItem>
|
|
<DropdownMenuItem
|
|
className="text-destructive"
|
|
onClick={() => onDelete(workflow.id)}
|
|
>
|
|
<Trash2 className="mr-2 h-4 w-4" />
|
|
Delete
|
|
</DropdownMenuItem>
|
|
</DropdownMenuContent>
|
|
</DropdownMenu>
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|