- 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>
- 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>
People picker ListBox used MouseBinding which fires before SelectedItem
updates, causing null CommandParameter. Replaced with SelectionChanged
event handler in code-behind.
AuditUsersAsync created TenantProfile with empty ClientId, causing
ArgumentException in SessionManager. Added currentProfile parameter
to pass the authenticated tenant's ClientId through.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Extended CreateViewModel helper to return (vm, auditMock, graphMock) 3-tuple
- Updated all 8 existing tests to use _ discard for the new graphMock slot
- Added Test 9: SearchQuery_debounced_calls_SearchUsersAsync verifying that
setting SearchQuery to "Ali" calls SearchUsersAsync after 300ms debounce
- All 9 ViewModel tests pass; full suite 177 passed / 22 skipped
- 12 tests: user filtering, claim format matching, Direct/Group/Inherited
access type classification, Full Control + SCA high-privilege detection,
external user flagging (#EXT#), semicolon user/level splitting, multi-site scan
- Message broadcast: GlobalSitesChangedMessage carries site list to receivers
- Base class: FeatureViewModelBase.GlobalSites updated on message receive
- Storage tab: SiteUrl pre-filled from first global site
- Storage tab: local override prevents global from overwriting SiteUrl
- Storage tab: clearing SiteUrl reverts to global site (override reset)
- Permissions tab: SelectedSites pre-populated from global sites
- Permissions tab: local picker override blocks subsequent global updates
- Tenant switch: resets local override so new global sites apply cleanly
- Transfer tab: SourceSiteUrl pre-filled from first global site
- MainWindowViewModel: GlobalSitesSelectedLabel reflects site count
Archive 5 phases (36 plans) to milestones/v1.0-phases/.
Archive roadmap, requirements, and audit to milestones/.
Evolve PROJECT.md with shipped state and validated requirements.
Collapse ROADMAP.md to one-line milestone summary.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Add DataGrid RowStyle with red highlighting for invalid CSV rows
in BulkMembersView, BulkSitesView, and FolderStructureView
- Fix cancel test locale mismatch by setting EN culture before assertion
- Remove dead FeatureTabBase placeholder (replaced by full tab views)
- Clean up unused xmlns:controls from MainWindow.xaml
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Test 1 (AllEnKeys_HaveNonEmptyFrTranslation): verifies every EN key has a non-empty, non-bracketed FR translation
- Test 2 (FrStrings_ContainExpectedDiacritics): spot-checks 5 keys for correct diacritics (é/è)
- Both tests pass — FR file already contains correct diacritics
- BulkSiteService creates Team sites via TeamSiteCollectionCreationInformation with owners/members
- BulkSiteService creates Communication sites via CommunicationSiteCollectionCreationInformation with generated URL
- Per-site error handling via BulkOperationRunner with continue-on-error semantics
- SanitizeAlias generates URL-safe aliases from site names for Communication sites
- BulkSiteServiceTests: 3 pass (interface check + model defaults + CSV parsing), 3 skip (live SP)
- Fixed pre-existing BulkMemberService.cs Group type ambiguity (MSCSC.Group vs Graph.Models.Group)
- SessionManager owns all ClientContexts; callers must not store references
- IsAuthenticated(tenantUrl) returns false before auth, true after GetOrCreateContextAsync
- ClearSessionAsync disposes ClientContext and removes state (idempotent for unknown tenants)
- GetOrCreateContextAsync validates null/empty TenantUrl and ClientId (ArgumentException)
- MsalClientFactory.GetCacheHelper() added — exposes helper for PnP tokenCacheCallback wiring
- 8 unit tests pass, 1 interactive-login test skipped (integration-only)
- LoggingIntegrationTests: verifies Serilog writes rolling log file with correct content
- LogPanelSink structural smoke test: confirms type implements ILogEventSink
- App.xaml.cs: added comment for LogPanelSink DI registration deferred to plan 01-06
- Instance singleton test
- EN string lookup test
- FR culture fallback test
- Missing key returns bracketed key
- PropertyChanged fires with empty string on culture switch
- Same culture does not fire PropertyChanged