refactor(campaign-ui): align workspace layouts

This commit is contained in:
2026-07-20 20:09:11 +02:00
parent 0c4f198802
commit 78f52a36d4
6 changed files with 410 additions and 45 deletions

View File

@@ -19,7 +19,7 @@ export default function CampaignAuditPage({ settings, campaignId }: {settings: A
<VersionLine version={version} versions={data.versions} loadedAt={version?.updated_at} />
</div>
<div className="button-row compact-actions">
<Button onClick={reload} disabled={loading}>i18n:govoplan-campaign.reload.cce71553</Button>
<Button onClick={() => void reload({ force: true })} disabled={loading}>Discard</Button>
</div>
</div>
@@ -32,4 +32,4 @@ export default function CampaignAuditPage({ settings, campaignId }: {settings: A
</LoadingFrame>
</div>);
}
}

View File

@@ -22,7 +22,7 @@ export default function CampaignFieldsPage({ settings, campaignId }: {settings:
const version = data.currentVersion;
const locked = isAuditLockedVersion(version, data.campaign?.current_version_id);
const { draft, setDraft, displayDraft, dirty, saveState, setSaveState, localError, setLocalError, markDirty, saveDraft } = useCampaignDraftEditor({
const { draft, setDraft, displayDraft, dirty, saveState, setSaveState, localError, setLocalError, markDirty, discardDraft, saveDraft } = useCampaignDraftEditor({
settings,
campaignId,
version,
@@ -157,7 +157,7 @@ export default function CampaignFieldsPage({ settings, campaignId }: {settings:
<VersionLine version={version} versions={data.versions} status={saveState} />
</div>
<div className="button-row compact-actions">
<Button onClick={reload} disabled={loading}>i18n:govoplan-campaign.reload.cce71553</Button>
<Button onClick={() => void discardDraft()} disabled={loading}>Discard</Button>
<Button variant="primary" onClick={saveFields} disabled={!canSave}>i18n:govoplan-campaign.save.efc007a3</Button>
</div>
</div>

View File

@@ -24,7 +24,7 @@ export default function CampaignJsonView({ settings, campaignId }: {settings: Ap
<VersionLine version={version} versions={data.versions} loadedAt={version?.updated_at} />
</div>
<div className="button-row compact-actions">
<Button onClick={reload} disabled={loading}>i18n:govoplan-campaign.reload.cce71553</Button>
<Button onClick={() => void reload({ force: true })} disabled={loading}>Discard</Button>
<Button onClick={() => downloadJson(filename, campaignJson)} disabled={!version}>i18n:govoplan-campaign.download_json.d296a30a</Button>
</div>
</div>
@@ -36,4 +36,4 @@ export default function CampaignJsonView({ settings, campaignId }: {settings: Ap
</LoadingFrame>
</div>);
}
}

View File

@@ -149,7 +149,7 @@ export default function CampaignListPage({ settings }: {settings: ApiSettings;})
<p className="mono-small">{lastLoadedAt ? i18nMessage("i18n:govoplan-campaign.last_loaded_value.35ef046a", { value0: lastLoadedAt }) : "i18n:govoplan-campaign.not_loaded_yet.9968c191"}</p>
</div>
<div className="button-row compact-actions">
<Button onClick={load} disabled={loading}>i18n:govoplan-campaign.reload.cce71553</Button>
<Button onClick={() => void load(null)} disabled={loading}>Discard</Button>
<Button variant="primary" onClick={create} disabled={creating}>
{creating ? "i18n:govoplan-campaign.creating.94d7d8ee" : "i18n:govoplan-campaign.new_campaign.aaf9a8a4"}
</Button>

View File

@@ -131,6 +131,19 @@ export default function CampaignOverviewPage({ settings, campaignId }: {settings
}
}
async function discardOverview() {
if (campaign) {
setIdentity({
external_id: campaign.external_id ?? "",
name: campaign.name ?? "",
status: campaign.status ?? "",
description: campaign.description ?? ""
});
setIdentityDirty(false);
}
await reload({ force: true });
}
return (
<div className="content-pad workspace-data-page">
<div className="page-heading split workspace-heading">
@@ -139,8 +152,7 @@ export default function CampaignOverviewPage({ settings, campaignId }: {settings
<p className="mono-small">i18n:govoplan-campaign.campaign_overview_version_independent_identity_a.ebaf1113</p>
</div>
<div className="button-row compact-actions">
<Button onClick={reload} disabled={loading || savingIdentity || lockBusy}>i18n:govoplan-campaign.reload.cce71553</Button>
<Link to="wizard/create"><Button>i18n:govoplan-campaign.edit_with_wizard.672a7d1a</Button></Link>
<Button onClick={() => void discardOverview()} disabled={loading || savingIdentity || lockBusy}>Discard</Button>
<Button variant="primary" onClick={() => void saveIdentity()} disabled={!campaign || !identityDirty || savingIdentity}>{savingIdentity ? "i18n:govoplan-campaign.saving.56a2285c" : "i18n:govoplan-campaign.save.efc007a3"}</Button>
</div>
</div>
@@ -149,13 +161,6 @@ export default function CampaignOverviewPage({ settings, campaignId }: {settings
{message && <DismissibleAlert tone="success" resetKey={message} floating>{message}</DismissibleAlert>}
<LoadingFrame loading={loading} label="i18n:govoplan-campaign.loading_campaign_overview.ffa1adf0">
<div className="metric-grid campaign-overview-metrics current-version-metrics">
<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.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} />
</div>
<div className="metric-grid campaign-overview-metrics">
<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" />
@@ -163,23 +168,10 @@ export default function CampaignOverviewPage({ settings, campaignId }: {settings
<MetricCard label="i18n:govoplan-campaign.failed.09fef5d8" value={data.summary?.cards?.failed ?? "—"} tone="danger" detail="i18n:govoplan-campaign.smtp_failures.00b33b85" />
</div>
<Card title="i18n:govoplan-campaign.current_version_state.f581778f" actions={<Link
to={`send?version=${campaign?.current_version_id}`}
className={`btn btn-primary`}
aria-label={i18nMessage("i18n:govoplan-campaign.open_curent_version.cc1cd678", {})}
title={i18nMessage("i18n:govoplan-campaign.open_curent_version.cc1cd678", {})}>
i18n:govoplan-campaign.open.cf9b7706
</Link>}>
<div className="summary-grid overview-summary-grid">
<SummaryTile label="i18n:govoplan-campaign.validation_errors.e54ca4fe" value={summaryValue(data.currentVersion?.validation_summary, ["error_count", "errors", "blocked"])} />
<SummaryTile label="i18n:govoplan-campaign.warnings.1430f976" value={summaryValue(data.currentVersion?.validation_summary, ["warning_count", "warnings"])} />
<SummaryTile label="i18n:govoplan-campaign.built_messages.1fb804f2" value={summaryValue(data.currentVersion?.build_summary, ["built_count", "built", "messages_built"])} />
<SummaryTile label="i18n:govoplan-campaign.jobs_total.98da65bc" value={data.summary?.cards?.jobs_total ?? "—"} />
</div>
</Card>
<Card title="i18n:govoplan-campaign.campaign_identity.a00ca574" collapsible>
<Card
title="i18n:govoplan-campaign.campaign_identity.a00ca574"
collapsible
actions={<Link to="wizard/create"><Button>i18n:govoplan-campaign.edit_with_wizard.672a7d1a</Button></Link>}>
<div className="form-grid campaign-identity-grid">
<FormField label="i18n:govoplan-campaign.campaign_id.4c4ed79e">
<input value={identity.external_id} onChange={(event) => patchIdentity("external_id", event.target.value)} />
@@ -198,8 +190,27 @@ export default function CampaignOverviewPage({ settings, campaignId }: {settings
</div>
</Card>
<Card title="i18n:govoplan-campaign.version_history.91f86581" collapsible>
<div className="admin-table-surface">
<Card title="Versions" collapsible actions={<Link
to={`send?version=${campaign?.current_version_id}`}
className={`btn btn-primary`}
aria-label={i18nMessage("i18n:govoplan-campaign.open_curent_version.cc1cd678", {})}
title={i18nMessage("i18n:govoplan-campaign.open_curent_version.cc1cd678", {})}>
i18n:govoplan-campaign.open.cf9b7706
</Link>}>
<div className="metric-grid inside campaign-versions-metrics">
<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.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} />
</div>
<div className="summary-grid overview-summary-grid">
<SummaryTile label="i18n:govoplan-campaign.validation_errors.e54ca4fe" value={summaryValue(data.currentVersion?.validation_summary, ["error_count", "errors", "blocked"])} />
<SummaryTile label="i18n:govoplan-campaign.warnings.1430f976" value={summaryValue(data.currentVersion?.validation_summary, ["warning_count", "warnings"])} />
<SummaryTile label="i18n:govoplan-campaign.built_messages.1fb804f2" value={summaryValue(data.currentVersion?.build_summary, ["built_count", "built", "messages_built"])} />
<SummaryTile label="i18n:govoplan-campaign.jobs_total.98da65bc" value={data.summary?.cards?.jobs_total ?? "—"} />
</div>
<div className="admin-table-surface version-history-table-surface">
<DataGrid
id={`campaign-${campaignId}-versions`}
rows={versions}