The Email Campaigns widget, live on the launchpad

Featurekamo-internal
Shipped
September 16, 2026 at 3:56 PM UTC
Author
Kamo
Commit
d0b56ad

A new home widget, email.campaigns, on the launchpad of everybody who can open the campaigns. Its five rights (EMAIL_CAMPAIGNS_WIDGET, 321-325) hang off VIEW_BULK_EMAIL, and ADDED, OPTIONAL and MOVABLE seed from it in SecurityService, so it arrives on and is the member's to remove. The gate also asks for the Marketing app and VIEW_BULK_EMAIL itself. What it shows, reading EmailService's new /api/email/widget/campaigns once and moving live after that: - Four figures for the last two weeks (sent, opens, clicks, bounces), each with a bar a day that reads by pointer or arrow keys, and open and click rates out of delivered mail by the rule the deliverability card uses (engagementRate, now shared by both). - Live / Sent / Drafts, with counts. A sending campaign is a lane that moves, with its pace and time left; opens and clicks rise off it as they land. A paused one says why it cannot send; a scheduled one counts down; a sent one shows its open and click rates. Pause and resume sit on the row for a member with MANAGE_BULK_EMAIL. - A campaign that finishes while the pane watches stays on Live for its moment, with a burst, before it moves to Sent. - The bottom line carries the news as it happens; a wide pane keeps it in a column with today's totals. - It lays out for its room: two figures and compact rows at one column, whole rows only at any height (the list wraps rather than cuts), and two columns of campaigns in a wide pane only once one would hide some. The live half rides /topic/campaigns/<orgId>. useEmailCampaignsWebSocket reads every frame through readCampaignFrame and gains onEngagement, onChanged and onSnapshot, plus requestSnapshot, which the widget turns off so a launchpad never asks the whole organization for a snapshot. onProgress still sees only progress frames. The finish chime now fires on a transition into SENT, not on every later frame that still says SENT (late bounce and delivery reports republish it for hours), and the hook no longer writes its handlers ref during render. Verified with tsc, the guard scripts, the new and affected vitest files, and a headless harness over the real component at 1x1, 2x1, 2x2, 2x3 and full width.

All changes

Like what you see shipping?

All of it arrives in your workspace on its own. Start on the free plan and read this page again in a month.

Start Free ForeverView Pricing