diff --git a/ui/litellm-dashboard/src/app/(dashboard)/playground/components/systemOneUI/CurlPreview.test.tsx b/ui/litellm-dashboard/src/app/(dashboard)/playground/components/systemOneUI/CurlPreview.test.tsx
new file mode 100644
index 00000000000..14a4e5dcbcf
--- /dev/null
+++ b/ui/litellm-dashboard/src/app/(dashboard)/playground/components/systemOneUI/CurlPreview.test.tsx
@@ -0,0 +1,26 @@
+import { render, screen } from "@testing-library/react";
+import { describe, expect, it } from "vitest";
+import CurlPreview from "./CurlPreview";
+
+const input = {
+ baseUrl: "http://localhost:4000",
+ endpoint: "/v1/systemone" as const,
+ payload: JSON.stringify({ model: "jev-latest", state: "ok" }),
+ authHeaderName: "Authorization",
+};
+
+describe("CurlPreview", () => {
+ it("shows the command and a copy button for a valid payload", () => {
+ render();
+ expect(screen.getByLabelText("cURL request")).toHaveTextContent("http://localhost:4000/v1/systemone");
+ expect(screen.getByRole("button", { name: /copy curl/i })).toBeInTheDocument();
+ expect(screen.queryByRole("alert")).not.toBeInTheDocument();
+ });
+
+ it("hides the copy button and points back to the form while the payload has errors", () => {
+ render();
+ expect(screen.getByRole("alert")).toHaveTextContent("Fix 2 issues on the Form tab");
+ expect(screen.getByLabelText("cURL request")).toHaveTextContent("jev-latest");
+ expect(screen.queryByRole("button", { name: /copy curl/i })).not.toBeInTheDocument();
+ });
+});
diff --git a/ui/litellm-dashboard/src/app/(dashboard)/playground/components/systemOneUI/CurlPreview.tsx b/ui/litellm-dashboard/src/app/(dashboard)/playground/components/systemOneUI/CurlPreview.tsx
index 2e01ebb0ea8..ecefd87933b 100644
--- a/ui/litellm-dashboard/src/app/(dashboard)/playground/components/systemOneUI/CurlPreview.tsx
+++ b/ui/litellm-dashboard/src/app/(dashboard)/playground/components/systemOneUI/CurlPreview.tsx
@@ -7,13 +7,12 @@ interface CurlPreviewProps extends CurlCommandInput {
export default function CurlPreview({ errorCount = 0, ...input }: CurlPreviewProps) {
const command = buildCurlCommand(input);
- const invalid = errorCount > 0;
return (
cURL request
- {invalid ? (
+ {errorCount > 0 ? (
Fix {errorCount} {errorCount === 1 ? "issue" : "issues"} on the Form tab before copying
diff --git a/ui/litellm-dashboard/src/app/(dashboard)/playground/components/systemOneUI/SystemOneUI.tsx b/ui/litellm-dashboard/src/app/(dashboard)/playground/components/systemOneUI/SystemOneUI.tsx
index f16b1e53661..ae5def7dc48 100644
--- a/ui/litellm-dashboard/src/app/(dashboard)/playground/components/systemOneUI/SystemOneUI.tsx
+++ b/ui/litellm-dashboard/src/app/(dashboard)/playground/components/systemOneUI/SystemOneUI.tsx
@@ -20,7 +20,7 @@ import CurlPreview from "./CurlPreview";
import ResponseView from "./ResponseView";
import SystemOneForm from "./SystemOneForm";
import OpenAIDecisionsForm from "./OpenAIDecisionsForm";
-import { validateSystemOnePayload, validateOpenAIDecisionsPayload } from "./lib/validatePayload";
+import { validateSystemOnePayload, validateOpenAIDecisionsPayload, errorCount } from "./lib/validatePayload";
import { useDecisionModels, type ApiKeySource } from "./useDecisionModels";
interface SystemOneUIProps {
@@ -281,7 +281,7 @@ export default function SystemOneUI({ accessToken, disabledPersonalKeyCreation =
endpoint={endpoint}
payload={validation.payload === undefined ? rawPayload : JSON.stringify(validation.payload)}
authHeaderName={getGlobalLitellmHeaderName()}
- errorCount={validation.issues.filter((issue) => issue.severity === "error").length}
+ errorCount={errorCount(validation)}
/>
diff --git a/ui/litellm-dashboard/src/app/(dashboard)/playground/components/systemOneUI/ValidationFeedback.tsx b/ui/litellm-dashboard/src/app/(dashboard)/playground/components/systemOneUI/ValidationFeedback.tsx
index 9b7f13bcfdf..369c4243857 100644
--- a/ui/litellm-dashboard/src/app/(dashboard)/playground/components/systemOneUI/ValidationFeedback.tsx
+++ b/ui/litellm-dashboard/src/app/(dashboard)/playground/components/systemOneUI/ValidationFeedback.tsx
@@ -1,9 +1,9 @@
import { Badge } from "@/components/ui/badge";
import { CircleAlert, CircleCheck, TriangleAlert } from "lucide-react";
-import type { PayloadValidation } from "./lib/validatePayload";
+import { errorCount as countErrors, type PayloadValidation } from "./lib/validatePayload";
export function ValidationStatus({ validation }: { validation: PayloadValidation
}) {
- const errorCount = validation.issues.filter((issue) => issue.severity === "error").length;
+ const errorCount = countErrors(validation);
if (errorCount > 0) {
return (
diff --git a/ui/litellm-dashboard/src/app/(dashboard)/playground/components/systemOneUI/lib/validatePayload.ts b/ui/litellm-dashboard/src/app/(dashboard)/playground/components/systemOneUI/lib/validatePayload.ts
index 316c98e6c92..d74923bb3e6 100644
--- a/ui/litellm-dashboard/src/app/(dashboard)/playground/components/systemOneUI/lib/validatePayload.ts
+++ b/ui/litellm-dashboard/src/app/(dashboard)/playground/components/systemOneUI/lib/validatePayload.ts
@@ -23,6 +23,9 @@ export interface PayloadValidation {
export type SystemOnePayloadValidation = PayloadValidation;
+export const errorCount = (validation: PayloadValidation): number =>
+ validation.issues.filter((issue) => issue.severity === "error").length;
+
const invalid = (path: string, message: string) => ({
isValid: false,
issues: [{ path, message, severity: "error" as const }],