feat(06-02): add global site selection state, command, and broadcast to MainWindowViewModel
- Add OpenGlobalSitePickerDialog factory property (dialog factory pattern) - Add GlobalSelectedSites ObservableCollection<SiteInfo> - Add GlobalSitesSelectedLabel computed property for toolbar display - Add OpenGlobalSitePickerCommand (disabled when no profile selected) - Broadcast GlobalSitesChangedMessage via WeakReferenceMessenger on collection change - Clear GlobalSelectedSites on tenant switch (OnSelectedProfileChanged) - Clear GlobalSelectedSites on session clear (ClearSessionAsync) - Add using SharepointToolbox.Views.Dialogs for SitePickerDialog cast
This commit is contained in:
@@ -7,6 +7,7 @@ using Microsoft.Extensions.Logging;
|
|||||||
using SharepointToolbox.Core.Messages;
|
using SharepointToolbox.Core.Messages;
|
||||||
using SharepointToolbox.Core.Models;
|
using SharepointToolbox.Core.Models;
|
||||||
using SharepointToolbox.Services;
|
using SharepointToolbox.Services;
|
||||||
|
using SharepointToolbox.Views.Dialogs;
|
||||||
|
|
||||||
namespace SharepointToolbox.ViewModels;
|
namespace SharepointToolbox.ViewModels;
|
||||||
|
|
||||||
@@ -19,6 +20,12 @@ public partial class MainWindowViewModel : ObservableRecipient
|
|||||||
// Set by the view layer (MainWindow.xaml.cs) to open the dialog using DI
|
// Set by the view layer (MainWindow.xaml.cs) to open the dialog using DI
|
||||||
public Func<Window>? OpenProfileManagementDialog { get; set; }
|
public Func<Window>? OpenProfileManagementDialog { get; set; }
|
||||||
|
|
||||||
|
/// <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; }
|
||||||
|
|
||||||
[ObservableProperty]
|
[ObservableProperty]
|
||||||
private TenantProfile? _selectedProfile;
|
private TenantProfile? _selectedProfile;
|
||||||
|
|
||||||
@@ -33,9 +40,20 @@ public partial class MainWindowViewModel : ObservableRecipient
|
|||||||
|
|
||||||
public ObservableCollection<TenantProfile> TenantProfiles { get; } = new();
|
public ObservableCollection<TenantProfile> TenantProfiles { get; } = new();
|
||||||
|
|
||||||
|
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";
|
||||||
|
|
||||||
public IAsyncRelayCommand ConnectCommand { get; }
|
public IAsyncRelayCommand ConnectCommand { get; }
|
||||||
public IAsyncRelayCommand ClearSessionCommand { get; }
|
public IAsyncRelayCommand ClearSessionCommand { get; }
|
||||||
public RelayCommand ManageProfilesCommand { get; }
|
public RelayCommand ManageProfilesCommand { get; }
|
||||||
|
public RelayCommand OpenGlobalSitePickerCommand { get; }
|
||||||
|
|
||||||
public MainWindowViewModel(
|
public MainWindowViewModel(
|
||||||
ProfileService profileService,
|
ProfileService profileService,
|
||||||
@@ -49,6 +67,12 @@ public partial class MainWindowViewModel : ObservableRecipient
|
|||||||
ConnectCommand = new AsyncRelayCommand(ConnectAsync, () => SelectedProfile != null);
|
ConnectCommand = new AsyncRelayCommand(ConnectAsync, () => SelectedProfile != null);
|
||||||
ClearSessionCommand = new AsyncRelayCommand(ClearSessionAsync, () => SelectedProfile != null);
|
ClearSessionCommand = new AsyncRelayCommand(ClearSessionAsync, () => SelectedProfile != null);
|
||||||
ManageProfilesCommand = new RelayCommand(OpenProfileManagement);
|
ManageProfilesCommand = new RelayCommand(OpenProfileManagement);
|
||||||
|
OpenGlobalSitePickerCommand = new RelayCommand(ExecuteOpenGlobalSitePicker, () => SelectedProfile != null);
|
||||||
|
GlobalSelectedSites.CollectionChanged += (_, _) =>
|
||||||
|
{
|
||||||
|
OnPropertyChanged(nameof(GlobalSitesSelectedLabel));
|
||||||
|
BroadcastGlobalSites();
|
||||||
|
};
|
||||||
|
|
||||||
IsActive = true;
|
IsActive = true;
|
||||||
}
|
}
|
||||||
@@ -74,6 +98,9 @@ public partial class MainWindowViewModel : ObservableRecipient
|
|||||||
}
|
}
|
||||||
ConnectCommand.NotifyCanExecuteChanged();
|
ConnectCommand.NotifyCanExecuteChanged();
|
||||||
ClearSessionCommand.NotifyCanExecuteChanged();
|
ClearSessionCommand.NotifyCanExecuteChanged();
|
||||||
|
// Clear global site selection on tenant switch (sites belong to a tenant)
|
||||||
|
GlobalSelectedSites.Clear();
|
||||||
|
OpenGlobalSitePickerCommand.NotifyCanExecuteChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task LoadProfilesAsync()
|
public async Task LoadProfilesAsync()
|
||||||
@@ -116,6 +143,7 @@ public partial class MainWindowViewModel : ObservableRecipient
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
await _sessionManager.ClearSessionAsync(SelectedProfile.TenantUrl);
|
await _sessionManager.ClearSessionAsync(SelectedProfile.TenantUrl);
|
||||||
|
GlobalSelectedSites.Clear();
|
||||||
ConnectionStatus = "Not connected";
|
ConnectionStatus = "Not connected";
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
@@ -134,4 +162,22 @@ public partial class MainWindowViewModel : ObservableRecipient
|
|||||||
// Reload profiles after dialog closes (modal — ShowDialog blocks until closed)
|
// Reload profiles after dialog closes (modal — ShowDialog blocks until closed)
|
||||||
_ = LoadProfilesAsync();
|
_ = LoadProfilesAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void ExecuteOpenGlobalSitePicker()
|
||||||
|
{
|
||||||
|
if (OpenGlobalSitePickerDialog == null) return;
|
||||||
|
var dialog = OpenGlobalSitePickerDialog.Invoke();
|
||||||
|
if (dialog?.ShowDialog() == true && dialog is SitePickerDialog picker)
|
||||||
|
{
|
||||||
|
GlobalSelectedSites.Clear();
|
||||||
|
foreach (var site in picker.SelectedUrls)
|
||||||
|
GlobalSelectedSites.Add(site);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void BroadcastGlobalSites()
|
||||||
|
{
|
||||||
|
WeakReferenceMessenger.Default.Send(
|
||||||
|
new GlobalSitesChangedMessage(GlobalSelectedSites.ToList().AsReadOnly()));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user