fix(compliance): group the Rapport view by report headline, tags as a caption (#1188) - #1203
Conversation
… caption (#1188) "Rapportoverskrift" is a real field (AreaRulePlanning.ItemPlanningTagId, the wizard's "report table header tag"), not a prototype placeholder. #1167 read it as one and grouped Rapport by tag x eForm template with the template name as heading, so a headline spanning several tags rendered as several tables, a multi-tag task was duplicated, and the export followed suit. Backend - EformColumns groups by row.Arp?.ItemPlanningTagId: one ComplianceReportHeadlineGroupModel per headline (HeadlineTagId, HeadlineName (null when unresolvable -> "#id" on the client), TagsCaption, CheckListIds, SchemaUnavailableCheckListIds, a FRESH union of the templates' columns, Cases once each). Cases carry Tags (excluding the headline, which the legacy area-rule path also stores as an ARP tag) and their own CheckListId. Rows without a headline form a last fallback group (WithoutReportHeadline). Order: caption, headline name, id. Tag-group/template-group DTOs deleted. - Export: ComplianceExportTable.Caption; BuildReport emits one table per headline (caption line above the bold headline, Delrapport = the row's own tags joined " - ", no headline column per product decision 4, appendix labelled by caption); Oversigt/Detaljer untouched. - localization.json: WithoutReportHeadline, ReportHeadline (26 locales). - Tests: EformColumns grouping tests rewritten (two headlines, union columns with in-place dash, no cache leak, caption A - B, legacy headline-as-tag excluded, fallback last, orphan headline id, order, clones); builder/writer tests updated for Caption and Delrapport. Frontend - Model/service/helper/view follow the new shape: caption (.compliance-report__tag) + headline (.compliance-report__heading), "#id" for unresolvable headlines, "Uden rapportoverskrift" fallback, per-template "columns unavailable" notice, Rediger uses the row's own checkListId. i18n: "Without tag" retired; "Without report headline" and the per-template notice key added in 26 locales, fallback label aligned with localization.json. - Jest specs rewritten; Playwright replaces the substring-matched "Rapportoverskrift" assertion with structural section assertions. Reverses #1160 decision 5, #1166 "mirror this shape", #1167 heading and grouping, and PR #1178's composite Delrapport column. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018qJL2WhHwhZ5CGZehZF2ro
There was a problem hiding this comment.
🟡 Changes recommended
Backend grouping should normalize/trim headline and tag names at the source to avoid inconsistent ordering/output between UI and exports when tag names contain surrounding whitespace.
Once you've addressed the issues Copilot identified, you can request another Copilot review.
Pull request overview
This PR updates the Compliance “Rapport” read model and UI to group results by report headline (AreaRulePlanning.ItemPlanningTagId) instead of the previous tag × template grouping, aligning the screen and exports with the customer PDF (“Tabel_Rapport”) requirements.
Changes:
- Backend: replace tag/template grouping DTOs with
ComplianceReportHeadlineGroupModeland build per-headline union columns + per-case tags (headline excluded). - Export: add
ComplianceExportTable.Caption(tags caption) rendered above the headline in Word/PDF; adjust Rapport export shaping to the new grouping andDelrapportsemantics. - Frontend/tests: map the new DTO shape into sections (caption + headline), add per-template schema-unavailable notices, update i18n and Playwright/Jest/NUnit fixtures.
File summaries
| File | Description |
|---|---|
| eFormAPI/Plugins/BackendConfiguration.Pn/BackendConfiguration.Pn/Services/BackendConfigurationComplianceReportService/IBackendConfigurationComplianceReportService.cs | Updates service contract to headline-grouped DTO |
| eFormAPI/Plugins/BackendConfiguration.Pn/BackendConfiguration.Pn/Services/BackendConfigurationComplianceReportService/ComplianceReportEformProjector.cs | Updates schema-unavailable docs to new DTO shape |
| eFormAPI/Plugins/BackendConfiguration.Pn/BackendConfiguration.Pn/Services/BackendConfigurationComplianceReportService/BackendConfigurationComplianceReportService.cs | Implements headline grouping + union columns + per-row tags |
| eFormAPI/Plugins/BackendConfiguration.Pn/BackendConfiguration.Pn/Services/BackendConfigurationComplianceExportService/ComplianceExportWordWriter.cs | Renders Rapport caption line above headline |
| eFormAPI/Plugins/BackendConfiguration.Pn/BackendConfiguration.Pn/Services/BackendConfigurationComplianceExportService/ComplianceExportDocumentBuilder.cs | Builds Rapport tables from headline groups + caption/title semantics |
| eFormAPI/Plugins/BackendConfiguration.Pn/BackendConfiguration.Pn/Resources/localization.json | Adds WithoutReportHeadline + ReportHeadline keys (26 locales) |
| eFormAPI/Plugins/BackendConfiguration.Pn/BackendConfiguration.Pn/Infrastructure/Models/ComplianceReport/ComplianceReportTemplateGroupModel.cs | Removes obsolete template-group DTO |
| eFormAPI/Plugins/BackendConfiguration.Pn/BackendConfiguration.Pn/Infrastructure/Models/ComplianceReport/ComplianceReportTagGroupModel.cs | Removes obsolete tag-group DTO |
| eFormAPI/Plugins/BackendConfiguration.Pn/BackendConfiguration.Pn/Infrastructure/Models/ComplianceReport/ComplianceReportHeadlineGroupModel.cs | Adds new headline-group DTO |
| eFormAPI/Plugins/BackendConfiguration.Pn/BackendConfiguration.Pn/Infrastructure/Models/ComplianceReport/ComplianceReportCaseModel.cs | Adds per-case CheckListId + Tags for new grouping/export |
| eFormAPI/Plugins/BackendConfiguration.Pn/BackendConfiguration.Pn/Infrastructure/Models/ComplianceReport/ComplianceExportDocument.cs | Adds ComplianceExportTable.Caption + updates Rapport grouping docs |
| eFormAPI/Plugins/BackendConfiguration.Pn/BackendConfiguration.Pn/Controllers/ComplianceReportController.cs | Updates endpoint return type to headline groups |
| eFormAPI/Plugins/BackendConfiguration.Pn/BackendConfiguration.Pn.Integration.Test/ComplianceExportWriterTests.cs | Updates writer tests for caption/title and CSV caption omission |
| eFormAPI/Plugins/BackendConfiguration.Pn/BackendConfiguration.Pn.Integration.Test/ComplianceExportServiceTests.cs | Updates stubbed service return types |
| eFormAPI/Plugins/BackendConfiguration.Pn/BackendConfiguration.Pn.Integration.Test/ComplianceExportDocumentBuilderTests.cs | Rewrites Rapport export builder tests for new grouping |
| eform-client/src/app/plugins/modules/backend-configuration-pn/services/backend-configuration-pn-compliance-report.service.ts | Updates frontend service return type to headline groups |
| eform-client/src/app/plugins/modules/backend-configuration-pn/modules/compliance-report/helpers/compliance-report-sections.ts | Maps headline groups to sections + schema notice logic |
| eform-client/src/app/plugins/modules/backend-configuration-pn/modules/compliance-report/helpers/compliance-report-sections.spec.ts | Rewrites pure helper tests for headline grouping rules |
| eform-client/src/app/plugins/modules/backend-configuration-pn/modules/compliance-report/components/compliance-report-view/compliance-report-view.component.ts | Updates Rapport view to render headline sections + per-row template id |
| eform-client/src/app/plugins/modules/backend-configuration-pn/modules/compliance-report/components/compliance-report-view/compliance-report-view.component.spec.ts | Updates component tests for new section shape + routing |
| eform-client/src/app/plugins/modules/backend-configuration-pn/modules/compliance-report/components/compliance-report-view/compliance-report-view.component.scss | Updates caption/heading styling semantics |
| eform-client/src/app/plugins/modules/backend-configuration-pn/modules/compliance-report/components/compliance-report-view/compliance-report-view.component.html | Updates markup for caption + headline + per-template notices |
| eform-client/src/app/plugins/modules/backend-configuration-pn/models/compliance-report/compliance-report.model.ts | Replaces tag/template DTOs with headline-group model |
| eform-client/src/app/plugins/modules/backend-configuration-pn/i18n/ukUA.ts | Replaces “Without tag” with new headline + template-notice keys |
| eform-client/src/app/plugins/modules/backend-configuration-pn/i18n/svSE.ts | Replaces “Without tag” with new headline + template-notice keys |
| eform-client/src/app/plugins/modules/backend-configuration-pn/i18n/slSL.ts | Replaces “Without tag” with new headline + template-notice keys |
| eform-client/src/app/plugins/modules/backend-configuration-pn/i18n/skSK.ts | Replaces “Without tag” with new headline + template-notice keys |
| eform-client/src/app/plugins/modules/backend-configuration-pn/i18n/roRO.ts | Replaces “Without tag” with new headline + template-notice keys |
| eform-client/src/app/plugins/modules/backend-configuration-pn/i18n/ptPT.ts | Replaces “Without tag” with new headline + template-notice keys |
| eform-client/src/app/plugins/modules/backend-configuration-pn/i18n/ptBR.ts | Replaces “Without tag” with new headline + template-notice keys |
| eform-client/src/app/plugins/modules/backend-configuration-pn/i18n/plPL.ts | Replaces “Without tag” with new headline + template-notice keys |
| eform-client/src/app/plugins/modules/backend-configuration-pn/i18n/noNO.ts | Replaces “Without tag” with new headline + template-notice keys |
| eform-client/src/app/plugins/modules/backend-configuration-pn/i18n/nlNL.ts | Replaces “Without tag” with new headline + template-notice keys |
| eform-client/src/app/plugins/modules/backend-configuration-pn/i18n/lvLV.ts | Replaces “Without tag” with new headline + template-notice keys |
| eform-client/src/app/plugins/modules/backend-configuration-pn/i18n/ltLT.ts | Replaces “Without tag” with new headline + template-notice keys |
| eform-client/src/app/plugins/modules/backend-configuration-pn/i18n/itIT.ts | Replaces “Without tag” with new headline + template-notice keys |
| eform-client/src/app/plugins/modules/backend-configuration-pn/i18n/isIS.ts | Replaces “Without tag” with new headline + template-notice keys |
| eform-client/src/app/plugins/modules/backend-configuration-pn/i18n/huHU.ts | Replaces “Without tag” with new headline + template-notice keys |
| eform-client/src/app/plugins/modules/backend-configuration-pn/i18n/hrHR.ts | Replaces “Without tag” with new headline + template-notice keys |
| eform-client/src/app/plugins/modules/backend-configuration-pn/i18n/frFR.ts | Replaces “Without tag” with new headline + template-notice keys |
| eform-client/src/app/plugins/modules/backend-configuration-pn/i18n/fiFI.ts | Replaces “Without tag” with new headline + template-notice keys |
| eform-client/src/app/plugins/modules/backend-configuration-pn/i18n/etET.ts | Replaces “Without tag” with new headline + template-notice keys |
| eform-client/src/app/plugins/modules/backend-configuration-pn/i18n/esES.ts | Replaces “Without tag” with new headline + template-notice keys |
| eform-client/src/app/plugins/modules/backend-configuration-pn/i18n/enUS.ts | Updates keys/comments for headline grouping + template notice |
| eform-client/src/app/plugins/modules/backend-configuration-pn/i18n/elGR.ts | Replaces “Without tag” with new headline + template-notice keys |
| eform-client/src/app/plugins/modules/backend-configuration-pn/i18n/deDE.ts | Replaces “Without tag” with new headline + template-notice keys |
| eform-client/src/app/plugins/modules/backend-configuration-pn/i18n/da.ts | Replaces “Without tag” with Danish headline + template-notice keys |
| eform-client/src/app/plugins/modules/backend-configuration-pn/i18n/csCZ.ts | Replaces “Without tag” with new headline + template-notice keys |
| eform-client/src/app/plugins/modules/backend-configuration-pn/i18n/bgBG.ts | Replaces “Without tag” with new headline + template-notice keys |
| eform-client/playwright/e2e/plugins/backend-configuration-pn/s/compliance-report-view.spec.ts | Updates Playwright assertions to structural section checks |
Review details
Suppressed comments (1)
eFormAPI/Plugins/BackendConfiguration.Pn/BackendConfiguration.Pn/Services/BackendConfigurationComplianceReportService/BackendConfigurationComplianceReportService.cs:1184
TagLabelreturns rawPlanningTags.Name, so names with surrounding whitespace can produce duplicate-looking tags, affectTagsCaptionordering, and make screen/export output diverge (the frontend trims). Trimming here keeps captions deterministic and consistent with the UI/export formatting rules.
private static string TagLabel(int tagId, Dictionary<int, string> planningTagNames)
{
var name = planningTagNames.GetValueOrDefault(tagId);
return string.IsNullOrWhiteSpace(name) ? $"#{tagId}" : name;
}
- Files reviewed: 51/51 changed files
- Comments generated: 1
- Review effort level: Lite
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
| group = new HeadlineGroupBuilder( | ||
| headlineTagId, planningTagNames.GetValueOrDefault(headlineTagId.Value)); | ||
| groupsByHeadlineId[headlineTagId.Value] = group; |
Closes #1188. Part of #1183 (customer bug list, PDF pages 4–5 "Tabel_Rapport").
Decisions (final)
D1 server-side union of columns per headline · D2 caption = the section's tags (excluding the headline) alphabetical, joined
-· D3 (a) rows without a headline form a last Uden rapportoverskrift section · D4 = noRapportoverskriftCSV column (product sign-off: follow the mock-up) · D5 sections ordered by caption, then headline name, then id · D6 tag-filter semantics unchanged · D7 #1185 took B1.What
Backend —
EformColumnsgroups byAreaRulePlanning.ItemPlanningTagId(the wizard's "report table header tag"): newComplianceReportHeadlineGroupModel(headlineTagId,headlineName— null when noPlanningTagsrow, rendered#{id};tagsCaption;checkListIds;schemaUnavailableCheckListIds; a fresh union of the templates' columns keyedf{fieldId};casesonce each). Cases carrytags(headline excluded — required, the legacy area-rule path also stores the headline as an ARP tag) and their owncheckListId.ComplianceReportTagGroupModel/ComplianceReportTemplateGroupModeldeleted; headline ids ride the single existingPlanningTagslookup; no DB calls in the loop. Export:ComplianceExportTable.Caption; Rapport = one table per headline with a plain caption line above the bold headline,Delrapport= the row's own tags, no headline column, appendix labelled by caption; Oversigt/Detaljer untouched.localization.json:WithoutReportHeadline,ReportHeadline(26 locales).Frontend — model/service/helper/view on the new shape:
.compliance-report__tag= caption,.compliance-report__heading= headline (#{id}/ fallback), union columns with–under foreign-template fields, per-template "Kolonner utilgængelige for eForm #{{id}}" notice (whole-section notice only when all templates lack a schema),Redigerroutes with the row's owncheckListId. i18n:Without tagretired (no consumer left);Without report headline+ the notice key added in 26 locales, the fallback label aligned withlocalization.jsonso screen and export agree.Tests — NUnit grouping tests rewritten (two headlines; one headline over two templates → union with in-place dash; no leak into another group sharing the template; caption
A - B; legacy headline-as-tag excluded; tag filter shows full membership; fallback last; orphan headline id keeps its group with null name; order; cloned templates), builder/writer tests updated (Caption,Delrapport, appendix, partial-schema suffix); Jest helper + component specs rewritten; Playwrights/compliance-report-view.spec.tsreplaces the substring-matchedtext=Rapportoverskriftassertion with structural section assertions.Reversed documented decisions
#1160 decision 5 (tag → template grouping), #1166 ("mirror this shape; do not reuse the type"), #1167 (heading = template name; grouping divergence), PR #1178 /
ComplianceExportDocumentBuilder.cscomposite{tag} – {template}Delrapport. The "Excel sheet name" wording in the issue is moot (#1189 removed xlsx).Verified against the running dev stack (gate 2)
Live
eform-columns: 11 groups, Σ cases = 438 = index rows with an answeredcheckListId; every case in exactly one group; captions sorted; fallback last;tagsnever contain the headline (0 mismatches over 438 rows); legacy headline-as-tag plannings de-duplicated in the caption; a 7-template group renders the union with–in place;Rediger→/case/5552/13/874(the row's template). Exports: PDF caption above bold headline per section,Delrapport= row tags, no headline column, fallback section last; CSVDelrapportfirst, blanks for empties, no headline column; Detaljer/Oversigt exports unchanged.Handoff notes for #1192 (Rapport export restyle)
Bilag: …(pre-existing); feat(compliance-export): Rapport export — Billeder text, Bilag pages, flat CSV #1192 restyles toBilag – ….WithoutTagstays inlocalization.jsonunused (append-only).🤖 Generated with Claude Code
https://claude.ai/code/session_018qJL2WhHwhZ5CGZehZF2ro