diff --git a/client/src/routes/admin/views/PostEditor.jsx b/client/src/routes/admin/views/PostEditor.jsx index fb7e68c..61b90b5 100644 --- a/client/src/routes/admin/views/PostEditor.jsx +++ b/client/src/routes/admin/views/PostEditor.jsx @@ -177,14 +177,15 @@ const delStyle = { } // ── Announcement status panel ──────────────────────────────────────────────── -// Shows the town-crier + Discord delivery state for a published news post and -// offers a per-leg retry (useful after fixing the sidecar / news channel without -// re-publishing). Only rendered for news posts in edit mode; renders nothing -// until the post has actually been announced (no job row yet → nothing to show). -const LEG_META = { - towncrier: { label: 'In-game town crier' }, - discord: { label: 'Discord #news' }, -} +// Shows each delivery leg's state for a published news post and offers a per-leg +// retry (useful after fixing the sidecar / news channel without re-publishing). +// Only rendered for news posts in edit mode; renders nothing until the post has +// actually been announced (no job row yet → nothing to show). +// +// The legs and their labels come from the JOB, not from a constant here: which +// legs exist is decided by what the server has registered, so an installed module +// brings its own leg and this panel renders it with no client change +// (docs/website/MODULE_SYSTEM.md §1.8). const STATUS_STYLE = { done: { color: '#7bbf8f', label: 'delivered' }, pending: { color: '#d9b84a', label: 'pending' }, @@ -227,14 +228,12 @@ function AnnouncePanel({ postId }) { return (
Announcement - {['towncrier', 'discord'].map((leg) => { - const status = job[`${leg}_status`] - const err = job[`${leg}_last_error`] + {(job.legs || []).map(({ leg, label, status, last_error: err }) => { const s = STATUS_STYLE[status] || STATUS_STYLE.pending return (
- {LEG_META[leg].label} + {label} ● {s.label} {status !== 'done' && (