From 22c8d0af439705a9dc7416ac0e8f23b472b32279 Mon Sep 17 00:00:00 2001 From: Albrecht Degering Date: Wed, 9 Sep 2026 02:03:54 +0200 Subject: [PATCH] fix(ui): align contextual documentation with headings Verified with the coordinated workspace changes by devkit full run 2026-09-08T225814-186389-0000-3e3ed7cd (all seven phases passed). This shared UI pass does not mark the individual module reviews complete. --- src/govoplan_mail/backend/manifest.py | 10 +++++++++- webui/scripts/test-interface-pattern-language.mjs | 2 +- webui/src/features/mail/MailBouncePage.tsx | 2 +- webui/src/features/mail/MailLegacyImportPage.tsx | 2 +- webui/src/features/mail/MailProfileManagement.tsx | 2 +- webui/src/features/mail/MailProfilePolicyEditor.tsx | 2 +- webui/src/features/mail/MailboxPage.tsx | 3 ++- 7 files changed, 16 insertions(+), 7 deletions(-) diff --git a/src/govoplan_mail/backend/manifest.py b/src/govoplan_mail/backend/manifest.py index d3e5b14..7e0395a 100644 --- a/src/govoplan_mail/backend/manifest.py +++ b/src/govoplan_mail/backend/manifest.py @@ -1075,7 +1075,9 @@ manifest = ModuleManifest( id="mail.profiles-and-policy", title="Mail profiles and policy hierarchy", summary="Mail sending and mailbox access use reusable SMTP/IMAP/JMAP profiles governed by an effective system, tenant, owner, and campaign policy.", - body="The active policy decides whether users can only choose approved profiles or whether user, group, and campaign scopes may define additional reusable profiles. SMTP, IMAP, and JMAP host allow/deny rules are inherited independently. JMAP Session discovery fails closed when its advertised API origin differs unless an administrator explicitly allows that origin. Runtime documentation adds the current tenant posture when the actor may read mail profile policy. In the Mail profile policy editor, Credential selection separately controls SMTP and IMAP: allow a profile default or require an explicit authorized Mail-owned server and credential reference in Campaign Mail settings. Both choices keep secrets in Mail. Inherit policy leaves the local choice unset and follows the parent; it is not the same as allowing default credentials. System values are concrete, while lower scopes show local, effective, and source-path values. Allow override sets the matching allow_lower_level_limits protocol key; an ancestor lock cannot be changed or re-enabled below that scope. Campaign policy has no lower-level override controls. Scope-write permission and an unlocked workflow remain required. A failed write preserves the draft for explicit retry; a successful write followed by a dependent refresh failure remains saved and asks only to reload the display.", + body="Documentation books sit beside the Mailbox, legacy-import, bounce-processing, profile, and " + "policy headings; field help stays with its label. " + "The active policy decides whether users can only choose approved profiles or whether user, group, and campaign scopes may define additional reusable profiles. SMTP, IMAP, and JMAP host allow/deny rules are inherited independently. JMAP Session discovery fails closed when its advertised API origin differs unless an administrator explicitly allows that origin. Runtime documentation adds the current tenant posture when the actor may read mail profile policy. In the Mail profile policy editor, Credential selection separately controls SMTP and IMAP: allow a profile default or require an explicit authorized Mail-owned server and credential reference in Campaign Mail settings. Both choices keep secrets in Mail. Inherit policy leaves the local choice unset and follows the parent; it is not the same as allowing default credentials. System values are concrete, while lower scopes show local, effective, and source-path values. Allow override sets the matching allow_lower_level_limits protocol key; an ancestor lock cannot be changed or re-enabled below that scope. Campaign policy has no lower-level override controls. Scope-write permission and an unlocked workflow remain required. A failed write preserves the draft for explicit retry; a successful write followed by a dependent refresh failure remains saved and asks only to reload the display.", layer="configured", documentation_types=("admin",), audience=("tenant_admin", "mail_admin", "campaign_admin"), @@ -1102,6 +1104,8 @@ manifest = ModuleManifest( "title": "Mail-Profile und Richtlinienhierarchie", "summary": "Mail-Versand und Postfachzugriff über wiederverwendbare SMTP-/IMAP-/JMAP-Profile und eine wirksame Richtlinie aus System-, Mandanten-, Eigentümer- und gegebenenfalls Campaign-Ebene steuern.", "body": ( + "Dokumentationsbücher stehen neben den Überschriften für Postfach, Altimport, " + "Rückläuferverarbeitung, Profile und Richtlinien; Feldhilfe bleibt bei der Feldbezeichnung. " "Die wirksame Richtlinie entscheidet, ob Personen ausschließlich freigegebene Profile auswählen dürfen " "oder ob auf Personen-, Gruppen- und Campaign-Ebene zusätzliche wiederverwendbare Profile angelegt werden können. " "Host-Freigaben und -Sperren für SMTP, IMAP und JMAP werden unabhängig vererbt. Ein von der JMAP-Session " @@ -1362,6 +1366,8 @@ manifest = ModuleManifest( title="Read a permitted mailbox without changing it", summary="Choose an IMAP- or JMAP-enabled profile, browse folders, search or page messages, and inspect bounded content through the read-only mailbox surface.", body=( + "Documentation books sit beside the Mailbox, legacy-import, bounce-processing, profile, and " + "policy headings; field help stays with its label. " "Mailbox access requires both mailbox-read and profile-use authority for a profile visible in the actor's scope. IMAP retains its existing bounded list behavior. IMAP folder names appear as readable Unicode, including umlauts and literal ampersands, and are encoded for the active connection when opened. Refresh an already-loaded folder list after an upgrade; folder discovery does not rename remote folders. Folder icons expand or collapse the tree; labels select without changing expansion. Selecting a synthetic parent grouping highlights that group and clears message selection without opening an invented provider folder. JMAP adds capability discovery, server-side text search, query-state cursors, and bounded Email/changes synchronization; an expired state explicitly requires a full refresh. Lists expose provider read/unread flags and provenance without mutating them. Message HTML is isolated and sanitized, while attachment metadata, unavailable content, and provider failures remain explicit. Listing folders or messages must not mark mail read, move it, delete it, or expose unbounded content. " "The persistent workspace header keeps the profile selector, Mailbox tools, Help, and one right-aligned Reload available even without a profile or message selection. Reload first rechecks authorized profiles, then refreshes the current folder catalogue and bounded message page together; a selected message is reread only if still present. IMAP retains the current page; JMAP starts a fresh cursor chain on page one while retaining the search. A selected synthetic grouping refreshes only the folder catalogue, not an invented mailbox. Folder expansion is retained. Failed refreshes preserve usable loaded data with an explicit error and retry action, never present failure as an empty mailbox, and ignore late reads from a previous profile or tenant. Mailbox tools groups the optional profile-only, folder-only, and message-only refreshes separately from Bounce status. The latter remains visible with a permission explanation when bounce-read/manage authority is absent. These controls do not grant profile administration rights, run SMTP delivery, append mail, or change read/unread flags. " "Mailbox context reads bypass browser response reuse; bounded server-side indexes and their provenance remain governed by Mail. A failed pagination request restores the page and size that belong to the retained rows. Dismissing or changing the preview while Reload is pending takes precedence over its remembered selection. On narrow screens, scroll vertically through folders, messages, and preview inside the mailbox workspace; its action header remains visible." @@ -1386,6 +1392,8 @@ manifest = ModuleManifest( "title": "Ein berechtigtes Postfach ohne Änderungen lesen", "summary": "Ein IMAP- oder JMAP-fähiges Profil auswählen, Ordner durchsuchen und begrenzte Nachrichteninhalte in der nur lesbaren Postfachoberfläche prüfen.", "body": ( + "Dokumentationsbücher stehen neben den Überschriften für Postfach, Altimport, " + "Rückläuferverarbeitung, Profile und Richtlinien; Feldhilfe bleibt bei der Feldbezeichnung. " "Der Postfachzugriff erfordert sowohl Leseberechtigung für das Postfach als auch Nutzungsberechtigung für ein " "im Bereich der handelnden Person sichtbares Profil. IMAP zeigt lesbare Unicode-Ordnernamen mit Umlauten " "und kaufmännischen Und-Zeichen; beim Öffnen werden sie für die aktive Verbindung kodiert. Eine bereits " diff --git a/webui/scripts/test-interface-pattern-language.mjs b/webui/scripts/test-interface-pattern-language.mjs index a54b719..00494c2 100644 --- a/webui/scripts/test-interface-pattern-language.mjs +++ b/webui/scripts/test-interface-pattern-language.mjs @@ -41,7 +41,7 @@ assert.match(openFolderNode, /setSelectedFolderGroup\(\{ id: node\.id, label: no assert.match(openFolderNode, /messageDetailRequestRef\.current \+= 1/, "Selecting a grouping invalidates pending message detail."); assert.match(mailbox, /selectedFolderGroup\?\.id \?\? findFolderNodeId/); assert.match(mailbox, /]*height="viewport"/); -assert.match(mailbox, / void reloadMailbox\(\)/); +assert.match(mailbox, /\}\s+variant="workspace"\s+scope="workspace"[\s\S]*refreshable[\s\S]*onReload: \(\) => void reloadMailbox\(\)/); assert.ok(mailbox.indexOf("} description="Watch IMAP delivery-status folders and correlate recipient failures with Mail delivery commands." actions={ void load(), disabled: Boolean(pageMutationBlocker), disabledReason: pageMutationBlocker }} contextActions={} - helpAction={} createAction={} />} loading={loading} diff --git a/webui/src/features/mail/MailLegacyImportPage.tsx b/webui/src/features/mail/MailLegacyImportPage.tsx index 656f0d2..0cd9f03 100644 --- a/webui/src/features/mail/MailLegacyImportPage.tsx +++ b/webui/src/features/mail/MailLegacyImportPage.tsx @@ -379,6 +379,7 @@ export default function MailLegacyImportPage({ } description="Migrate bounded messages into encrypted local review records. POP3 is disabled by default and is not recommended for ongoing mailbox access." helpContextId="mail.pop3" helpModuleId="mail" @@ -388,7 +389,6 @@ export default function MailLegacyImportPage({ refreshable reloadAction={{ onReload: () => void load(), helpContextId: "mail.pop3.action.reload", helpModuleId: "mail", helpTopicId: "mail.workflow.legacy-pop3-import", disabled: Boolean(busy), disabledReason: busy ? "Wait for the current POP3 action to finish." : undefined }} contextActions={} - helpAction={} createAction={canManage ? : undefined} />} loading={loading} diff --git a/webui/src/features/mail/MailProfileManagement.tsx b/webui/src/features/mail/MailProfileManagement.tsx index 4b8bd21..8868b01 100644 --- a/webui/src/features/mail/MailProfileManagement.tsx +++ b/webui/src/features/mail/MailProfileManagement.tsx @@ -630,9 +630,9 @@ export function MailProfileScopeManager({ <> } actions={
-
diff --git a/webui/src/features/mail/MailProfilePolicyEditor.tsx b/webui/src/features/mail/MailProfilePolicyEditor.tsx index e09c53a..28138a0 100644 --- a/webui/src/features/mail/MailProfilePolicyEditor.tsx +++ b/webui/src/features/mail/MailProfilePolicyEditor.tsx @@ -224,9 +224,9 @@ export function MailProfilePolicyEditor({ return ( } actions={
-
diff --git a/webui/src/features/mail/MailboxPage.tsx b/webui/src/features/mail/MailboxPage.tsx index 3ca5760..bd769ec 100644 --- a/webui/src/features/mail/MailboxPage.tsx +++ b/webui/src/features/mail/MailboxPage.tsx @@ -626,6 +626,8 @@ export default function MailboxPage({ settings, auth }: { settings: ApiSettings; {error && {error}} } variant="workspace" scope="workspace" label="i18n:govoplan-mail.mail_actions.c08b5f08" @@ -647,7 +649,6 @@ export default function MailboxPage({ settings, auth }: { settings: ApiSettings; } - helpAction={} />