fix(ui): align campaign tables, recipient sizing and contextual help

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.
This commit is contained in:
2026-09-09 02:03:36 +02:00
parent 19437ce378
commit 11598b7b5b
9 changed files with 108 additions and 25 deletions
@@ -28,6 +28,8 @@ assert(!page.includes("downloadCampaignJobsCsv"), "the aggregate page has no exp
assert(!page.includes("localStorage"), "the aggregate page does not persist report data in local storage");
assert(!page.includes("sessionStorage"), "the aggregate page does not persist report data in session storage");
assert(page.includes("TableActionGroup"), "campaign selection uses the central icon-only table action group");
assert.match(page, /<Card\s+title="i18n:govoplan-campaign\.campaign_reports_available_to_you\.f14fa403"\s+bodyLayout="table">\s*<LoadingFrame[\s\S]*?<DataGrid/, "the report selector uses the shared edge-to-edge table body through its loading frame");
assert.match(attachmentsPage, /<Card\s+id="campaign-global-attachments"[^>]*bodyLayout="table"[^>]*collapsible>[\s\S]*?\{version && draft && <AttachmentRulesDataGrid/, "global attachments retain their collapsible table body and wait for real draft columns before restoring personal widths");
assert(page.includes("disabled: campaign.id === selectedFromUrl"), "the selected row action stays visible and disabled");
assert(page.includes('columnType: "from-list"'), "campaign status uses the stable shared list-filter model");
const expectedCampaignStatuses = [
@@ -29,4 +29,14 @@ assertIncludes(
"a row must explain when its match came from a hidden address"
);
assertIncludes("version && draft && !source.type", "recipient grids wait for the initial draft before restoring column widths");
const profileColumns = readFileSync(new URL("../src/features/campaigns/recipients/recipientProfileColumns.tsx", import.meta.url), "utf8");
for (const id of ["recipients", "delivery"]) {
const start = profileColumns.indexOf(`id: "${id}"`);
const declarations = profileColumns.slice(start, profileColumns.indexOf("render:", start));
if (!declarations.includes("resizable: true") || declarations.includes("maxWidth:")) {
throw new Error(`${id} remains user-expandable without an arbitrary hard display cap`);
}
}
console.log("Campaign recipient search covers and explains hidden address matches.");