- SUMMARY.md: BuildConsolidatedHtml with expandable location sub-lists, by-site view suppression, ViewModel wiring - STATE.md: updated position, decisions, session - ROADMAP.md: phase 16 marked Complete (2/2 plans with summaries)
6.7 KiB
phase, plan, subsystem, tags, dependency-graph, tech-stack, key-files, decisions, metrics
| phase | plan | subsystem | tags | dependency-graph | tech-stack | key-files | decisions | metrics | |||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 16-report-consolidation-toggle | 02 | export |
|
|
|
|
|
|
Phase 16 Plan 02: Consolidated HTML Rendering Path Summary
Consolidated HTML export with expandable [N sites] badges using toggleGroup() JS, by-site view suppression when mergePermissions=true, and ViewModel wiring for the HTML export call site.
Tasks Completed
| Task | Name | Commit | Files |
|---|---|---|---|
| 1 (RED) | Add failing tests for RPT-03-b through RPT-03-e | 3d95d2a |
UserAccessHtmlExportServiceTests.cs |
| 1 (GREEN) | Implement consolidated HTML rendering path and wire ViewModel | 0ebe707 |
UserAccessHtmlExportService.cs, UserAccessAuditViewModel.cs, UserAccessHtmlExportServiceTests.cs |
| 2 | Full solution build and test suite verification | — | (no source changes — verification only) |
What Was Built
BuildHtml Signature Change
BuildHtml now accepts bool mergePermissions = false as the second parameter (before branding):
public string BuildHtml(IReadOnlyList<UserAccessEntry> entries, bool mergePermissions = false, ReportBranding? branding = null)
The early-return branch:
if (mergePermissions)
{
var consolidated = PermissionConsolidator.Consolidate(entries);
return BuildConsolidatedHtml(consolidated, entries, branding);
}
The entire existing code path below this branch is completely untouched.
WriteAsync Signature Change
WriteAsync now accepts bool mergePermissions = false after ct and passes it through to BuildHtml:
public async Task WriteAsync(IReadOnlyList<UserAccessEntry> entries, string filePath, CancellationToken ct, bool mergePermissions = false, ReportBranding? branding = null)
BuildConsolidatedHtml Private Method
Produces a consolidated HTML report:
- Same HTML shell (DOCTYPE, head, CSS, stats cards, user summary cards)
- Single by-user table with columns: User, Permission Level, Access Type, Granted Through, Sites
- Group headers per UserLogin with
ugrp{n}IDs - Sites column behavior:
- 1 location: plain text site title (no badge, no sub-rows)
- 2+ locations:
<span class="badge" onclick="toggleGroup('loc{n}')">N sites</span>with hidden sub-rows (data-group="loc{n}" style="display:none") containing linked site titles
- By-site view (view-site div) is completely omitted
- btn-site is completely omitted — only By User button rendered
- Separate
locIdxcounter for location groups, distinct fromgrpIdxfor user groups
ViewModel Wiring
UserAccessAuditViewModel.ExportHtmlAsync now passes MergePermissions to WriteAsync:
await _htmlExportService.WriteAsync(Results, dialog.FileName, CancellationToken.None, MergePermissions, branding);
Tests (TDD)
4 new test methods added:
BuildHtml_mergePermissionsFalse_identical_to_default— RPT-03-b: byte-identical output to default callBuildHtml_mergePermissionsTrue_contains_sites_column— RPT-03-c: "Sites" column header presentBuildHtml_mergePermissionsTrue_multiLocation_has_badge_and_subrows— RPT-03-d: onclick toggleGroup + data-group=loc patternBuildHtml_mergePermissionsTrue_omits_bysite_view— RPT-03-e: no btn-site, no view-site
All 12 UserAccessHtmlExportServiceTests pass. Full suite: 302 passed, 26 skipped.
Decisions Made
-
Early-return + private method — Same pattern as Plan 01's consolidated CSV path.
BuildConsolidatedHtmlis extracted as a private method to keepBuildHtmlclean. The branch guarantees the existing code path is never reached whenmergePermissions=true. -
Separate locIdx counter — RESEARCH.md Pitfall 2 explicitly warned about ID collision between user group headers and location sub-rows. Used distinct
int grpIdx(forugrp{n}) andint locIdx(forloc{n}) to prevent any overlap. -
Named parameter fix for branding test — The existing
BuildHtml_WithBranding_ContainsLogoImgtest calledBuildHtml(entries, MakeBranding(...))positionally. InsertingmergePermissionsbeforebrandingbroke that call — fixed by addingbranding:named argument. This is a Rule 1 auto-fix (broken test).
Verification Results
dotnet build— 0 errors, 0 warningsdotnet test --filter "FullyQualifiedName~UserAccessHtmlExportServiceTests"— 12/12 passeddotnet testfull suite — 302 passed, 26 skipped, 0 failed (no regressions)- Test count increased by 4 from Plan 02 (RPT-03-b through RPT-03-e) + 2 previously flaky tests now stable
Deviations from Plan
Auto-fixed Issues
1. [Rule 1 - Bug] Fixed branding test call site broken by parameter insertion
- Found during: Task 1 (GREEN phase — first test run)
- Issue: Existing
BuildHtml_WithBranding_ContainsLogoImgtest passedMakeBranding(...)as positional argument 2, which collided with the newly insertedbool mergePermissionsparameter at position 2 - Fix: Added named
branding:argument:svc.BuildHtml(new[] { DefaultEntry }, branding: MakeBranding(msp: true)) - Files modified: SharepointToolbox.Tests/Services/Export/UserAccessHtmlExportServiceTests.cs
- Commit:
0ebe707
Self-Check: PASSED
Files exist:
- SharepointToolbox/Services/Export/UserAccessHtmlExportService.cs — contains
mergePermissions,BuildConsolidatedHtml,PermissionConsolidator.Consolidate - SharepointToolbox/ViewModels/Tabs/UserAccessAuditViewModel.cs — contains
MergePermissionsin WriteAsync call - SharepointToolbox.Tests/Services/Export/UserAccessHtmlExportServiceTests.cs — contains 4 new consolidation test methods