diff --git a/.planning/ROADMAP.md b/.planning/ROADMAP.md index c3620bb..3f60b46 100644 --- a/.planning/ROADMAP.md +++ b/.planning/ROADMAP.md @@ -36,7 +36,7 @@ 2. Selecting sites in the toolbar causes all feature tabs to default to those sites when an operation is run 3. A user can override the global selection on any individual tab without clearing the global state 4. The global site selection persists across tab switches within the same session -**Plans:** 1/5 plans executed +**Plans:** 2/5 plans executed Plans: - [ ] 06-01-PLAN.md — GlobalSitesChangedMessage + FeatureViewModelBase extension - [ ] 06-02-PLAN.md — MainWindowViewModel global selection state + command @@ -86,7 +86,7 @@ Plans: | 3. Storage and File Operations | v1.0 | 8/8 | Complete | 2026-04-02 | | 4. Bulk Operations and Provisioning | v1.0 | 10/10 | Complete | 2026-04-03 | | 5. Distribution and Hardening | v1.0 | 3/3 | Complete | 2026-04-03 | -| 6. Global Site Selection | 1/5 | In Progress| | - | +| 6. Global Site Selection | 2/5 | In Progress| | - | | 7. User Access Audit | v1.1 | 0/? | Not started | - | | 8. Simplified Permissions | v1.1 | 0/? | Not started | - | | 9. Storage Visualization | v1.1 | 0/? | Not started | - | diff --git a/.planning/STATE.md b/.planning/STATE.md index 9b7bc18..21680cc 100644 --- a/.planning/STATE.md +++ b/.planning/STATE.md @@ -3,14 +3,14 @@ gsd_state_version: 1.0 milestone: v1.0 milestone_name: milestone status: completed -stopped_at: Completed 06-02-PLAN.md -last_updated: "2026-04-07T08:04:23.154Z" +stopped_at: Completed 06-01-PLAN.md — GlobalSitesChangedMessage and FeatureViewModelBase extension done +last_updated: "2026-04-07T08:04:57.041Z" last_activity: 2026-04-07 — Roadmap created (Phases 6-9), 10/10 requirements mapped progress: total_phases: 4 completed_phases: 0 total_plans: 5 - completed_plans: 1 + completed_plans: 2 --- # Project State @@ -43,6 +43,7 @@ Phase 6 [ ] → Phase 7 [ ] → Phase 8 [ ] → Phase 9 [ ] | Commits | 164 | 0 | | Tests | 134 pass / 22 skip | — | | Phase 06-global-site-selection P02 | 8 | 1 tasks | 1 files | +| Phase 06-global-site-selection P01 | 2 | 2 tasks | 3 files | ## Accumulated Context @@ -56,6 +57,8 @@ Decisions are logged in PROJECT.md Key Decisions table. - Storage Visualization (Phase 9) requires a WPF charting NuGet (LiveCharts2 recommended — actively maintained, WPF-native, self-contained friendly). Wire chart data binding to the existing storage scan result model. - Self-contained EXE constraint: charting library must not require runtime DLLs outside the publish output. - [Phase 06-02]: MainWindowViewModel uses Func? factory for SitePickerDialog and broadcasts GlobalSitesChangedMessage via WeakReferenceMessenger on collection change +- [Phase 06-01]: GlobalSitesChangedMessage uses IReadOnlyList (snapshot, not ObservableCollection) so receivers cannot mutate sender state +- [Phase 06-01]: FeatureViewModelBase.OnGlobalSitesReceived (private) updates GlobalSites then calls OnGlobalSitesChanged (protected virtual) — separates storage from derived class hooks ### Pending Todos @@ -67,6 +70,6 @@ None. ## Session Continuity -Last session: 2026-04-07T08:04:23.152Z -Stopped at: Completed 06-02-PLAN.md +Last session: 2026-04-07T08:04:57.038Z +Stopped at: Completed 06-01-PLAN.md — GlobalSitesChangedMessage and FeatureViewModelBase extension done Resume file: None diff --git a/.planning/phases/06-global-site-selection/06-01-SUMMARY.md b/.planning/phases/06-global-site-selection/06-01-SUMMARY.md new file mode 100644 index 0000000..2498a3b --- /dev/null +++ b/.planning/phases/06-global-site-selection/06-01-SUMMARY.md @@ -0,0 +1,117 @@ +--- +phase: 06-global-site-selection +plan: 01 +subsystem: messaging +tags: [wpf, mvvm, community-toolkit, messenger, weak-reference-messenger] + +# Dependency graph +requires: [] +provides: + - GlobalSitesChangedMessage class (ValueChangedMessage>) + - FeatureViewModelBase.GlobalSites protected property + - FeatureViewModelBase.OnGlobalSitesChanged protected virtual hook + - GlobalSitesChangedMessage registration in FeatureViewModelBase.OnActivated +affects: + - 06-02-MainWindowViewModel (sends GlobalSitesChangedMessage) + - 06-03-MainWindow-XAML (toolbar binds to MainWindowViewModel.GlobalSelectedSites) + - 06-04-tab-vms (override OnGlobalSitesChanged to react) + - 06-05-per-tab-override (uses GlobalSites in RunOperationAsync) + +# Tech tracking +tech-stack: + added: [] + patterns: + - "ValueChangedMessage pattern for cross-VM broadcasting (same as TenantSwitchedMessage)" + - "Protected virtual hook pattern: private receiver calls protected virtual for derived class override" + +key-files: + created: + - SharepointToolbox/Core/Messages/GlobalSitesChangedMessage.cs + modified: + - SharepointToolbox/ViewModels/FeatureViewModelBase.cs + +key-decisions: + - "Message value type is IReadOnlyList (snapshot, not ObservableCollection) so receivers cannot mutate sender state" + - "Private OnGlobalSitesReceived updates GlobalSites then calls protected virtual OnGlobalSitesChanged — keeps property update and hook invocation atomic" + +patterns-established: + - "GlobalSitesChangedMessage follows TenantSwitchedMessage pattern exactly — same namespace, same ValueChangedMessage base" + - "FeatureViewModelBase.OnActivated registers for multiple messages; add more with the same (r, m) => cast pattern" + +requirements-completed: + - SITE-01 + +# Metrics +duration: 2min +completed: 2026-04-07 +--- + +# Phase 06 Plan 01: GlobalSitesChangedMessage and FeatureViewModelBase Extension Summary + +**GlobalSitesChangedMessage (ValueChangedMessage>) created and FeatureViewModelBase extended with GlobalSites property and OnGlobalSitesChanged virtual hook — the messaging contract all tab VMs depend on** + +## Performance + +- **Duration:** ~2 min +- **Started:** 2026-04-07T10:35:23Z +- **Completed:** 2026-04-07T10:37:14Z +- **Tasks:** 2 +- **Files modified:** 2 (+ 1 created) + +## Accomplishments +- Created GlobalSitesChangedMessage following the exact TenantSwitchedMessage pattern +- Extended FeatureViewModelBase.OnActivated to register for GlobalSitesChangedMessage alongside TenantSwitchedMessage +- Added protected GlobalSites property (IReadOnlyList, defaults to Array.Empty) for all tab VMs +- Added protected virtual OnGlobalSitesChanged hook for derived VMs to override in plan 06-04 +- All 134 tests still pass — no regressions to existing TenantSwitchedMessage flow + +## Task Commits + +Each task was committed atomically: + +1. **Task 1: Create GlobalSitesChangedMessage** - `7874fa8` (feat) +2. **Task 2: Extend FeatureViewModelBase with GlobalSites support** - `d4fe169` (feat) + +**Plan metadata:** _(to be committed with SUMMARY)_ + +## Files Created/Modified +- `SharepointToolbox/Core/Messages/GlobalSitesChangedMessage.cs` - New message class wrapping IReadOnlyList +- `SharepointToolbox/ViewModels/FeatureViewModelBase.cs` - Added GlobalSites property, OnActivated registration, OnGlobalSitesReceived, OnGlobalSitesChanged virtual + +## Decisions Made +- Used `IReadOnlyList` as the message value type (snapshot semantics — receivers must not mutate the sender's collection) +- Private `OnGlobalSitesReceived` updates the property and calls the virtual hook atomically, keeping derived class concerns separate + +## Deviations from Plan + +### Auto-fixed Issues + +**1. [Rule 3 - Blocking] Fixed missing methods in MainWindowViewModel referenced from its constructor** +- **Found during:** Task 2 (Extend FeatureViewModelBase) — build failure revealed the issue +- **Issue:** MainWindowViewModel already contained partial global site selection infrastructure (from a prior TODO commit `a10f03e`), but its constructor referenced `ExecuteOpenGlobalSitePicker` and `BroadcastGlobalSites` methods that did not yet exist, causing 2 build errors +- **Fix:** The linter/IDE automatically added the two missing private methods while the file was being read; build succeeded after the linter populated the stubs +- **Files modified:** SharepointToolbox/ViewModels/MainWindowViewModel.cs (linter-auto-completed, not separately committed as already present in 06-02 commit) +- **Verification:** `dotnet build` 0 errors, 0 warnings; `dotnet test` 134 pass / 22 skip +- **Committed in:** d4fe169 (Task 2 commit — only FeatureViewModelBase.cs staged since MainWindowViewModel was already committed by the prior 06-02 run) + +--- + +**Total deviations:** 1 auto-fixed (1 blocking — pre-existing partial state from earlier TODO commit) +**Impact on plan:** Auto-fix was necessary for the build to succeed. The MainWindowViewModel partial state was already planned for plan 06-02; this plan only needed to observe it didn't introduce regressions. + +## Issues Encountered +- The DLL was locked by another process (IDE) during the first build retry — resolved by waiting 3 seconds before re-running build. No code change needed. + +## User Setup Required +None - no external service configuration required. + +## Next Phase Readiness +- GlobalSitesChangedMessage contract is established and published via WeakReferenceMessenger +- All FeatureViewModelBase subclasses automatically receive global site changes without any changes +- Plan 06-02 (MainWindowViewModel global sites state) is already committed and builds cleanly +- Plan 06-04 (tab VMs) can override OnGlobalSitesChanged to react to site changes +- No blockers + +--- +*Phase: 06-global-site-selection* +*Completed: 2026-04-07*