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.Models;
|
||||
using SharepointToolbox.Services;
|
||||
using SharepointToolbox.Views.Dialogs;
|
||||
|
||||
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
|
||||
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]
|
||||
private TenantProfile? _selectedProfile;
|
||||
|
||||
@@ -33,9 +40,20 @@ public partial class MainWindowViewModel : ObservableRecipient
|
||||
|
||||
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 ClearSessionCommand { get; }
|
||||
public RelayCommand ManageProfilesCommand { get; }
|
||||
public RelayCommand OpenGlobalSitePickerCommand { get; }
|
||||
|
||||
public MainWindowViewModel(
|
||||
ProfileService profileService,
|
||||
@@ -49,6 +67,12 @@ public partial class MainWindowViewModel : ObservableRecipient
|
||||
ConnectCommand = new AsyncRelayCommand(ConnectAsync, () => SelectedProfile != null);
|
||||
ClearSessionCommand = new AsyncRelayCommand(ClearSessionAsync, () => SelectedProfile != null);
|
||||
ManageProfilesCommand = new RelayCommand(OpenProfileManagement);
|
||||
OpenGlobalSitePickerCommand = new RelayCommand(ExecuteOpenGlobalSitePicker, () => SelectedProfile != null);
|
||||
GlobalSelectedSites.CollectionChanged += (_, _) =>
|
||||
{
|
||||
OnPropertyChanged(nameof(GlobalSitesSelectedLabel));
|
||||
BroadcastGlobalSites();
|
||||
};
|
||||
|
||||
IsActive = true;
|
||||
}
|
||||
@@ -74,6 +98,9 @@ public partial class MainWindowViewModel : ObservableRecipient
|
||||
}
|
||||
ConnectCommand.NotifyCanExecuteChanged();
|
||||
ClearSessionCommand.NotifyCanExecuteChanged();
|
||||
// Clear global site selection on tenant switch (sites belong to a tenant)
|
||||
GlobalSelectedSites.Clear();
|
||||
OpenGlobalSitePickerCommand.NotifyCanExecuteChanged();
|
||||
}
|
||||
|
||||
public async Task LoadProfilesAsync()
|
||||
@@ -116,6 +143,7 @@ public partial class MainWindowViewModel : ObservableRecipient
|
||||
try
|
||||
{
|
||||
await _sessionManager.ClearSessionAsync(SelectedProfile.TenantUrl);
|
||||
GlobalSelectedSites.Clear();
|
||||
ConnectionStatus = "Not connected";
|
||||
}
|
||||
catch (Exception ex)
|
||||
@@ -134,4 +162,22 @@ public partial class MainWindowViewModel : ObservableRecipient
|
||||
// Reload profiles after dialog closes (modal — ShowDialog blocks until closed)
|
||||
_ = 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