--- phase: 06-global-site-selection plan: 02 type: execute wave: 1 depends_on: [] files_modified: - SharepointToolbox/ViewModels/MainWindowViewModel.cs autonomous: true requirements: - SITE-01 must_haves: truths: - "MainWindowViewModel has an ObservableCollection GlobalSelectedSites property" - "OpenGlobalSitePickerCommand opens the site picker dialog and populates GlobalSelectedSites from the result" - "Changing GlobalSelectedSites broadcasts GlobalSitesChangedMessage via WeakReferenceMessenger" - "Switching tenant profiles clears GlobalSelectedSites" - "Clearing session clears GlobalSelectedSites" - "OpenGlobalSitePickerCommand is disabled when no profile is selected" artifacts: - path: "SharepointToolbox/ViewModels/MainWindowViewModel.cs" provides: "Global site selection state, command, and message broadcast" contains: "GlobalSelectedSites" key_links: - from: "SharepointToolbox/ViewModels/MainWindowViewModel.cs" to: "SharepointToolbox/Core/Messages/GlobalSitesChangedMessage.cs" via: "WeakReferenceMessenger.Default.Send in GlobalSelectedSites setter" pattern: "Send.*GlobalSitesChangedMessage" --- Add global site selection state and command to MainWindowViewModel. This VM owns the global site list, broadcasts changes via GlobalSitesChangedMessage, and clears the selection on tenant switch and session clear. Purpose: Central state management for global site selection — the toolbar UI (plan 06-03) binds to these properties. Output: Updated MainWindowViewModel.cs with GlobalSelectedSites, OpenGlobalSitePickerCommand, GlobalSitesSelectedLabel, and broadcast logic. @C:/Users/SebastienQUEROL/.claude/get-shit-done/workflows/execute-plan.md @C:/Users/SebastienQUEROL/.claude/get-shit-done/templates/summary.md @.planning/PROJECT.md @.planning/ROADMAP.md @.planning/STATE.md @.planning/phases/06-global-site-selection/06-CONTEXT.md From SharepointToolbox/ViewModels/MainWindowViewModel.cs: ```csharp public partial class MainWindowViewModel : ObservableRecipient { // Existing — DO NOT MODIFY public Func? OpenProfileManagementDialog { get; set; } public ObservableCollection TenantProfiles { get; } public IAsyncRelayCommand ConnectCommand { get; } public IAsyncRelayCommand ClearSessionCommand { get; } public RelayCommand ManageProfilesCommand { get; } // OnSelectedProfileChanged sends TenantSwitchedMessage // ClearSessionAsync clears session } ``` From SharepointToolbox/Core/Models/SiteInfo.cs: ```csharp public record SiteInfo(string Url, string Title); ``` From SharepointToolbox/Views/Tabs/PermissionsView.xaml.cs: ```csharp vm.OpenSitePickerDialog = () => { var factory = serviceProvider.GetRequiredService>(); return factory(vm.CurrentProfile ?? new TenantProfile()); }; ``` From SharepointToolbox/Views/Dialogs/SitePickerDialog.xaml.cs: ```csharp public IReadOnlyList SelectedUrls => _allItems.Where(i => i.IsSelected).Select(i => new SiteInfo(i.Url, i.Title)).ToList(); // DialogResult = true on OK click ``` Task 1: Add global site selection state, command, and broadcast to MainWindowViewModel SharepointToolbox/ViewModels/MainWindowViewModel.cs Modify MainWindowViewModel to add global site selection support. All changes are additive — do not remove or modify any existing properties/methods except where noted. 1. Add using directives at the top (if not already present): ```csharp using SharepointToolbox.Core.Models; // for SiteInfo — may already be there for TenantProfile ``` 2. Add a dialog factory property (same pattern as OpenProfileManagementDialog). Place it near the other dialog factory: ```csharp /// /// Factory set by MainWindow.xaml.cs to open the SitePickerDialog for global site selection. /// Returns the opened Window; ViewModel calls ShowDialog() on it. /// public Func? OpenGlobalSitePickerDialog { get; set; } ``` 3. Add the global site selection collection and label. Place after existing observable properties: ```csharp public ObservableCollection GlobalSelectedSites { get; } = new(); /// /// Label for toolbar display: "3 site(s) selected" or "No sites selected". /// public string GlobalSitesSelectedLabel => GlobalSelectedSites.Count > 0 ? $"{GlobalSelectedSites.Count} site(s) selected" : "No sites selected"; ``` Note: The label uses a hardcoded string for now. Plan 06-03 will replace it with a localized string once the localization keys are added. 4. Add the command. Declare it near the other commands: ```csharp public RelayCommand OpenGlobalSitePickerCommand { get; } ``` 5. In the constructor, initialize the command (after ManageProfilesCommand initialization): ```csharp OpenGlobalSitePickerCommand = new RelayCommand(ExecuteOpenGlobalSitePicker, () => SelectedProfile != null); GlobalSelectedSites.CollectionChanged += (_, _) => { OnPropertyChanged(nameof(GlobalSitesSelectedLabel)); BroadcastGlobalSites(); }; ``` 6. Add the command implementation method: ```csharp private void ExecuteOpenGlobalSitePicker() { if (OpenGlobalSitePickerDialog == null) return; var dialog = OpenGlobalSitePickerDialog.Invoke(); if (dialog?.ShowDialog() == true && dialog is Views.Dialogs.SitePickerDialog picker) { GlobalSelectedSites.Clear(); foreach (var site in picker.SelectedUrls) GlobalSelectedSites.Add(site); } } ``` 7. Add the broadcast helper method: ```csharp private void BroadcastGlobalSites() { WeakReferenceMessenger.Default.Send( new GlobalSitesChangedMessage(GlobalSelectedSites.ToList().AsReadOnly())); } ``` 8. In `OnSelectedProfileChanged`, add after the existing body: ```csharp // Clear global site selection on tenant switch (sites belong to a tenant) GlobalSelectedSites.Clear(); OpenGlobalSitePickerCommand.NotifyCanExecuteChanged(); ``` 9. In `ClearSessionAsync`, add at the END of the try block (before ConnectionStatus = "Not connected"): ```csharp GlobalSelectedSites.Clear(); ``` 10. Add required using for the message (if not already imported): ```csharp using SharepointToolbox.Core.Messages; // already present for TenantSwitchedMessage ``` IMPORTANT: The `using SharepointToolbox.Views.Dialogs;` namespace is needed for the `SitePickerDialog` cast in ExecuteOpenGlobalSitePicker. Add it if not present. This is acceptable since MainWindowViewModel already references `System.Windows.Window` (a View-layer type) via the dialog factory pattern. cd "C:\Users\dev\Documents\projets\Sharepoint" && dotnet build SharepointToolbox/SharepointToolbox.csproj --no-incremental 2>&1 | tail -5 MainWindowViewModel compiles with GlobalSelectedSites collection, OpenGlobalSitePickerCommand (disabled when no profile), GlobalSitesSelectedLabel, broadcast on collection change, and clear on tenant switch + session clear. - `dotnet build SharepointToolbox/SharepointToolbox.csproj` succeeds with 0 errors - MainWindowViewModel.cs contains GlobalSelectedSites ObservableCollection - MainWindowViewModel.cs contains OpenGlobalSitePickerCommand - MainWindowViewModel.cs contains GlobalSitesSelectedLabel property - MainWindowViewModel.cs sends GlobalSitesChangedMessage when collection changes - OnSelectedProfileChanged clears GlobalSelectedSites - ClearSessionAsync clears GlobalSelectedSites MainWindowViewModel owns the global site selection state, can open the site picker dialog, broadcasts changes to all tab VMs, and clears the selection on tenant switch and session clear. The toolbar UI (plan 06-03) can bind directly to these properties and commands. After completion, create `.planning/phases/06-global-site-selection/06-02-SUMMARY.md`