diff --git a/webui/src/features/campaigns/AttachmentsDataPage.tsx b/webui/src/features/campaigns/AttachmentsDataPage.tsx index d4aac9c..aff90f2 100644 --- a/webui/src/features/campaigns/AttachmentsDataPage.tsx +++ b/webui/src/features/campaigns/AttachmentsDataPage.tsx @@ -1,3 +1,4 @@ +import { MetricGrid } from "@govoplan/core-webui"; import { useEffect, useMemo, useState } from "react"; import { Pencil } from "lucide-react"; import { useGuardedNavigate, usePlatformModuleInstalled, usePlatformUiCapability, type FilesFileExplorerUiCapability, type FilesFileSpace } from "@govoplan/core-webui"; @@ -268,12 +269,12 @@ export default function AttachmentsDataPage({ settings, campaignId }: {settings: <> -
+ -
+
diff --git a/webui/src/features/campaigns/CampaignOverviewPage.tsx b/webui/src/features/campaigns/CampaignOverviewPage.tsx index 32056f4..761db7f 100644 --- a/webui/src/features/campaigns/CampaignOverviewPage.tsx +++ b/webui/src/features/campaigns/CampaignOverviewPage.tsx @@ -1,3 +1,4 @@ +import { MetricGrid } from "@govoplan/core-webui"; import { useEffect, useMemo, useState } from "react"; import { Archive, CalendarClock, Copy, ExternalLink, LockKeyhole, LockOpen, Pause, Play, Trash2 } from "lucide-react"; import { Link } from "react-router"; @@ -378,12 +379,12 @@ export default function CampaignOverviewPage({ settings, auth, campaignId }: {se > -
+ -
+
}> -
+ -
-
+ + -
+
-
+
i18n:govoplan-campaign.generated.8eefdd52
{formatDateTime(data.summary?.generated_at)}
{deliveryOutcomeShortcuts.map(({ label, value, shortcutId }) => { const active = activeJobGridShortcut === shortcutId; @@ -478,10 +479,10 @@ export default function CampaignReportPage({ settings, campaignId }: {settings:
); })} - +
-
+ {imapOutcomeShortcuts.map(({ label, value, shortcutId }) => { const active = activeJobGridShortcut === shortcutId; return ( @@ -499,10 +500,10 @@ export default function CampaignReportPage({ settings, campaignId }: {settings:
i18n:govoplan-campaign.rate_limit.d08e55f5
{rateLimit.messages_per_minute ? i18nMessage("i18n:govoplan-campaign.value_minute.aeb1a9ea", { value0: String(rateLimit.messages_per_minute) }) : "—"}
i18n:govoplan-campaign.minimum_remaining_duration.639b792c
{String(delivery.estimated_remaining_send_human ?? "—")}
i18n:govoplan-campaign.execution_snapshot.5a67f098
{delivery.execution_snapshot_hash ? i18nMessage("i18n:govoplan-campaign.value.382bcd25", { value0: String(delivery.execution_snapshot_hash).slice(0, 12) }) : "i18n:govoplan-campaign.missing.92185dc5"}
-
+
-
+
Evidence state
@@ -523,7 +524,7 @@ export default function CampaignReportPage({ settings, campaignId }: {settings:
Read
{String(postboxReceipts.read_delivery_count ?? "—")}
Acknowledged
{String(postboxReceipts.acknowledged_delivery_count ?? "—")}
Withdrawn / expired copies
{String(Number(postboxReceipts.withdrawn_message_count ?? 0) + Number(postboxReceipts.expired_message_count ?? 0))}
-
+
@@ -607,7 +608,7 @@ export default function CampaignReportPage({ settings, campaignId }: {settings: {detail &&
-
+
i18n:govoplan-campaign.recipient.90343260
{String(detail.job.recipient_email ?? "—")}
i18n:govoplan-campaign.subject.8d183dbd
{String(detail.job.subject ?? "—")}
i18n:govoplan-campaign.message_id.465056ba
{String(detail.job.message_id_header ?? "—")}
@@ -619,7 +620,7 @@ export default function CampaignReportPage({ settings, campaignId }: {settings:
i18n:govoplan-campaign.imap_state.03b83be0
i18n:govoplan-campaign.attachments.6771ade6
{String(detail.job.matched_file_count ?? detail.job.attachment_count ?? 0)}
Message SHA-256
{String(detail.job.eml_sha256 ?? "—")}
-
+

{retention.privacy_impact.summary}

{retention.policy_reason &&

{retention.policy_reason}

} -
+
i18n:govoplan-campaign.policy_state.7e955a0d
@@ -713,7 +714,7 @@ function RetentionPrivacyCard({ retention }: { retention?: CampaignRetentionRepo
)} -
+ ); } diff --git a/webui/src/features/campaigns/MailSettingsPage.tsx b/webui/src/features/campaigns/MailSettingsPage.tsx index 45a3964..8f2e0ce 100644 --- a/webui/src/features/campaigns/MailSettingsPage.tsx +++ b/webui/src/features/campaigns/MailSettingsPage.tsx @@ -1,3 +1,4 @@ +import { MetricGrid } from "@govoplan/core-webui"; import { useEffect, useState } from "react"; import { FormGrid, Button, @@ -412,12 +413,12 @@ export default function MailSettingsPage({ settings, campaignId, view = "setting {selectedProfileUnavailable && i18n:govoplan-campaign.the_referenced_mail_profile_is_inactive_unavaila.abeebe26} - {selectedProfile &&
+ {selectedProfile && -
} + }
@@ -432,7 +433,6 @@ export default function MailSettingsPage({ settings, campaignId, view = "setting title="Add campaign credential" onClose={() => setCredentialDialogOpen(false)} closeDisabled={credentialSaving} - className="adaptive-config-dialog" footerClassName="button-row compact-actions" footer={ <> diff --git a/webui/src/features/campaigns/ReviewSendPage.tsx b/webui/src/features/campaigns/ReviewSendPage.tsx index 3cc14ef..60a0f88 100644 --- a/webui/src/features/campaigns/ReviewSendPage.tsx +++ b/webui/src/features/campaigns/ReviewSendPage.tsx @@ -1,3 +1,4 @@ +import { DescriptionList } from "@govoplan/core-webui"; import { useCallback, useEffect, useMemo, useRef, useState } from "react"; import { BarChart3, @@ -1423,7 +1424,7 @@ export default function ReviewSendPage({ {visibleValidationIssues.length > 0 &&

i18n:govoplan-campaign.validation_details.aa503267

-
+ {visibleValidationIssues.map((issue, index) =>
{humanize(String(issue.severity ?? "issue"))}
@@ -1434,7 +1435,7 @@ export default function ReviewSendPage({
)} -
+ {validationIssues.length > visibleValidationIssues.length &&

i18n:govoplan-campaign.showing.163d8174 {visibleValidationIssues.length} of {validationIssues.length} i18n:govoplan-campaign.validation_issue_s.c6a8b911

}
} @@ -1488,11 +1489,11 @@ export default function ReviewSendPage({ )}
-
+
Template hash
{getText(printOutput, "template_hash") || "—"}
Input hash
{getText(printOutput, "input_hash") || "—"}
Output hash
{getText(printOutput, "output_sha256") || "—"}
-
+
)}
@@ -1815,7 +1816,7 @@ export default function ReviewSendPage({ {recentFailures.length > 0 &&

i18n:govoplan-campaign.recent_delivery_failures.282285fb

-
+ {recentFailures.map((failure, index) =>
{String(failure.recipient_email ?? failure.entry_id ?? i18nMessage("i18n:govoplan-campaign.value.44b8c76f", { value0: String(failure.entry_index ?? index + 1) }))}
@@ -1826,7 +1827,7 @@ export default function ReviewSendPage({
)} -
+
}
diff --git a/webui/src/features/campaigns/TemplateDataPage.tsx b/webui/src/features/campaigns/TemplateDataPage.tsx index 77f5e30..a0b79cf 100644 --- a/webui/src/features/campaigns/TemplateDataPage.tsx +++ b/webui/src/features/campaigns/TemplateDataPage.tsx @@ -694,7 +694,7 @@ export default function TemplateDataPage({ settings, campaignId }: {settings: Ap setContentSaveOpen(false)} diff --git a/webui/src/features/campaigns/components/PostboxTargetsDialog.tsx b/webui/src/features/campaigns/components/PostboxTargetsDialog.tsx index cd15d91..c93fbf1 100644 --- a/webui/src/features/campaigns/components/PostboxTargetsDialog.tsx +++ b/webui/src/features/campaigns/components/PostboxTargetsDialog.tsx @@ -91,7 +91,7 @@ export default function PostboxTargetsDialog({ -
+
Source
{snapshot.source_label}
@@ -295,7 +296,7 @@ export default function AddressSourceImportDialog({
Revision
{snapshot.source_revision}
-
+ {snapshot.excluded_count > 0 && ( {snapshot.excluded_count} contact point{snapshot.excluded_count === 1 ? " was" : "s were"} excluded by effective communication-governance facts. diff --git a/webui/src/features/campaigns/recipients/DistributionListImportDialog.tsx b/webui/src/features/campaigns/recipients/DistributionListImportDialog.tsx index 452e163..8d2949e 100644 --- a/webui/src/features/campaigns/recipients/DistributionListImportDialog.tsx +++ b/webui/src/features/campaigns/recipients/DistributionListImportDialog.tsx @@ -1,3 +1,4 @@ +import { DescriptionList } from "@govoplan/core-webui"; import { useEffect, useMemo, useState } from "react"; import { Button, @@ -294,7 +295,7 @@ export default function DistributionListImportDialog({ )} {preview && ( <> -
+
List
{preview.source.name}
Revision
{preview.source.revision}
Included
{preview.recipients.length}
@@ -302,7 +303,7 @@ export default function DistributionListImportDialog({
Providers
{preview.provider_evidence.length}
Route decisions
{unresolvedRoutes.length ? `${unresolvedRoutes.length} required` : "Complete"}
State
{preview.stale ? "Stale" : preview.truncated ? "Truncated" : "Current"}
-
+ {preview.stale && ( At least one provider result is stale. Review its diagnostics before freezing this expansion. diff --git a/webui/src/features/campaigns/recipients/RecipientImportDialog.tsx b/webui/src/features/campaigns/recipients/RecipientImportDialog.tsx index 3af2146..3946226 100644 --- a/webui/src/features/campaigns/recipients/RecipientImportDialog.tsx +++ b/webui/src/features/campaigns/recipients/RecipientImportDialog.tsx @@ -1,3 +1,4 @@ +import { DescriptionList } from "@govoplan/core-webui"; import { useEffect, useMemo, useState } from "react"; import type { ApiSettings } from "../../../types"; import { @@ -506,12 +507,12 @@ export function RecipientImportDialog({ settings, campaignId, existingEntries, e
{table && <> -
+
{sourceType === "xlsx" ? "i18n:govoplan-campaign.sheet.53bc47a7" : "i18n:govoplan-campaign.separator.b4b289a7"}
{sourceType === "xlsx" ? selectedSheet?.name ?? "i18n:govoplan-campaign.workbook.b4418e62" : formatDelimiter(table.delimiter)}
i18n:govoplan-campaign.header_rows.9814b9e3
{table.headerRows.length}
i18n:govoplan-campaign.data_rows.3734724c
{table.dataRows.length}
i18n:govoplan-campaign.columns.cf723c59
{table.headers.length}
-
+ } @@ -543,12 +544,12 @@ export function RecipientImportDialog({ settings, campaignId, existingEntries, e <> {preview && <> -
+
i18n:govoplan-campaign.rows.52d0b352
{preview.validCount} i18n:govoplan-campaign.valid.210cece7 {preview.invalidCount} invalid
i18n:govoplan-campaign.fields.e8b68527
{preview.fieldNamesToCreate.length} new
i18n:govoplan-campaign.patterns.4d34f7a2
{preview.patternCount} from {patternRows} i18n:govoplan-campaign.row_s.61464061
i18n:govoplan-campaign.source.6da13add
{preview.patternCount ? defaultAttachmentBasePath?.name ?? "i18n:govoplan-campaign.campaign_files.96e7004b" : "i18n:govoplan-campaign.no_patterns.5e1e46fa"}
-
+ {preview.fieldNamesToCreate.length > 0 &&

i18n:govoplan-campaign.new_fields.c61e20c0 {preview.fieldNamesToCreate.join(", ")}

} @@ -676,12 +677,12 @@ function RecipientImportFileLinkStep({ preview, basePath, resolution, resolving, {resolution && <> -
+
i18n:govoplan-campaign.patterns.4d34f7a2
{resolution.patterns.length}
i18n:govoplan-campaign.matched_files.f79c63bb
{resolution.files.length}
i18n:govoplan-campaign.already_linked.7d6c3dd5
{resolution.linkedFiles.length}
i18n:govoplan-campaign.need_linking.a7617722
{resolution.linkableFiles.length}
-
+ {resolution.unmatchedPatterns.length > 0 &&
diff --git a/webui/src/features/campaigns/review/DeliveryJobDetailOverlay.tsx b/webui/src/features/campaigns/review/DeliveryJobDetailOverlay.tsx index 6e5de23..b4c193c 100644 --- a/webui/src/features/campaigns/review/DeliveryJobDetailOverlay.tsx +++ b/webui/src/features/campaigns/review/DeliveryJobDetailOverlay.tsx @@ -1,3 +1,4 @@ +import { DescriptionList } from "@govoplan/core-webui"; import { Button, Dialog, i18nMessage } from "@govoplan/core-webui"; import { asArray, asRecord, formatDateTime, humanize } from "../utils/campaignView"; @@ -28,7 +29,7 @@ export default function DeliveryJobDetailOverlay({ } > -
+
i18n:govoplan-campaign.recipient.90343260
@@ -54,7 +55,7 @@ export default function DeliveryJobDetailOverlay({
{String(job.last_error)}
) : null} -
+ {issues.length > 0 && ( {emptyText}

) : ( -
+ {rows.map((row, index) => (
@@ -129,7 +130,7 @@ function AttemptList({
))} -
+ )} ); diff --git a/webui/src/features/campaigns/wizard/steps/CreateWizardSteps.tsx b/webui/src/features/campaigns/wizard/steps/CreateWizardSteps.tsx index 698dd62..e8cf826 100644 --- a/webui/src/features/campaigns/wizard/steps/CreateWizardSteps.tsx +++ b/webui/src/features/campaigns/wizard/steps/CreateWizardSteps.tsx @@ -1,3 +1,4 @@ +import { MetricGrid } from "@govoplan/core-webui"; import { useEffect, useState } from "react"; import { FormGrid, Button } from "@govoplan/core-webui"; import { FieldLabel } from "@govoplan/core-webui"; @@ -189,11 +190,11 @@ export function ReviewStep({ version, onValidate }: {version: unknown;onValidate

i18n:govoplan-campaign.review_setup.d0059acb

i18n:govoplan-campaign.validate_the_campaign_definition_before_building.d36ee1dc

-
+ -
+
); diff --git a/webui/src/features/operator/OperatorQueuePage.tsx b/webui/src/features/operator/OperatorQueuePage.tsx index 179466c..db96283 100644 --- a/webui/src/features/operator/OperatorQueuePage.tsx +++ b/webui/src/features/operator/OperatorQueuePage.tsx @@ -1,3 +1,4 @@ +import { MetricGrid } from "@govoplan/core-webui"; import { useCallback, useEffect, useMemo, useRef, useState } from "react"; import { Ban, ExternalLink, Eye, Pause, Play, RotateCcw, Send, ShieldCheck } from "lucide-react"; import { useSearchParams } from "react-router"; @@ -774,7 +775,7 @@ export default function OperatorQueuePage({ settings, auth }: {settings: ApiSett

i18n:govoplan-campaign.queue_pressure.28eee15e

-
+ @@ -784,7 +785,7 @@ export default function OperatorQueuePage({ settings, auth }: {settings: ApiSett -
+
diff --git a/webui/src/features/reports/AggregateReportsPage.tsx b/webui/src/features/reports/AggregateReportsPage.tsx index 92412b1..a2e7040 100644 --- a/webui/src/features/reports/AggregateReportsPage.tsx +++ b/webui/src/features/reports/AggregateReportsPage.tsx @@ -1,3 +1,4 @@ +import { DescriptionList } from "@govoplan/core-webui"; import { useCallback, useEffect, useMemo, useRef, useState } from "react"; import { Eye, RefreshCw } from "lucide-react"; import { useSearchParams } from "react-router"; @@ -198,12 +199,12 @@ export default function AggregateReportsPage({ settings }: {settings: ApiSetting {report && outcomes && ( <> -
+
i18n:govoplan-campaign.status.bae7d5be
i18n:govoplan-campaign.completion.2ff25568
i18n:govoplan-campaign.version.2da600bf
{report.version_number ?? "—"}
i18n:govoplan-campaign.generated.8eefdd52
{formatDateTime(report.generated_at)}
-
+
{/* Aggregate outcome cards are deliberately not filter shortcuts: each subgroup @@ -223,19 +224,19 @@ export default function AggregateReportsPage({ settings }: {settings: ApiSetting -
+
i18n:govoplan-campaign.report_denominator.d089074a
{countValue(report.population.denominator)}
i18n:govoplan-campaign.inactive_source_entries.88fa0cf8
{countValue(report.population.inactive_source_entries)}
i18n:govoplan-campaign.excluded_or_blocked_jobs.e2190d47
{countValue(report.population.excluded_or_blocked_jobs)}
-
+

i18n:govoplan-campaign.all_persisted_recipient_delivery_jobs_for_the_se.208e90cc

-
+
i18n:govoplan-campaign.first_activity.3fe36ef4
{report.time_range.suppressed ? "i18n:govoplan-campaign.suppressed.fce88db5" : formatDateTime(report.time_range.first_activity_at ?? undefined)}
i18n:govoplan-campaign.last_activity.1c73b806
{report.time_range.suppressed ? "i18n:govoplan-campaign.suppressed.fce88db5" : formatDateTime(report.time_range.last_activity_at ?? undefined)}
-
+
diff --git a/webui/src/features/templates/TemplatesPage.tsx b/webui/src/features/templates/TemplatesPage.tsx index dd25940..a4efa15 100644 --- a/webui/src/features/templates/TemplatesPage.tsx +++ b/webui/src/features/templates/TemplatesPage.tsx @@ -1,3 +1,4 @@ +import { DescriptionList } from "@govoplan/core-webui"; import { useMemo, useState } from "react"; import { ExternalLink } from "lucide-react"; import { FormGrid, ContentGrid, Button } from "@govoplan/core-webui"; @@ -206,12 +207,12 @@ function TemplateOverview({ template }: {template: TemplateRecord;}) { return ( -
+
i18n:govoplan-campaign.status.bae7d5be
i18n:govoplan-campaign.type.3deb7456
{templateTypeLabel(template.type)}
i18n:govoplan-campaign.updated.f2f8570d
{template.updatedAt}
i18n:govoplan-campaign.versions.a239107e
{template.versions}
-
+

i18n:govoplan-campaign.campaigns_can_reuse_this_template_but_each_campa.bdb25009

@@ -285,10 +286,10 @@ function TemplateUsage({ template }: {template: TemplateRecord;}) { return (

i18n:govoplan-campaign.this_view_will_list_campaigns_using_the_template.116f7ee0

-
+
i18n:govoplan-campaign.currently_used_by.a065cfbe
{template.usedBy}
i18n:govoplan-campaign.safe_to_edit.57b64df5
i18n:govoplan-campaign.requires_versioning_once_templates_are_shared.e020b221
-
+
); } diff --git a/webui/src/styles/campaign-workspace.css b/webui/src/styles/campaign-workspace.css index d924ef1..34c498d 100644 --- a/webui/src/styles/campaign-workspace.css +++ b/webui/src/styles/campaign-workspace.css @@ -299,20 +299,16 @@ color: var(--text-strong); font-size: 16px; } -.queue-pressure-grid { - grid-template-columns: repeat(5, minmax(112px, 1fr)); - margin: 0; -} -.queue-pressure-grid .metric-card { +.queue-pressure-metrics { min-width: 0; } -.queue-pressure-grid .metric-label { +.queue-pressure-metrics .metric-card { + min-width: 0; +} +.queue-pressure-metrics .metric-label { min-height: 2.4em; } -@media (max-width: 1150px) { - .queue-pressure-grid { grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); } -} .module-table th, .module-table td { white-space: nowrap; @@ -966,10 +962,6 @@ margin-top: 16px; } -.campaign-postbox-target-modal { - width: min(1040px, calc(100vw - 32px)); -} - .campaign-postbox-target-body { max-height: min(76vh, 820px); overflow: auto; @@ -2799,7 +2791,6 @@ } .campaign-content-library-dialog { width: min(880px, calc(100vw - 32px)); } -.campaign-content-save-dialog { width: min(680px, calc(100vw - 32px)); } .campaign-content-library, .campaign-content-save-form { display: grid; gap: 14px; } .campaign-content-library input, .campaign-content-save-form input, .campaign-content-save-form textarea { width: 100%; } .campaign-content-library-list { display: grid; max-height: min(56vh, 560px); overflow: auto; border: var(--border-line); }