feat: move Notifications to its own settings sub-page

Adds GET /settings/notifications (dedicated page with channel form + two
test buttons) and updates POST /settings/notifications to render that page.
Settings page now shows a compact link card instead of the full form.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Scott Idem
2026-05-08 23:43:52 -04:00
parent 3c7ecf4e4f
commit 19475610be
3 changed files with 334 additions and 63 deletions

View File

@@ -54,6 +54,26 @@ def _preferred_persona(request: Request, username: str) -> str:
return names[0]
def _notifications_page(username: str, back_persona: str = "", success: str = "", error: str = "") -> str:
html = (_STATIC / "notifications.html").read_text()
channels = get_user_channels(username)
notify_ch = _html.escape(channels.get("notification_channel", "") or "")
notify_email = _html.escape(channels.get("notification_email", "") or "")
nc_room = _html.escape((channels.get("nextcloud") or {}).get("notification_room", "") or "")
gc_webhook = _html.escape((channels.get("google_chat") or {}).get("outbound_webhook", "") or "")
html = html.replace("{{ notify_channel }}", notify_ch)
html = html.replace("{{ notify_email_override }}", notify_email)
html = html.replace("{{ nc_notify_room }}", nc_room)
html = html.replace("{{ gc_webhook }}", gc_webhook)
html = html.replace("{{ back_href }}", f"/{username}/{back_persona}" if back_persona else "/")
html = html.replace("{{ help_href }}", f"/help?persona={back_persona}" if back_persona else "/help")
if success:
html = html.replace("<!-- SUCCESS -->", f'<p class="success">{success}</p>')
if error:
html = html.replace("<!-- ERROR -->", f'<p class="error">{error}</p>')
return html
def _settings_page(username: str, personas: list[str], back_persona: str = "", success: str = "", error: str = "") -> str:
html = (_STATIC / "settings.html").read_text()
html = html.replace("{{ username }}", username)
@@ -74,17 +94,6 @@ def _settings_page(username: str, personas: list[str], back_persona: str = "", s
allowlist_text = ""
html = html.replace("{{ email_allowlist }}", allowlist_text)
# Notification channel settings
channels = get_user_channels(username)
notify_ch = _html.escape(channels.get("notification_channel", "") or "")
notify_email = _html.escape(channels.get("notification_email", "") or "")
nc_room = _html.escape((channels.get("nextcloud") or {}).get("notification_room", "") or "")
gc_webhook = _html.escape((channels.get("google_chat") or {}).get("outbound_webhook", "") or "")
html = html.replace("{{ notify_channel }}", notify_ch)
html = html.replace("{{ notify_email_override }}", notify_email)
html = html.replace("{{ nc_notify_room }}", nc_room)
html = html.replace("{{ gc_webhook }}", gc_webhook)
# Tool permission policy
policy = get_tool_policy(username)
tool_allow_text = _html.escape("\n".join(policy.get("allow", [])))
@@ -261,6 +270,15 @@ async def rename_persona(
return RedirectResponse("/settings", status_code=302)
@router.get("/settings/notifications", include_in_schema=False)
async def notifications_page(request: Request):
username = _get_session_user(request)
if not username:
return RedirectResponse("/login", status_code=302)
back_persona = _preferred_persona(request, username)
return HTMLResponse(_notifications_page(username, back_persona))
@router.post("/settings/notifications", include_in_schema=False)
async def save_notifications(
request: Request,
@@ -273,7 +291,6 @@ async def save_notifications(
if not username:
return RedirectResponse("/login", status_code=302)
personas = list_user_personas(username)
back_persona = _preferred_persona(request, username)
channels_path = app_settings.home_root() / username / "channels.json"
@@ -308,8 +325,7 @@ async def save_notifications(
channels_path.write_text(json.dumps(channels, indent=2) + "\n")
logger.info("notifications updated for %s (channel=%s)", username, notification_channel or "none")
return HTMLResponse(_settings_page(username, personas, back_persona,
success="Notification settings saved."))
return HTMLResponse(_notifications_page(username, back_persona, success="Notification settings saved."))
@router.post("/settings/tool-policy", include_in_schema=False)