diff --git a/docs/ACCESSIBILITY_REVIEW.md b/docs/ACCESSIBILITY_REVIEW.md index 5047425..82e9aa0 100644 --- a/docs/ACCESSIBILITY_REVIEW.md +++ b/docs/ACCESSIBILITY_REVIEW.md @@ -1,8 +1,11 @@ # Campaign Accessibility Review The Campaign WebUI uses Core's semantic `Button`, `Dialog`, `DataGrid`, form, -alert, and segmented-control components. Core owns focus trapping, focus return, -Escape handling, labels, disabled state, and keyboard behavior for those shared +alert, and segmented-control components. Its page frames use Core `PageLayout` +and its full-canvas navigation/content shells use `WorkspaceLayout`, so pane +scrolling, sticky headings, action collapse, narrow-layout behavior, and help +scope remain platform-owned. Core also owns focus trapping, focus return, +Escape handling, labels, disabled state, and keyboard behavior for the shared primitives. ## Repeatable review matrix diff --git a/webui/src/features/campaigns/AttachmentsDataPage.tsx b/webui/src/features/campaigns/AttachmentsDataPage.tsx index e905f1a..d4aac9c 100644 --- a/webui/src/features/campaigns/AttachmentsDataPage.tsx +++ b/webui/src/features/campaigns/AttachmentsDataPage.tsx @@ -4,7 +4,7 @@ import { useGuardedNavigate, usePlatformModuleInstalled, usePlatformUiCapability import type { ApiSettings } from "../../types"; import { Button } from "@govoplan/core-webui"; import { Card } from "@govoplan/core-webui"; -import { PageTitle } from "@govoplan/core-webui"; +import { PageLayout } from "@govoplan/core-webui"; import { LoadingFrame } from "@govoplan/core-webui"; import { MetricCard } from "@govoplan/core-webui"; import { FormField } from "@govoplan/core-webui"; @@ -247,22 +247,24 @@ export default function AttachmentsDataPage({ settings, campaignId }: {settings: return ( -
-
-
- i18n:govoplan-campaign.attachments.6771ade6 - -
-
+ } + headerLoading={loading} + error={error} + actions={ + <> {filesModuleInstalled && } -
-
- - {error && {error}} - {localError && {localError}} - {locked && } + + } + notices={(localError || locked) ? <> + {localError && {localError}} + {locked && } + : undefined} + > <> @@ -452,7 +454,7 @@ export default function AttachmentsDataPage({ settings, campaignId }: {settings: onConfirm={confirmIndividualDisable} onCancel={() => setIndividualDisable(null)} /> -
); + ); } diff --git a/webui/src/features/campaigns/CampaignAuditPage.tsx b/webui/src/features/campaigns/CampaignAuditPage.tsx index f1987c0..755bdc0 100644 --- a/webui/src/features/campaigns/CampaignAuditPage.tsx +++ b/webui/src/features/campaigns/CampaignAuditPage.tsx @@ -1,11 +1,8 @@ import type { ApiSettings } from "../../types"; import { Button } from "@govoplan/core-webui"; import { Card } from "@govoplan/core-webui"; -import { DismissibleAlert } from "@govoplan/core-webui"; -import { PageTitle } from "@govoplan/core-webui"; import VersionLine from "./components/VersionLine"; -import { LoadingFrame } from "@govoplan/core-webui"; -import { ActionBlockerHint, DocumentationHelpLink } from "@govoplan/core-webui"; +import { ActionBlockerHint, DocumentationHelpLink, PageLayout } from "@govoplan/core-webui"; import { useCampaignWorkspaceData } from "./hooks/useCampaignWorkspaceData"; export default function CampaignAuditPage({ settings, campaignId }: {settings: ApiSettings;campaignId: string;}) { @@ -13,20 +10,17 @@ export default function CampaignAuditPage({ settings, campaignId }: {settings: A const version = data.currentVersion; return ( -
-
-
- i18n:govoplan-campaign.audit_log.3cfc5f1c - -
-
+ } + loading={loading} + loadingLabel="i18n:govoplan-campaign.loading_audit_data.af52b968" + error={error} + actions={ -
-
- - {error && {error}} - - + } + > - -
); + ); } diff --git a/webui/src/features/campaigns/CampaignFieldsPage.tsx b/webui/src/features/campaigns/CampaignFieldsPage.tsx index 21759c4..f4cf926 100644 --- a/webui/src/features/campaigns/CampaignFieldsPage.tsx +++ b/webui/src/features/campaigns/CampaignFieldsPage.tsx @@ -1,7 +1,7 @@ import { useMemo, useRef } from "react"; import type { ApiSettings } from "../../types"; import { Button } from "@govoplan/core-webui"; -import { PageTitle } from "@govoplan/core-webui"; +import { PageLayout } from "@govoplan/core-webui"; import { Card } from "@govoplan/core-webui"; import { LoadingFrame } from "@govoplan/core-webui"; import LockedVersionNotice from "./components/LockedVersionNotice"; @@ -150,22 +150,24 @@ export default function CampaignFieldsPage({ settings, campaignId }: {settings: return ( -
-
-
- i18n:govoplan-campaign.fields.e8b68527 - -
-
+ } + headerLoading={loading} + error={error} + actions={ + <> -
-
- - {error && {error}} - {localError && {localError}} - {fieldNameWarning && {fieldNameWarning}} - {locked && } + + } + notices={(localError || fieldNameWarning || locked) ? <> + {localError && {localError}} + {fieldNameWarning && {fieldNameWarning}} + {locked && } + : undefined} + > <> @@ -184,7 +186,7 @@ export default function CampaignFieldsPage({ settings, campaignId }: {settings: -
); + ); } diff --git a/webui/src/features/campaigns/CampaignJsonView.tsx b/webui/src/features/campaigns/CampaignJsonView.tsx index 3f12dd0..2f047a6 100644 --- a/webui/src/features/campaigns/CampaignJsonView.tsx +++ b/webui/src/features/campaigns/CampaignJsonView.tsx @@ -1,10 +1,8 @@ import type { ApiSettings } from "../../types"; import { Card } from "@govoplan/core-webui"; import { Button } from "@govoplan/core-webui"; -import { DismissibleAlert } from "@govoplan/core-webui"; -import { PageTitle } from "@govoplan/core-webui"; +import { DismissibleAlert, PageLayout } from "@govoplan/core-webui"; import VersionLine from "./components/VersionLine"; -import { LoadingFrame } from "@govoplan/core-webui"; import { useCampaignWorkspaceData } from "./hooks/useCampaignWorkspaceData"; import { asRecord, getCampaignJson } from "./utils/campaignView"; import { downloadJson, safeFileStem } from "./utils/draftEditor"; @@ -17,28 +15,30 @@ export default function CampaignJsonView({ settings, campaignId }: {settings: Ap const filename = `${safeFileStem(String(campaign.id || data.campaign?.external_id || campaignId))}.json`; return ( -
-
-
- i18n:govoplan-campaign.json.031a4e76 - -
-
+ } + loading={loading} + loadingLabel="i18n:govoplan-campaign.loading_json.812c7a50" + error={error} + actions={ + <> -
-
- {error && {error}} - - This expert view contains the complete authorized campaign configuration, - including recipient and message fields that may contain personal data. - Download and share it only for an authorized purpose. - - + + } + notices={ + + This expert view contains the complete authorized campaign configuration, + including recipient and message fields that may contain personal data. + Download and share it only for an authorized purpose. + + } + > {!loading || version ?
{JSON.stringify(campaignJson, null, 2)}
:
{"{}"}
}
-
-
); + ); } diff --git a/webui/src/features/campaigns/CampaignListPage.tsx b/webui/src/features/campaigns/CampaignListPage.tsx index 2d85b2a..8931400 100644 --- a/webui/src/features/campaigns/CampaignListPage.tsx +++ b/webui/src/features/campaigns/CampaignListPage.tsx @@ -6,10 +6,8 @@ import type { ApiSettings } from "../../types"; import { Card } from "@govoplan/core-webui"; import { Button } from "@govoplan/core-webui"; import { StatusBadge } from "@govoplan/core-webui"; -import { PageTitle } from "@govoplan/core-webui"; import { LoadingFrame } from "@govoplan/core-webui"; -import { PageScrollViewport } from "@govoplan/core-webui"; -import { DismissibleAlert, TableActionGroup, i18nMessage, useGuardedNavigate } from "@govoplan/core-webui"; +import { PageLayout, TableActionGroup, i18nMessage, useGuardedNavigate } from "@govoplan/core-webui"; import { DataGrid, type DataGridColumn } from "@govoplan/core-webui"; import { createNewCampaign, listCampaignsDelta, type CampaignDeltaResponse } from "../../api/campaigns"; import type { CampaignListItem } from "../../types"; @@ -144,22 +142,22 @@ export default function CampaignListPage({ settings }: {settings: ApiSettings;}) return ( - -
- {error && {error}} - -
-
- i18n:govoplan-campaign.all_campaigns.2bd1ee3a -

{lastLoadedAt ? i18nMessage("i18n:govoplan-campaign.last_loaded_value.35ef046a", { value0: lastLoadedAt }) : "i18n:govoplan-campaign.not_loaded_yet.9968c191"}

-
-
+ {lastLoadedAt ? i18nMessage("i18n:govoplan-campaign.last_loaded_value.35ef046a", { value0: lastLoadedAt }) : "i18n:govoplan-campaign.not_loaded_yet.9968c191"}

} + headerLoading={loading} + error={error} + actions={ + <> -
-
+ + } + > @@ -186,8 +184,7 @@ export default function CampaignListPage({ settings }: {settings: ApiSettings;}) } -
-
); + ); } diff --git a/webui/src/features/campaigns/CampaignModulePage.tsx b/webui/src/features/campaigns/CampaignModulePage.tsx index 46f0f62..b981707 100644 --- a/webui/src/features/campaigns/CampaignModulePage.tsx +++ b/webui/src/features/campaigns/CampaignModulePage.tsx @@ -1,6 +1,7 @@ import { lazy } from "react"; import { ModuleSubnav, + WorkspaceLayout, hasAnyScope, useGuardedNavigate, type ApiSettings, @@ -64,15 +65,19 @@ export default function CampaignModulePage({ } return ( -
- -
+ } + primaryLabel="Campaign module sections" + contentLabel="Campaign module content" + interfaceId="campaign.module-workspace" + helpModuleId="campaign" + > {active === "queue" ? : active === "reports" ? : } -
-
+ ); } diff --git a/webui/src/features/campaigns/CampaignOverviewPage.tsx b/webui/src/features/campaigns/CampaignOverviewPage.tsx index 7ebba58..83ae27d 100644 --- a/webui/src/features/campaigns/CampaignOverviewPage.tsx +++ b/webui/src/features/campaigns/CampaignOverviewPage.tsx @@ -9,7 +9,7 @@ import { Dialog } from "@govoplan/core-webui"; import { FormField } from "@govoplan/core-webui"; import { LoadingFrame } from "@govoplan/core-webui"; import { MetricCard } from "@govoplan/core-webui"; -import { PageTitle } from "@govoplan/core-webui"; +import { PageLayout } from "@govoplan/core-webui"; import { StatusBadge } from "@govoplan/core-webui"; import { ToggleSwitch } from "@govoplan/core-webui"; import { DismissibleAlert, TableActionGroup, hasScope, i18nMessage, useGuardedNavigate, useUnsavedDraftGuard } from "@govoplan/core-webui"; @@ -332,13 +332,15 @@ export default function CampaignOverviewPage({ settings, auth, campaignId }: {se } return ( -
-
-
- {campaign?.name || "i18n:govoplan-campaign.overview.0efc2e6b"} -

i18n:govoplan-campaign.campaign_overview_version_independent_identity_a.ebaf1113

-
-
+ i18n:govoplan-campaign.campaign_overview_version_independent_identity_a.ebaf1113

} + headerLoading={loading} + error={error} + success={message} + actions={ + <> {canCopy && data.currentVersion && } -
-
- - {error && {error}} - {message && {message}} + + } + >
@@ -618,7 +618,7 @@ export default function CampaignOverviewPage({ settings, auth, campaignId }: {se onCancel={() => setPendingLockAction(null)} onConfirm={() => void applyLockAction()} /> -
); + ); } diff --git a/webui/src/features/campaigns/CampaignReportPage.tsx b/webui/src/features/campaigns/CampaignReportPage.tsx index 12d0d3c..343cc91 100644 --- a/webui/src/features/campaigns/CampaignReportPage.tsx +++ b/webui/src/features/campaigns/CampaignReportPage.tsx @@ -21,7 +21,7 @@ import { DataGrid, type DataGridColumn, type DataGridListOption, type DataGridQu import { Dialog } from "@govoplan/core-webui"; import { DismissibleAlert } from "@govoplan/core-webui"; import { FormField } from "@govoplan/core-webui"; -import { PageTitle } from "@govoplan/core-webui"; +import { PageLayout } from "@govoplan/core-webui"; import { StatusBadge } from "@govoplan/core-webui"; import VersionLine from "./components/VersionLine"; import { LoadingFrame, TableActionGroup, ToggleSwitch, i18nMessage } from "@govoplan/core-webui"; @@ -445,20 +445,21 @@ export default function CampaignReportPage({ settings, campaignId }: {settings: [busyAction, retryFailedSynchronously]); return ( -
-
-
- i18n:govoplan-campaign.report.ee45c303 - -
-
+ } + headerLoading={loading} + error={error || actionError} + success={actionMessage} + actions={ + <> -
-
- {(error || actionError) && {error || actionError}} - {actionMessage && {actionMessage}} + + } + >
@@ -647,7 +648,7 @@ export default function CampaignReportPage({ settings, campaignId }: {settings: onConfirm={() => void reconcileOutcome()} onCancel={() => setReconcile(null)} /> -
); + ); } diff --git a/webui/src/features/campaigns/CampaignWorkspace.tsx b/webui/src/features/campaigns/CampaignWorkspace.tsx index f28530c..5c1d45d 100644 --- a/webui/src/features/campaigns/CampaignWorkspace.tsx +++ b/webui/src/features/campaigns/CampaignWorkspace.tsx @@ -2,6 +2,7 @@ import { lazy, useEffect, useState } from "react"; import { Navigate, Route, Routes, useLocation, useNavigate, useParams } from "react-router"; import { ConcurrencyConflictProvider, + WorkspaceLayout, useGuardedNavigate } from "@govoplan/core-webui"; import type { ApiSettings, AuthInfo, CampaignWorkspaceSection } from "../../types"; @@ -85,9 +86,13 @@ function CampaignWorkspaceInner({ settings, auth }: { settings: ApiSettings; aut } return ( -
- -
+ } + primaryLabel="Campaign sections" + contentLabel="Campaign workspace" + interfaceId="campaign.workspace" + helpModuleId="campaign" + > } /> } /> @@ -121,8 +126,7 @@ function CampaignWorkspaceInner({ settings, auth }: { settings: ApiSettings; aut } /> } /> -
-
+ ); } diff --git a/webui/src/features/campaigns/GlobalSettingsPage.tsx b/webui/src/features/campaigns/GlobalSettingsPage.tsx index e9eeef4..c4c6120 100644 --- a/webui/src/features/campaigns/GlobalSettingsPage.tsx +++ b/webui/src/features/campaigns/GlobalSettingsPage.tsx @@ -10,7 +10,7 @@ import { Button } from "@govoplan/core-webui"; import { Card } from "@govoplan/core-webui"; import { FormField } from "@govoplan/core-webui"; import { DismissibleAlert } from "@govoplan/core-webui"; -import { PageTitle } from "@govoplan/core-webui"; +import { PageLayout } from "@govoplan/core-webui"; import { LoadingFrame } from "@govoplan/core-webui"; import { PolicyRow } from "@govoplan/core-webui"; import { PolicyTable } from "@govoplan/core-webui"; @@ -178,21 +178,23 @@ export default function GlobalSettingsPage({ settings, auth, campaignId, view = } return ( -
-
-
- {pageTitle} - -
-
+ } + headerLoading={loading} + error={error} + actions={ + <> -
-
- - {error && {error}} - {localError && {localError}} - {locked && } + + } + notices={(localError || locked) ? <> + {localError && {localError}} + {locked && } + : undefined} + > {isPolicyView ? @@ -500,7 +502,7 @@ export default function GlobalSettingsPage({ settings, auth, campaignId, view = onClose={() => setPostboxTargetsOpen(false)} /> } -
); + ); } diff --git a/webui/src/features/campaigns/MailSettingsPage.tsx b/webui/src/features/campaigns/MailSettingsPage.tsx index d8f1fb3..bcf2016 100644 --- a/webui/src/features/campaigns/MailSettingsPage.tsx +++ b/webui/src/features/campaigns/MailSettingsPage.tsx @@ -8,7 +8,7 @@ import { LoadingFrame, MailServerFolderLookupResultView, MetricCard, - PageTitle, + PageLayout, PasswordField, ToggleSwitch, usePlatformModuleInstalled, @@ -326,21 +326,23 @@ export default function MailSettingsPage({ settings, campaignId, view = "setting } return ( -
-
-
- {isPolicyView ? "i18n:govoplan-campaign.mail_policy.3eb5d32a" : "i18n:govoplan-campaign.mail_settings.19e07f55"} - -
-
+ } + headerLoading={loading} + error={error} + actions={ + <> {!isPolicyView && } -
-
- - {error && {error}} - {localError && {localError}} - {locked && } + + } + notices={(localError || locked) ? <> + {localError && {localError}} + {locked && } + : undefined} + > <> @@ -501,7 +503,7 @@ export default function MailSettingsPage({ settings, campaignId, view = "setting } -
+ ); } diff --git a/webui/src/features/campaigns/ReviewSendPage.tsx b/webui/src/features/campaigns/ReviewSendPage.tsx index ed6f373..8077162 100644 --- a/webui/src/features/campaigns/ReviewSendPage.tsx +++ b/webui/src/features/campaigns/ReviewSendPage.tsx @@ -42,7 +42,7 @@ import { DataGrid, type DataGridQueryState } from "@govoplan/core-webui"; import { DismissibleAlert } from "@govoplan/core-webui"; import { ConfirmDialog } from "@govoplan/core-webui"; import { LoadingFrame } from "@govoplan/core-webui"; -import { PageTitle } from "@govoplan/core-webui"; +import { PageLayout } from "@govoplan/core-webui"; import { StatusBadge } from "@govoplan/core-webui"; import { ToggleSwitch } from "@govoplan/core-webui"; import { i18nMessage } from "@govoplan/core-webui"; @@ -1364,34 +1364,33 @@ export default function ReviewSendPage({ reviewedExplicitCount === explicitReviewCount; return ( -
-
-
- i18n:govoplan-campaign.review_send.1627617d - -
-
+ } + headerLoading={loading || Boolean(busy)} + error={error} + actions={ + <> -
-
- - {error && {error}} - {message && {message}} - - - {version && (historicalVersion || readyForDelivery || userLockedVersion || finalVersion) && - - + } + notices={(message || (version && (historicalVersion || readyForDelivery || userLockedVersion || finalVersion))) ? <> + {message && {message}} + {version && (historicalVersion || readyForDelivery || userLockedVersion || finalVersion) && + } + : undefined} + > @@ -2113,6 +2112,6 @@ export default function ReviewSendPage({ onClose={() => setSelectedMockMessage(null)} /> } -
); + ); } diff --git a/webui/src/features/campaigns/TemplateDataPage.tsx b/webui/src/features/campaigns/TemplateDataPage.tsx index 429fd0f..1250763 100644 --- a/webui/src/features/campaigns/TemplateDataPage.tsx +++ b/webui/src/features/campaigns/TemplateDataPage.tsx @@ -16,7 +16,7 @@ import { Card } from "@govoplan/core-webui"; import { Dialog } from "@govoplan/core-webui"; import { FormField } from "@govoplan/core-webui"; import { FieldLabel } from "@govoplan/core-webui"; -import { PageTitle } from "@govoplan/core-webui"; +import { PageLayout } from "@govoplan/core-webui"; import { LoadingFrame } from "@govoplan/core-webui"; import { DismissibleAlert, SegmentedControl, ToggleSwitch, i18nMessage } from "@govoplan/core-webui"; import { WysiwygEditor, type WysiwygEditorHandle } from "@govoplan/core-webui/wysiwyg"; @@ -411,23 +411,25 @@ export default function TemplateDataPage({ settings, campaignId }: {settings: Ap return ( -
-
-
- i18n:govoplan-campaign.template.3ec1ae06 - -
-
+ } + headerLoading={loading} + error={error} + success={contentLibraryNotice} + actions={ + <> -
-
- - {error && {error}} - {localError && {localError}} - {contentLibraryNotice && {contentLibraryNotice}} - {locked && } + + } + notices={(localError || locked) ? <> + {localError && {localError}} + {locked && } + : undefined} + > <> @@ -783,7 +785,7 @@ export default function TemplateDataPage({ settings, campaignId }: {settings: Ap localFields={localFieldOptions} globalFields={globalFieldOptions} /> -
); + ); } diff --git a/webui/src/features/campaigns/components/CampaignDraftPageScaffold.tsx b/webui/src/features/campaigns/components/CampaignDraftPageScaffold.tsx index 51519bd..84008d7 100644 --- a/webui/src/features/campaigns/components/CampaignDraftPageScaffold.tsx +++ b/webui/src/features/campaigns/components/CampaignDraftPageScaffold.tsx @@ -1,5 +1,5 @@ import type { ReactNode } from "react"; -import { Button, DismissibleAlert, LoadingFrame, PageTitle } from "@govoplan/core-webui"; +import { Button, DismissibleAlert, PageLayout } from "@govoplan/core-webui"; import type { ApiSettings } from "../../../types"; import type { CampaignVersionDetail, CampaignVersionListItem } from "../../../api/campaigns"; import LockedVersionNotice from "./LockedVersionNotice"; @@ -43,25 +43,26 @@ export default function CampaignDraftPageScaffold({ children }: CampaignDraftPageScaffoldProps) { return ( -
-
-
- {title} - -
-
+ } + loading={loading || !draft} + loadingLabel="i18n:govoplan-campaign.loading_campaign_draft.1cf47e50" + error={error || ""} + actions={ + <> -
-
- - {error && {error}} - {localError && {localError}} - {locked && } - - - <>{children} - -
); + + } + notices={(localError || locked) ? + <> + {localError && {localError}} + {locked && } + : undefined} + > + {children} + ); } diff --git a/webui/src/features/campaigns/wizard/WizardDirectoryPage.tsx b/webui/src/features/campaigns/wizard/WizardDirectoryPage.tsx index bafd500..12bf390 100644 --- a/webui/src/features/campaigns/wizard/WizardDirectoryPage.tsx +++ b/webui/src/features/campaigns/wizard/WizardDirectoryPage.tsx @@ -1,6 +1,6 @@ import { Link } from "react-router"; import { - PageTitle, + PageLayout, WizardDirectory, usePlatformUiCapabilities, wizardEntriesForContext, @@ -38,18 +38,20 @@ export default function WizardDirectoryPage({ }); return ( -
-
- i18n:govoplan-campaign.guided_workflows + i18n:govoplan-campaign.back_to_overview.ec986cba -
+ } + > -
+ ); } diff --git a/webui/src/features/operator/OperatorQueuePage.tsx b/webui/src/features/operator/OperatorQueuePage.tsx index edf2a99..179466c 100644 --- a/webui/src/features/operator/OperatorQueuePage.tsx +++ b/webui/src/features/operator/OperatorQueuePage.tsx @@ -25,11 +25,9 @@ import { type DataGridListOption, type DataGridQueryState } from "@govoplan/core-webui"; -import { DismissibleAlert } from "@govoplan/core-webui"; +import { DismissibleAlert, PageLayout } from "@govoplan/core-webui"; import { LoadingFrame } from "@govoplan/core-webui"; import { MetricCard } from "@govoplan/core-webui"; -import { PageTitle } from "@govoplan/core-webui"; -import { PageScrollViewport } from "@govoplan/core-webui"; import { StatusBadge, TableActionGroup, @@ -757,22 +755,22 @@ export default function OperatorQueuePage({ settings, auth }: {settings: ApiSett ], [navigate, permissions.canOpenReport, selectedRow, selectedVersionId]); return ( - -
-
-
- i18n:govoplan-campaign.operator_queue.72492fb5 +

i18n:govoplan-campaign.queue_state_retry_candidates_and_reconciliation_.1b592bbe

i18n:govoplan-campaign.queue_refreshes_automatically_while_delivery_is_active.df8dc205

-
-
+ + } + error={error} + success={message} + actions={ -
-
- - {error && {error}} - {jobsError && {jobsError}} - {message && {message}} + } + notices={jobsError ? {jobsError} : undefined} + >

i18n:govoplan-campaign.queue_pressure.28eee15e

@@ -847,8 +845,7 @@ export default function OperatorQueuePage({ settings, auth }: {settings: ApiSett if (cancelTarget) void runAction(cancelTarget, "cancel"); }} onCancel={() => setCancelTarget(null)} /> -
-
); + ); } diff --git a/webui/src/features/reports/AggregateReportsPage.tsx b/webui/src/features/reports/AggregateReportsPage.tsx index 3418807..b9c9be2 100644 --- a/webui/src/features/reports/AggregateReportsPage.tsx +++ b/webui/src/features/reports/AggregateReportsPage.tsx @@ -5,11 +5,9 @@ import { Button, Card, DataGrid, - DismissibleAlert, LoadingFrame, MetricCard, - PageScrollViewport, - PageTitle, + PageLayout, StatusBadge, TableActionGroup, formatDateTime, @@ -167,24 +165,21 @@ export default function AggregateReportsPage({ settings }: {settings: ApiSetting const outcomes = report?.outcomes; return ( - -
-
-
- i18n:govoplan-campaign.reports.88bc3fe3 -

i18n:govoplan-campaign.privacy_protected_campaign_outcomes_without_reci.5b8a100d

-
-
+ void Promise.all([loadCampaigns(), selectedFromUrl ? loadReport(selectedFromUrl) : Promise.resolve()])} disabled={listLoading || reportLoading} >
-
- - {error && {error}} + } + > @@ -252,8 +247,7 @@ export default function AggregateReportsPage({ settings }: {settings: ApiSetting )} -
-
+ ); } diff --git a/webui/src/features/templates/TemplatesPage.tsx b/webui/src/features/templates/TemplatesPage.tsx index d60e4a2..d58d561 100644 --- a/webui/src/features/templates/TemplatesPage.tsx +++ b/webui/src/features/templates/TemplatesPage.tsx @@ -2,8 +2,7 @@ import { useMemo, useState } from "react"; import { ExternalLink } from "lucide-react"; import { Button } from "@govoplan/core-webui"; import { Card } from "@govoplan/core-webui"; -import { PageScrollViewport } from "@govoplan/core-webui"; -import { PageTitle } from "@govoplan/core-webui"; +import { PageLayout, WorkspaceLayout } from "@govoplan/core-webui"; import { FieldLabel } from "@govoplan/core-webui"; import { StatusBadge, TableActionGroup, i18nMessage } from "@govoplan/core-webui"; import { usePlatformLanguage } from "@govoplan/core-webui"; @@ -137,20 +136,25 @@ export default function TemplatesPage() { if (selectedTemplate) { return ( -
- setSelectedId(null))} onSelect={setActive} /> -
-
-
-
- {selectedTemplate.name} -

{selectedTemplate.description}

-
-
+ setSelectedId(null))} onSelect={setActive} />} + primaryLabel="Template sections" + contentLabel="Template workspace" + interfaceId="campaign.template-workspace" + helpModuleId="campaign" + > + -
-
+ + } + > {active === "overview" && } {active === "content" && } @@ -158,25 +162,23 @@ export default function TemplatesPage() { {active === "preview" && } {active === "usage" && } {active === "versions" && } -
-
-
); + + ); } return ( - -
-
-
- i18n:govoplan-campaign.templates.f25b700e -

i18n:govoplan-campaign.reusable_message_templates_open_a_template_to_ed.792e2afb

-
-
+ -
-
+ + } + > -
-
); + ); } diff --git a/webui/tests/accessibility-contract.test.mjs b/webui/tests/accessibility-contract.test.mjs index d2dff49..e687b36 100644 --- a/webui/tests/accessibility-contract.test.mjs +++ b/webui/tests/accessibility-contract.test.mjs @@ -17,6 +17,26 @@ const sources = sourceFiles(sourceRoot).map((file) => ({ value: fs.readFileSync(file, "utf8"), })); +for (const { file, value } of sources) { + assert.ok( + !value.includes('className="content-pad workspace-data-page'), + `${path.relative(sourceRoot, file)} must use Core PageLayout instead of a raw page frame`, + ); + assert.ok( + !/ [...value.matchAll(/<(div|span|li|tr)\b[^>]*\bonClick\s*=/g)].map( (match) => `${path.relative(sourceRoot, file)}:${match.index}`,