- Added ReportBranding? branding = null to BuildHtml on all 5 services
- Added ReportBranding? branding = null after CancellationToken ct on all WriteAsync overloads
- Injected BrandingHtmlHelper.BuildBrandingHeader(branding) between <body> and <h1> in each
- StorageHtmlExportService both overloads updated (nodes-only and nodes+fileTypeMetrics)
- HtmlExportService both overloads updated (PermissionEntry and SimplifiedPermissionEntry)
- Build passes with 0 warnings — all existing callers compile unchanged via default null
- Add ReportBranding positional record bundling MspLogo and ClientLogo
- Add BrandingHtmlHelper static class generating flex branding header HTML
- Add BrandingHtmlHelperTests covering all 4 logo states (null, both null, single, both)
- Add InternalsVisibleTo for SharepointToolbox.Tests in project file
- Add IBrandingService interface with ImportLogoAsync, Save/Clear/GetMspLogoAsync
- Add BrandingService: PNG/JPEG magic byte detection, rejects unsupported formats with
descriptive error, auto-compresses files over 512 KB using WPF PresentationCore imaging
- Add BrandingServiceTests: 9 tests covering validation, rejection, compression, CRUD
- Deviation: used WPF BitmapEncoder/TransformedBitmap instead of System.Drawing.Bitmap
(System.Drawing.Common not available without new NuGet package; WPF PresentationCore
is in the existing stack per architectural decisions)
- GraphUserDirectoryService uses PageIterator<User, UserCollectionResponse> for pagination
- Filter: accountEnabled eq true and userType eq 'Member' (no ConsistencyLevel header)
- Cancellation checked in PageIterator callback (return false stops iteration)
- Progress reported via IProgress<int> with running count per user
- MapUser extracted as internal static for direct unit test coverage
- Tests: 5 unit tests for MapUser field mapping and fallback logic
- Integration-level tests (pagination/cancellation) skipped with rationale documented
- Note: test project compilation blocked by pre-existing BrandingServiceTests.cs (10-01 artifact)
Adds v2.2 milestone section (Report Branding & User Directory) while
preserving the original v1.0 summary. Covers stack additions (none),
feature table stakes vs. differentiators, architecture integration
points with dependency-aware build order, top 6 critical pitfalls with
prevention strategies, suggested roadmap phase structure, open product
questions, and confidence assessment.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- 7 tests covering chart series from metrics, bar series structure,
donut/bar toggle, top-10+Other aggregation, no-Other for <=10,
tenant switch cleanup, and empty data handling
- Added LiveChartsCore.SkiaSharpView.WPF to test project
- Uses reflection to set FileTypeMetrics (private setter) directly
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Update StorageView.xaml: DataGrid top, GridSplitter, chart panel bottom
- Add PieChart and CartesianChart with MultiDataTrigger visibility
- Add radio buttons for donut/bar chart toggle in left panel
- Create BytesLabelConverter for chart tooltip formatting
- Add stor.chart.* localization keys in EN and FR resx files
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- SUMMARY.md with implementation details and deviation log
- STATE.md updated to plan 2 of 4, 92% progress
- ROADMAP.md and REQUIREMENTS.md updated (VIZZ-02 complete)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- CamlQuery with RecursiveAll scope enumerates files across all non-hidden document libraries
- Paginated 500-item batches avoid list view threshold issues
- Files grouped by extension (case-insensitive) with summed size and count
- Results returned as IReadOnlyList<FileTypeMetric> sorted by TotalSizeBytes descending
- Existing CollectStorageAsync, LoadFolderNodeAsync, CollectSubfoldersAsync unchanged
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Add 09-01-SUMMARY.md with task details and self-check
- Update STATE.md position to Phase 9, Plan 1 of 4
- Update ROADMAP.md and REQUIREMENTS.md progress
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Add CollectFileTypeMetricsAsync method signature to IStorageService
- Returns IReadOnlyList<FileTypeMetric> for chart visualization data
- Existing CollectStorageAsync signature unchanged
- CS0535 expected until StorageService implements in Plan 09-02
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Add LiveChartsCore.SkiaSharpView.WPF 2.0.0-rc5.4 package reference
- Create FileTypeMetric record with Extension, TotalSizeBytes, FileCount
- Include DisplayLabel computed property for chart label binding
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- IsSimplifiedMode default false, toggle rebuilds SimplifiedResults
- IsDetailView toggle does not re-compute simplified data
- Summaries contains correct risk breakdown after toggle
- Helper method CreateViewModelWithResults for test reuse
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- ExportCsvAsync branches on IsSimplifiedMode to call simplified WriteAsync overload
- ExportHtmlAsync branches on IsSimplifiedMode to call simplified WriteAsync overload
- Standard PermissionEntry export path unchanged when simplified mode is off
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Add 6 keys to Strings.resx: chk.simplified.mode, grp.display.opts, lbl.detail.level, rad.detail.detailed, rad.detail.simple, lbl.summary.users
- Add matching French translations to Strings.fr.resx with proper XML entities for accented characters
- Wire hardcoded "user(s)" text in PermissionsView.xaml summary cards to lbl.summary.users localization key
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Created 08-03-SUMMARY.md with task results and self-check
- Updated STATE.md with metrics and decisions
- Updated ROADMAP.md plan progress for phase 08
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- SUMMARY.md with task commits and decisions
- STATE.md updated to plan 4 of 6
- ROADMAP.md progress updated
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Add RiskLevelColors helper for risk-level color coding
- Add BuildHtml(IReadOnlyList<SimplifiedPermissionEntry>) with risk summary cards, Simplified column, and color-coded Risk badges
- Add WriteAsync overload for simplified entries
- Original PermissionEntry methods unchanged
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Add Display Options GroupBox with Simplified Mode toggle and Simple/Detailed radio buttons
- Add summary panel with color-coded risk level cards bound to Summaries collection
- DataGrid binds to ActiveItemsSource, rows color-coded by RiskLevel via DataTriggers
- SimplifiedLabels column visible only in simplified mode via BooleanToVisibilityConverter
- DataGrid collapses in Simple mode via MultiDataTrigger on IsSimplifiedMode+IsDetailView
- Create InvertBoolConverter for radio button inverse binding
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Add BuildCsv(IReadOnlyList<SimplifiedPermissionEntry>) overload with SimplifiedLabels and RiskLevel columns
- Add WriteAsync overload for simplified entries
- Original PermissionEntry methods unchanged
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- IsSimplifiedMode toggle switches between raw and simplified labels
- IsDetailView toggle controls individual vs summary row display
- SimplifiedResults and Summaries computed from cached Results
- ActiveItemsSource provides correct collection for DataGrid binding
- Mode toggles rebuild from cache without re-running scan
- OnTenantSwitched resets simplified state
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>