chore: archive v2.2 Report Branding & User Directory milestone
Some checks failed
Release SharePoint Toolbox v2 / release (push) Failing after 14s
Some checks failed
Release SharePoint Toolbox v2 / release (push) Failing after 14s
5 phases (10-14), 14 plans, 11/11 requirements complete. Key features: HTML report branding with MSP/client logos, user directory browse mode with paginated load and member/guest filtering. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -1,37 +1,38 @@
|
||||
---
|
||||
gsd_state_version: 1.0
|
||||
milestone: v2.2
|
||||
milestone_name: Report Branding & User Directory
|
||||
status: completed
|
||||
stopped_at: Completed 14-02-PLAN.md
|
||||
last_updated: "2026-04-09T07:30:58.818Z"
|
||||
last_activity: 2026-04-08 — Phase 11 planning completed
|
||||
milestone: none
|
||||
milestone_name: Between milestones
|
||||
status: idle
|
||||
stopped_at: v2.2 milestone archived
|
||||
last_updated: "2026-04-09"
|
||||
last_activity: 2026-04-09 — v2.2 milestone completed and archived
|
||||
progress:
|
||||
total_phases: 5
|
||||
completed_phases: 5
|
||||
total_plans: 14
|
||||
completed_plans: 14
|
||||
total_phases: 0
|
||||
completed_phases: 0
|
||||
total_plans: 0
|
||||
completed_plans: 0
|
||||
---
|
||||
|
||||
# Project State
|
||||
|
||||
## Project Reference
|
||||
|
||||
See: .planning/PROJECT.md (updated 2026-04-08)
|
||||
See: .planning/PROJECT.md (updated 2026-04-09)
|
||||
|
||||
**Core value:** Administrators can audit and manage SharePoint/Teams permissions and storage across multiple client tenants from a single, reliable desktop application.
|
||||
**Current focus:** v2.2 Report Branding & User Directory — HTML report logos (Phases 10-12), user directory browse mode (Phases 13-14)
|
||||
**Current focus:** Between milestones — v2.2 shipped, ready for `/gsd:new-milestone`
|
||||
|
||||
## Current Position
|
||||
|
||||
Phase: 11 (planned, ready to execute)
|
||||
Plan: 4 plans (11-01 through 11-04) in 3 waves
|
||||
Status: Phase 10 complete, Phase 11 planned — ready to execute
|
||||
Last activity: 2026-04-08 — Phase 11 planning completed
|
||||
Phase: None (between milestones)
|
||||
Status: v2.2 Report Branding & User Directory shipped 2026-04-09
|
||||
Next step: `/gsd:new-milestone` to start next milestone
|
||||
|
||||
```
|
||||
v2.2 Progress: [██░░░░░░░░] 20% (1/5 phases, 3/7 plans)
|
||||
```
|
||||
## Shipped Milestones
|
||||
|
||||
- v1.0 MVP — Phases 1-5 (shipped 2026-04-07)
|
||||
- v1.1 Enhanced Reports — Phases 6-9 (shipped 2026-04-08)
|
||||
- v2.2 Report Branding & User Directory — Phases 10-14 (shipped 2026-04-09)
|
||||
|
||||
## Accumulated Context
|
||||
|
||||
@@ -39,48 +40,9 @@ v2.2 Progress: [██░░░░░░░░] 20% (1/5 phases, 3/7 plans)
|
||||
|
||||
Decisions are logged in PROJECT.md Key Decisions table.
|
||||
|
||||
**v2.2 architectural decisions (locked at roadmap):**
|
||||
- Logos stored as base64 strings in JSON (not file paths). `BrandingSettings.cs` holds MSP logo; `TenantProfile` holds client logo. File path is discarded after import. This decision is locked — all downstream phases depend on it.
|
||||
- Client logo lives on `TenantProfile`, NOT in `BrandingSettings`. Per-tenant ownership; prevents serialization and deletion awkwardness.
|
||||
- Export services use optional `ReportBranding? branding = null` parameter. All existing call sites compile unchanged. No new `IHtmlExportService` interface needed.
|
||||
- `GraphUserDirectoryService` is a new service, separate from `GraphUserSearchService`. Different pagination model (`PageIterator`), different cancellation needs.
|
||||
- Directory does NOT load automatically on tab open. Explicit "Load Directory" button required to avoid blocking UI on large tenants.
|
||||
- SVG logo support: rejected. XSS risk in data-URIs. PNG/JPG only.
|
||||
- No new NuGet packages for v2.2. All capabilities provided by existing stack (BCL, Microsoft.Graph 5.74.0, WPF PresentationCore).
|
||||
|
||||
**v1.1 architectural notes (carried forward):**
|
||||
- Global site selection (Phase 6) changes the toolbar; all tabs bind to shared `GlobalSiteSelectionViewModel`. `WeakReferenceMessenger` for cross-tab site-changed notifications.
|
||||
- Per-tab override (SITE-02): each `FeatureViewModelBase` subclass stores a nullable local site override; null means "use global".
|
||||
- Storage Visualization (Phase 9): LiveCharts2, WPF-native, self-contained friendly.
|
||||
- [Phase 10-branding-data-foundation]: No ConsistencyLevel header on equality filter for GetUsersAsync (unlike GraphUserSearchService startsWith which requires it)
|
||||
- [Phase 10-branding-data-foundation]: MapUser extracted as internal static in GraphUserDirectoryService for direct unit testability without live Graph endpoint
|
||||
- [Phase 10-branding-data-foundation]: Type alias AppGraphClientFactory used in GraphUserDirectoryService to disambiguate from Microsoft.Graph.GraphClientFactory
|
||||
- [Phase 10-branding-data-foundation]: Used WPF PresentationCore (BitmapDecoder/TransformedBitmap/JpegBitmapEncoder) for image compression instead of System.Drawing.Bitmap — System.Drawing.Common is not available without a new NuGet package on .NET 10, and WPF PresentationCore is already in the stack
|
||||
- [Phase 10-branding-data-foundation]: LogoData is a non-positional record with init properties (not positional constructor) to avoid System.Text.Json deserialization failure
|
||||
- [Phase 10-branding-data-foundation]: No new using statements required for Phase 10 DI registrations — SharepointToolbox.Infrastructure.Persistence and SharepointToolbox.Services were already imported
|
||||
- [Phase 11-html-export-branding]: BrandingHtmlHelper is internal — only used within Services.Export namespace, tests access via InternalsVisibleTo
|
||||
- [Phase 11-html-export-branding]: InternalsVisibleTo added via MSBuild AssemblyAttribute ItemGroup in csproj
|
||||
- [Phase 11-html-export-branding]: branding parameter placed AFTER CancellationToken ct in WriteAsync — existing positional callers unaffected
|
||||
- [Phase 11-html-export-branding]: MakeBranding helper added locally to each test class — test files stay self-contained
|
||||
- [Phase 11]: Test constructors on 3 ViewModels received optional IBrandingService? brandingService = null as last parameter to preserve all existing test call sites
|
||||
- [Phase 11]: Guard clause (if _brandingService is not null) used for graceful degradation — branding = null fallback preserves backward compat
|
||||
- [Phase 11]: No App.xaml.cs changes needed for ViewModel branding injection — IBrandingService already registered as singleton, ViewModel registrations auto-resolve
|
||||
- [Phase 12]: Skipped BitmapImage creation test due to missing Xunit.StaFact; STA thread required for WPF BitmapImage
|
||||
- [Phase 12]: Used Grid overlay with DataTrigger for logo/placeholder visibility toggle in SettingsView
|
||||
- [Phase 12]: Label+StackPanel layout for logo section in ProfileManagementDialog, consistent with SettingsView pattern
|
||||
- [Phase 13]: UserType added as last positional param for backward compat; includeGuests defaults false; userType always in Select
|
||||
- [Phase 13]: Directory always fetches with includeGuests=true from Graph; member/guest filtering is in-memory via ICollectionView
|
||||
- [Phase 13]: Separate _directoryCts for directory load cancellation (independent from base class _cts)
|
||||
- [Phase 14]: SelectDirectoryUserCommand does not clear SearchQuery/SearchResults since it operates in browse mode context
|
||||
- [Phase 14]: Used DataTrigger inverse visibility for search panel instead of ConverterParameter=Inverse
|
||||
- [Phase 14]: Used plain English DataGrid column headers -- DataGridTextColumn.Header binding is unreliable in WPF
|
||||
|
||||
### Pending Todos
|
||||
|
||||
- Confirm `$filter=accountEnabled eq true and userType eq 'Member'` behavior without `ConsistencyLevel: eventual` against a real tenant before Phase 13 planning.
|
||||
- Verify Entra `bannerLogo` stream endpoint returns empty body (not HTTP 404) when no tenant branding is configured — determines error handling branch for BRAND-04 auto-pull.
|
||||
- Decide report header layout before Phase 11: logos side-by-side (current spec: `display: flex; gap: 16px`, MSP left + client right).
|
||||
- Decide "Load Directory" button placement before Phase 14: inside browse panel (recommended) or tab-level toolbar.
|
||||
None — milestone complete.
|
||||
|
||||
### Blockers/Concerns
|
||||
|
||||
@@ -88,7 +50,7 @@ None.
|
||||
|
||||
## Session Continuity
|
||||
|
||||
Last session: 2026-04-09T07:30:58.816Z
|
||||
Stopped at: Completed 14-02-PLAN.md
|
||||
Last session: 2026-04-09
|
||||
Stopped at: v2.2 milestone archived
|
||||
Resume file: None
|
||||
Next step: `/gsd:execute-phase 11`
|
||||
Next step: `/gsd:new-milestone`
|
||||
|
||||
Reference in New Issue
Block a user