From e6ef15e90f8589df59bc31e461ce234b71fc0dd0 Mon Sep 17 00:00:00 2001 From: Ishaan Jaffer Date: Fri, 13 Feb 2026 19:24:28 -0800 Subject: [PATCH] Restyle flow builder cards to match reference design --- .../policies/pipeline_flow_builder.tsx | 407 ++++++++++-------- 1 file changed, 228 insertions(+), 179 deletions(-) diff --git a/ui/litellm-dashboard/src/components/policies/pipeline_flow_builder.tsx b/ui/litellm-dashboard/src/components/policies/pipeline_flow_builder.tsx index 01318378321..1a99acca777 100644 --- a/ui/litellm-dashboard/src/components/policies/pipeline_flow_builder.tsx +++ b/ui/litellm-dashboard/src/components/policies/pipeline_flow_builder.tsx @@ -1,7 +1,8 @@ import React, { useState } from "react"; import { Select, Typography, message } from "antd"; import { Button, TextInput } from "@tremor/react"; -import { ArrowLeftIcon, PlusIcon, TrashIcon } from "@heroicons/react/outline"; +import { ArrowLeftIcon, PlusIcon } from "@heroicons/react/outline"; +import { DotsVerticalIcon } from "@heroicons/react/solid"; import { GuardrailPipeline, PipelineStep, PolicyCreateRequest, PolicyUpdateRequest, Policy } from "./types"; import { Guardrail } from "../guardrails/types"; import NotificationsManager from "../molecules/notifications_manager"; @@ -9,12 +10,19 @@ import NotificationsManager from "../molecules/notifications_manager"; const { Text } = Typography; const ACTION_OPTIONS = [ - { label: "Continue to next step", value: "next" }, - { label: "Allow (end flow)", value: "allow" }, - { label: "Block with error response", value: "block" }, - { label: "Return custom response", value: "modify_response" }, + { label: "Next Step", value: "next" }, + { label: "Allow", value: "allow" }, + { label: "Block", value: "block" }, + { label: "Custom Response", value: "modify_response" }, ]; +const ACTION_LABELS: Record = { + allow: "Allow", + block: "Block", + next: "Next Step", + modify_response: "Custom Response", +}; + function createDefaultStep(): PipelineStep { return { guardrail: "", @@ -47,7 +55,63 @@ function updateStepAtIndex( } // ───────────────────────────────────────────────────────────────────────────── -// Sub-components +// Icons (matching the reference image) +// ───────────────────────────────────────────────────────────────────────────── + +const GuardrailIcon: React.FC = () => ( +
+ + + + +
+); + +const PlayIcon: React.FC = () => ( +
+ + + +
+); + +const PassIcon: React.FC = () => ( + + + + +); + +const FailIcon: React.FC = () => ( + + + +); + +// ───────────────────────────────────────────────────────────────────────────── +// Connector // ───────────────────────────────────────────────────────────────────────────── interface ConnectorProps { @@ -55,39 +119,41 @@ interface ConnectorProps { } const Connector: React.FC = ({ onInsert }) => ( -
-
+
+
-
+
); +// ───────────────────────────────────────────────────────────────────────────── +// Step Card (editable) +// ───────────────────────────────────────────────────────────────────────────── + interface StepCardProps { step: PipelineStep; stepIndex: number; @@ -114,31 +180,57 @@ const StepCard: React.FC = ({
- {/* Row 1: GUARDRAIL label + selector + step number + delete */} -
- - GUARDRAIL - + {/* Header row: icon + GUARDRAIL label ... Step N + menu */} +
+
+ + + GUARDRAIL + +
+
+ + Step {stepIndex + 1} + + +
+
+ + {/* Guardrail name / selector */} +
onChange({ on_pass: value as PipelineStep["on_pass"] })} options={ACTION_OPTIONS} />
-
- - ON FAIL - +
+ + Fail + →