Admin Attestation Cycle Page¶
Overview¶
The Attestation Cycle page (/admin/attestation) allows compliance officers (COMP), HR admins, org admins, and system admins to launch and track quarterly fit-and-proper attestation cycles. The page is implemented in client/src/pages/admin/AttestationCyclePage.tsx.
Access control: @Roles("COMP", "HR_ADMIN", "ORG_ADMIN", "SYS_ADMIN") on all GraphQL queries and mutations.
Page Layout¶
Top Section: Organisation Selector¶
The page opens with an organisation dropdown. SYS_ADMIN users can switch between all organisations; all other roles default to their own organisation. The selected org is displayed as a badge alongside the dropdown. Until an org is selected, the main content area shows an EmptyState component prompting org selection.
Header¶
The PageHeader component displays:
- Title: "Attestation Cycles"
- Subtitle: "Launch and track quarterly fit-and-proper attestations across your representatives."
- Breadcrumbs: Dashboard > Attestation Cycles
- Action button: "New cycle" (visible only when an organisation is selected; opens the launch modal)
Main Table¶
The table lists up to 20 attestation cycles for the selected organisation (via the attestationCycles(orgId, limit) GraphQL query). Columns:
| Column | Content | Source Field |
|---|---|---|
| Cycle | First 8 chars of UUID + "..." | cycleId.slice(0, 8) |
| Launched | SG-locale datetime (e.g., "02 May 2026, 14:30") | launchedAt |
| Template | # + numeric template ID |
templateId |
| Reps | Total representatives in cycle | totalReps |
| Progress | Completion badge with counts | completedCount / totalReps |
Progress Badge Variants¶
The completionVariant() function determines badge coloring:
- Green (success): pendingCount === 0 -- all reps have completed
- Amber (warning): completedCount === 0 -- no reps have completed yet
- Blue (info): partial completion or totalReps === 0 -- in progress
Badge text format: "N / M complete" (e.g., "5 / 12 complete") plus "X pending" if pendingCount > 0.
Empty States¶
- No org selected: "Select an organisation" with
CalendarClockicon - No cycles for org: "No cycles found" with description "No attestation cycles have been launched for this organisation yet. Click 'New cycle' to start one."
Launch New Cycle Modal¶
Activated by the "New cycle" button. Contains the LaunchCycleForm component which:
Step 1: Template Selection¶
- If workflow templates exist for the org: a
<Select>dropdown listing all templates with name and form_type - If no templates: a numeric
<Input>field for manually entering a workflow template ID (with help text: "Enter the numeric id of an approval template in this org.")
Step 2: Representative Selection¶
- Displays "Representatives (N selected)" label with "Select all" / "Clear all" toggle
- Search/filter input that matches on rep name, username, rep number, or email address
- Scrollable list (max-height 64) of rep profiles with checkboxes
- Each row shows: rep name (bold), rep number, email address
- Data sourced from
repProfiles(filter: { principalOrganisationId: orgId })query - Minimum 1 rep must be selected; validation toast: "Select at least one representative to attest."
Submission¶
- Calls
launchAttestationCyclemutation with{ orgId, templateId, repIds, launchedByUserId? } - On success: toast message, modal closes, table refetches
- On failure: toast with error message
GraphQL Data Sources¶
| Query/Mutation | Purpose | Returnd Fields |
|---|---|---|
attestationCycles(orgId, limit) |
List cycles for org | cycleId, orgId, templateId, launchedAt, launchedByUserId, totalReps, completedCount, pendingCount, repProfileIds |
repProfiles(filter) |
List reps in org for selection | id, userId, repNumber, principalOrganisationId, user { id, username, name, emailAddress } |
launchAttestationCycle(input) |
Create new cycle | Returns full AttestationCycle object |
Page Context¶
The AttestationCyclePage does not wrap its content in a PageEntityProvider. The chatbot receives no entity context when opened from this page (kind: 'none'). The chatbot can still assist by using the launch_attestation_cycle tool (which takes org_id from ctx.org_id when not specified).
Related Pages¶
/admin/rep-register-- Rep health register with per-rep CMFAS + CPD status (feeds the attestation cycle's rep selection)/declarations/:id/workflow-- Individual declaration workflow (view attestation responses)