diff --git a/ui/litellm-dashboard/src/components/team/TeamAdminSettingsForm.test.tsx b/ui/litellm-dashboard/src/components/team/TeamAdminSettingsForm.test.tsx index 65f7a13652d..677c8859eb2 100644 --- a/ui/litellm-dashboard/src/components/team/TeamAdminSettingsForm.test.tsx +++ b/ui/litellm-dashboard/src/components/team/TeamAdminSettingsForm.test.tsx @@ -53,6 +53,18 @@ describe("TeamAdminSettingsForm", () => { await waitFor(() => expect(onSave).toHaveBeenCalledWith({ tpm_limit: null })); }); + it("keeps Save disabled until the TPM limit differs from the team's", () => { + renderForm(new Set(["tpm_limit"])); + const tpmInput = screen.getByLabelText("Tokens per minute Limit (TPM)"); + const save = screen.getByRole("button", { name: /save changes/i }); + + expect(save).toBeDisabled(); + fireEvent.change(tpmInput, { target: { value: "5000" } }); + expect(save).toBeEnabled(); + fireEvent.change(tpmInput, { target: { value: "1000" } }); + expect(save).toBeDisabled(); + }); + it("closes without saving on cancel", async () => { const user = userEvent.setup(); const { onSave, onCancel } = renderForm(new Set(["tpm_limit"])); @@ -65,6 +77,7 @@ describe("TeamAdminSettingsForm", () => { it("locks both buttons while a save is in flight", () => { renderForm(new Set(["tpm_limit"]), { isSaving: true }); + fireEvent.change(screen.getByLabelText("Tokens per minute Limit (TPM)"), { target: { value: "5000" } }); expect(screen.getByRole("button", { name: "Cancel" })).toBeDisabled(); expect(screen.getByRole("button", { name: /save changes/i })).toBeDisabled(); diff --git a/ui/litellm-dashboard/src/components/team/TeamAdminSettingsForm.tsx b/ui/litellm-dashboard/src/components/team/TeamAdminSettingsForm.tsx index 581215b7fdf..140533fada5 100644 --- a/ui/litellm-dashboard/src/components/team/TeamAdminSettingsForm.tsx +++ b/ui/litellm-dashboard/src/components/team/TeamAdminSettingsForm.tsx @@ -1,6 +1,7 @@ "use client"; import { Save } from "lucide-react"; +import { useWatch } from "react-hook-form"; import { z } from "zod/v4"; import { FormField } from "@/components/shared/form/FormField"; @@ -37,7 +38,9 @@ export default function TeamAdminSettingsForm({ onSave, }: TeamAdminSettingsFormProps) { const form = useZodForm(teamAdminSettingsSchema, { defaultValues: initialValues }); - const submit = form.handleSubmit((values) => onSave(teamAdminSettingsChanges(values, editableFields))); + const draft = useWatch({ control: form.control }); + const hasChanges = Object.keys(teamAdminSettingsChanges(draft, initialValues, editableFields)).length > 0; + const submit = form.handleSubmit((values) => onSave(teamAdminSettingsChanges(values, initialValues, editableFields))); return (