From 761dd76b9e281053af2ec49dd21fc8b618f9c49f Mon Sep 17 00:00:00 2001 From: Albrecht Degering Date: Tue, 18 Aug 2026 13:17:31 +0200 Subject: [PATCH] Adopt shared WebUI structural primitives --- docs/INTERFACE_PATTERN_MIGRATION.md | 5 +- webui/src/features/mail/MailBouncePage.tsx | 50 +++++++++---------- .../features/mail/MailProfileManagement.tsx | 6 +-- webui/src/features/mail/MailboxPage.tsx | 5 +- webui/src/styles/mail-profiles.css | 18 +------ 5 files changed, 36 insertions(+), 48 deletions(-) diff --git a/docs/INTERFACE_PATTERN_MIGRATION.md b/docs/INTERFACE_PATTERN_MIGRATION.md index 5e7739f..b840d1d 100644 --- a/docs/INTERFACE_PATTERN_MIGRATION.md +++ b/docs/INTERFACE_PATTERN_MIGRATION.md @@ -13,7 +13,7 @@ mailbox, policy, and delivery-evidence consequences described here. | System/tenant/group/user/campaign profile surfaces | Compare profiles, protocol servers, reusable credentials, status, and scope | Administration/configuration | High because endpoints, credentials, and inheritance control external communication | Shared `ConnectionTree`, stable row actions, textual status, permission/target blockers, and contextual admin help | | Profile creation and focused profile/server/credential editors | Create a governed transport identity or edit one hierarchy object | Guided setup plus adaptive create/edit | High because saving may enable provider access or replace encrypted credentials | Shared `Dialog` and `StageRail` for multi-object setup; focused edit modes show only the selected hierarchy object; field help, connection tests, unsaved-draft guard, and disabled-save reasons | | Mail profile policy card | Narrow visible profiles, lower-scope definitions, hosts, senders, and recipients | Effective-policy editor | High because inherited allow/deny rules govern delivery and lower scopes | Shared policy rows, typed selectors, source path, locked/read-only blocker, dirty-save state, and contextual policy help | -| `/mail/bounces` watcher table | Configure bounded IMAP evidence sources and run an explicit scan | Operational administration | High because it accesses a provider mailbox and changes durable evidence cursors | Shared `DataGrid`, status, loading/error feedback, field help, actionable no-profile blocker, and stable row actions | +| `/mail/bounces` watcher table | Configure bounded IMAP evidence sources and run an explicit scan | Operational administration | High because it accesses a provider mailbox and changes durable evidence cursors | Shared `PageLayout`, `ContentGrid`, `DataGrid`, status, loading/error feedback, field help, actionable no-profile blocker, and stable row actions | | `/mail/bounces` observation table | Inspect correlated or unmatched delivery-status evidence | Evidence/reporting | Medium because recipient and diagnostic data may be sensitive | Bounded sanitized rows, textual status, filters, correlation state, and no raw bounce body | | Bounce watcher removal | Stop future scans while retaining evidence | Destructive confirmation | Medium and reversible by recreating the watcher; observations are retained | Shared `ConfirmDialog` states the immediate consequence and retained evidence | | `mail.profiles` and credential-reference capabilities | Let another module select or validate Mail-owned transport without receiving secrets | Governed capability composition | High because the selected identity can perform external effects | Stable references and Core capability boundaries; no sibling-private WebUI import; authorization and credential resolution remain Mail-owned | @@ -22,6 +22,9 @@ mailbox, policy, and delivery-evidence consequences described here. - Loading, success, error, empty results, permission blockers, and destructive confirmation use Core components. Mail does not reproduce the shell. +- Bounce processing now delegates its page inset, sticky responsive heading, + route actions, alert regions, loading boundary, scrolling, and help audience + to Core `PageLayout`; Mail retains only watcher and evidence semantics. - A target-dependent profile surface cannot load until a concrete user, group, or campaign is selected. The blocker identifies the responsible actor and destination instead of silently hiding the editor. diff --git a/webui/src/features/mail/MailBouncePage.tsx b/webui/src/features/mail/MailBouncePage.tsx index 9544336..1bda639 100644 --- a/webui/src/features/mail/MailBouncePage.tsx +++ b/webui/src/features/mail/MailBouncePage.tsx @@ -7,12 +7,9 @@ import { FormGrid, ContentGrid, ConfirmDialog, DataGrid, Dialog, - DismissibleAlert, DocumentationHelpLink, FormField, - LoadingFrame, - PageScrollViewport, - PageTitle, + PageLayout, StatusBadge, TableActionGroup, ToggleSwitch, @@ -194,30 +191,33 @@ export default function MailBouncePage({ settings }: { settings: ApiSettings }) ]; return ( - -
-
-
Bounce processing

Watch IMAP delivery-status folders and correlate recipient failures with Mail delivery commands.

-
+ <> + -
-
- {error && {error}} - {message && {message}} - - - - source.id} emptyText="No bounce mailbox watchers configured." /> - - - item.id} emptyText="No bounce observations recorded." /> - - - -
+ + )} + loading={loading} + loadingLabel="Loading bounce processing" + error={error} + success={message} + documentationType="admin" + > + + + source.id} emptyText="No bounce mailbox watchers configured." /> + + + item.id} emptyText="No bounce observations recorded." /> + + + !busy && setAddOpen(false)} footer={<>}> @@ -254,6 +254,6 @@ export default function MailBouncePage({ settings }: { settings: ApiSettings }) busy={Boolean(busy)} onCancel={() => setDeleteSource(null)} onConfirm={() => void removeSource()} /> -
+ ); } diff --git a/webui/src/features/mail/MailProfileManagement.tsx b/webui/src/features/mail/MailProfileManagement.tsx index 389e8fe..9861a27 100644 --- a/webui/src/features/mail/MailProfileManagement.tsx +++ b/webui/src/features/mail/MailProfileManagement.tsx @@ -1,5 +1,5 @@ import { useEffect, useMemo, useState, type ReactNode } from "react"; -import { FormGrid, ActionBlockerHint, AdminSelectionList, ConnectionTree, DocumentationHelpLink, FieldLabel, LoadingFrame, MailServerSettingsPanel, PolicyLockedHint, PolicyPathHelp, PolicyRow, PolicySourcePath, PolicyTable, StageRail, StatusBadge, TableActionGroup, ToggleSwitch, hasMailImapSettings, mailImapSettingsPayload, mailServerSecurityOptions, mailSmtpSettingsPayload, mailTextOrNull, mailTransportCredentialsPayload, mergeDeltaRows, normalizeMailServerSecurity, normalizePolicySourcePathItems, useDeltaWatermarks, type ConnectionTreeColumn, type MailServerConnectionTestResult, type MailServerCredentialSettings, type MailServerImapSettings, type MailServerSmtpSettings, type NormalizedPolicySourcePathItem, type PolicySourcePathItem } from "@govoplan/core-webui"; +import { ActionToolbar, FormGrid, ActionBlockerHint, AdminSelectionList, ConnectionTree, DocumentationHelpLink, FieldLabel, LoadingFrame, MailServerSettingsPanel, PolicyLockedHint, PolicyPathHelp, PolicyRow, PolicySourcePath, PolicyTable, StageRail, StatusBadge, TableActionGroup, ToggleSwitch, hasMailImapSettings, mailImapSettingsPayload, mailServerSecurityOptions, mailSmtpSettingsPayload, mailTextOrNull, mailTransportCredentialsPayload, mergeDeltaRows, normalizeMailServerSecurity, normalizePolicySourcePathItems, useDeltaWatermarks, type ConnectionTreeColumn, type MailServerConnectionTestResult, type MailServerCredentialSettings, type MailServerImapSettings, type MailServerSmtpSettings, type NormalizedPolicySourcePathItem, type PolicySourcePathItem } from "@govoplan/core-webui"; import { ArrowLeft, ArrowRight, Inbox, KeyRound, Link2, Pencil, Plus, Send, Settings2, Trash2, Unlink } from "lucide-react"; import type { ApiSettings } from "../../types"; import { @@ -1020,13 +1020,13 @@ export function MailProfilePolicyEditor({ {success && {success}}
-
+

i18n:govoplan-mail.profile_allow_list.507dfe6c

{lowerLevelLimitToggle("allowed_profile_ids")}
-
+

{selectedProfileIds.size === 0 ? "i18n:govoplan-mail.no_local_profile_allow_list_is_set.31072e39" : i18nMessage("i18n:govoplan-mail.value_profile_s_allowed_by_this_scope.6fe9ba44", { value0: selectedProfileIds.size })}

({ diff --git a/webui/src/features/mail/MailboxPage.tsx b/webui/src/features/mail/MailboxPage.tsx index ab2eb9f..10b08d6 100644 --- a/webui/src/features/mail/MailboxPage.tsx +++ b/webui/src/features/mail/MailboxPage.tsx @@ -3,6 +3,7 @@ import { Activity, ChevronRight, Home, Mail, Paperclip, RefreshCw, Search, X } f import { ToolbarGroup, ActionToolbar, ActionBlockerHint, Button, + CountBadge, DataGridPaginationBar, DocumentationHelpLink, DismissibleAlert, @@ -395,7 +396,7 @@ export default function MailboxPage({ settings, auth }: { settings: ApiSettings; {node.label} - {showCount && {node.messageCount}} + {showCount && {node.messageCount}} {flagText && {flagText}} ); @@ -407,7 +408,7 @@ export default function MailboxPage({ settings, auth }: { settings: ApiSettings;
- +