Adopt shared WebUI layout primitives
This commit is contained in:
@@ -1,3 +1,4 @@
|
|||||||
|
import { MetricGrid } from "@govoplan/core-webui";
|
||||||
import { useEffect, useMemo, useState } from "react";
|
import { useEffect, useMemo, useState } from "react";
|
||||||
import { Pencil } from "lucide-react";
|
import { Pencil } from "lucide-react";
|
||||||
import { useGuardedNavigate, usePlatformModuleInstalled, usePlatformUiCapability, type FilesFileExplorerUiCapability, type FilesFileSpace } from "@govoplan/core-webui";
|
import { useGuardedNavigate, usePlatformModuleInstalled, usePlatformUiCapability, type FilesFileExplorerUiCapability, type FilesFileSpace } from "@govoplan/core-webui";
|
||||||
@@ -268,12 +269,12 @@ export default function AttachmentsDataPage({ settings, campaignId }: {settings:
|
|||||||
|
|
||||||
<LoadingFrame loading={loading || !draft} label="i18n:govoplan-campaign.loading_campaign_draft.1cf47e50">
|
<LoadingFrame loading={loading || !draft} label="i18n:govoplan-campaign.loading_campaign_draft.1cf47e50">
|
||||||
<>
|
<>
|
||||||
<div className="metric-grid attachment-statistics-grid">
|
<MetricGrid>
|
||||||
<MetricCard label="i18n:govoplan-campaign.base_paths.edf35a97" value={basePaths.length} tone="neutral" />
|
<MetricCard label="i18n:govoplan-campaign.base_paths.edf35a97" value={basePaths.length} tone="neutral" />
|
||||||
<MetricCard label="i18n:govoplan-campaign.global_attachments.438263a1" value={`${globalSummary.direct} / ${globalSummary.rules}`} tone="info" detail="direct / rules" />
|
<MetricCard label="i18n:govoplan-campaign.global_attachments.438263a1" value={`${globalSummary.direct} / ${globalSummary.rules}`} tone="info" detail="direct / rules" />
|
||||||
<MetricCard label="i18n:govoplan-campaign.per_recipient_patterns.53da30da" value={individualRulesCount} tone="neutral" />
|
<MetricCard label="i18n:govoplan-campaign.per_recipient_patterns.53da30da" value={individualRulesCount} tone="neutral" />
|
||||||
<MetricCard label="i18n:govoplan-campaign.upload_support.1c54931c" value={managedFilesAvailable ? "Files" : "Manual"} tone={managedFilesAvailable ? "good" : filesModuleInstalled ? "warning" : "neutral"} />
|
<MetricCard label="i18n:govoplan-campaign.upload_support.1c54931c" value={managedFilesAvailable ? "Files" : "Manual"} tone={managedFilesAvailable ? "good" : filesModuleInstalled ? "warning" : "neutral"} />
|
||||||
</div>
|
</MetricGrid>
|
||||||
|
|
||||||
<Card title="i18n:govoplan-campaign.attachment_sources.8ef0a6ce">
|
<Card title="i18n:govoplan-campaign.attachment_sources.8ef0a6ce">
|
||||||
<div className="admin-table-surface attachment-sources-table-surface">
|
<div className="admin-table-surface attachment-sources-table-surface">
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import { MetricGrid } from "@govoplan/core-webui";
|
||||||
import { useEffect, useMemo, useState } from "react";
|
import { useEffect, useMemo, useState } from "react";
|
||||||
import { Archive, CalendarClock, Copy, ExternalLink, LockKeyhole, LockOpen, Pause, Play, Trash2 } from "lucide-react";
|
import { Archive, CalendarClock, Copy, ExternalLink, LockKeyhole, LockOpen, Pause, Play, Trash2 } from "lucide-react";
|
||||||
import { Link } from "react-router";
|
import { Link } from "react-router";
|
||||||
@@ -378,12 +379,12 @@ export default function CampaignOverviewPage({ settings, auth, campaignId }: {se
|
|||||||
>
|
>
|
||||||
|
|
||||||
<LoadingFrame loading={loading} label="i18n:govoplan-campaign.loading_campaign_overview.ffa1adf0">
|
<LoadingFrame loading={loading} label="i18n:govoplan-campaign.loading_campaign_overview.ffa1adf0">
|
||||||
<div className="metric-grid campaign-overview-metrics">
|
<MetricGrid>
|
||||||
<MetricCard label="i18n:govoplan-campaign.queueable.ea776f8d" value={data.summary?.cards?.queueable ?? "—"} tone="good" detail="i18n:govoplan-campaign.ready_or_warning.4dcce676" />
|
<MetricCard label="i18n:govoplan-campaign.queueable.ea776f8d" value={data.summary?.cards?.queueable ?? "—"} tone="good" detail="i18n:govoplan-campaign.ready_or_warning.4dcce676" />
|
||||||
<MetricCard label="i18n:govoplan-campaign.needs_attention.a126722e" value={data.summary?.cards?.needs_attention ?? "—"} tone="warning" detail="i18n:govoplan-campaign.review_first.741ac781" />
|
<MetricCard label="i18n:govoplan-campaign.needs_attention.a126722e" value={data.summary?.cards?.needs_attention ?? "—"} tone="warning" detail="i18n:govoplan-campaign.review_first.741ac781" />
|
||||||
<MetricCard label="i18n:govoplan-campaign.sent.35f49dcf" value={data.summary?.cards?.sent ?? "—"} tone="info" detail="i18n:govoplan-campaign.smtp_success.3591a856" />
|
<MetricCard label="i18n:govoplan-campaign.sent.35f49dcf" value={data.summary?.cards?.sent ?? "—"} tone="info" detail="i18n:govoplan-campaign.smtp_success.3591a856" />
|
||||||
<MetricCard label="i18n:govoplan-campaign.failed.09fef5d8" value={data.summary?.cards?.failed ?? "—"} tone="danger" detail="i18n:govoplan-campaign.smtp_failures.00b33b85" />
|
<MetricCard label="i18n:govoplan-campaign.failed.09fef5d8" value={data.summary?.cards?.failed ?? "—"} tone="danger" detail="i18n:govoplan-campaign.smtp_failures.00b33b85" />
|
||||||
</div>
|
</MetricGrid>
|
||||||
|
|
||||||
<Card
|
<Card
|
||||||
title="i18n:govoplan-campaign.campaign_identity.a00ca574"
|
title="i18n:govoplan-campaign.campaign_identity.a00ca574"
|
||||||
@@ -451,18 +452,18 @@ export default function CampaignOverviewPage({ settings, auth, campaignId }: {se
|
|||||||
i18n:govoplan-campaign.open.cf9b7706
|
i18n:govoplan-campaign.open.cf9b7706
|
||||||
</Link>
|
</Link>
|
||||||
</div>}>
|
</div>}>
|
||||||
<div className="metric-grid inside campaign-versions-metrics">
|
<MetricGrid spacing="inset">
|
||||||
<MetricCard label="i18n:govoplan-campaign.version.2da600bf" value={data.currentVersion?.version_number ? `#${data.currentVersion.version_number}` : "—"} tone="neutral" />
|
<MetricCard label="i18n:govoplan-campaign.version.2da600bf" value={data.currentVersion?.version_number ? `#${data.currentVersion.version_number}` : "—"} tone="neutral" />
|
||||||
<MetricCard label="i18n:govoplan-campaign.fields.e8b68527" value={versionMetrics.fieldCount} tone="info" />
|
<MetricCard label="i18n:govoplan-campaign.fields.e8b68527" value={versionMetrics.fieldCount} tone="info" />
|
||||||
<MetricCard label="i18n:govoplan-campaign.recipients.78cbf8eb" value={versionMetrics.recipientCount} tone="neutral" detail="i18n:govoplan-campaign.active_inline_recipients.8ba58f6e" />
|
<MetricCard label="i18n:govoplan-campaign.recipients.78cbf8eb" value={versionMetrics.recipientCount} tone="neutral" detail="i18n:govoplan-campaign.active_inline_recipients.8ba58f6e" />
|
||||||
<MetricCard label="i18n:govoplan-campaign.template_health.22e14b59" value={versionMetrics.templateHealthValue} tone={versionMetrics.templateHealthTone} detail={versionMetrics.templateHealthDetail} />
|
<MetricCard label="i18n:govoplan-campaign.template_health.22e14b59" value={versionMetrics.templateHealthValue} tone={versionMetrics.templateHealthTone} detail={versionMetrics.templateHealthDetail} />
|
||||||
</div>
|
</MetricGrid>
|
||||||
<div className="metric-grid inside">
|
<MetricGrid spacing="inset">
|
||||||
<MetricCard label="i18n:govoplan-campaign.validation_errors.e54ca4fe" value={summaryValue(data.currentVersion?.validation_summary, ["error_count", "errors", "blocked"])} />
|
<MetricCard label="i18n:govoplan-campaign.validation_errors.e54ca4fe" value={summaryValue(data.currentVersion?.validation_summary, ["error_count", "errors", "blocked"])} />
|
||||||
<MetricCard label="i18n:govoplan-campaign.warnings.1430f976" value={summaryValue(data.currentVersion?.validation_summary, ["warning_count", "warnings"])} />
|
<MetricCard label="i18n:govoplan-campaign.warnings.1430f976" value={summaryValue(data.currentVersion?.validation_summary, ["warning_count", "warnings"])} />
|
||||||
<MetricCard label="i18n:govoplan-campaign.built_messages.1fb804f2" value={summaryValue(data.currentVersion?.build_summary, ["built_count", "built", "messages_built"])} />
|
<MetricCard label="i18n:govoplan-campaign.built_messages.1fb804f2" value={summaryValue(data.currentVersion?.build_summary, ["built_count", "built", "messages_built"])} />
|
||||||
<MetricCard label="i18n:govoplan-campaign.jobs_total.98da65bc" value={data.summary?.cards?.jobs_total ?? "—"} />
|
<MetricCard label="i18n:govoplan-campaign.jobs_total.98da65bc" value={data.summary?.cards?.jobs_total ?? "—"} />
|
||||||
</div>
|
</MetricGrid>
|
||||||
<div className="admin-table-surface version-history-table-surface">
|
<div className="admin-table-surface version-history-table-surface">
|
||||||
<DataGrid
|
<DataGrid
|
||||||
id={`campaign-${campaignId}-versions`}
|
id={`campaign-${campaignId}-versions`}
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import { DescriptionList } from "@govoplan/core-webui";
|
||||||
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
|
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
|
||||||
import { Check, RotateCcw, Search, X } from "lucide-react";
|
import { Check, RotateCcw, Search, X } from "lucide-react";
|
||||||
import type { ApiSettings } from "../../types";
|
import type { ApiSettings } from "../../types";
|
||||||
@@ -463,7 +464,7 @@ export default function CampaignReportPage({ settings, campaignId }: {settings:
|
|||||||
<LoadingFrame loading={loading} label="i18n:govoplan-campaign.loading_report_data.0908ade5">
|
<LoadingFrame loading={loading} label="i18n:govoplan-campaign.loading_report_data.0908ade5">
|
||||||
<ContentGrid columns={2} collapseAt="workspace" className="">
|
<ContentGrid columns={2} collapseAt="workspace" className="">
|
||||||
<Card title="i18n:govoplan-campaign.delivery_outcome.f9d7c085">
|
<Card title="i18n:govoplan-campaign.delivery_outcome.f9d7c085">
|
||||||
<dl className="detail-list">
|
<DescriptionList variant="inline">
|
||||||
<div><dt>i18n:govoplan-campaign.generated.8eefdd52</dt><dd>{formatDateTime(data.summary?.generated_at)}</dd></div>
|
<div><dt>i18n:govoplan-campaign.generated.8eefdd52</dt><dd>{formatDateTime(data.summary?.generated_at)}</dd></div>
|
||||||
{deliveryOutcomeShortcuts.map(({ label, value, shortcutId }) => {
|
{deliveryOutcomeShortcuts.map(({ label, value, shortcutId }) => {
|
||||||
const active = activeJobGridShortcut === shortcutId;
|
const active = activeJobGridShortcut === shortcutId;
|
||||||
@@ -478,10 +479,10 @@ export default function CampaignReportPage({ settings, campaignId }: {settings:
|
|||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
</dl>
|
</DescriptionList>
|
||||||
</Card>
|
</Card>
|
||||||
<Card title="i18n:govoplan-campaign.imap_and_execution_plan.4c80c058">
|
<Card title="i18n:govoplan-campaign.imap_and_execution_plan.4c80c058">
|
||||||
<dl className="detail-list">
|
<DescriptionList variant="inline">
|
||||||
{imapOutcomeShortcuts.map(({ label, value, shortcutId }) => {
|
{imapOutcomeShortcuts.map(({ label, value, shortcutId }) => {
|
||||||
const active = activeJobGridShortcut === shortcutId;
|
const active = activeJobGridShortcut === shortcutId;
|
||||||
return (
|
return (
|
||||||
@@ -499,10 +500,10 @@ export default function CampaignReportPage({ settings, campaignId }: {settings:
|
|||||||
<div><dt>i18n:govoplan-campaign.rate_limit.d08e55f5</dt><dd>{rateLimit.messages_per_minute ? i18nMessage("i18n:govoplan-campaign.value_minute.aeb1a9ea", { value0: String(rateLimit.messages_per_minute) }) : "—"}</dd></div>
|
<div><dt>i18n:govoplan-campaign.rate_limit.d08e55f5</dt><dd>{rateLimit.messages_per_minute ? i18nMessage("i18n:govoplan-campaign.value_minute.aeb1a9ea", { value0: String(rateLimit.messages_per_minute) }) : "—"}</dd></div>
|
||||||
<div><dt>i18n:govoplan-campaign.minimum_remaining_duration.639b792c</dt><dd>{String(delivery.estimated_remaining_send_human ?? "—")}</dd></div>
|
<div><dt>i18n:govoplan-campaign.minimum_remaining_duration.639b792c</dt><dd>{String(delivery.estimated_remaining_send_human ?? "—")}</dd></div>
|
||||||
<div><dt>i18n:govoplan-campaign.execution_snapshot.5a67f098</dt><dd title={String(delivery.execution_snapshot_hash ?? "")}>{delivery.execution_snapshot_hash ? i18nMessage("i18n:govoplan-campaign.value.382bcd25", { value0: String(delivery.execution_snapshot_hash).slice(0, 12) }) : "i18n:govoplan-campaign.missing.92185dc5"}</dd></div>
|
<div><dt>i18n:govoplan-campaign.execution_snapshot.5a67f098</dt><dd title={String(delivery.execution_snapshot_hash ?? "")}>{delivery.execution_snapshot_hash ? i18nMessage("i18n:govoplan-campaign.value.382bcd25", { value0: String(delivery.execution_snapshot_hash).slice(0, 12) }) : "i18n:govoplan-campaign.missing.92185dc5"}</dd></div>
|
||||||
</dl>
|
</DescriptionList>
|
||||||
</Card>
|
</Card>
|
||||||
<Card title="Postbox receipt evidence">
|
<Card title="Postbox receipt evidence">
|
||||||
<dl className="detail-list">
|
<DescriptionList variant="inline">
|
||||||
<div>
|
<div>
|
||||||
<dt>Evidence state</dt>
|
<dt>Evidence state</dt>
|
||||||
<dd>
|
<dd>
|
||||||
@@ -523,7 +524,7 @@ export default function CampaignReportPage({ settings, campaignId }: {settings:
|
|||||||
<div><dt>Read</dt><dd>{String(postboxReceipts.read_delivery_count ?? "—")}</dd></div>
|
<div><dt>Read</dt><dd>{String(postboxReceipts.read_delivery_count ?? "—")}</dd></div>
|
||||||
<div><dt>Acknowledged</dt><dd>{String(postboxReceipts.acknowledged_delivery_count ?? "—")}</dd></div>
|
<div><dt>Acknowledged</dt><dd>{String(postboxReceipts.acknowledged_delivery_count ?? "—")}</dd></div>
|
||||||
<div><dt>Withdrawn / expired copies</dt><dd>{String(Number(postboxReceipts.withdrawn_message_count ?? 0) + Number(postboxReceipts.expired_message_count ?? 0))}</dd></div>
|
<div><dt>Withdrawn / expired copies</dt><dd>{String(Number(postboxReceipts.withdrawn_message_count ?? 0) + Number(postboxReceipts.expired_message_count ?? 0))}</dd></div>
|
||||||
</dl>
|
</DescriptionList>
|
||||||
</Card>
|
</Card>
|
||||||
<RetentionPrivacyCard retention={retention} />
|
<RetentionPrivacyCard retention={retention} />
|
||||||
<Card title="i18n:govoplan-campaign.explicit_delivery_actions.b35e72a4">
|
<Card title="i18n:govoplan-campaign.explicit_delivery_actions.b35e72a4">
|
||||||
@@ -607,7 +608,7 @@ export default function CampaignReportPage({ settings, campaignId }: {settings:
|
|||||||
|
|
||||||
{detail &&
|
{detail &&
|
||||||
<div className="stacked-sections">
|
<div className="stacked-sections">
|
||||||
<dl className="detail-list">
|
<DescriptionList variant="inline">
|
||||||
<div><dt>i18n:govoplan-campaign.recipient.90343260</dt><dd>{String(detail.job.recipient_email ?? "—")}</dd></div>
|
<div><dt>i18n:govoplan-campaign.recipient.90343260</dt><dd>{String(detail.job.recipient_email ?? "—")}</dd></div>
|
||||||
<div><dt>i18n:govoplan-campaign.subject.8d183dbd</dt><dd>{String(detail.job.subject ?? "—")}</dd></div>
|
<div><dt>i18n:govoplan-campaign.subject.8d183dbd</dt><dd>{String(detail.job.subject ?? "—")}</dd></div>
|
||||||
<div><dt>i18n:govoplan-campaign.message_id.465056ba</dt><dd>{String(detail.job.message_id_header ?? "—")}</dd></div>
|
<div><dt>i18n:govoplan-campaign.message_id.465056ba</dt><dd>{String(detail.job.message_id_header ?? "—")}</dd></div>
|
||||||
@@ -619,7 +620,7 @@ export default function CampaignReportPage({ settings, campaignId }: {settings:
|
|||||||
<div><dt>i18n:govoplan-campaign.imap_state.03b83be0</dt><dd><StatusBadge status={String(detail.job.imap_status ?? "unknown")} label={deliveryStatusLabel(String(detail.job.imap_status ?? "unknown"))} /></dd></div>
|
<div><dt>i18n:govoplan-campaign.imap_state.03b83be0</dt><dd><StatusBadge status={String(detail.job.imap_status ?? "unknown")} label={deliveryStatusLabel(String(detail.job.imap_status ?? "unknown"))} /></dd></div>
|
||||||
<div><dt>i18n:govoplan-campaign.attachments.6771ade6</dt><dd>{String(detail.job.matched_file_count ?? detail.job.attachment_count ?? 0)}</dd></div>
|
<div><dt>i18n:govoplan-campaign.attachments.6771ade6</dt><dd>{String(detail.job.matched_file_count ?? detail.job.attachment_count ?? 0)}</dd></div>
|
||||||
<div><dt>Message SHA-256</dt><dd><code>{String(detail.job.eml_sha256 ?? "—")}</code></dd></div>
|
<div><dt>Message SHA-256</dt><dd><code>{String(detail.job.eml_sha256 ?? "—")}</code></dd></div>
|
||||||
</dl>
|
</DescriptionList>
|
||||||
<PostboxTargetEvidenceSection
|
<PostboxTargetEvidenceSection
|
||||||
targets={
|
targets={
|
||||||
Array.isArray(detail.job.resolved_postbox_targets)
|
Array.isArray(detail.job.resolved_postbox_targets)
|
||||||
@@ -671,7 +672,7 @@ function RetentionPrivacyCard({ retention }: { retention?: CampaignRetentionRepo
|
|||||||
<Card title="i18n:govoplan-campaign.retention_and_privacy.24418676">
|
<Card title="i18n:govoplan-campaign.retention_and_privacy.24418676">
|
||||||
<p>{retention.privacy_impact.summary}</p>
|
<p>{retention.privacy_impact.summary}</p>
|
||||||
{retention.policy_reason && <p className="muted">{retention.policy_reason}</p>}
|
{retention.policy_reason && <p className="muted">{retention.policy_reason}</p>}
|
||||||
<dl className="detail-list">
|
<DescriptionList variant="inline">
|
||||||
<div>
|
<div>
|
||||||
<dt>i18n:govoplan-campaign.policy_state.7e955a0d</dt>
|
<dt>i18n:govoplan-campaign.policy_state.7e955a0d</dt>
|
||||||
<dd>
|
<dd>
|
||||||
@@ -713,7 +714,7 @@ function RetentionPrivacyCard({ retention }: { retention?: CampaignRetentionRepo
|
|||||||
</dd>
|
</dd>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</dl>
|
</DescriptionList>
|
||||||
</Card>
|
</Card>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import { MetricGrid } from "@govoplan/core-webui";
|
||||||
import { useEffect, useState } from "react";
|
import { useEffect, useState } from "react";
|
||||||
import { FormGrid,
|
import { FormGrid,
|
||||||
Button,
|
Button,
|
||||||
@@ -412,12 +413,12 @@ export default function MailSettingsPage({ settings, campaignId, view = "setting
|
|||||||
</FormField>
|
</FormField>
|
||||||
</FormGrid>
|
</FormGrid>
|
||||||
{selectedProfileUnavailable && <DismissibleAlert tone="warning" dismissible={false}>i18n:govoplan-campaign.the_referenced_mail_profile_is_inactive_unavaila.abeebe26</DismissibleAlert>}
|
{selectedProfileUnavailable && <DismissibleAlert tone="warning" dismissible={false}>i18n:govoplan-campaign.the_referenced_mail_profile_is_inactive_unavaila.abeebe26</DismissibleAlert>}
|
||||||
{selectedProfile && <div className="metric-grid inside">
|
{selectedProfile && <MetricGrid spacing="inset">
|
||||||
<MetricCard label="i18n:govoplan-campaign.profile.ff4fc027" value={selectedProfile.name} />
|
<MetricCard label="i18n:govoplan-campaign.profile.ff4fc027" value={selectedProfile.name} />
|
||||||
<MetricCard label="i18n:govoplan-campaign.scope.4651a34e" value={profileScopeLabel(selectedProfile)} />
|
<MetricCard label="i18n:govoplan-campaign.scope.4651a34e" value={profileScopeLabel(selectedProfile)} />
|
||||||
<MetricCard label="i18n:govoplan-campaign.smtp.efff9cca" value={selectedSmtpServer?.name || "i18n:govoplan-campaign.not_configured.811931bb"} tone={selectedSmtpServer ? "good" : "neutral"} />
|
<MetricCard label="i18n:govoplan-campaign.smtp.efff9cca" value={selectedSmtpServer?.name || "i18n:govoplan-campaign.not_configured.811931bb"} tone={selectedSmtpServer ? "good" : "neutral"} />
|
||||||
<MetricCard label="i18n:govoplan-campaign.imap.271f9ef2" value={selectedImapServer?.name || "i18n:govoplan-campaign.not_configured.811931bb"} tone={selectedImapServer ? "good" : "neutral"} />
|
<MetricCard label="i18n:govoplan-campaign.imap.271f9ef2" value={selectedImapServer?.name || "i18n:govoplan-campaign.not_configured.811931bb"} tone={selectedImapServer ? "good" : "neutral"} />
|
||||||
</div>}
|
</MetricGrid>}
|
||||||
<div className="button-row compact-actions">
|
<div className="button-row compact-actions">
|
||||||
<Button onClick={() => void runProfileTest("smtp")} disabled={!selectedSmtpServer || locked || Boolean(mailActionState)}>{mailActionState === "smtp" ? "i18n:govoplan-campaign.testing_smtp.8e9f8247" : "i18n:govoplan-campaign.test_profile_smtp.884a0e66"}</Button>
|
<Button onClick={() => void runProfileTest("smtp")} disabled={!selectedSmtpServer || locked || Boolean(mailActionState)}>{mailActionState === "smtp" ? "i18n:govoplan-campaign.testing_smtp.8e9f8247" : "i18n:govoplan-campaign.test_profile_smtp.884a0e66"}</Button>
|
||||||
<Button onClick={() => void runProfileTest("imap")} disabled={!selectedProfileHasImap || locked || Boolean(mailActionState)}>{mailActionState === "imap" ? "i18n:govoplan-campaign.testing_imap.13d255cf" : "i18n:govoplan-campaign.test_profile_imap.e1cec0e0"}</Button>
|
<Button onClick={() => void runProfileTest("imap")} disabled={!selectedProfileHasImap || locked || Boolean(mailActionState)}>{mailActionState === "imap" ? "i18n:govoplan-campaign.testing_imap.13d255cf" : "i18n:govoplan-campaign.test_profile_imap.e1cec0e0"}</Button>
|
||||||
@@ -432,7 +433,6 @@ export default function MailSettingsPage({ settings, campaignId, view = "setting
|
|||||||
title="Add campaign credential"
|
title="Add campaign credential"
|
||||||
onClose={() => setCredentialDialogOpen(false)}
|
onClose={() => setCredentialDialogOpen(false)}
|
||||||
closeDisabled={credentialSaving}
|
closeDisabled={credentialSaving}
|
||||||
className="adaptive-config-dialog"
|
|
||||||
footerClassName="button-row compact-actions"
|
footerClassName="button-row compact-actions"
|
||||||
footer={
|
footer={
|
||||||
<>
|
<>
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import { DescriptionList } from "@govoplan/core-webui";
|
||||||
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
|
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
|
||||||
import {
|
import {
|
||||||
BarChart3,
|
BarChart3,
|
||||||
@@ -1423,7 +1424,7 @@ export default function ReviewSendPage({
|
|||||||
{visibleValidationIssues.length > 0 &&
|
{visibleValidationIssues.length > 0 &&
|
||||||
<div className="review-flow-data-section">
|
<div className="review-flow-data-section">
|
||||||
<h3>i18n:govoplan-campaign.validation_details.aa503267</h3>
|
<h3>i18n:govoplan-campaign.validation_details.aa503267</h3>
|
||||||
<dl className="detail-list">
|
<DescriptionList variant="inline">
|
||||||
{visibleValidationIssues.map((issue, index) =>
|
{visibleValidationIssues.map((issue, index) =>
|
||||||
<div key={`${String(issue.code ?? "issue")}:${index}`}>
|
<div key={`${String(issue.code ?? "issue")}:${index}`}>
|
||||||
<dt>{humanize(String(issue.severity ?? "issue"))}</dt>
|
<dt>{humanize(String(issue.severity ?? "issue"))}</dt>
|
||||||
@@ -1434,7 +1435,7 @@ export default function ReviewSendPage({
|
|||||||
</dd>
|
</dd>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</dl>
|
</DescriptionList>
|
||||||
{validationIssues.length > visibleValidationIssues.length && <p className="muted small-note">i18n:govoplan-campaign.showing.163d8174 {visibleValidationIssues.length} of {validationIssues.length} i18n:govoplan-campaign.validation_issue_s.c6a8b911</p>}
|
{validationIssues.length > visibleValidationIssues.length && <p className="muted small-note">i18n:govoplan-campaign.showing.163d8174 {visibleValidationIssues.length} of {validationIssues.length} i18n:govoplan-campaign.validation_issue_s.c6a8b911</p>}
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
@@ -1488,11 +1489,11 @@ export default function ReviewSendPage({
|
|||||||
</Button>
|
</Button>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
<dl className="detail-list">
|
<DescriptionList variant="inline">
|
||||||
<div><dt>Template hash</dt><dd><code>{getText(printOutput, "template_hash") || "—"}</code></dd></div>
|
<div><dt>Template hash</dt><dd><code>{getText(printOutput, "template_hash") || "—"}</code></dd></div>
|
||||||
<div><dt>Input hash</dt><dd><code>{getText(printOutput, "input_hash") || "—"}</code></dd></div>
|
<div><dt>Input hash</dt><dd><code>{getText(printOutput, "input_hash") || "—"}</code></dd></div>
|
||||||
<div><dt>Output hash</dt><dd><code>{getText(printOutput, "output_sha256") || "—"}</code></dd></div>
|
<div><dt>Output hash</dt><dd><code>{getText(printOutput, "output_sha256") || "—"}</code></dd></div>
|
||||||
</dl>
|
</DescriptionList>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
<div className="button-row compact-actions review-flow-stage-actions">
|
<div className="button-row compact-actions review-flow-stage-actions">
|
||||||
@@ -1815,7 +1816,7 @@ export default function ReviewSendPage({
|
|||||||
{recentFailures.length > 0 &&
|
{recentFailures.length > 0 &&
|
||||||
<div className="review-flow-data-section">
|
<div className="review-flow-data-section">
|
||||||
<h3>i18n:govoplan-campaign.recent_delivery_failures.282285fb</h3>
|
<h3>i18n:govoplan-campaign.recent_delivery_failures.282285fb</h3>
|
||||||
<dl className="detail-list">
|
<DescriptionList variant="inline">
|
||||||
{recentFailures.map((failure, index) =>
|
{recentFailures.map((failure, index) =>
|
||||||
<div key={String(failure.job_id ?? index)}>
|
<div key={String(failure.job_id ?? index)}>
|
||||||
<dt>{String(failure.recipient_email ?? failure.entry_id ?? i18nMessage("i18n:govoplan-campaign.value.44b8c76f", { value0: String(failure.entry_index ?? index + 1) }))}</dt>
|
<dt>{String(failure.recipient_email ?? failure.entry_id ?? i18nMessage("i18n:govoplan-campaign.value.44b8c76f", { value0: String(failure.entry_index ?? index + 1) }))}</dt>
|
||||||
@@ -1826,7 +1827,7 @@ export default function ReviewSendPage({
|
|||||||
</dd>
|
</dd>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</dl>
|
</DescriptionList>
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
<div className="button-row compact-actions">
|
<div className="button-row compact-actions">
|
||||||
|
|||||||
@@ -694,7 +694,7 @@ export default function TemplateDataPage({ settings, campaignId }: {settings: Ap
|
|||||||
<Dialog
|
<Dialog
|
||||||
open={contentSaveOpen}
|
open={contentSaveOpen}
|
||||||
title="Save reusable content"
|
title="Save reusable content"
|
||||||
className="campaign-content-save-dialog"
|
size="large"
|
||||||
helpContextId="campaign.template.content-library"
|
helpContextId="campaign.template.content-library"
|
||||||
closeDisabled={contentSaveBusy}
|
closeDisabled={contentSaveBusy}
|
||||||
onClose={() => setContentSaveOpen(false)}
|
onClose={() => setContentSaveOpen(false)}
|
||||||
|
|||||||
@@ -91,7 +91,7 @@ export default function PostboxTargetsDialog({
|
|||||||
<Dialog
|
<Dialog
|
||||||
open={open}
|
open={open}
|
||||||
title={title}
|
title={title}
|
||||||
className="campaign-postbox-target-modal"
|
size="wide"
|
||||||
bodyClassName="campaign-postbox-target-body"
|
bodyClassName="campaign-postbox-target-body"
|
||||||
onClose={onClose}
|
onClose={onClose}
|
||||||
footer={
|
footer={
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import { DescriptionList } from "@govoplan/core-webui";
|
||||||
import { useEffect, useMemo, useState } from "react";
|
import { useEffect, useMemo, useState } from "react";
|
||||||
import {
|
import {
|
||||||
Button,
|
Button,
|
||||||
@@ -264,7 +265,7 @@ export default function AddressSourceImportDialog({
|
|||||||
|
|
||||||
{snapshot && (
|
{snapshot && (
|
||||||
<>
|
<>
|
||||||
<dl className="detail-list recipient-import-summary">
|
<DescriptionList columns={5} collapseAt="never" className="recipient-import-summary">
|
||||||
<div>
|
<div>
|
||||||
<dt>Source</dt>
|
<dt>Source</dt>
|
||||||
<dd>{snapshot.source_label}</dd>
|
<dd>{snapshot.source_label}</dd>
|
||||||
@@ -295,7 +296,7 @@ export default function AddressSourceImportDialog({
|
|||||||
<dt>Revision</dt>
|
<dt>Revision</dt>
|
||||||
<dd className="mono-small">{snapshot.source_revision}</dd>
|
<dd className="mono-small">{snapshot.source_revision}</dd>
|
||||||
</div>
|
</div>
|
||||||
</dl>
|
</DescriptionList>
|
||||||
{snapshot.excluded_count > 0 && (
|
{snapshot.excluded_count > 0 && (
|
||||||
<DismissibleAlert tone="warning" compact dismissible={false}>
|
<DismissibleAlert tone="warning" compact dismissible={false}>
|
||||||
{snapshot.excluded_count} contact point{snapshot.excluded_count === 1 ? " was" : "s were"} excluded by effective communication-governance facts.
|
{snapshot.excluded_count} contact point{snapshot.excluded_count === 1 ? " was" : "s were"} excluded by effective communication-governance facts.
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import { DescriptionList } from "@govoplan/core-webui";
|
||||||
import { useEffect, useMemo, useState } from "react";
|
import { useEffect, useMemo, useState } from "react";
|
||||||
import {
|
import {
|
||||||
Button,
|
Button,
|
||||||
@@ -294,7 +295,7 @@ export default function DistributionListImportDialog({
|
|||||||
)}
|
)}
|
||||||
{preview && (
|
{preview && (
|
||||||
<>
|
<>
|
||||||
<dl className="detail-list recipient-import-summary">
|
<DescriptionList columns={5} collapseAt="never" className="recipient-import-summary">
|
||||||
<div><dt>List</dt><dd>{preview.source.name}</dd></div>
|
<div><dt>List</dt><dd>{preview.source.name}</dd></div>
|
||||||
<div><dt>Revision</dt><dd>{preview.source.revision}</dd></div>
|
<div><dt>Revision</dt><dd>{preview.source.revision}</dd></div>
|
||||||
<div><dt>Included</dt><dd>{preview.recipients.length}</dd></div>
|
<div><dt>Included</dt><dd>{preview.recipients.length}</dd></div>
|
||||||
@@ -302,7 +303,7 @@ export default function DistributionListImportDialog({
|
|||||||
<div><dt>Providers</dt><dd>{preview.provider_evidence.length}</dd></div>
|
<div><dt>Providers</dt><dd>{preview.provider_evidence.length}</dd></div>
|
||||||
<div><dt>Route decisions</dt><dd>{unresolvedRoutes.length ? `${unresolvedRoutes.length} required` : "Complete"}</dd></div>
|
<div><dt>Route decisions</dt><dd>{unresolvedRoutes.length ? `${unresolvedRoutes.length} required` : "Complete"}</dd></div>
|
||||||
<div><dt>State</dt><dd>{preview.stale ? "Stale" : preview.truncated ? "Truncated" : "Current"}</dd></div>
|
<div><dt>State</dt><dd>{preview.stale ? "Stale" : preview.truncated ? "Truncated" : "Current"}</dd></div>
|
||||||
</dl>
|
</DescriptionList>
|
||||||
{preview.stale && (
|
{preview.stale && (
|
||||||
<DismissibleAlert tone="warning" compact dismissible={false}>
|
<DismissibleAlert tone="warning" compact dismissible={false}>
|
||||||
At least one provider result is stale. Review its diagnostics before freezing this expansion.
|
At least one provider result is stale. Review its diagnostics before freezing this expansion.
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import { DescriptionList } from "@govoplan/core-webui";
|
||||||
import { useEffect, useMemo, useState } from "react";
|
import { useEffect, useMemo, useState } from "react";
|
||||||
import type { ApiSettings } from "../../../types";
|
import type { ApiSettings } from "../../../types";
|
||||||
import {
|
import {
|
||||||
@@ -506,12 +507,12 @@ export function RecipientImportDialog({ settings, campaignId, existingEntries, e
|
|||||||
</div>
|
</div>
|
||||||
{table &&
|
{table &&
|
||||||
<>
|
<>
|
||||||
<dl className="detail-list recipient-import-summary">
|
<DescriptionList columns={5} collapseAt="never" className="recipient-import-summary">
|
||||||
<div><dt>{sourceType === "xlsx" ? "i18n:govoplan-campaign.sheet.53bc47a7" : "i18n:govoplan-campaign.separator.b4b289a7"}</dt><dd>{sourceType === "xlsx" ? selectedSheet?.name ?? "i18n:govoplan-campaign.workbook.b4418e62" : formatDelimiter(table.delimiter)}</dd></div>
|
<div><dt>{sourceType === "xlsx" ? "i18n:govoplan-campaign.sheet.53bc47a7" : "i18n:govoplan-campaign.separator.b4b289a7"}</dt><dd>{sourceType === "xlsx" ? selectedSheet?.name ?? "i18n:govoplan-campaign.workbook.b4418e62" : formatDelimiter(table.delimiter)}</dd></div>
|
||||||
<div><dt>i18n:govoplan-campaign.header_rows.9814b9e3</dt><dd>{table.headerRows.length}</dd></div>
|
<div><dt>i18n:govoplan-campaign.header_rows.9814b9e3</dt><dd>{table.headerRows.length}</dd></div>
|
||||||
<div><dt>i18n:govoplan-campaign.data_rows.3734724c</dt><dd>{table.dataRows.length}</dd></div>
|
<div><dt>i18n:govoplan-campaign.data_rows.3734724c</dt><dd>{table.dataRows.length}</dd></div>
|
||||||
<div><dt>i18n:govoplan-campaign.columns.cf723c59</dt><dd>{table.headers.length}</dd></div>
|
<div><dt>i18n:govoplan-campaign.columns.cf723c59</dt><dd>{table.headers.length}</dd></div>
|
||||||
</dl>
|
</DescriptionList>
|
||||||
<RecipientImportRawTable tableRows={table.rows} headerRowCount={table.headerRows.length} columnCount={table.headers.length} />
|
<RecipientImportRawTable tableRows={table.rows} headerRowCount={table.headerRows.length} columnCount={table.headers.length} />
|
||||||
</>
|
</>
|
||||||
}
|
}
|
||||||
@@ -543,12 +544,12 @@ export function RecipientImportDialog({ settings, campaignId, existingEntries, e
|
|||||||
<>
|
<>
|
||||||
{preview &&
|
{preview &&
|
||||||
<>
|
<>
|
||||||
<dl className="detail-list recipient-import-summary">
|
<DescriptionList columns={5} collapseAt="never" className="recipient-import-summary">
|
||||||
<div><dt>i18n:govoplan-campaign.rows.52d0b352</dt><dd>{preview.validCount} i18n:govoplan-campaign.valid.210cece7 {preview.invalidCount} invalid</dd></div>
|
<div><dt>i18n:govoplan-campaign.rows.52d0b352</dt><dd>{preview.validCount} i18n:govoplan-campaign.valid.210cece7 {preview.invalidCount} invalid</dd></div>
|
||||||
<div><dt>i18n:govoplan-campaign.fields.e8b68527</dt><dd>{preview.fieldNamesToCreate.length} new</dd></div>
|
<div><dt>i18n:govoplan-campaign.fields.e8b68527</dt><dd>{preview.fieldNamesToCreate.length} new</dd></div>
|
||||||
<div><dt>i18n:govoplan-campaign.patterns.4d34f7a2</dt><dd>{preview.patternCount} from {patternRows} i18n:govoplan-campaign.row_s.61464061</dd></div>
|
<div><dt>i18n:govoplan-campaign.patterns.4d34f7a2</dt><dd>{preview.patternCount} from {patternRows} i18n:govoplan-campaign.row_s.61464061</dd></div>
|
||||||
<div><dt>i18n:govoplan-campaign.source.6da13add</dt><dd>{preview.patternCount ? defaultAttachmentBasePath?.name ?? "i18n:govoplan-campaign.campaign_files.96e7004b" : "i18n:govoplan-campaign.no_patterns.5e1e46fa"}</dd></div>
|
<div><dt>i18n:govoplan-campaign.source.6da13add</dt><dd>{preview.patternCount ? defaultAttachmentBasePath?.name ?? "i18n:govoplan-campaign.campaign_files.96e7004b" : "i18n:govoplan-campaign.no_patterns.5e1e46fa"}</dd></div>
|
||||||
</dl>
|
</DescriptionList>
|
||||||
{preview.fieldNamesToCreate.length > 0 &&
|
{preview.fieldNamesToCreate.length > 0 &&
|
||||||
<p className="muted small-note">i18n:govoplan-campaign.new_fields.c61e20c0 {preview.fieldNamesToCreate.join(", ")}</p>
|
<p className="muted small-note">i18n:govoplan-campaign.new_fields.c61e20c0 {preview.fieldNamesToCreate.join(", ")}</p>
|
||||||
}
|
}
|
||||||
@@ -676,12 +677,12 @@ function RecipientImportFileLinkStep({ preview, basePath, resolution, resolving,
|
|||||||
|
|
||||||
{resolution &&
|
{resolution &&
|
||||||
<>
|
<>
|
||||||
<dl className="detail-list recipient-import-summary">
|
<DescriptionList columns={5} collapseAt="never" className="recipient-import-summary">
|
||||||
<div><dt>i18n:govoplan-campaign.patterns.4d34f7a2</dt><dd>{resolution.patterns.length}</dd></div>
|
<div><dt>i18n:govoplan-campaign.patterns.4d34f7a2</dt><dd>{resolution.patterns.length}</dd></div>
|
||||||
<div><dt>i18n:govoplan-campaign.matched_files.f79c63bb</dt><dd>{resolution.files.length}</dd></div>
|
<div><dt>i18n:govoplan-campaign.matched_files.f79c63bb</dt><dd>{resolution.files.length}</dd></div>
|
||||||
<div><dt>i18n:govoplan-campaign.already_linked.7d6c3dd5</dt><dd>{resolution.linkedFiles.length}</dd></div>
|
<div><dt>i18n:govoplan-campaign.already_linked.7d6c3dd5</dt><dd>{resolution.linkedFiles.length}</dd></div>
|
||||||
<div><dt>i18n:govoplan-campaign.need_linking.a7617722</dt><dd>{resolution.linkableFiles.length}</dd></div>
|
<div><dt>i18n:govoplan-campaign.need_linking.a7617722</dt><dd>{resolution.linkableFiles.length}</dd></div>
|
||||||
</dl>
|
</DescriptionList>
|
||||||
|
|
||||||
{resolution.unmatchedPatterns.length > 0 &&
|
{resolution.unmatchedPatterns.length > 0 &&
|
||||||
<div className="recipient-import-unmatched-patterns">
|
<div className="recipient-import-unmatched-patterns">
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import { DescriptionList } from "@govoplan/core-webui";
|
||||||
import { Button, Dialog, i18nMessage } from "@govoplan/core-webui";
|
import { Button, Dialog, i18nMessage } from "@govoplan/core-webui";
|
||||||
|
|
||||||
import { asArray, asRecord, formatDateTime, humanize } from "../utils/campaignView";
|
import { asArray, asRecord, formatDateTime, humanize } from "../utils/campaignView";
|
||||||
@@ -28,7 +29,7 @@ export default function DeliveryJobDetailOverlay({
|
|||||||
</Button>
|
</Button>
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<dl className="detail-list">
|
<DescriptionList variant="inline">
|
||||||
<div>
|
<div>
|
||||||
<dt>i18n:govoplan-campaign.recipient.90343260</dt>
|
<dt>i18n:govoplan-campaign.recipient.90343260</dt>
|
||||||
<dd>
|
<dd>
|
||||||
@@ -54,7 +55,7 @@ export default function DeliveryJobDetailOverlay({
|
|||||||
<dd>{String(job.last_error)}</dd>
|
<dd>{String(job.last_error)}</dd>
|
||||||
</div>
|
</div>
|
||||||
) : null}
|
) : null}
|
||||||
</dl>
|
</DescriptionList>
|
||||||
{issues.length > 0 && (
|
{issues.length > 0 && (
|
||||||
<AttemptList
|
<AttemptList
|
||||||
title="i18n:govoplan-campaign.message_issues.9092a7db"
|
title="i18n:govoplan-campaign.message_issues.9092a7db"
|
||||||
@@ -90,7 +91,7 @@ function AttemptList({
|
|||||||
{rows.length === 0 ? (
|
{rows.length === 0 ? (
|
||||||
<p className="muted small-note">{emptyText}</p>
|
<p className="muted small-note">{emptyText}</p>
|
||||||
) : (
|
) : (
|
||||||
<dl className="detail-list">
|
<DescriptionList variant="inline">
|
||||||
{rows.map((row, index) => (
|
{rows.map((row, index) => (
|
||||||
<div key={`${String(row.id ?? row.code ?? index)}:${index}`}>
|
<div key={`${String(row.id ?? row.code ?? index)}:${index}`}>
|
||||||
<dt>
|
<dt>
|
||||||
@@ -129,7 +130,7 @@ function AttemptList({
|
|||||||
</dd>
|
</dd>
|
||||||
</div>
|
</div>
|
||||||
))}
|
))}
|
||||||
</dl>
|
</DescriptionList>
|
||||||
)}
|
)}
|
||||||
</section>
|
</section>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import { MetricGrid } from "@govoplan/core-webui";
|
||||||
import { useEffect, useState } from "react";
|
import { useEffect, useState } from "react";
|
||||||
import { FormGrid, Button } from "@govoplan/core-webui";
|
import { FormGrid, Button } from "@govoplan/core-webui";
|
||||||
import { FieldLabel } from "@govoplan/core-webui";
|
import { FieldLabel } from "@govoplan/core-webui";
|
||||||
@@ -189,11 +190,11 @@ export function ReviewStep({ version, onValidate }: {version: unknown;onValidate
|
|||||||
<h2>i18n:govoplan-campaign.review_setup.d0059acb</h2>
|
<h2>i18n:govoplan-campaign.review_setup.d0059acb</h2>
|
||||||
<p>i18n:govoplan-campaign.validate_the_campaign_definition_before_building.d36ee1dc</p>
|
<p>i18n:govoplan-campaign.validate_the_campaign_definition_before_building.d36ee1dc</p>
|
||||||
</div>
|
</div>
|
||||||
<div className="metric-grid inside">
|
<MetricGrid spacing="inset">
|
||||||
<MetricCard label="i18n:govoplan-campaign.errors.805e86a8" value={summaryValue(asRecord(record.validation_summary), ["error_count", "errors", "blocked"])} tone="danger" />
|
<MetricCard label="i18n:govoplan-campaign.errors.805e86a8" value={summaryValue(asRecord(record.validation_summary), ["error_count", "errors", "blocked"])} tone="danger" />
|
||||||
<MetricCard label="i18n:govoplan-campaign.warnings.1430f976" value={summaryValue(asRecord(record.validation_summary), ["warning_count", "warnings"])} tone="warning" />
|
<MetricCard label="i18n:govoplan-campaign.warnings.1430f976" value={summaryValue(asRecord(record.validation_summary), ["warning_count", "warnings"])} tone="warning" />
|
||||||
<MetricCard label="i18n:govoplan-campaign.built.a6ad3f82" value={summaryValue(asRecord(record.build_summary), ["built_count", "built", "messages_built"])} tone="info" />
|
<MetricCard label="i18n:govoplan-campaign.built.a6ad3f82" value={summaryValue(asRecord(record.build_summary), ["built_count", "built", "messages_built"])} tone="info" />
|
||||||
</div>
|
</MetricGrid>
|
||||||
<Button variant="primary" onClick={onValidate}>i18n:govoplan-campaign.validate_campaign.6934c1c2</Button>
|
<Button variant="primary" onClick={onValidate}>i18n:govoplan-campaign.validate_campaign.6934c1c2</Button>
|
||||||
</div>);
|
</div>);
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import { MetricGrid } from "@govoplan/core-webui";
|
||||||
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
|
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
|
||||||
import { Ban, ExternalLink, Eye, Pause, Play, RotateCcw, Send, ShieldCheck } from "lucide-react";
|
import { Ban, ExternalLink, Eye, Pause, Play, RotateCcw, Send, ShieldCheck } from "lucide-react";
|
||||||
import { useSearchParams } from "react-router";
|
import { useSearchParams } from "react-router";
|
||||||
@@ -774,7 +775,7 @@ export default function OperatorQueuePage({ settings, auth }: {settings: ApiSett
|
|||||||
|
|
||||||
<section className="queue-pressure-section" aria-labelledby="operator-queue-pressure-title">
|
<section className="queue-pressure-section" aria-labelledby="operator-queue-pressure-title">
|
||||||
<h2 id="operator-queue-pressure-title" className="queue-pressure-heading">i18n:govoplan-campaign.queue_pressure.28eee15e</h2>
|
<h2 id="operator-queue-pressure-title" className="queue-pressure-heading">i18n:govoplan-campaign.queue_pressure.28eee15e</h2>
|
||||||
<div className="metric-grid queue-pressure-grid">
|
<MetricGrid columns="auto" spacing="none" className="queue-pressure-metrics">
|
||||||
<MetricCard label="i18n:govoplan-campaign.queued.6a599877" value={totals.queued} tone="neutral" />
|
<MetricCard label="i18n:govoplan-campaign.queued.6a599877" value={totals.queued} tone="neutral" />
|
||||||
<MetricCard label="i18n:govoplan-campaign.claimed.83c87884" value={totals.claimed} tone="info" />
|
<MetricCard label="i18n:govoplan-campaign.claimed.83c87884" value={totals.claimed} tone="info" />
|
||||||
<MetricCard label="i18n:govoplan-campaign.sending.ceafde86" value={totals.sending} tone="info" />
|
<MetricCard label="i18n:govoplan-campaign.sending.ceafde86" value={totals.sending} tone="info" />
|
||||||
@@ -784,7 +785,7 @@ export default function OperatorQueuePage({ settings, auth }: {settings: ApiSett
|
|||||||
<MetricCard label="i18n:govoplan-campaign.unattempted.e7411dd6" value={totals.notAttempted} tone="neutral" />
|
<MetricCard label="i18n:govoplan-campaign.unattempted.e7411dd6" value={totals.notAttempted} tone="neutral" />
|
||||||
<MetricCard label="i18n:govoplan-campaign.paused.c7dfb6f1" value={totals.paused} tone="neutral" />
|
<MetricCard label="i18n:govoplan-campaign.paused.c7dfb6f1" value={totals.paused} tone="neutral" />
|
||||||
<MetricCard label="i18n:govoplan-campaign.imap_failed.50dbca55" value={totals.imapFailed} tone="warning" />
|
<MetricCard label="i18n:govoplan-campaign.imap_failed.50dbca55" value={totals.imapFailed} tone="warning" />
|
||||||
</div>
|
</MetricGrid>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<LoadingFrame loading={loading} label="i18n:govoplan-campaign.loading_operator_queue.ae6576e0">
|
<LoadingFrame loading={loading} label="i18n:govoplan-campaign.loading_operator_queue.ae6576e0">
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import { DescriptionList } from "@govoplan/core-webui";
|
||||||
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
|
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
|
||||||
import { Eye, RefreshCw } from "lucide-react";
|
import { Eye, RefreshCw } from "lucide-react";
|
||||||
import { useSearchParams } from "react-router";
|
import { useSearchParams } from "react-router";
|
||||||
@@ -198,12 +199,12 @@ export default function AggregateReportsPage({ settings }: {settings: ApiSetting
|
|||||||
{report && outcomes && (
|
{report && outcomes && (
|
||||||
<>
|
<>
|
||||||
<Card title={report.campaign.name}>
|
<Card title={report.campaign.name}>
|
||||||
<dl className="detail-list">
|
<DescriptionList variant="inline">
|
||||||
<div><dt>i18n:govoplan-campaign.status.bae7d5be</dt><dd><StatusBadge status={report.campaign.status} /></dd></div>
|
<div><dt>i18n:govoplan-campaign.status.bae7d5be</dt><dd><StatusBadge status={report.campaign.status} /></dd></div>
|
||||||
<div><dt>i18n:govoplan-campaign.completion.2ff25568</dt><dd><StatusBadge status={report.completion_state} label={aggregateCompletionLabel(report.completion_state)} /></dd></div>
|
<div><dt>i18n:govoplan-campaign.completion.2ff25568</dt><dd><StatusBadge status={report.completion_state} label={aggregateCompletionLabel(report.completion_state)} /></dd></div>
|
||||||
<div><dt>i18n:govoplan-campaign.version.2da600bf</dt><dd>{report.version_number ?? "—"}</dd></div>
|
<div><dt>i18n:govoplan-campaign.version.2da600bf</dt><dd>{report.version_number ?? "—"}</dd></div>
|
||||||
<div><dt>i18n:govoplan-campaign.generated.8eefdd52</dt><dd>{formatDateTime(report.generated_at)}</dd></div>
|
<div><dt>i18n:govoplan-campaign.generated.8eefdd52</dt><dd>{formatDateTime(report.generated_at)}</dd></div>
|
||||||
</dl>
|
</DescriptionList>
|
||||||
</Card>
|
</Card>
|
||||||
|
|
||||||
{/* Aggregate outcome cards are deliberately not filter shortcuts: each subgroup
|
{/* Aggregate outcome cards are deliberately not filter shortcuts: each subgroup
|
||||||
@@ -223,19 +224,19 @@ export default function AggregateReportsPage({ settings }: {settings: ApiSetting
|
|||||||
</ContentGrid>
|
</ContentGrid>
|
||||||
|
|
||||||
<Card title="i18n:govoplan-campaign.population_and_exclusions.cdff62ad">
|
<Card title="i18n:govoplan-campaign.population_and_exclusions.cdff62ad">
|
||||||
<dl className="detail-list">
|
<DescriptionList variant="inline">
|
||||||
<div><dt>i18n:govoplan-campaign.report_denominator.d089074a</dt><dd>{countValue(report.population.denominator)}</dd></div>
|
<div><dt>i18n:govoplan-campaign.report_denominator.d089074a</dt><dd>{countValue(report.population.denominator)}</dd></div>
|
||||||
<div><dt>i18n:govoplan-campaign.inactive_source_entries.88fa0cf8</dt><dd>{countValue(report.population.inactive_source_entries)}</dd></div>
|
<div><dt>i18n:govoplan-campaign.inactive_source_entries.88fa0cf8</dt><dd>{countValue(report.population.inactive_source_entries)}</dd></div>
|
||||||
<div><dt>i18n:govoplan-campaign.excluded_or_blocked_jobs.e2190d47</dt><dd>{countValue(report.population.excluded_or_blocked_jobs)}</dd></div>
|
<div><dt>i18n:govoplan-campaign.excluded_or_blocked_jobs.e2190d47</dt><dd>{countValue(report.population.excluded_or_blocked_jobs)}</dd></div>
|
||||||
</dl>
|
</DescriptionList>
|
||||||
<p className="muted">i18n:govoplan-campaign.all_persisted_recipient_delivery_jobs_for_the_se.208e90cc</p>
|
<p className="muted">i18n:govoplan-campaign.all_persisted_recipient_delivery_jobs_for_the_se.208e90cc</p>
|
||||||
</Card>
|
</Card>
|
||||||
|
|
||||||
<Card title="i18n:govoplan-campaign.delivery_activity_range.0d1b62ec">
|
<Card title="i18n:govoplan-campaign.delivery_activity_range.0d1b62ec">
|
||||||
<dl className="detail-list">
|
<DescriptionList variant="inline">
|
||||||
<div><dt>i18n:govoplan-campaign.first_activity.3fe36ef4</dt><dd>{report.time_range.suppressed ? "i18n:govoplan-campaign.suppressed.fce88db5" : formatDateTime(report.time_range.first_activity_at ?? undefined)}</dd></div>
|
<div><dt>i18n:govoplan-campaign.first_activity.3fe36ef4</dt><dd>{report.time_range.suppressed ? "i18n:govoplan-campaign.suppressed.fce88db5" : formatDateTime(report.time_range.first_activity_at ?? undefined)}</dd></div>
|
||||||
<div><dt>i18n:govoplan-campaign.last_activity.1c73b806</dt><dd>{report.time_range.suppressed ? "i18n:govoplan-campaign.suppressed.fce88db5" : formatDateTime(report.time_range.last_activity_at ?? undefined)}</dd></div>
|
<div><dt>i18n:govoplan-campaign.last_activity.1c73b806</dt><dd>{report.time_range.suppressed ? "i18n:govoplan-campaign.suppressed.fce88db5" : formatDateTime(report.time_range.last_activity_at ?? undefined)}</dd></div>
|
||||||
</dl>
|
</DescriptionList>
|
||||||
</Card>
|
</Card>
|
||||||
|
|
||||||
<Card title="i18n:govoplan-campaign.privacy_boundary.d37e12bc">
|
<Card title="i18n:govoplan-campaign.privacy_boundary.d37e12bc">
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import { DescriptionList } from "@govoplan/core-webui";
|
||||||
import { useMemo, useState } from "react";
|
import { useMemo, useState } from "react";
|
||||||
import { ExternalLink } from "lucide-react";
|
import { ExternalLink } from "lucide-react";
|
||||||
import { FormGrid, ContentGrid, Button } from "@govoplan/core-webui";
|
import { FormGrid, ContentGrid, Button } from "@govoplan/core-webui";
|
||||||
@@ -206,12 +207,12 @@ function TemplateOverview({ template }: {template: TemplateRecord;}) {
|
|||||||
return (
|
return (
|
||||||
<ContentGrid columns={2} collapseAt="workspace" className="">
|
<ContentGrid columns={2} collapseAt="workspace" className="">
|
||||||
<Card title="i18n:govoplan-campaign.template_status.8bec97cf">
|
<Card title="i18n:govoplan-campaign.template_status.8bec97cf">
|
||||||
<dl className="detail-list compact-detail-list">
|
<DescriptionList variant="inline" density="compact">
|
||||||
<div><dt>i18n:govoplan-campaign.status.bae7d5be</dt><dd><StatusBadge status={template.status} /></dd></div>
|
<div><dt>i18n:govoplan-campaign.status.bae7d5be</dt><dd><StatusBadge status={template.status} /></dd></div>
|
||||||
<div><dt>i18n:govoplan-campaign.type.3deb7456</dt><dd>{templateTypeLabel(template.type)}</dd></div>
|
<div><dt>i18n:govoplan-campaign.type.3deb7456</dt><dd>{templateTypeLabel(template.type)}</dd></div>
|
||||||
<div><dt>i18n:govoplan-campaign.updated.f2f8570d</dt><dd>{template.updatedAt}</dd></div>
|
<div><dt>i18n:govoplan-campaign.updated.f2f8570d</dt><dd>{template.updatedAt}</dd></div>
|
||||||
<div><dt>i18n:govoplan-campaign.versions.a239107e</dt><dd>{template.versions}</dd></div>
|
<div><dt>i18n:govoplan-campaign.versions.a239107e</dt><dd>{template.versions}</dd></div>
|
||||||
</dl>
|
</DescriptionList>
|
||||||
</Card>
|
</Card>
|
||||||
<Card title="i18n:govoplan-campaign.compatibility_notes.7d648a6d">
|
<Card title="i18n:govoplan-campaign.compatibility_notes.7d648a6d">
|
||||||
<p className="muted">i18n:govoplan-campaign.campaigns_can_reuse_this_template_but_each_campa.bdb25009</p>
|
<p className="muted">i18n:govoplan-campaign.campaigns_can_reuse_this_template_but_each_campa.bdb25009</p>
|
||||||
@@ -285,10 +286,10 @@ function TemplateUsage({ template }: {template: TemplateRecord;}) {
|
|||||||
return (
|
return (
|
||||||
<Card title="i18n:govoplan-campaign.usage.0bb18642">
|
<Card title="i18n:govoplan-campaign.usage.0bb18642">
|
||||||
<p className="muted">i18n:govoplan-campaign.this_view_will_list_campaigns_using_the_template.116f7ee0</p>
|
<p className="muted">i18n:govoplan-campaign.this_view_will_list_campaigns_using_the_template.116f7ee0</p>
|
||||||
<dl className="detail-list compact-detail-list">
|
<DescriptionList variant="inline" density="compact">
|
||||||
<div><dt>i18n:govoplan-campaign.currently_used_by.a065cfbe</dt><dd>{template.usedBy}</dd></div>
|
<div><dt>i18n:govoplan-campaign.currently_used_by.a065cfbe</dt><dd>{template.usedBy}</dd></div>
|
||||||
<div><dt>i18n:govoplan-campaign.safe_to_edit.57b64df5</dt><dd>i18n:govoplan-campaign.requires_versioning_once_templates_are_shared.e020b221</dd></div>
|
<div><dt>i18n:govoplan-campaign.safe_to_edit.57b64df5</dt><dd>i18n:govoplan-campaign.requires_versioning_once_templates_are_shared.e020b221</dd></div>
|
||||||
</dl>
|
</DescriptionList>
|
||||||
</Card>);
|
</Card>);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -299,20 +299,16 @@
|
|||||||
color: var(--text-strong);
|
color: var(--text-strong);
|
||||||
font-size: 16px;
|
font-size: 16px;
|
||||||
}
|
}
|
||||||
.queue-pressure-grid {
|
.queue-pressure-metrics {
|
||||||
grid-template-columns: repeat(5, minmax(112px, 1fr));
|
|
||||||
margin: 0;
|
|
||||||
}
|
|
||||||
.queue-pressure-grid .metric-card {
|
|
||||||
min-width: 0;
|
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;
|
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 th,
|
||||||
.module-table td {
|
.module-table td {
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
@@ -966,10 +962,6 @@
|
|||||||
margin-top: 16px;
|
margin-top: 16px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.campaign-postbox-target-modal {
|
|
||||||
width: min(1040px, calc(100vw - 32px));
|
|
||||||
}
|
|
||||||
|
|
||||||
.campaign-postbox-target-body {
|
.campaign-postbox-target-body {
|
||||||
max-height: min(76vh, 820px);
|
max-height: min(76vh, 820px);
|
||||||
overflow: auto;
|
overflow: auto;
|
||||||
@@ -2799,7 +2791,6 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.campaign-content-library-dialog { width: min(880px, calc(100vw - 32px)); }
|
.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, .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 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); }
|
.campaign-content-library-list { display: grid; max-height: min(56vh, 560px); overflow: auto; border: var(--border-line); }
|
||||||
|
|||||||
Reference in New Issue
Block a user