i18n:govoplan-campaign.campaign_specific_audit_api_integration_will_be_.e53c8280
+{JSON.stringify(campaignJson, null, 2)} : {"{}"}}
diff --git a/webui/src/features/campaigns/review/AttachmentLinkingPreview.tsx b/webui/src/features/campaigns/review/AttachmentLinkingPreview.tsx
index e4a146b..c5c306c 100644
--- a/webui/src/features/campaigns/review/AttachmentLinkingPreview.tsx
+++ b/webui/src/features/campaigns/review/AttachmentLinkingPreview.tsx
@@ -1,6 +1,6 @@
import { useState } from "react";
import { Link2, X } from "lucide-react";
-import { Button, Dialog, i18nMessage } from "@govoplan/core-webui";
+import { Button, Dialog, DismissibleAlert, i18nMessage } from "@govoplan/core-webui";
import type {
CampaignAttachmentPreviewFile,
@@ -108,7 +108,11 @@ export default function AttachmentLinkingPreview({
value={loading ? "..." : preview?.shared_file_count ?? "—"}
/>
- {error && {error}
} + {error && ( +
i18n:govoplan-campaign.unlinked_candidate_files_are_not_yet_part_of_the.b8fd5998
diff --git a/webui/src/module.ts b/webui/src/module.ts
index 7bb314c..5bf928a 100644
--- a/webui/src/module.ts
+++ b/webui/src/module.ts
@@ -17,7 +17,6 @@ import "./styles/campaign-workspace.css";
const CampaignModulePage = lazy(() => import("./features/campaigns/CampaignModulePage"));
const CampaignWorkspace = lazy(() => import("./features/campaigns/CampaignWorkspace"));
-const TemplatesPage = lazy(() => import("./features/templates/TemplatesPage"));
const campaignRead = ["campaigns:campaign:read"];
const reportRead = ["campaigns:report:read"];
@@ -91,16 +90,14 @@ export const campaignModule: PlatformWebModule = {
}
],
navItems: [
- { to: "/campaigns", label: "i18n:govoplan-campaign.campaigns.01a23a28", iconName: "campaign", anyOf: campaignModuleRead, order: 20 },
- { to: "/templates", label: "i18n:govoplan-campaign.templates.f25b700e", iconName: "layout-template", order: 90 }],
+ { to: "/campaigns", label: "i18n:govoplan-campaign.campaigns.01a23a28", iconName: "campaign", anyOf: campaignModuleRead, order: 20 }],
routes: [
{ path: "/campaigns", anyOf: campaignModuleRead, order: 20, render: ({ settings, auth }) => createElement(CampaignModuleLandingRoute, { settings, auth }) },
{ path: "/operator", anyOf: OPERATOR_QUEUE_ROUTE_SCOPES, allOf: campaignRead, order: 21, surfaceId: operatorQueueSurface, render: () => createElement(Navigate, { to: "/campaigns/queue", replace: true }) },
{ path: "/campaigns/queue", anyOf: OPERATOR_QUEUE_ROUTE_SCOPES, allOf: campaignRead, order: 21, surfaceId: operatorQueueSurface, render: ({ settings, auth }) => createElement(CampaignModulePage, { active: "queue", settings, auth }) },
{ path: "/campaigns/reports", anyOf: reportRead, order: 22, surfaceId: reportsSurface, render: ({ settings, auth }) => createElement(CampaignModulePage, { active: "reports", settings, auth }) },
- { path: "/campaigns/:campaignId/*", anyOf: campaignRead, order: 22, render: ({ settings, auth }) => createElement(CampaignResourceRoute, { settings, auth }) },
- { path: "/templates", order: 90, render: () => createElement(TemplatesPage) }],
+ { path: "/campaigns/:campaignId/*", anyOf: campaignRead, order: 22, render: ({ settings, auth }) => createElement(CampaignResourceRoute, { settings, auth }) }],
uiCapabilities: {
"dashboard.widgets": campaignDashboardWidgets,
"wizard.directories": campaignWizardDirectories
diff --git a/webui/tests/accessibility-contract.test.mjs b/webui/tests/accessibility-contract.test.mjs
index 5023a35..d2dff49 100644
--- a/webui/tests/accessibility-contract.test.mjs
+++ b/webui/tests/accessibility-contract.test.mjs
@@ -32,6 +32,47 @@ const preview = fs.readFileSync(
path.join(sourceRoot, "features/campaigns/components/MessagePreviewOverlay.tsx"),
"utf8",
);
+
+const styles = fs.readFileSync(
+ path.join(sourceRoot, "styles/campaign-workspace.css"),
+ "utf8",
+);
+const jsonView = fs.readFileSync(
+ path.join(sourceRoot, "features/campaigns/CampaignJsonView.tsx"),
+ "utf8",
+);
+const auditView = fs.readFileSync(
+ path.join(sourceRoot, "features/campaigns/CampaignAuditPage.tsx"),
+ "utf8",
+);
+const attachmentPreview = fs.readFileSync(
+ path.join(sourceRoot, "features/campaigns/review/AttachmentLinkingPreview.tsx"),
+ "utf8",
+);
+assert.ok(
+ jsonView.includes('DismissibleAlert tone="warning" dismissible={false}'),
+ "The full Campaign JSON projection must retain an explicit privacy warning",
+);
+assert.ok(
+ auditView.includes("ActionBlockerHint"),
+ "Unavailable Campaign audit projection must retain an actionable shared blocker",
+);
+assert.ok(
+ attachmentPreview.includes('