From 03fb63ca98b4e64d0f5e1ef6331dab187e45ca7a Mon Sep 17 00:00:00 2001 From: yuneng-jiang Date: Fri, 20 Mar 2026 15:58:30 -0700 Subject: [PATCH] Refactor pipeline_flow_builder.tsx to reduce duplication and improve maintainability Extract shared style constants, deduplicate ON PASS/ON FAIL sections into StepOutcomeSection, unify version status handlers, use extractErrorMessage utility, and add useMemo optimizations. Co-Authored-By: Claude Opus 4.6 --- .../policies/pipeline_flow_builder.tsx | 471 +++++++----------- 1 file changed, 185 insertions(+), 286 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 89665774eee..f173849d5d9 100644 --- a/ui/litellm-dashboard/src/components/policies/pipeline_flow_builder.tsx +++ b/ui/litellm-dashboard/src/components/policies/pipeline_flow_builder.tsx @@ -1,12 +1,12 @@ -import React, { useState } from "react"; +import React, { useState, useMemo } from "react"; import { Select, Typography, message, Spin } from "antd"; import { Button, TextInput } from "@tremor/react"; import { ArrowLeftIcon, PlusIcon } from "@heroicons/react/outline"; -import { DotsVerticalIcon } from "@heroicons/react/solid"; import { GuardrailPipeline, PipelineStep, PipelineTestResult, PolicyCreateRequest, PolicyUpdateRequest, Policy } from "./types"; import { Guardrail } from "../guardrails/types"; import { testPipelineCall, listPolicyVersions, createPolicyVersion, updatePolicyVersionStatus } from "../networking"; import NotificationsManager from "../molecules/notifications_manager"; +import { extractErrorMessage } from "../../utils/errorUtils"; import { getComplianceDatasetPrompts, getFrameworks, @@ -39,6 +39,31 @@ const ACTION_LABELS: Record = { modify_response: "Custom Response", }; +const SECTION_LABEL_STYLE: React.CSSProperties = { + fontSize: 11, + fontWeight: 700, + textTransform: "uppercase", + letterSpacing: "0.06em", +}; + +const CARD_STYLE: React.CSSProperties = { + border: "1px solid #e5e7eb", + borderRadius: 10, + backgroundColor: "#fff", + maxWidth: 720, + width: "100%", +}; + +const ICON_CIRCLE_STYLE: React.CSSProperties = { + width: 28, + height: 28, + borderRadius: "50%", + display: "flex", + alignItems: "center", + justifyContent: "center", + flexShrink: 0, +}; + function createDefaultStep(): PipelineStep { return { guardrail: "", @@ -103,18 +128,7 @@ function derivePipelineFromPolicy(policy: Policy | null | undefined): GuardrailP // ───────────────────────────────────────────────────────────────────────────── const GuardrailIcon: React.FC = () => ( -
+
@@ -123,18 +137,7 @@ const GuardrailIcon: React.FC = () => ( ); const PlayIcon: React.FC = () => ( -
+
@@ -198,6 +201,52 @@ const Connector: React.FC = ({ onInsert }) => ( // Step Card (editable) // ───────────────────────────────────────────────────────────────────────────── +interface StepOutcomeSectionProps { + icon: React.ReactNode; + label: string; + value: string; + modifyMessage: string | null; + onChangeAction: (value: string) => void; + onChangeMessage: (value: string | null) => void; +} + +const StepOutcomeSection: React.FC = ({ + icon, + label, + value, + modifyMessage, + onChangeAction, + onChangeMessage, +}) => ( +
+
+ {icon} + {label} +
+ + onChange({ on_pass: value as PipelineStep["on_pass"] })} - options={ACTION_OPTIONS} - /> - {step.on_pass === "modify_response" && ( -
- - onChange({ modify_response_message: e.target.value || null })} - /> -
- )} -
- - {/* ON FAIL section */} -
-
- - ON FAIL -
- -