docs(16-01): complete MergePermissions toggle and consolidated CSV export plan
- 16-01-SUMMARY.md created with all task outcomes and verification results - STATE.md updated with decisions, session info, progress bar (98%) - ROADMAP.md updated: phase 16 in-progress (1/2 summaries complete) - REQUIREMENTS.md: RPT-03 marked complete
This commit is contained in:
@@ -25,7 +25,7 @@ Requirements for v2.3 Tenant Management & Report Enhancements. Each maps to road
|
|||||||
|
|
||||||
- [ ] **RPT-01**: User can expand SharePoint groups in HTML reports to see group members
|
- [ ] **RPT-01**: User can expand SharePoint groups in HTML reports to see group members
|
||||||
- [ ] **RPT-02**: Group member resolution uses transitive membership to include nested group members
|
- [ ] **RPT-02**: Group member resolution uses transitive membership to include nested group members
|
||||||
- [ ] **RPT-03**: User can enable/disable entry consolidation per export (toggle in export settings)
|
- [x] **RPT-03**: User can enable/disable entry consolidation per export (toggle in export settings)
|
||||||
- [x] **RPT-04**: Consolidated reports merge rows for the same user with identical access levels across multiple locations into a single row
|
- [x] **RPT-04**: Consolidated reports merge rows for the same user with identical access levels across multiple locations into a single row
|
||||||
|
|
||||||
## Future Requirements
|
## Future Requirements
|
||||||
@@ -58,7 +58,7 @@ Requirements for v2.3 Tenant Management & Report Enhancements. Each maps to road
|
|||||||
| OWN-02 | Phase 18 | Pending |
|
| OWN-02 | Phase 18 | Pending |
|
||||||
| RPT-01 | Phase 17 | Pending |
|
| RPT-01 | Phase 17 | Pending |
|
||||||
| RPT-02 | Phase 17 | Pending |
|
| RPT-02 | Phase 17 | Pending |
|
||||||
| RPT-03 | Phase 16 | Pending |
|
| RPT-03 | Phase 16 | Complete |
|
||||||
| RPT-04 | Phase 15 | Complete |
|
| RPT-04 | Phase 15 | Complete |
|
||||||
|
|
||||||
**Coverage:**
|
**Coverage:**
|
||||||
|
|||||||
@@ -74,7 +74,7 @@ Plans:
|
|||||||
2. When the toggle is OFF, the exported HTML report is byte-for-byte identical to the pre-v2.3 output
|
2. When the toggle is OFF, the exported HTML report is byte-for-byte identical to the pre-v2.3 output
|
||||||
3. When the toggle is ON, the exported HTML report merges rows for the same user with identical access levels into a single row showing all affected locations
|
3. When the toggle is ON, the exported HTML report merges rows for the same user with identical access levels into a single row showing all affected locations
|
||||||
4. The toggle state is remembered for the session (does not reset between exports within the same session)
|
4. The toggle state is remembered for the session (does not reset between exports within the same session)
|
||||||
**Plans:** 2 plans
|
**Plans:** 1/2 plans executed
|
||||||
Plans:
|
Plans:
|
||||||
- [ ] 16-01-PLAN.md — ViewModel properties + XAML Export Options GroupBox + localization + CSV consolidation
|
- [ ] 16-01-PLAN.md — ViewModel properties + XAML Export Options GroupBox + localization + CSV consolidation
|
||||||
- [ ] 16-02-PLAN.md — HTML consolidated rendering with expandable location sub-lists + full test verification
|
- [ ] 16-02-PLAN.md — HTML consolidated rendering with expandable location sub-lists + full test verification
|
||||||
@@ -121,7 +121,7 @@ Plans:
|
|||||||
| 6-9 | v1.1 | 25/25 | Shipped | 2026-04-08 |
|
| 6-9 | v1.1 | 25/25 | Shipped | 2026-04-08 |
|
||||||
| 10-14 | v2.2 | 14/14 | Shipped | 2026-04-09 |
|
| 10-14 | v2.2 | 14/14 | Shipped | 2026-04-09 |
|
||||||
| 15. Consolidation Data Model | v2.3 | 2/2 | Complete | 2026-04-09 |
|
| 15. Consolidation Data Model | v2.3 | 2/2 | Complete | 2026-04-09 |
|
||||||
| 16. Report Consolidation Toggle | v2.3 | 0/2 | Not started | — |
|
| 16. Report Consolidation Toggle | 1/2 | In Progress| | — |
|
||||||
| 17. Group Expansion in HTML Reports | v2.3 | 0/? | Not started | — |
|
| 17. Group Expansion in HTML Reports | v2.3 | 0/? | Not started | — |
|
||||||
| 18. Auto-Take Ownership | v2.3 | 0/? | Not started | — |
|
| 18. Auto-Take Ownership | v2.3 | 0/? | Not started | — |
|
||||||
| 19. App Registration & Removal | v2.3 | 0/? | Not started | — |
|
| 19. App Registration & Removal | v2.3 | 0/? | Not started | — |
|
||||||
|
|||||||
@@ -3,14 +3,14 @@ gsd_state_version: 1.0
|
|||||||
milestone: v2.3
|
milestone: v2.3
|
||||||
milestone_name: Tenant Management & Report Enhancements
|
milestone_name: Tenant Management & Report Enhancements
|
||||||
status: planning
|
status: planning
|
||||||
stopped_at: Completed 15-02-PLAN.md
|
stopped_at: Completed 16-01-PLAN.md
|
||||||
last_updated: "2026-04-09T09:49:21.960Z"
|
last_updated: "2026-04-09T10:34:56.209Z"
|
||||||
last_activity: 2026-04-09 — Roadmap created for v2.3 (phases 15-19)
|
last_activity: 2026-04-09 — Roadmap created for v2.3 (phases 15-19)
|
||||||
progress:
|
progress:
|
||||||
total_phases: 5
|
total_phases: 5
|
||||||
completed_phases: 1
|
completed_phases: 1
|
||||||
total_plans: 2
|
total_plans: 4
|
||||||
completed_plans: 2
|
completed_plans: 3
|
||||||
---
|
---
|
||||||
|
|
||||||
# Project State
|
# Project State
|
||||||
@@ -64,6 +64,8 @@ Decisions are logged in PROJECT.md Key Decisions table.
|
|||||||
- [Phase 15]: MakeKey declared internal for test access via InternalsVisibleTo without exposing as public API
|
- [Phase 15]: MakeKey declared internal for test access via InternalsVisibleTo without exposing as public API
|
||||||
- [Phase 15]: LINQ GroupBy+Select for consolidation merge instead of mutable dictionary — consistent with functional codebase style
|
- [Phase 15]: LINQ GroupBy+Select for consolidation merge instead of mutable dictionary — consistent with functional codebase style
|
||||||
- [Phase 15-consolidation-data-model]: RPT-04-g test data uses 11 rows (not 10) to produce 7 consolidated rows — plan description had a counting error; 4 unique rows + 3 merged groups = 7
|
- [Phase 15-consolidation-data-model]: RPT-04-g test data uses 11 rows (not 10) to produce 7 consolidated rows — plan description had a counting error; 4 unique rows + 3 merged groups = 7
|
||||||
|
- [Phase 16-01]: Consolidated branch uses early-return pattern inside WriteSingleFileAsync to leave existing code path untouched
|
||||||
|
- [Phase 16-01]: PermissionsViewModel gets MergePermissions as no-op placeholder reserved for future use
|
||||||
|
|
||||||
### Pending Todos
|
### Pending Todos
|
||||||
|
|
||||||
@@ -75,7 +77,7 @@ None.
|
|||||||
|
|
||||||
## Session Continuity
|
## Session Continuity
|
||||||
|
|
||||||
Last session: 2026-04-09T09:46:35.243Z
|
Last session: 2026-04-09T10:34:56.207Z
|
||||||
Stopped at: Completed 15-02-PLAN.md
|
Stopped at: Completed 16-01-PLAN.md
|
||||||
Resume file: None
|
Resume file: None
|
||||||
Next step: `/gsd:plan-phase 15`
|
Next step: `/gsd:plan-phase 15`
|
||||||
|
|||||||
106
.planning/phases/16-report-consolidation-toggle/16-01-SUMMARY.md
Normal file
106
.planning/phases/16-report-consolidation-toggle/16-01-SUMMARY.md
Normal file
@@ -0,0 +1,106 @@
|
|||||||
|
---
|
||||||
|
phase: 16-report-consolidation-toggle
|
||||||
|
plan: "01"
|
||||||
|
subsystem: export
|
||||||
|
tags: [csv-export, consolidation, viewmodel, xaml, localization, tdd]
|
||||||
|
dependency-graph:
|
||||||
|
requires: [15-01, 15-02]
|
||||||
|
provides: [MergePermissions toggle UI, consolidated CSV export path]
|
||||||
|
affects: [UserAccessAuditViewModel, PermissionsViewModel, UserAccessCsvExportService]
|
||||||
|
tech-stack:
|
||||||
|
added: []
|
||||||
|
patterns: [ObservableProperty, XAML GroupBox binding, optional parameter default, early-return branch, TDD red-green]
|
||||||
|
key-files:
|
||||||
|
created: []
|
||||||
|
modified:
|
||||||
|
- SharepointToolbox/ViewModels/Tabs/UserAccessAuditViewModel.cs
|
||||||
|
- SharepointToolbox/ViewModels/Tabs/PermissionsViewModel.cs
|
||||||
|
- SharepointToolbox/Views/Tabs/UserAccessAuditView.xaml
|
||||||
|
- SharepointToolbox/Views/Tabs/PermissionsView.xaml
|
||||||
|
- SharepointToolbox/Localization/Strings.resx
|
||||||
|
- SharepointToolbox/Localization/Strings.fr.resx
|
||||||
|
- SharepointToolbox/Services/Export/UserAccessCsvExportService.cs
|
||||||
|
- SharepointToolbox.Tests/Services/Export/UserAccessCsvExportServiceTests.cs
|
||||||
|
decisions:
|
||||||
|
- "Consolidated branch uses early-return pattern inside WriteSingleFileAsync to leave existing code path completely untouched"
|
||||||
|
- "PermissionsViewModel gets MergePermissions as a no-op placeholder — PermissionsViewModel uses a different export service (CsvExportService, not UserAccessCsvExportService) so the property is reserved for future use"
|
||||||
|
- "Export Options GroupBox placed after Scan Options in UserAccessAuditView and after Display Options in PermissionsView — keeps related configuration grouped"
|
||||||
|
metrics:
|
||||||
|
duration: ~15min
|
||||||
|
completed: 2026-04-09
|
||||||
|
tasks: 3
|
||||||
|
files-modified: 8
|
||||||
|
---
|
||||||
|
|
||||||
|
# Phase 16 Plan 01: MergePermissions Toggle UI + Consolidated CSV Export Summary
|
||||||
|
|
||||||
|
MergePermissions ObservableProperty on both ViewModels, Export Options GroupBox in both XAML tabs, localized EN/FR strings, and consolidated CSV export path using PermissionConsolidator.
|
||||||
|
|
||||||
|
## Tasks Completed
|
||||||
|
|
||||||
|
| Task | Name | Commit | Files |
|
||||||
|
|------|------|--------|-------|
|
||||||
|
| 1 | Add MergePermissions property to both ViewModels and localization keys | ed9f149 | UserAccessAuditViewModel.cs, PermissionsViewModel.cs, Strings.resx, Strings.fr.resx |
|
||||||
|
| 2 | Add Export Options GroupBox to both XAML views | db42047 | UserAccessAuditView.xaml, PermissionsView.xaml |
|
||||||
|
| 3 (RED) | Add failing tests for RPT-03-f and RPT-03-g | 4f7a6e3 | UserAccessCsvExportServiceTests.cs |
|
||||||
|
| 3 (GREEN) | Implement consolidated CSV export path and wire ViewModel call site | 28714fb | UserAccessCsvExportService.cs, UserAccessAuditViewModel.cs |
|
||||||
|
|
||||||
|
## What Was Built
|
||||||
|
|
||||||
|
### MergePermissions Property
|
||||||
|
- `UserAccessAuditViewModel`: `[ObservableProperty] private bool _mergePermissions;` — defaults false, no partial handler needed
|
||||||
|
- `PermissionsViewModel`: same property as a no-op placeholder (PermissionsViewModel uses `CsvExportService`, not `UserAccessCsvExportService`)
|
||||||
|
|
||||||
|
### Localization
|
||||||
|
- `audit.grp.export` — "Export Options" / "Options d'exportation"
|
||||||
|
- `chk.merge.permissions` — "Merge duplicate permissions" / "Fusionner les permissions en double"
|
||||||
|
|
||||||
|
### XAML GroupBoxes
|
||||||
|
Both views received an "Export Options" GroupBox with a single checkbox bound to `MergePermissions`. The groupbox is always visible (never conditionally hidden). Existing XAML elements are untouched.
|
||||||
|
|
||||||
|
### Consolidated CSV Export
|
||||||
|
`WriteSingleFileAsync` now accepts `bool mergePermissions = false`. When true:
|
||||||
|
1. Calls `PermissionConsolidator.Consolidate(entries)` to merge rows sharing the same (UserLogin, PermissionLevel, AccessType, GrantedThrough) key
|
||||||
|
2. Writes a consolidated CSV with header: `"User","User Login","Permission Level","Access Type","Granted Through","Locations","Location Count"`
|
||||||
|
3. Locations column = semicolon-separated `SiteTitle` values from all merged locations
|
||||||
|
4. Returns early — existing code path below is completely untouched
|
||||||
|
|
||||||
|
`UserAccessAuditViewModel.ExportCsvAsync` now passes `MergePermissions` to the service.
|
||||||
|
|
||||||
|
### Tests (TDD)
|
||||||
|
3 new test methods covering RPT-03-f and RPT-03-g:
|
||||||
|
- `WriteSingleFileAsync_mergePermissionsfalse_produces_identical_output` — byte-identical to default call
|
||||||
|
- `WriteSingleFileAsync_mergePermissionstrue_writes_consolidated_rows` — consolidated header + merged rows
|
||||||
|
- `WriteSingleFileAsync_mergePermissionstrue_singleLocation_noSemicolon` — single location has LocationCount=1
|
||||||
|
|
||||||
|
All 8 UserAccessCsvExportServiceTests pass.
|
||||||
|
|
||||||
|
## Decisions Made
|
||||||
|
|
||||||
|
1. **Early-return consolidated branch** — Plan specified leaving existing code path untouched. Added `if (mergePermissions) { ... return; }` before the existing `var sb = new StringBuilder()` block. The existing block is wrapped in an anonymous `{}` scope for clarity but behavior is unchanged.
|
||||||
|
|
||||||
|
2. **PermissionsViewModel as no-op placeholder** — The Permissions tab uses `CsvExportService` (not `UserAccessCsvExportService`), so `MergePermissions` cannot be wired to export logic in this plan. The property is added for XAML binding completeness and future implementation.
|
||||||
|
|
||||||
|
3. **GroupBox placement** — Export Options placed immediately before the Run/Export buttons in UserAccessAuditView, and before Action buttons in PermissionsView. This keeps export-related options adjacent to export buttons.
|
||||||
|
|
||||||
|
## Verification Results
|
||||||
|
|
||||||
|
- `dotnet build` — 0 errors, 0 warnings
|
||||||
|
- `dotnet test --filter "FullyQualifiedName~UserAccessCsvExportServiceTests"` — 8/8 passed
|
||||||
|
- `dotnet test` full suite — 296 passed, 26 skipped, 2 flaky timing failures (pre-existing debounce tests, pass when run individually)
|
||||||
|
|
||||||
|
## Deviations from Plan
|
||||||
|
|
||||||
|
None — plan executed exactly as written.
|
||||||
|
|
||||||
|
## Self-Check: PASSED
|
||||||
|
|
||||||
|
Files exist:
|
||||||
|
- SharepointToolbox/ViewModels/Tabs/UserAccessAuditViewModel.cs — contains `_mergePermissions`
|
||||||
|
- SharepointToolbox/ViewModels/Tabs/PermissionsViewModel.cs — contains `_mergePermissions`
|
||||||
|
- SharepointToolbox/Views/Tabs/UserAccessAuditView.xaml — contains `Export Options`
|
||||||
|
- SharepointToolbox/Views/Tabs/PermissionsView.xaml — contains `Export Options`
|
||||||
|
- SharepointToolbox/Services/Export/UserAccessCsvExportService.cs — contains `mergePermissions`
|
||||||
|
- SharepointToolbox.Tests/Services/Export/UserAccessCsvExportServiceTests.cs — 3 new test methods
|
||||||
|
|
||||||
|
Commits exist: ed9f149, db42047, 4f7a6e3, 28714fb
|
||||||
Reference in New Issue
Block a user