mirror of
https://github.com/BerriAI/litellm.git
synced 2026-11-14 09:03:16 +00:00
fix(ui): let alert type switches toggle before slack alerting is set up
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
This commit is contained in:
parent
df78b16941
commit
2bc2dbc11e
2 changed files with 91 additions and 10 deletions
|
|
@ -2,6 +2,7 @@ import { act, fireEvent, render, screen, waitFor, within } from "@testing-librar
|
|||
import userEvent from "@testing-library/user-event";
|
||||
import { FormProvider, useForm } from "react-hook-form";
|
||||
import { beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import { toast } from "@/lib/toast";
|
||||
import { alertingSettingsCall, getCallbackConfigsCall, getCallbacksCall, setCallbacksCall } from "./networking";
|
||||
import Settings, { backendCallbackLogoSrc, CallbackSelector } from "./settings";
|
||||
|
||||
|
|
@ -14,6 +15,10 @@ vi.mock("./networking", () => ({
|
|||
alertingSettingsCall: vi.fn().mockResolvedValue([]),
|
||||
}));
|
||||
|
||||
vi.mock("@/lib/toast", () => ({
|
||||
toast: { success: vi.fn(), fromError: vi.fn() },
|
||||
}));
|
||||
|
||||
vi.mock("./alerting/alerting_settings", () => ({
|
||||
__esModule: true,
|
||||
default: () => <div>Mock Alerting Settings</div>,
|
||||
|
|
@ -513,6 +518,79 @@ describe("Settings", () => {
|
|||
});
|
||||
});
|
||||
|
||||
it("should allow alert types to be enabled when Slack alerting is not configured", async () => {
|
||||
mockGetCallbacksCall.mockResolvedValue({
|
||||
callbacks: [],
|
||||
available_callbacks: [],
|
||||
alerts: [
|
||||
{ name: "email", variables: { EMAIL_ADDRESS: null } },
|
||||
{ name: "ms_teams", variables: { MS_TEAMS_WEBHOOK_URL: null } },
|
||||
],
|
||||
});
|
||||
|
||||
const user = userEvent.setup();
|
||||
render(<Settings {...defaultProps} />);
|
||||
await user.click(await screen.findByRole("tab", { name: "Alerting Types" }));
|
||||
|
||||
const deprecationWarningsRow = screen.getByRole("row", { name: "Model Deprecation Warnings" });
|
||||
const deprecationWarningsSwitch = within(deprecationWarningsRow).getByRole("switch");
|
||||
await user.click(deprecationWarningsSwitch);
|
||||
|
||||
expect(deprecationWarningsSwitch).toBeChecked();
|
||||
await user.click(screen.getByRole("button", { name: "Save Changes" }));
|
||||
|
||||
await waitFor(() => {
|
||||
expect(vi.mocked(setCallbacksCall)).toHaveBeenCalledWith(
|
||||
"token",
|
||||
expect.objectContaining({
|
||||
general_settings: expect.objectContaining({
|
||||
alert_types: ["model_deprecation_warnings"],
|
||||
}),
|
||||
}),
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
it("should load alert types and webhook values from the Slack callback row", async () => {
|
||||
mockGetCallbacksCall.mockResolvedValue({
|
||||
callbacks: [],
|
||||
available_callbacks: [],
|
||||
alerts: [
|
||||
{ name: "email", variables: { EMAIL_ADDRESS: null } },
|
||||
{
|
||||
name: "slack",
|
||||
active_alerts: ["llm_exceptions"],
|
||||
variables: { SLACK_WEBHOOK_URL: null },
|
||||
alerts_to_webhook: { model_deprecation_warnings: "https://hooks.example.com/dep" },
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
const user = userEvent.setup();
|
||||
render(<Settings {...defaultProps} />);
|
||||
await user.click(await screen.findByRole("tab", { name: "Alerting Types" }));
|
||||
|
||||
const llmExceptionsRow = screen.getByRole("row", { name: "LLM Exceptions" });
|
||||
const deprecationWarningsRow = screen.getByRole("row", { name: "Model Deprecation Warnings" });
|
||||
expect(within(llmExceptionsRow).getByRole("switch")).toBeChecked();
|
||||
expect(within(deprecationWarningsRow).getByRole("switch")).not.toBeChecked();
|
||||
expect(screen.getByDisplayValue("https://hooks.example.com/dep")).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("should show an error toast and no success toast when saving alert types fails", async () => {
|
||||
vi.mocked(setCallbacksCall).mockRejectedValueOnce(new Error("save failed"));
|
||||
|
||||
const user = userEvent.setup();
|
||||
render(<Settings {...defaultProps} />);
|
||||
await user.click(await screen.findByRole("tab", { name: "Alerting Types" }));
|
||||
await user.click(screen.getByRole("button", { name: "Save Changes" }));
|
||||
|
||||
await waitFor(() => {
|
||||
expect(vi.mocked(toast.fromError)).toHaveBeenCalledWith(expect.any(Error));
|
||||
});
|
||||
expect(vi.mocked(toast.success)).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("should hold the callbacks table in loading state until the fetch settles", async () => {
|
||||
let resolveCallbacks: (value: {
|
||||
callbacks: never[];
|
||||
|
|
|
|||
|
|
@ -421,16 +421,18 @@ const Settings: React.FC<SettingsPageProps> = ({ accessToken, userRole, userID,
|
|||
setAllCallbacks(data.available_callbacks);
|
||||
|
||||
let alerts_data = data.alerts;
|
||||
if (alerts_data) {
|
||||
if (alerts_data.length > 0) {
|
||||
let _alert_info = alerts_data[0];
|
||||
let catch_all_webhook = _alert_info.variables.SLACK_WEBHOOK_URL;
|
||||
|
||||
let active_alerts = _alert_info.active_alerts;
|
||||
setActiveAlerts(active_alerts);
|
||||
setCatchAllWebhookURL(catch_all_webhook);
|
||||
setAlertToWebhooks(_alert_info.alerts_to_webhook);
|
||||
}
|
||||
const slack_alert_info = alerts_data?.find(
|
||||
(alert: {
|
||||
name: string;
|
||||
active_alerts?: string[] | null;
|
||||
variables?: { SLACK_WEBHOOK_URL?: string | null } | null;
|
||||
alerts_to_webhook?: Record<string, string> | null;
|
||||
}) => alert.name === "slack",
|
||||
);
|
||||
if (slack_alert_info) {
|
||||
setActiveAlerts(slack_alert_info.active_alerts ?? []);
|
||||
setCatchAllWebhookURL(slack_alert_info.variables?.SLACK_WEBHOOK_URL ?? "");
|
||||
setAlertToWebhooks(slack_alert_info.alerts_to_webhook ?? {});
|
||||
}
|
||||
|
||||
setAlerts(alerts_data);
|
||||
|
|
@ -555,6 +557,7 @@ const Settings: React.FC<SettingsPageProps> = ({ accessToken, userRole, userID,
|
|||
await setCallbacksCall(accessToken, payload);
|
||||
} catch (error) {
|
||||
toast.fromError(error);
|
||||
return;
|
||||
}
|
||||
toast.success(t("loggingAndAlerts.alertTypes.toasts.saved"));
|
||||
};
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue