FN-7828: fix cramped padding on notifications failure-mode settings card
Wraps the failure-notification mode fields in the shared .notification-provider-body wrapper so the card's padding/gutters match sibling provider cards on desktop and mobile. - Wrap failure-notification mode select and delay input in .notification-provider-body within NotificationsSection.tsx - Add FNXC:SettingsLayout comment documenting why .notification-provider-body is needed (parent .notification-provider-card has no own padding) - Add regression test asserting the failure-notification mode field nests inside .notification-provider-body, itself inside .notification-provider-card - Add changeset (patch) documenting the fix Files changed: .changeset/fuzzy-notification-padding.md | 7 +++ .../app/__tests__/settings-sections.test.tsx | 18 ++++++++ .../settings/sections/NotificationsSection.tsx | 50 ++++++++++++---------- 3 files changed, 53 insertions(+), 22 deletions(-) Fusion-Task-Id: FN-7828 Fusion-Task-Lineage: 734c652d-400e-4cb1-b6a9-3a001f0b10b7 Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
This commit is contained in:
7
.changeset/fuzzy-notification-padding.md
Normal file
7
.changeset/fuzzy-notification-padding.md
Normal file
@@ -0,0 +1,7 @@
|
||||
---
|
||||
"@runfusion/fusion": patch
|
||||
---
|
||||
|
||||
summary: Fix cramped padding on the Notifications "Failure notification mode" settings card.
|
||||
category: fix
|
||||
dev: Wrap the failure-notification card fields in `.notification-provider-body` in NotificationsSection so it matches sibling provider-card padding on desktop and mobile.
|
||||
@@ -165,6 +165,24 @@ describe("NotificationsSection", () => {
|
||||
expect(updater(emptyForm)).toMatchObject({ failureNotificationMode: "all" });
|
||||
});
|
||||
|
||||
it("nests the failure-notification mode field inside the padded provider body", () => {
|
||||
render(
|
||||
<NotificationsSection
|
||||
scopeBanner={null}
|
||||
form={emptyForm}
|
||||
setForm={vi.fn()}
|
||||
testNotificationLoading={{}}
|
||||
testNotificationResult={{}}
|
||||
onTestProviderNotification={vi.fn()}
|
||||
/>,
|
||||
);
|
||||
|
||||
const select = screen.getByLabelText("Failure notification mode") as HTMLSelectElement;
|
||||
const providerBody = select.closest(".notification-provider-body");
|
||||
expect(providerBody).not.toBeNull();
|
||||
expect(providerBody?.closest(".notification-provider-card")).not.toBeNull();
|
||||
});
|
||||
|
||||
it("shows the ntfy topic field only when ntfy is enabled", () => {
|
||||
const { rerender } = render(
|
||||
<NotificationsSection
|
||||
|
||||
@@ -58,28 +58,34 @@ export function NotificationsSection({ scopeBanner, form, setForm, testNotificat
|
||||
<h4 className="settings-section-heading">{t("settings.notifications.notifications", "Notifications")}</h4>
|
||||
|
||||
<div className="notification-provider-card">
|
||||
<div className="form-group">
|
||||
<label htmlFor="failureNotificationMode">{t("settings.notifications.failureNotificationMode", "Failure notification mode")}</label>
|
||||
<select id="failureNotificationMode" value={form.failureNotificationMode ?? "sticky-only"} onChange={(e) => {
|
||||
const value = e.target.value as "sticky-only" | "all" | "terminal-only";
|
||||
setForm((f) => ({ ...f, failureNotificationMode: value }));
|
||||
}}>
|
||||
<option value="sticky-only">{t("settings.notifications.stickyFailuresOnlyDefault", "Sticky failures only (default)")}</option>
|
||||
<option value="terminal-only">{t("settings.notifications.terminalFailuresOnlySuppressAutoRetried", "Terminal failures only (suppress auto-retried)")}</option>
|
||||
<option value="all">{t("settings.notifications.allFailuresLegacy", "All failures (legacy)")}</option>
|
||||
</select>
|
||||
<small>{t("settings.notifications.stickyOnlySuppressesRecoveredFailuresTerminalOnlyWaits", "Sticky-only suppresses recovered failures; terminal-only waits for paused/in-review failed tasks; all restores legacy alerts.")}</small>
|
||||
</div>
|
||||
<div className="form-group">
|
||||
<label htmlFor="failureNotificationDelayMs">{t("settings.notifications.failureNotificationDelayMs", "Failure notification delay (ms)")}</label>
|
||||
<input id="failureNotificationDelayMs" type="number" min={0} step={1000} disabled={(form.failureNotificationMode ?? "sticky-only") === "all"} value={form.failureNotificationDelayMs ?? 30000} onChange={(e) => {
|
||||
const parsed = Number(e.target.value);
|
||||
setForm((f) => ({
|
||||
...f,
|
||||
failureNotificationDelayMs: Number.isFinite(parsed) && parsed >= 0 ? parsed : 0,
|
||||
}));
|
||||
}}/>
|
||||
<small>{t("settings.notifications.howLongAFailureMustPersistBeforeA", " How long a failure must persist before a push notification is sent. 0 = notify immediately. Default: 30000 (30 seconds). ")}</small>
|
||||
{/*
|
||||
FNXC:SettingsLayout 2026-07-11-19:00:
|
||||
The failure-notification card must reuse `.notification-provider-body` because `.notification-provider-card` has no own padding; this keeps its field gutters aligned with ntfy/webhook provider cards on desktop and mobile.
|
||||
*/}
|
||||
<div className="notification-provider-body">
|
||||
<div className="form-group">
|
||||
<label htmlFor="failureNotificationMode">{t("settings.notifications.failureNotificationMode", "Failure notification mode")}</label>
|
||||
<select id="failureNotificationMode" value={form.failureNotificationMode ?? "sticky-only"} onChange={(e) => {
|
||||
const value = e.target.value as "sticky-only" | "all" | "terminal-only";
|
||||
setForm((f) => ({ ...f, failureNotificationMode: value }));
|
||||
}}>
|
||||
<option value="sticky-only">{t("settings.notifications.stickyFailuresOnlyDefault", "Sticky failures only (default)")}</option>
|
||||
<option value="terminal-only">{t("settings.notifications.terminalFailuresOnlySuppressAutoRetried", "Terminal failures only (suppress auto-retried)")}</option>
|
||||
<option value="all">{t("settings.notifications.allFailuresLegacy", "All failures (legacy)")}</option>
|
||||
</select>
|
||||
<small>{t("settings.notifications.stickyOnlySuppressesRecoveredFailuresTerminalOnlyWaits", "Sticky-only suppresses recovered failures; terminal-only waits for paused/in-review failed tasks; all restores legacy alerts.")}</small>
|
||||
</div>
|
||||
<div className="form-group">
|
||||
<label htmlFor="failureNotificationDelayMs">{t("settings.notifications.failureNotificationDelayMs", "Failure notification delay (ms)")}</label>
|
||||
<input id="failureNotificationDelayMs" type="number" min={0} step={1000} disabled={(form.failureNotificationMode ?? "sticky-only") === "all"} value={form.failureNotificationDelayMs ?? 30000} onChange={(e) => {
|
||||
const parsed = Number(e.target.value);
|
||||
setForm((f) => ({
|
||||
...f,
|
||||
failureNotificationDelayMs: Number.isFinite(parsed) && parsed >= 0 ? parsed : 0,
|
||||
}));
|
||||
}}/>
|
||||
<small>{t("settings.notifications.howLongAFailureMustPersistBeforeA", " How long a failure must persist before a push notification is sent. 0 = notify immediately. Default: 30000 (30 seconds). ")}</small>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user