import { Badge } from "@/components/ui/badge"; import { ProviderIconType, RenderProviderIcon } from "@/lib/constants/icons"; import { getProviderLabel } from "@/lib/constants/logs"; import { RoutingRule } from "@/lib/types/routingRules"; import { Position } from "@xyflow/react"; import { Link2 } from "lucide-react"; import { useState } from "react"; import { RULE_W, SCOPE_CONFIG, type ScopeKey } from "../constants"; import { RFEdgeHandle } from "./rfEdgeHandle"; export function RFRuleNode({ data }: { data: any }) { const rule = data.rule as RoutingRule; const scopeColor = data.scopeColor as string; const cfg = SCOPE_CONFIG[rule.scope as ScopeKey]; const multi = rule.targets.length > 1; const [hovered, setHovered] = useState(false); return (
setHovered(true)} onMouseLeave={() => setHovered(false)} onFocus={() => setHovered(true)} onBlur={() => setHovered(false)} onClick={() => setHovered((v) => !v)} onKeyDown={(e) => { if (e.key === "Enter" || e.key === " ") { e.preventDefault(); setHovered((v) => !v); } }} > {rule.chain_rule && }
{/* scope header */}
{cfg?.label ?? rule.scope}
{rule.chain_rule && } {!rule.enabled && ( Off )}
{/* rule name */}

{rule.name}

{rule.priority > 0 &&

Priority {rule.priority}

}
{/* targets footer */}
{rule.targets .slice(0, 4) .map((t, i) => t.provider ? ( ) : ( ), )} {rule.targets.length > 4 && +{rule.targets.length - 4}}
{rule.targets.length} target{rule.targets.length !== 1 ? "s" : ""}
{/* hover popover */} {hovered && (
{rule.scope !== "global" && rule.scope_id && (

{cfg?.label ?? rule.scope}:{" "} {rule.scope_id}

)} {rule.chain_rule && (

Chain rule — resolved provider/model feeds back as the new input and the full scope chain re-evaluates.

)}

{rule.chain_rule ? "Resolved target (new input)" : "Targets"}

{rule.targets.map((t, i) => { const isPassthrough = !t.provider && !t.model; return (
{t.provider ? ( ) : ( )}

{isPassthrough ? "Passthrough" : t.provider ? getProviderLabel(t.provider) : t.model}

{t.model && t.provider &&

{t.model}

} {isPassthrough &&

original provider & model

}
{multi && ( {Math.round(t.weight * 100)}% )}
); })}
)}
); }