+
+
+ ),
+ }}
+ />
+
+ {limits.any_limit_reached && (
+
+
+ {t("customerPortal.limits.reachedTitle")}
+
+ {t("customerPortal.limits.reachedDescription")}
+
+ {t("customerPortal.limits.upgrade")}
+
+
+
+ )}
+
+ )}
+ {children}
+ >
+ );
+}
diff --git a/litellm/ui/litellm-dashboard/src/app/(dashboard)/customers/limits.integration.test.tsx b/litellm/ui/litellm-dashboard/src/app/(dashboard)/customers/limits.integration.test.tsx
new file mode 100644
index 00000000000..7b8f6cdf7ce
--- /dev/null
+++ b/litellm/ui/litellm-dashboard/src/app/(dashboard)/customers/limits.integration.test.tsx
@@ -0,0 +1,85 @@
+import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
+import { act, renderWithProviders, screen, testQueryClient } from "../../../../tests/test-utils";
+import CustomersLayout from "./layout";
+
+beforeEach(() => testQueryClient.clear());
+afterEach(() => {
+ testQueryClient.clear();
+ vi.unstubAllGlobals();
+});
+
+describe("Customer portal limits", () => {
+ it.each([
+ { limitsApply: true, reached: false },
+ { limitsApply: true, reached: true },
+ { limitsApply: false, reached: true },
+ { limitsApply: false, reached: false },
+ ])("shows the notices for limits_apply=$limitsApply and reached=$reached", async ({ limitsApply, reached }) => {
+ vi.stubGlobal(
+ "fetch",
+ vi.fn(async (request: Request) => {
+ expect(new URL(request.url).pathname).toBe("/management/v1/customer_portal/limits");
+ const limits = {
+ limits_apply: limitsApply,
+ organization_limit: 5,
+ teams_per_organization_limit: 5,
+ members_per_team_limit: 5,
+ organization_count: reached ? 5 : 1,
+ any_limit_reached: reached,
+ };
+ return Response.json(limits);
+ }),
+ );
+ renderWithProviders(
+