mirror of
https://github.com/BerriAI/litellm.git
synced 2026-11-13 08:52:02 +00:00
fix(ui): align SMTP settings with runtime configuration
Use appropriate input types and required markers for SMTP settings, keep authentication fields optional, and expose SMTP_USE_SSL in the Admin UI. Add regression coverage for the UI field contract and API descriptor resolution.
This commit is contained in:
parent
491eda319c
commit
40805ba4cc
4 changed files with 56 additions and 7 deletions
|
|
@ -12,6 +12,7 @@ EMAIL_DESCRIPTORS: tuple[FieldDescriptor, ...] = (
|
|||
FieldDescriptor("SMTP_HOST", "SMTP_HOST", "SMTP_HOST"),
|
||||
FieldDescriptor("SMTP_PORT", "SMTP_PORT", "SMTP_PORT", default="587"),
|
||||
FieldDescriptor("SMTP_TLS", "SMTP_TLS", "SMTP_TLS", default="True"),
|
||||
FieldDescriptor("SMTP_USE_SSL", "SMTP_USE_SSL", "SMTP_USE_SSL", default="False"),
|
||||
FieldDescriptor("SMTP_USERNAME", "SMTP_USERNAME", "SMTP_USERNAME", is_secret=True),
|
||||
FieldDescriptor("SMTP_PASSWORD", "SMTP_PASSWORD", "SMTP_PASSWORD", is_secret=True),
|
||||
FieldDescriptor("SMTP_SENDER_EMAIL", "SMTP_SENDER_EMAIL", "SMTP_SENDER_EMAIL"),
|
||||
|
|
|
|||
|
|
@ -1218,6 +1218,7 @@ def test_get_config_returns_email_settings_set_only_in_process_env(monkeypatch):
|
|||
monkeypatch.setenv("SMTP_HOST", "smtp.env-host.com")
|
||||
monkeypatch.setenv("SMTP_PORT", "2525")
|
||||
monkeypatch.setenv("SMTP_TLS", "False")
|
||||
monkeypatch.setenv("SMTP_USE_SSL", "True")
|
||||
monkeypatch.setenv("SMTP_USERNAME", "env-user")
|
||||
monkeypatch.setenv("SMTP_PASSWORD", smtp_password)
|
||||
monkeypatch.setenv("SMTP_SENDER_EMAIL", "alerts@env-host.com")
|
||||
|
|
@ -1236,6 +1237,7 @@ def test_get_config_returns_email_settings_set_only_in_process_env(monkeypatch):
|
|||
assert variables["SMTP_HOST"] == "smtp.env-host.com"
|
||||
assert variables["SMTP_PORT"] == "2525"
|
||||
assert variables["SMTP_TLS"] == "False"
|
||||
assert variables["SMTP_USE_SSL"] == "True"
|
||||
assert variables["SMTP_USERNAME"] == "env-user"
|
||||
assert variables["SMTP_SENDER_EMAIL"] == "alerts@env-host.com"
|
||||
assert variables["TEST_EMAIL_ADDRESS"] == "admin@env-host.com"
|
||||
|
|
@ -1269,7 +1271,15 @@ def test_get_config_email_settings_prefer_stored_over_process_env(monkeypatch):
|
|||
|
||||
def test_get_config_email_settings_absent_everywhere_stay_none(monkeypatch):
|
||||
"""A field set in neither source is reported unset rather than invented."""
|
||||
for var in ("SMTP_HOST", "SMTP_PORT", "SMTP_TLS", "SMTP_USERNAME", "SMTP_PASSWORD", "SMTP_SENDER_EMAIL"):
|
||||
for var in (
|
||||
"SMTP_HOST",
|
||||
"SMTP_PORT",
|
||||
"SMTP_TLS",
|
||||
"SMTP_USE_SSL",
|
||||
"SMTP_USERNAME",
|
||||
"SMTP_PASSWORD",
|
||||
"SMTP_SENDER_EMAIL",
|
||||
):
|
||||
monkeypatch.delenv(var, raising=False)
|
||||
|
||||
variables = _get_email_alert_variables(
|
||||
|
|
|
|||
|
|
@ -22,7 +22,12 @@ const alerts = [
|
|||
variables: {
|
||||
SMTP_HOST: "smtp.example.com",
|
||||
SMTP_PORT: "587",
|
||||
SMTP_TLS: "True",
|
||||
SMTP_USE_SSL: "False",
|
||||
SMTP_USERNAME: "smtp-user",
|
||||
SMTP_PASSWORD: "********",
|
||||
SMTP_SENDER_EMAIL: "alerts@example.com",
|
||||
TEST_EMAIL_ADDRESS: "admin@example.com",
|
||||
EMAIL_LOGO_URL: "https://example.com/logo.png",
|
||||
},
|
||||
},
|
||||
|
|
@ -53,7 +58,15 @@ describe("EmailSettings", () => {
|
|||
|
||||
expect(inputNamed("SMTP_HOST")).toHaveValue("smtp.example.com");
|
||||
expect(inputNamed("SMTP_PORT")).toHaveValue("587");
|
||||
expect(inputNamed("SMTP_PORT")).toHaveAttribute("type", "number");
|
||||
expect(inputNamed("SMTP_HOST")).toHaveAttribute("type", "text");
|
||||
expect(inputNamed("SMTP_TLS")).toHaveAttribute("type", "text");
|
||||
expect(inputNamed("SMTP_USE_SSL")).toHaveAttribute("type", "text");
|
||||
expect(inputNamed("SMTP_USERNAME")).toHaveAttribute("type", "text");
|
||||
expect(inputNamed("SMTP_PASSWORD")).toHaveValue("********");
|
||||
expect(inputNamed("SMTP_SENDER_EMAIL")).toHaveAttribute("type", "text");
|
||||
expect(inputNamed("TEST_EMAIL_ADDRESS")).toHaveAttribute("type", "text");
|
||||
expect(inputNamed("EMAIL_LOGO_URL")).toHaveAttribute("type", "text");
|
||||
expect(document.querySelector('input[name="SLACK_WEBHOOK_URL"]')).toBeNull();
|
||||
});
|
||||
|
||||
|
|
@ -63,6 +76,21 @@ describe("EmailSettings", () => {
|
|||
expect(screen.getByText("SMTP_HOST")).toBeInTheDocument();
|
||||
expect(screen.getByText(/Enter the SMTP host address/)).toBeInTheDocument();
|
||||
expect(screen.getByText(/Enter the SMTP port number/)).toBeInTheDocument();
|
||||
expect(screen.getByText(/Optional SMTP username/)).toBeInTheDocument();
|
||||
expect(screen.getByText(/Optional SMTP password/)).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("only requires the SMTP host and sender email", () => {
|
||||
renderWithProviders(<EmailSettings accessToken="sk-test" premiumUser alerts={alerts} />);
|
||||
|
||||
expect(inputNamed("SMTP_HOST")).toBeRequired();
|
||||
expect(inputNamed("SMTP_SENDER_EMAIL")).toBeRequired();
|
||||
expect(inputNamed("SMTP_PORT")).not.toBeRequired();
|
||||
expect(inputNamed("SMTP_TLS")).not.toBeRequired();
|
||||
expect(inputNamed("SMTP_USE_SSL")).not.toBeRequired();
|
||||
expect(inputNamed("SMTP_USERNAME")).not.toBeRequired();
|
||||
expect(inputNamed("SMTP_PASSWORD")).not.toBeRequired();
|
||||
expect(inputNamed("TEST_EMAIL_ADDRESS")).not.toBeRequired();
|
||||
});
|
||||
|
||||
it("submits only the fields the admin actually edited", async () => {
|
||||
|
|
|
|||
|
|
@ -14,13 +14,22 @@ interface EmailSettingsProps {
|
|||
|
||||
const REQUIRED_MARKER = <span className="text-destructive"> Required * </span>;
|
||||
|
||||
const REQUIRED_FIELDS = new Set(["SMTP_HOST", "SMTP_SENDER_EMAIL"]);
|
||||
|
||||
const FIELD_TYPES: Record<string, React.HTMLInputTypeAttribute> = {
|
||||
SMTP_PORT: "number",
|
||||
SMTP_PASSWORD: "password",
|
||||
};
|
||||
|
||||
const FIELD_HELP: Record<string, React.ReactNode> = {
|
||||
SMTP_HOST: <>Enter the SMTP host address, e.g. `smtp.resend.com`{REQUIRED_MARKER}</>,
|
||||
SMTP_PORT: <>Enter the SMTP port number, e.g. `587`{REQUIRED_MARKER}</>,
|
||||
SMTP_USERNAME: <>Enter the SMTP username, e.g. `username`{REQUIRED_MARKER}</>,
|
||||
SMTP_PASSWORD: REQUIRED_MARKER,
|
||||
SMTP_PORT: <>Enter the SMTP port number, e.g. `587`</>,
|
||||
SMTP_TLS: <>Use STARTTLS for the SMTP connection. Defaults to `True`</>,
|
||||
SMTP_USE_SSL: <>Use implicit SSL for the SMTP connection. Defaults to `False`</>,
|
||||
SMTP_USERNAME: <>Optional SMTP username for authenticated servers</>,
|
||||
SMTP_PASSWORD: <>Optional SMTP password for authenticated servers</>,
|
||||
SMTP_SENDER_EMAIL: <>Enter the sender email address, e.g. `sender@berri.ai`{REQUIRED_MARKER}</>,
|
||||
TEST_EMAIL_ADDRESS: <>Email Address to send `Test Email Alert` to. example: `info@berri.ai`{REQUIRED_MARKER}</>,
|
||||
TEST_EMAIL_ADDRESS: <>Optional address for the `Test Email Alert` action</>,
|
||||
EMAIL_LOGO_URL: <>(Optional) Customize the Logo that appears in the email, pass a url to your logo</>,
|
||||
EMAIL_SUPPORT_CONTACT: (
|
||||
<>(Optional) Customize the support email address that appears in the email. Default is support@berri.ai</>
|
||||
|
|
@ -115,8 +124,9 @@ const EmailSettings: React.FC<EmailSettingsProps> = ({ accessToken, premiumUser,
|
|||
)}
|
||||
<Input
|
||||
name={key}
|
||||
defaultValue={value as string}
|
||||
type="password"
|
||||
defaultValue={value as string | undefined}
|
||||
type={FIELD_TYPES[key] ?? "text"}
|
||||
required={REQUIRED_FIELDS.has(key)}
|
||||
disabled={isLocked}
|
||||
className="max-w-100"
|
||||
/>
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue