Files
OpenFlare/frontend/app/(main)/waf/rules/editor/components/rule-node.tsx
T
2026-07-13 15:10:28 +08:00

77 lines
2.2 KiB
TypeScript

import { Handle, Position, type NodeProps } from '@xyflow/react';
import {
Ban,
Fingerprint,
Flag,
Globe2,
Play,
ShieldCheck,
} from 'lucide-react';
import { Badge } from '@/components/ui/badge';
import { cn } from '@/lib/utils';
import type { WAFRuleNode } from '@/lib/services/openflare';
export interface RuleFlowNodeData extends Record<string, unknown> {
rule: WAFRuleNode;
issues: number;
}
const meta = {
start: { label: '开始', icon: Play },
ip_match: { label: 'IP 匹配', icon: Fingerprint },
geo_match: { label: '地域匹配', icon: Globe2 },
pow: { label: 'PoW 挑战', icon: ShieldCheck },
allow: { label: '通过', icon: Flag },
block: { label: '阻止', icon: Ban },
} as const;
const outputHandles: Partial<Record<WAFRuleNode['type'], string[]>> = {
start: ['next'],
ip_match: ['true', 'false'],
geo_match: ['true', 'false'],
pow: ['next'],
};
export function RuleNode({ data, selected }: NodeProps) {
const value = data as RuleFlowNodeData;
const { rule, issues } = value;
const { label, icon: Icon } = meta[rule.type];
return (
<div
className={cn(
'min-w-44 rounded-lg border bg-card shadow-sm transition-shadow',
selected && 'ring-2 ring-ring',
issues > 0 && 'border-destructive',
)}
>
{rule.type !== 'start' && (
<Handle type='target' position={Position.Left} />
)}
<div className='flex items-center gap-3 px-4 py-3'>
<Icon className='size-5 text-primary' />
<div className='flex min-w-0 flex-1 flex-col gap-0.5'>
<span className='text-sm font-medium'>{label}</span>
<span className='font-mono text-[10px] text-muted-foreground'>
{rule.id}
</span>
</div>
{issues > 0 && <Badge variant='destructive'>{issues}</Badge>}
</div>
{(outputHandles[rule.type] ?? []).map((handle, index, all) => (
<Handle
key={handle}
id={handle}
type='source'
position={Position.Right}
style={{ top: `${((index + 1) / (all.length + 1)) * 100}%` }}
>
<span className='absolute right-3 -translate-y-1/2 text-[9px] text-muted-foreground'>
{handle}
</span>
</Handle>
))}
</div>
);
}