Closes #3600. Previously the From header on test emails and notifications showed only the raw email address. Adds an optional "Sender name" field so emails appear from a friendly name like "Checkmate notifications" <user@example.org>. ## Behaviour - Field is optional. When empty/null/whitespace, the From header falls back to the raw email address — identical to current behaviour, no regression for existing installs. - When set, the email service hands nodemailer { name, address } as the message from field. Nodemailer handles RFC-5322 encoding (quotes, commas, non-ASCII) so the display name is safe for any input. - Unsetting works: clearing the input transforms the value to null in the Zod parse step, and the settings repository already turns null values into a $unset operation. - Both client and server Zod schemas trim and empty-string-to-null, preventing whitespace-only display names from being stored. ## Surfaces - AppSettings schema, Settings type, EmailTransportConfig pick, server Zod validation, client Zod validation, client form defaults, and the Settings page form all carry the new systemEmailDisplayName field. - The transport preview pre-block on /settings now includes a `from` key showing exactly what the email service hands nodemailer — the string when no display name is set, or { name, address } when it is. - en.json carries the new label and placeholder. Other locales fall back until translated (16 locales pending — separate follow-up). ## Conventions conformance (per docs/frontend-conventions.md) - The pre-block I touched had three rule #1 violations (sx p, borderRadius, backgroundColor); hoisted those to native props using theme.shape.borderRadius. Other rule #1 violations elsewhere on this page are pre-existing and intentionally left alone. - No new sx-with-native-equivalents introduced. - No color="text.X" shorthand introduced. - No theme module import introduced.
51 lines
1.8 KiB
TypeScript
51 lines
1.8 KiB
TypeScript
import { useMemo } from "react";
|
|
import { settingsSchema } from "@/Validation/settings";
|
|
import type { Settings } from "@/Types/Settings";
|
|
import type { SettingsFormInput } from "@/Validation/settings";
|
|
|
|
interface UseSettingsFormOptions {
|
|
data?: Settings | null;
|
|
}
|
|
export const useSettingsForm = ({ data = null }: UseSettingsFormOptions = {}) => {
|
|
return useMemo(() => {
|
|
const defaults: SettingsFormInput = {
|
|
systemEmailIgnoreTLS: data?.systemEmailIgnoreTLS ?? false,
|
|
systemEmailRequireTLS: data?.systemEmailRequireTLS ?? false,
|
|
systemEmailRejectUnauthorized: data?.systemEmailRejectUnauthorized ?? true,
|
|
systemEmailSecure: data?.systemEmailSecure ?? false,
|
|
systemEmailPool: data?.systemEmailPool ?? false,
|
|
showURL: data?.showURL ?? false,
|
|
systemEmailHost: data?.systemEmailHost || "",
|
|
systemEmailUser: data?.systemEmailUser || "",
|
|
systemEmailAddress: data?.systemEmailAddress || "",
|
|
systemEmailDisplayName: data?.systemEmailDisplayName || "",
|
|
systemEmailConnectionHost: data?.systemEmailConnectionHost || "localhost",
|
|
systemEmailTLSServername: data?.systemEmailTLSServername || "",
|
|
systemEmailPort: data?.systemEmailPort,
|
|
globalThresholds: {
|
|
cpu:
|
|
data?.globalThresholds?.cpu && data.globalThresholds.cpu >= 1
|
|
? data.globalThresholds.cpu
|
|
: 80,
|
|
memory:
|
|
data?.globalThresholds?.memory && data.globalThresholds.memory >= 1
|
|
? data.globalThresholds.memory
|
|
: 80,
|
|
disk:
|
|
data?.globalThresholds?.disk && data.globalThresholds.disk >= 1
|
|
? data.globalThresholds.disk
|
|
: 80,
|
|
temperature:
|
|
data?.globalThresholds?.temperature && data.globalThresholds.temperature >= 1
|
|
? data.globalThresholds.temperature
|
|
: 80,
|
|
},
|
|
checkTTL: data?.checkTTL ?? 30,
|
|
pagespeedApiKey: "",
|
|
systemEmailPassword: "",
|
|
};
|
|
|
|
return { schema: settingsSchema, defaults };
|
|
}, [data]);
|
|
};
|