--- 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*