diff --git a/frontend/src/app/pages/Settings/sections/general/NotificationsSection.tsx b/frontend/src/app/pages/Settings/sections/general/NotificationsSection.tsx index 3e081c6f..15871a53 100644 --- a/frontend/src/app/pages/Settings/sections/general/NotificationsSection.tsx +++ b/frontend/src/app/pages/Settings/sections/general/NotificationsSection.tsx @@ -55,7 +55,7 @@ const NotificationsSection: React.FC = ({ form, setForm }) => { const row = (title: string, body: string, key: NotifyKey, defaultOn = true): React.ReactElement => ( {title} @@ -68,28 +68,45 @@ const NotificationsSection: React.FC = ({ form, setForm }) => { /> ); + // One bounded box per section. Without it the dividers ran straight through the headings, so the + // labels read as text floating in a single long list instead of titles of anything. + const group = (label: string, rows: React.ReactElement[]): React.ReactElement => ( + + {heading(label)} + *:not(:last-child)': { borderBottom: `1px solid ${c.border.subtle}` }, + }}> + {rows} + + + ); const heading = (text: string): React.ReactElement => ( {text} ); return ( - {heading('Agents')} - {row('Finished', 'When an agent completes its work.', 'notify_agent_completion')} - {row('Errored', 'When an agent stops because something went wrong. Worth keeping on even if you turn the rest off.', 'notify_agent_errors')} - {heading('Workflows')} - {row('Run succeeded', 'When a scheduled run finishes cleanly, with quick actions.', 'notify_workflow_runs')} - {row('Run failed', 'When a scheduled run does not finish.', 'notify_workflow_failures')} - {heading('How they arrive')} - {row('Play a sound', 'Off makes every notification above silent.', 'notify_sound')} - {row('Even when OpenSwarm is in front', 'Normally these are held back while you are already looking at the window.', 'notify_when_focused', false)} + {group('Agents', [ + row('Finished', 'When an agent completes its work.', 'notify_agent_completion'), + row('Errored', 'When an agent stops because something went wrong. Worth keeping on even if you turn the rest off.', 'notify_agent_errors'), + ])} + {group('Workflows', [ + row('Run succeeded', 'When a scheduled run finishes cleanly, with quick actions.', 'notify_workflow_runs'), + row('Run failed', 'When a scheduled run does not finish.', 'notify_workflow_failures'), + ])} + {group('How they arrive', [ + row('Play a sound', 'Off makes every notification above silent.', 'notify_sound'), + row('Even when OpenSwarm is in front', 'Normally these are held back while you are already looking at the window.', 'notify_when_focused', false), + ])} {heading('Email')} + {emailPrefs?.available ? ( Email on cloud runs @@ -105,12 +122,13 @@ const NotificationsSection: React.FC = ({ form, setForm }) => { /> ) : ( - + {signedIn ? 'Email alerts are not available right now.' : 'Sign in to get an email when a cloud workflow run finishes.'} )} + ); };