--- phase: 06-global-site-selection plan: 04 type: execute wave: 2 depends_on: [06-01] files_modified: - SharepointToolbox/ViewModels/Tabs/PermissionsViewModel.cs - SharepointToolbox/ViewModels/Tabs/StorageViewModel.cs - SharepointToolbox/ViewModels/Tabs/SearchViewModel.cs - SharepointToolbox/ViewModels/Tabs/DuplicatesViewModel.cs - SharepointToolbox/ViewModels/Tabs/FolderStructureViewModel.cs - SharepointToolbox/ViewModels/Tabs/TransferViewModel.cs - SharepointToolbox/ViewModels/Tabs/BulkMembersViewModel.cs autonomous: true requirements: - SITE-01 - SITE-02 must_haves: truths: - "Permissions tab pre-populates SelectedSites from global sites when no local override exists" - "Storage, Search, Duplicates, FolderStructure tabs pre-fill SiteUrl from first global site URL" - "Transfer tab pre-fills SourceSiteUrl from first global site URL" - "BulkMembers tab does not consume global sites (CSV-driven, no SiteUrl field)" - "Settings, BulkSites, Templates tabs do not consume global sites (per CONTEXT decisions)" - "A user can type into a tab's SiteUrl field (local override) without clearing the global state" - "Global site selection changes update all consuming tabs automatically" artifacts: - path: "SharepointToolbox/ViewModels/Tabs/PermissionsViewModel.cs" provides: "Multi-site global consumption — pre-populates SelectedSites" contains: "OnGlobalSitesChanged" - path: "SharepointToolbox/ViewModels/Tabs/StorageViewModel.cs" provides: "Single-site global consumption — pre-fills SiteUrl" contains: "OnGlobalSitesChanged" - path: "SharepointToolbox/ViewModels/Tabs/SearchViewModel.cs" provides: "Single-site global consumption — pre-fills SiteUrl" contains: "OnGlobalSitesChanged" - path: "SharepointToolbox/ViewModels/Tabs/DuplicatesViewModel.cs" provides: "Single-site global consumption — pre-fills SiteUrl" contains: "OnGlobalSitesChanged" - path: "SharepointToolbox/ViewModels/Tabs/FolderStructureViewModel.cs" provides: "Single-site global consumption — pre-fills SiteUrl" contains: "OnGlobalSitesChanged" - path: "SharepointToolbox/ViewModels/Tabs/TransferViewModel.cs" provides: "Single-site global consumption — pre-fills SourceSiteUrl" contains: "OnGlobalSitesChanged" key_links: - from: "SharepointToolbox/ViewModels/Tabs/PermissionsViewModel.cs" to: "SharepointToolbox/ViewModels/FeatureViewModelBase.cs" via: "Override of OnGlobalSitesChanged virtual method" pattern: "override.*OnGlobalSitesChanged" - from: "SharepointToolbox/ViewModels/Tabs/StorageViewModel.cs" to: "SharepointToolbox/ViewModels/FeatureViewModelBase.cs" via: "Override of OnGlobalSitesChanged virtual method" pattern: "override.*OnGlobalSitesChanged" --- Update all consuming tab ViewModels to react to global site selection changes. Multi-site tabs (Permissions) pre-populate their site list; single-site tabs pre-fill their SiteUrl from the first global site. Local overrides take priority at run time. Purpose: Fulfills SITE-01 (all tabs consume global selection) and SITE-02 (per-tab override without clearing global state). Output: 6 updated tab ViewModels with OnGlobalSitesChanged overrides. @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 @.planning/phases/06-global-site-selection/06-01-SUMMARY.md From SharepointToolbox/ViewModels/FeatureViewModelBase.cs: ```csharp protected IReadOnlyList GlobalSites { get; private set; } protected virtual void OnGlobalSitesChanged(IReadOnlyList sites) { // Derived classes override to react to global site changes } ``` From SharepointToolbox/ViewModels/Tabs/PermissionsViewModel.cs: ```csharp public ObservableCollection SelectedSites { get; } = new(); [ObservableProperty] private string _siteUrl = string.Empty; // RunOperationAsync uses SelectedSites.Count > 0 ? SelectedSites : SiteUrl ``` From SharepointToolbox/ViewModels/Tabs/StorageViewModel.cs: ```csharp [ObservableProperty] private string _siteUrl = string.Empty; // RunOperationAsync checks string.IsNullOrWhiteSpace(SiteUrl) ``` From SharepointToolbox/ViewModels/Tabs/TransferViewModel.cs: ```csharp [ObservableProperty] private string _sourceSiteUrl = string.Empty; ``` Task 1: Update PermissionsViewModel for multi-site global consumption SharepointToolbox/ViewModels/Tabs/PermissionsViewModel.cs PermissionsViewModel already supports multi-site via its SelectedSites collection. The global sites should pre-populate SelectedSites when the user has not made a local override. Add a private field to track whether the user has made a local site selection on this tab: ```csharp private bool _hasLocalSiteOverride; ``` Override OnGlobalSitesChanged to pre-populate SelectedSites when no local override exists: ```csharp protected override void OnGlobalSitesChanged(IReadOnlyList sites) { if (_hasLocalSiteOverride) return; SelectedSites.Clear(); foreach (var site in sites) SelectedSites.Add(site); } ``` In the existing `ExecuteOpenSitePicker` method, set `_hasLocalSiteOverride = true;` after the user picks sites locally. Add this line right before `SelectedSites.Clear()`: ```csharp private void ExecuteOpenSitePicker() { if (OpenSitePickerDialog == null) return; var dialog = OpenSitePickerDialog.Invoke(); if (dialog?.ShowDialog() == true && dialog is Views.Dialogs.SitePickerDialog picker) { _hasLocalSiteOverride = true; // <-- ADD THIS LINE SelectedSites.Clear(); foreach (var site in picker.SelectedUrls) SelectedSites.Add(site); } } ``` In the existing `OnTenantSwitched` method, reset the local override flag: ```csharp protected override void OnTenantSwitched(TenantProfile profile) { _currentProfile = profile; _hasLocalSiteOverride = false; // <-- ADD THIS LINE Results = new ObservableCollection(); SiteUrl = string.Empty; SelectedSites.Clear(); // ... rest unchanged } ``` Do NOT modify RunOperationAsync — its existing logic already handles the correct priority: `SelectedSites.Count > 0 ? SelectedSites : SiteUrl`. When global sites are active, SelectedSites will be populated, so it naturally uses global sites. When user picks locally, SelectedSites has the local override. cd "C:\Users\dev\Documents\projets\Sharepoint" && dotnet build SharepointToolbox/SharepointToolbox.csproj --no-incremental 2>&1 | tail -5 PermissionsViewModel overrides OnGlobalSitesChanged to pre-populate SelectedSites. Local site picker sets _hasLocalSiteOverride=true to prevent global from overwriting. Tenant switch resets the flag. Task 2: Update single-site tab VMs (Storage, Search, Duplicates, FolderStructure) for global consumption SharepointToolbox/ViewModels/Tabs/StorageViewModel.cs, SharepointToolbox/ViewModels/Tabs/SearchViewModel.cs, SharepointToolbox/ViewModels/Tabs/DuplicatesViewModel.cs, SharepointToolbox/ViewModels/Tabs/FolderStructureViewModel.cs All four single-site tabs follow the identical pattern: pre-fill SiteUrl from the first global site when the user has not typed a local URL. For EACH of these four ViewModels, apply the same changes: 1. Add a using directive if not present: ```csharp using SharepointToolbox.Core.Models; // for SiteInfo — likely already imported for TenantProfile ``` 2. Add a private tracking field (place near other private fields): ```csharp private bool _hasLocalSiteOverride; ``` 3. Override OnGlobalSitesChanged: ```csharp protected override void OnGlobalSitesChanged(IReadOnlyList sites) { if (_hasLocalSiteOverride) return; SiteUrl = sites.Count > 0 ? sites[0].Url : string.Empty; } ``` 4. Detect local override when user modifies SiteUrl. Add a partial method for the [ObservableProperty] SiteUrl change notification: ```csharp partial void OnSiteUrlChanged(string value) { // If the user typed something different from the global site, mark as local override. // Empty string means user cleared it — revert to global. if (string.IsNullOrWhiteSpace(value)) { _hasLocalSiteOverride = false; // Re-apply global sites if available if (GlobalSites.Count > 0) SiteUrl = GlobalSites[0].Url; } else if (GlobalSites.Count == 0 || value != GlobalSites[0].Url) { _hasLocalSiteOverride = true; } } ``` IMPORTANT: Check if any of these VMs already has a `partial void OnSiteUrlChanged` method. If so, merge the logic into the existing method rather than creating a duplicate. Currently: - StorageViewModel: no OnSiteUrlChanged — add it - SearchViewModel: no OnSiteUrlChanged — add it - DuplicatesViewModel: no OnSiteUrlChanged — add it - FolderStructureViewModel: no OnSiteUrlChanged — add it 5. In the existing `OnTenantSwitched` method of each VM, add `_hasLocalSiteOverride = false;` at the beginning of the method body (after `_currentProfile = profile;`). Do NOT modify RunOperationAsync in any of these VMs — they already check `string.IsNullOrWhiteSpace(SiteUrl)` and use the value directly. When global sites are active, SiteUrl will be pre-filled, so the existing logic works. cd "C:\Users\dev\Documents\projets\Sharepoint" && dotnet build SharepointToolbox/SharepointToolbox.csproj --no-incremental 2>&1 | tail -5 StorageViewModel, SearchViewModel, DuplicatesViewModel, and FolderStructureViewModel all override OnGlobalSitesChanged to pre-fill SiteUrl from first global site. Local typing sets _hasLocalSiteOverride=true. Tenant switch resets the flag. Build succeeds. Task 3: Update TransferViewModel and verify BulkMembersViewModel excluded SharepointToolbox/ViewModels/Tabs/TransferViewModel.cs, SharepointToolbox/ViewModels/Tabs/BulkMembersViewModel.cs **TransferViewModel** — Pre-fill SourceSiteUrl from first global site (same pattern as single-site tabs, but the field is SourceSiteUrl not SiteUrl). 1. Add tracking field: ```csharp private bool _hasLocalSourceSiteOverride; ``` 2. Override OnGlobalSitesChanged: ```csharp protected override void OnGlobalSitesChanged(IReadOnlyList sites) { if (_hasLocalSourceSiteOverride) return; SourceSiteUrl = sites.Count > 0 ? sites[0].Url : string.Empty; } ``` 3. Add partial method for SourceSiteUrl change notification: ```csharp partial void OnSourceSiteUrlChanged(string value) { if (string.IsNullOrWhiteSpace(value)) { _hasLocalSourceSiteOverride = false; if (GlobalSites.Count > 0) SourceSiteUrl = GlobalSites[0].Url; } else if (GlobalSites.Count == 0 || value != GlobalSites[0].Url) { _hasLocalSourceSiteOverride = true; } } ``` 4. In the existing `OnTenantSwitched` method, add `_hasLocalSourceSiteOverride = false;` at the beginning. **BulkMembersViewModel** — Verify it does NOT need changes. BulkMembersViewModel has no SiteUrl field (it reads site URLs from CSV rows). Confirm this by checking: it should NOT have an OnGlobalSitesChanged override. Do NOT modify this file — only verify it has no SiteUrl property. Note: SettingsViewModel, BulkSitesViewModel, and TemplatesViewModel also do NOT consume global sites per the CONTEXT decisions. Do NOT modify them. cd "C:\Users\dev\Documents\projets\Sharepoint" && dotnet build SharepointToolbox/SharepointToolbox.csproj --no-incremental 2>&1 | tail -5 TransferViewModel overrides OnGlobalSitesChanged to pre-fill SourceSiteUrl. BulkMembersViewModel is confirmed excluded (no SiteUrl, no override). Build succeeds. - `dotnet build SharepointToolbox/SharepointToolbox.csproj` succeeds with 0 errors - `dotnet test` shows no new failures - PermissionsViewModel has OnGlobalSitesChanged override populating SelectedSites - StorageViewModel, SearchViewModel, DuplicatesViewModel, FolderStructureViewModel have OnGlobalSitesChanged override setting SiteUrl - TransferViewModel has OnGlobalSitesChanged override setting SourceSiteUrl - BulkMembersViewModel, SettingsViewModel, BulkSitesViewModel, TemplatesViewModel are NOT modified - All consuming VMs have _hasLocalSiteOverride tracking - All consuming VMs reset the override flag on tenant switch Every tab that should consume global sites does so automatically. Multi-site tab (Permissions) pre-populates its SelectedSites collection. Single-site tabs pre-fill their SiteUrl/SourceSiteUrl from the first global site. Users can type a different URL on any tab without clearing the global state. Tabs that don't apply (Settings, BulkSites, Templates, BulkMembers) are unaffected. After completion, create `.planning/phases/06-global-site-selection/06-04-SUMMARY.md`