211 lines
8.4 KiB
Markdown
211 lines
8.4 KiB
Markdown
---
|
|
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<SiteInfo> 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"
|
|
---
|
|
|
|
<objective>
|
|
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.
|
|
</objective>
|
|
|
|
<execution_context>
|
|
@C:/Users/SebastienQUEROL/.claude/get-shit-done/workflows/execute-plan.md
|
|
@C:/Users/SebastienQUEROL/.claude/get-shit-done/templates/summary.md
|
|
</execution_context>
|
|
|
|
<context>
|
|
@.planning/PROJECT.md
|
|
@.planning/ROADMAP.md
|
|
@.planning/STATE.md
|
|
@.planning/phases/06-global-site-selection/06-CONTEXT.md
|
|
|
|
<interfaces>
|
|
<!-- MainWindowViewModel current structure (add to, do not replace) -->
|
|
From SharepointToolbox/ViewModels/MainWindowViewModel.cs:
|
|
```csharp
|
|
public partial class MainWindowViewModel : ObservableRecipient
|
|
{
|
|
// Existing — DO NOT MODIFY
|
|
public Func<Window>? OpenProfileManagementDialog { get; set; }
|
|
public ObservableCollection<TenantProfile> 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);
|
|
```
|
|
|
|
<!-- Dialog factory pattern used by PermissionsView — same pattern for MainWindow -->
|
|
From SharepointToolbox/Views/Tabs/PermissionsView.xaml.cs:
|
|
```csharp
|
|
vm.OpenSitePickerDialog = () =>
|
|
{
|
|
var factory = serviceProvider.GetRequiredService<Func<TenantProfile, SitePickerDialog>>();
|
|
return factory(vm.CurrentProfile ?? new TenantProfile());
|
|
};
|
|
```
|
|
|
|
From SharepointToolbox/Views/Dialogs/SitePickerDialog.xaml.cs:
|
|
```csharp
|
|
public IReadOnlyList<SiteInfo> SelectedUrls =>
|
|
_allItems.Where(i => i.IsSelected).Select(i => new SiteInfo(i.Url, i.Title)).ToList();
|
|
// DialogResult = true on OK click
|
|
```
|
|
</interfaces>
|
|
</context>
|
|
|
|
<tasks>
|
|
|
|
<task type="auto">
|
|
<name>Task 1: Add global site selection state, command, and broadcast to MainWindowViewModel</name>
|
|
<files>SharepointToolbox/ViewModels/MainWindowViewModel.cs</files>
|
|
<action>
|
|
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
|
|
/// <summary>
|
|
/// Factory set by MainWindow.xaml.cs to open the SitePickerDialog for global site selection.
|
|
/// Returns the opened Window; ViewModel calls ShowDialog() on it.
|
|
/// </summary>
|
|
public Func<Window>? OpenGlobalSitePickerDialog { get; set; }
|
|
```
|
|
|
|
3. Add the global site selection collection and label. Place after existing observable properties:
|
|
```csharp
|
|
public ObservableCollection<SiteInfo> GlobalSelectedSites { get; } = new();
|
|
|
|
/// <summary>
|
|
/// Label for toolbar display: "3 site(s) selected" or "No sites selected".
|
|
/// </summary>
|
|
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.
|
|
</action>
|
|
<verify>
|
|
<automated>cd "C:\Users\dev\Documents\projets\Sharepoint" && dotnet build SharepointToolbox/SharepointToolbox.csproj --no-incremental 2>&1 | tail -5</automated>
|
|
</verify>
|
|
<done>MainWindowViewModel compiles with GlobalSelectedSites collection, OpenGlobalSitePickerCommand (disabled when no profile), GlobalSitesSelectedLabel, broadcast on collection change, and clear on tenant switch + session clear.</done>
|
|
</task>
|
|
|
|
</tasks>
|
|
|
|
<verification>
|
|
- `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
|
|
</verification>
|
|
|
|
<success_criteria>
|
|
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.
|
|
</success_criteria>
|
|
|
|
<output>
|
|
After completion, create `.planning/phases/06-global-site-selection/06-02-SUMMARY.md`
|
|
</output>
|