panel-redesign: Help with seventeen topics; every box links to its own

Follows the design commit before it. Written by Sonnet, reviewed by
Opus.

  - view/help.go, templates/help.html: the mockup's topics, texts, ids
    and menu. The page shows the groups the reader's menu shows:
    Overview and Server for the global role, Outbound and Inbound by
    reach (Inbound only with the feature on), Account for everyone;
    boxes are numbered as shown.
  - Box.Help set on the boxes the mockups mark; the inbound MX box has
    its link again.
  - TestEveryHelpLinkLandsOnATopic also fails on a topic that no page
    links to, unless it is listed as menu-only (account) - and on a
    stale exception.

Known until the change that follows: the dns, dmarc and account topics
describe the three-choice report address, which the code does not have
yet; Account's DMARC box still links to #dns.

Not verified by running: three sentences rest on Postfix behaviour
(delivery is deferred when a required TLS session cannot be made; a
milter with default_action=tempfail answers 4xx; with "any recipient"
an address the upstream refuses comes back as a bounce).

Evidence
  - docs/assets/panel-redesign/evidence/help.png (1440x3600) and
    in-domain.png: headless Edge, real templates served locally with
    their fixtures - NOT from the container.
  - go test -count=1 ./internal/web/... ./cmd/panel: ok (six packages).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
mix
2026-10-10 11:58:36 +03:00
co-authored by Claude Opus 5.5
parent ef19c1448e
commit 4ab63d08ae
19 changed files with 474 additions and 136 deletions
+5 -5
View File
@@ -137,7 +137,7 @@ func NewInDomains(m Meta, canManage bool) *InDomains {
Lead: Plain("Backup-MX / forwarder. Port 25 accepts mail only for the domains listed here and hands it to their upstream. No mailboxes."),
},
CanManage: canManage,
List: Box{No: "01", Title: "Domains"},
List: Box{No: "01", Title: "Domains", Help: topicLink(HelpInbound, "Backup-MX and forwarding")},
Empty: EmptyState{Icon: "ti-world-download", Text: Plain("No inbound domains yet.")},
Legend: Foot{Bare: true, Text: Plain("The MX tag is green when at least one MX of the domain points at this server.")},
}
@@ -295,9 +295,9 @@ func NewInDomain(m Meta, in InDomainInput) *InDomain {
},
id: in.ID, name: in.Name, dnsStatus: in.DNSStatus, recipientCount: in.RecipientCount, recipientMode: in.RecipientMode,
DNS: Box{No: "01", Title: "MX record", ID: "dns"},
DNS: Box{No: "01", Title: "MX record", ID: "dns", Help: topicLink(HelpInbound, "Backup-MX and forwarding")},
Upstream: Box{No: "02", Title: "Upstream", ID: "upstream", End: Plain("Not a mailbox")},
Upstream: Box{No: "02", Title: "Upstream", ID: "upstream", End: Plain("Not a mailbox"), Help: topicLink(HelpUpstream, "Host, port and TLS")},
UpstreamAction: href + "/upstream",
Host: in.Host,
Port: strconv.Itoa(in.Port),
@@ -305,7 +305,7 @@ func NewInDomain(m Meta, in InDomainInput) *InDomain {
{Value: tlsModeNone, Label: "Off"}},
TLSSelected: in.TLSMode,
Recipients: Box{No: "03", Title: "Valid recipients", ID: "recipients"},
Recipients: Box{No: "03", Title: "Valid recipients", ID: "recipients", Help: topicLink(HelpRecipients, "Listed addresses or any address")},
RecipientsAction: href + "/recipients",
ModeOptions: []Option{{Value: "list", Label: "Listed addresses only"},
{Value: recipientModeAny, Label: "Any recipient at this domain"}},
@@ -313,7 +313,7 @@ func NewInDomain(m Meta, in InDomainInput) *InDomain {
Addresses: strings.Join(in.Addresses, "\n"),
RecipientsHelp: Plain("One per line or comma-separated. Unknown recipients are rejected at RCPT, so this relay generates no backscatter. Prefer a list unless the upstream itself rejects unknowns."),
Filter: Box{No: "04", Title: "Spam filter", ID: "filter"},
Filter: Box{No: "04", Title: "Spam filter", ID: "filter", Help: topicLink(HelpFilter, "A server setting")},
}
}