feat(04-09): create BulkMembers, BulkSites, and FolderStructure ViewModels and Views
- BulkMembersViewModel: CSV import, validate, preview, confirm, execute, retry failed, export failed - BulkSitesViewModel: same flow using IBulkSiteService.CreateSitesAsync - FolderStructureViewModel: site URL + library inputs, CSV folders, FolderStructureService.BuildUniquePaths - BulkMembersView/BulkSitesView/FolderStructureView: XAML + code-behind wiring ConfirmBulkOperationDialog - [Rule 3] Fixed duplicate converter definitions: removed untracked standalone EnumBoolConverter/StringToVisibilityConverter/ListToStringConverter files (already defined in IndentConverter.cs)
This commit is contained in:
166
SharepointToolbox/ViewModels/Tabs/BulkMembersViewModel.cs
Normal file
166
SharepointToolbox/ViewModels/Tabs/BulkMembersViewModel.cs
Normal file
@@ -0,0 +1,166 @@
|
||||
using System.Collections.ObjectModel;
|
||||
using System.IO;
|
||||
using System.Reflection;
|
||||
using System.Windows;
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
using CommunityToolkit.Mvvm.Input;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Win32;
|
||||
using Serilog;
|
||||
using SharepointToolbox.Core.Models;
|
||||
using SharepointToolbox.Localization;
|
||||
using SharepointToolbox.Services;
|
||||
using SharepointToolbox.Services.Export;
|
||||
|
||||
namespace SharepointToolbox.ViewModels.Tabs;
|
||||
|
||||
public partial class BulkMembersViewModel : FeatureViewModelBase
|
||||
{
|
||||
private readonly IBulkMemberService _memberService;
|
||||
private readonly ICsvValidationService _csvService;
|
||||
private readonly ISessionManager _sessionManager;
|
||||
private readonly BulkResultCsvExportService _exportService;
|
||||
private readonly ILogger<FeatureViewModelBase> _logger;
|
||||
private TenantProfile? _currentProfile;
|
||||
private List<BulkMemberRow>? _validRows;
|
||||
private List<BulkMemberRow>? _failedRowsForRetry;
|
||||
private BulkOperationSummary<BulkMemberRow>? _lastResult;
|
||||
|
||||
[ObservableProperty] private string _previewSummary = string.Empty;
|
||||
[ObservableProperty] private string _resultSummary = string.Empty;
|
||||
[ObservableProperty] private bool _hasFailures;
|
||||
[ObservableProperty] private bool _hasPreview;
|
||||
|
||||
private ObservableCollection<CsvValidationRow<BulkMemberRow>> _previewRows = new();
|
||||
public ObservableCollection<CsvValidationRow<BulkMemberRow>> PreviewRows
|
||||
{
|
||||
get => _previewRows;
|
||||
private set { _previewRows = value; OnPropertyChanged(); }
|
||||
}
|
||||
|
||||
public IRelayCommand ImportCsvCommand { get; }
|
||||
public IRelayCommand LoadExampleCommand { get; }
|
||||
public IAsyncRelayCommand ExportFailedCommand { get; }
|
||||
public IAsyncRelayCommand RetryFailedCommand { get; }
|
||||
|
||||
public Func<string, bool>? ShowConfirmDialog { get; set; }
|
||||
public TenantProfile? CurrentProfile => _currentProfile;
|
||||
|
||||
public BulkMembersViewModel(
|
||||
IBulkMemberService memberService,
|
||||
ICsvValidationService csvService,
|
||||
ISessionManager sessionManager,
|
||||
BulkResultCsvExportService exportService,
|
||||
ILogger<FeatureViewModelBase> logger)
|
||||
: base(logger)
|
||||
{
|
||||
_memberService = memberService;
|
||||
_csvService = csvService;
|
||||
_sessionManager = sessionManager;
|
||||
_exportService = exportService;
|
||||
_logger = logger;
|
||||
|
||||
ImportCsvCommand = new RelayCommand(ImportCsv);
|
||||
LoadExampleCommand = new RelayCommand(LoadExample);
|
||||
ExportFailedCommand = new AsyncRelayCommand(ExportFailedAsync, () => HasFailures);
|
||||
RetryFailedCommand = new AsyncRelayCommand(RetryFailedAsync, () => HasFailures);
|
||||
}
|
||||
|
||||
private void ImportCsv()
|
||||
{
|
||||
var dlg = new OpenFileDialog
|
||||
{
|
||||
Title = TranslationSource.Instance["bulk.csvimport.title"],
|
||||
Filter = TranslationSource.Instance["bulk.csvimport.filter"],
|
||||
};
|
||||
if (dlg.ShowDialog() != true) return;
|
||||
|
||||
using var stream = File.OpenRead(dlg.FileName);
|
||||
LoadAndPreview(stream);
|
||||
}
|
||||
|
||||
private void LoadExample()
|
||||
{
|
||||
var assembly = Assembly.GetExecutingAssembly();
|
||||
var resourceName = assembly.GetManifestResourceNames()
|
||||
.FirstOrDefault(n => n.EndsWith("bulk_add_members.csv", StringComparison.OrdinalIgnoreCase));
|
||||
if (resourceName == null) return;
|
||||
|
||||
using var stream = assembly.GetManifestResourceStream(resourceName);
|
||||
if (stream != null) LoadAndPreview(stream);
|
||||
}
|
||||
|
||||
private void LoadAndPreview(Stream stream)
|
||||
{
|
||||
var rows = _csvService.ParseAndValidateMembers(stream);
|
||||
PreviewRows = new ObservableCollection<CsvValidationRow<BulkMemberRow>>(rows);
|
||||
_validRows = rows.Where(r => r.IsValid && r.Record != null).Select(r => r.Record!).ToList();
|
||||
var invalidCount = rows.Count - _validRows.Count;
|
||||
PreviewSummary = string.Format(TranslationSource.Instance["bulkmembers.preview"],
|
||||
rows.Count, _validRows.Count, invalidCount);
|
||||
HasPreview = true;
|
||||
ResultSummary = string.Empty;
|
||||
HasFailures = false;
|
||||
}
|
||||
|
||||
protected override async Task RunOperationAsync(CancellationToken ct, IProgress<OperationProgress> progress)
|
||||
{
|
||||
if (_currentProfile == null) throw new InvalidOperationException("No tenant connected.");
|
||||
if (_validRows == null || _validRows.Count == 0)
|
||||
throw new InvalidOperationException("No valid rows to process. Import a CSV first.");
|
||||
|
||||
var message = string.Format(TranslationSource.Instance["bulk.confirm.message"],
|
||||
$"{_validRows.Count} members will be added");
|
||||
if (ShowConfirmDialog != null && !ShowConfirmDialog(message))
|
||||
return;
|
||||
|
||||
var ctx = await _sessionManager.GetOrCreateContextAsync(_currentProfile, ct);
|
||||
_lastResult = await _memberService.AddMembersAsync(ctx, _currentProfile.ClientId, _validRows, progress, ct);
|
||||
|
||||
await Application.Current.Dispatcher.InvokeAsync(() =>
|
||||
{
|
||||
HasFailures = _lastResult.HasFailures;
|
||||
_failedRowsForRetry = _lastResult.HasFailures
|
||||
? _lastResult.FailedItems.Select(r => r.Item).ToList()
|
||||
: null;
|
||||
ExportFailedCommand.NotifyCanExecuteChanged();
|
||||
RetryFailedCommand.NotifyCanExecuteChanged();
|
||||
|
||||
ResultSummary = _lastResult.HasFailures
|
||||
? string.Format(TranslationSource.Instance["bulk.result.success"],
|
||||
_lastResult.SuccessCount, _lastResult.FailedCount)
|
||||
: string.Format(TranslationSource.Instance["bulk.result.allsuccess"],
|
||||
_lastResult.TotalCount);
|
||||
});
|
||||
}
|
||||
|
||||
private async Task RetryFailedAsync()
|
||||
{
|
||||
if (_failedRowsForRetry == null || _failedRowsForRetry.Count == 0) return;
|
||||
_validRows = _failedRowsForRetry;
|
||||
HasFailures = false;
|
||||
await RunCommand.ExecuteAsync(null);
|
||||
}
|
||||
|
||||
private async Task ExportFailedAsync()
|
||||
{
|
||||
if (_lastResult == null || !_lastResult.HasFailures) return;
|
||||
var dlg = new SaveFileDialog { Filter = "CSV Files (*.csv)|*.csv", FileName = "failed_members.csv" };
|
||||
if (dlg.ShowDialog() == true)
|
||||
{
|
||||
await _exportService.WriteFailedItemsCsvAsync(_lastResult.FailedItems.ToList(), dlg.FileName, CancellationToken.None);
|
||||
Log.Information("Exported failed member rows to {Path}", dlg.FileName);
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnTenantSwitched(TenantProfile profile)
|
||||
{
|
||||
_currentProfile = profile;
|
||||
PreviewRows = new();
|
||||
_validRows = null;
|
||||
PreviewSummary = string.Empty;
|
||||
ResultSummary = string.Empty;
|
||||
HasFailures = false;
|
||||
HasPreview = false;
|
||||
}
|
||||
}
|
||||
165
SharepointToolbox/ViewModels/Tabs/BulkSitesViewModel.cs
Normal file
165
SharepointToolbox/ViewModels/Tabs/BulkSitesViewModel.cs
Normal file
@@ -0,0 +1,165 @@
|
||||
using System.Collections.ObjectModel;
|
||||
using System.IO;
|
||||
using System.Reflection;
|
||||
using System.Windows;
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
using CommunityToolkit.Mvvm.Input;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Win32;
|
||||
using Serilog;
|
||||
using SharepointToolbox.Core.Models;
|
||||
using SharepointToolbox.Localization;
|
||||
using SharepointToolbox.Services;
|
||||
using SharepointToolbox.Services.Export;
|
||||
|
||||
namespace SharepointToolbox.ViewModels.Tabs;
|
||||
|
||||
public partial class BulkSitesViewModel : FeatureViewModelBase
|
||||
{
|
||||
private readonly IBulkSiteService _siteService;
|
||||
private readonly ICsvValidationService _csvService;
|
||||
private readonly ISessionManager _sessionManager;
|
||||
private readonly BulkResultCsvExportService _exportService;
|
||||
private readonly ILogger<FeatureViewModelBase> _logger;
|
||||
private TenantProfile? _currentProfile;
|
||||
private List<BulkSiteRow>? _validRows;
|
||||
private List<BulkSiteRow>? _failedRowsForRetry;
|
||||
private BulkOperationSummary<BulkSiteRow>? _lastResult;
|
||||
|
||||
[ObservableProperty] private string _previewSummary = string.Empty;
|
||||
[ObservableProperty] private string _resultSummary = string.Empty;
|
||||
[ObservableProperty] private bool _hasFailures;
|
||||
[ObservableProperty] private bool _hasPreview;
|
||||
|
||||
private ObservableCollection<CsvValidationRow<BulkSiteRow>> _previewRows = new();
|
||||
public ObservableCollection<CsvValidationRow<BulkSiteRow>> PreviewRows
|
||||
{
|
||||
get => _previewRows;
|
||||
private set { _previewRows = value; OnPropertyChanged(); }
|
||||
}
|
||||
|
||||
public IRelayCommand ImportCsvCommand { get; }
|
||||
public IRelayCommand LoadExampleCommand { get; }
|
||||
public IAsyncRelayCommand ExportFailedCommand { get; }
|
||||
public IAsyncRelayCommand RetryFailedCommand { get; }
|
||||
|
||||
public Func<string, bool>? ShowConfirmDialog { get; set; }
|
||||
public TenantProfile? CurrentProfile => _currentProfile;
|
||||
|
||||
public BulkSitesViewModel(
|
||||
IBulkSiteService siteService,
|
||||
ICsvValidationService csvService,
|
||||
ISessionManager sessionManager,
|
||||
BulkResultCsvExportService exportService,
|
||||
ILogger<FeatureViewModelBase> logger)
|
||||
: base(logger)
|
||||
{
|
||||
_siteService = siteService;
|
||||
_csvService = csvService;
|
||||
_sessionManager = sessionManager;
|
||||
_exportService = exportService;
|
||||
_logger = logger;
|
||||
|
||||
ImportCsvCommand = new RelayCommand(ImportCsv);
|
||||
LoadExampleCommand = new RelayCommand(LoadExample);
|
||||
ExportFailedCommand = new AsyncRelayCommand(ExportFailedAsync, () => HasFailures);
|
||||
RetryFailedCommand = new AsyncRelayCommand(RetryFailedAsync, () => HasFailures);
|
||||
}
|
||||
|
||||
private void ImportCsv()
|
||||
{
|
||||
var dlg = new OpenFileDialog
|
||||
{
|
||||
Title = TranslationSource.Instance["bulk.csvimport.title"],
|
||||
Filter = TranslationSource.Instance["bulk.csvimport.filter"],
|
||||
};
|
||||
if (dlg.ShowDialog() != true) return;
|
||||
|
||||
using var stream = File.OpenRead(dlg.FileName);
|
||||
LoadAndPreview(stream);
|
||||
}
|
||||
|
||||
private void LoadExample()
|
||||
{
|
||||
var assembly = Assembly.GetExecutingAssembly();
|
||||
var resourceName = assembly.GetManifestResourceNames()
|
||||
.FirstOrDefault(n => n.EndsWith("bulk_create_sites.csv", StringComparison.OrdinalIgnoreCase));
|
||||
if (resourceName == null) return;
|
||||
|
||||
using var stream = assembly.GetManifestResourceStream(resourceName);
|
||||
if (stream != null) LoadAndPreview(stream);
|
||||
}
|
||||
|
||||
private void LoadAndPreview(Stream stream)
|
||||
{
|
||||
var rows = _csvService.ParseAndValidateSites(stream);
|
||||
PreviewRows = new ObservableCollection<CsvValidationRow<BulkSiteRow>>(rows);
|
||||
_validRows = rows.Where(r => r.IsValid && r.Record != null).Select(r => r.Record!).ToList();
|
||||
var invalidCount = rows.Count - _validRows.Count;
|
||||
PreviewSummary = string.Format(TranslationSource.Instance["bulksites.preview"],
|
||||
rows.Count, _validRows.Count, invalidCount);
|
||||
HasPreview = true;
|
||||
ResultSummary = string.Empty;
|
||||
HasFailures = false;
|
||||
}
|
||||
|
||||
protected override async Task RunOperationAsync(CancellationToken ct, IProgress<OperationProgress> progress)
|
||||
{
|
||||
if (_currentProfile == null) throw new InvalidOperationException("No tenant connected.");
|
||||
if (_validRows == null || _validRows.Count == 0)
|
||||
throw new InvalidOperationException("No valid rows to process. Import a CSV first.");
|
||||
|
||||
var message = string.Format(TranslationSource.Instance["bulk.confirm.message"],
|
||||
$"{_validRows.Count} sites will be created");
|
||||
if (ShowConfirmDialog != null && !ShowConfirmDialog(message))
|
||||
return;
|
||||
|
||||
var ctx = await _sessionManager.GetOrCreateContextAsync(_currentProfile, ct);
|
||||
_lastResult = await _siteService.CreateSitesAsync(ctx, _validRows, progress, ct);
|
||||
|
||||
await Application.Current.Dispatcher.InvokeAsync(() =>
|
||||
{
|
||||
HasFailures = _lastResult.HasFailures;
|
||||
_failedRowsForRetry = _lastResult.HasFailures
|
||||
? _lastResult.FailedItems.Select(r => r.Item).ToList()
|
||||
: null;
|
||||
ExportFailedCommand.NotifyCanExecuteChanged();
|
||||
RetryFailedCommand.NotifyCanExecuteChanged();
|
||||
|
||||
ResultSummary = _lastResult.HasFailures
|
||||
? string.Format(TranslationSource.Instance["bulk.result.success"],
|
||||
_lastResult.SuccessCount, _lastResult.FailedCount)
|
||||
: string.Format(TranslationSource.Instance["bulk.result.allsuccess"],
|
||||
_lastResult.TotalCount);
|
||||
});
|
||||
}
|
||||
|
||||
private async Task RetryFailedAsync()
|
||||
{
|
||||
if (_failedRowsForRetry == null || _failedRowsForRetry.Count == 0) return;
|
||||
_validRows = _failedRowsForRetry;
|
||||
HasFailures = false;
|
||||
await RunCommand.ExecuteAsync(null);
|
||||
}
|
||||
|
||||
private async Task ExportFailedAsync()
|
||||
{
|
||||
if (_lastResult == null || !_lastResult.HasFailures) return;
|
||||
var dlg = new SaveFileDialog { Filter = "CSV Files (*.csv)|*.csv", FileName = "failed_sites.csv" };
|
||||
if (dlg.ShowDialog() == true)
|
||||
{
|
||||
await _exportService.WriteFailedItemsCsvAsync(_lastResult.FailedItems.ToList(), dlg.FileName, CancellationToken.None);
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnTenantSwitched(TenantProfile profile)
|
||||
{
|
||||
_currentProfile = profile;
|
||||
PreviewRows = new();
|
||||
_validRows = null;
|
||||
PreviewSummary = string.Empty;
|
||||
ResultSummary = string.Empty;
|
||||
HasFailures = false;
|
||||
HasPreview = false;
|
||||
}
|
||||
}
|
||||
166
SharepointToolbox/ViewModels/Tabs/FolderStructureViewModel.cs
Normal file
166
SharepointToolbox/ViewModels/Tabs/FolderStructureViewModel.cs
Normal file
@@ -0,0 +1,166 @@
|
||||
using System.Collections.ObjectModel;
|
||||
using System.IO;
|
||||
using System.Reflection;
|
||||
using System.Windows;
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
using CommunityToolkit.Mvvm.Input;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Win32;
|
||||
using Serilog;
|
||||
using SharepointToolbox.Core.Models;
|
||||
using SharepointToolbox.Localization;
|
||||
using SharepointToolbox.Services;
|
||||
using SharepointToolbox.Services.Export;
|
||||
|
||||
namespace SharepointToolbox.ViewModels.Tabs;
|
||||
|
||||
public partial class FolderStructureViewModel : FeatureViewModelBase
|
||||
{
|
||||
private readonly IFolderStructureService _folderService;
|
||||
private readonly ICsvValidationService _csvService;
|
||||
private readonly ISessionManager _sessionManager;
|
||||
private readonly BulkResultCsvExportService _exportService;
|
||||
private readonly ILogger<FeatureViewModelBase> _logger;
|
||||
private TenantProfile? _currentProfile;
|
||||
private List<FolderStructureRow>? _validRows;
|
||||
private BulkOperationSummary<string>? _lastResult;
|
||||
|
||||
[ObservableProperty] private string _siteUrl = string.Empty;
|
||||
[ObservableProperty] private string _libraryTitle = string.Empty;
|
||||
[ObservableProperty] private string _previewSummary = string.Empty;
|
||||
[ObservableProperty] private string _resultSummary = string.Empty;
|
||||
[ObservableProperty] private bool _hasFailures;
|
||||
[ObservableProperty] private bool _hasPreview;
|
||||
|
||||
private ObservableCollection<CsvValidationRow<FolderStructureRow>> _previewRows = new();
|
||||
public ObservableCollection<CsvValidationRow<FolderStructureRow>> PreviewRows
|
||||
{
|
||||
get => _previewRows;
|
||||
private set { _previewRows = value; OnPropertyChanged(); }
|
||||
}
|
||||
|
||||
public IRelayCommand ImportCsvCommand { get; }
|
||||
public IRelayCommand LoadExampleCommand { get; }
|
||||
public IAsyncRelayCommand ExportFailedCommand { get; }
|
||||
|
||||
public Func<string, bool>? ShowConfirmDialog { get; set; }
|
||||
public TenantProfile? CurrentProfile => _currentProfile;
|
||||
|
||||
public FolderStructureViewModel(
|
||||
IFolderStructureService folderService,
|
||||
ICsvValidationService csvService,
|
||||
ISessionManager sessionManager,
|
||||
BulkResultCsvExportService exportService,
|
||||
ILogger<FeatureViewModelBase> logger)
|
||||
: base(logger)
|
||||
{
|
||||
_folderService = folderService;
|
||||
_csvService = csvService;
|
||||
_sessionManager = sessionManager;
|
||||
_exportService = exportService;
|
||||
_logger = logger;
|
||||
|
||||
ImportCsvCommand = new RelayCommand(ImportCsv);
|
||||
LoadExampleCommand = new RelayCommand(LoadExample);
|
||||
ExportFailedCommand = new AsyncRelayCommand(ExportFailedAsync, () => HasFailures);
|
||||
}
|
||||
|
||||
private void ImportCsv()
|
||||
{
|
||||
var dlg = new OpenFileDialog
|
||||
{
|
||||
Title = TranslationSource.Instance["bulk.csvimport.title"],
|
||||
Filter = TranslationSource.Instance["bulk.csvimport.filter"],
|
||||
};
|
||||
if (dlg.ShowDialog() != true) return;
|
||||
|
||||
using var stream = File.OpenRead(dlg.FileName);
|
||||
LoadAndPreview(stream);
|
||||
}
|
||||
|
||||
private void LoadExample()
|
||||
{
|
||||
var assembly = Assembly.GetExecutingAssembly();
|
||||
var resourceName = assembly.GetManifestResourceNames()
|
||||
.FirstOrDefault(n => n.EndsWith("folder_structure.csv", StringComparison.OrdinalIgnoreCase));
|
||||
if (resourceName == null) return;
|
||||
|
||||
using var stream = assembly.GetManifestResourceStream(resourceName);
|
||||
if (stream != null) LoadAndPreview(stream);
|
||||
}
|
||||
|
||||
private void LoadAndPreview(Stream stream)
|
||||
{
|
||||
var rows = _csvService.ParseAndValidateFolders(stream);
|
||||
PreviewRows = new ObservableCollection<CsvValidationRow<FolderStructureRow>>(rows);
|
||||
_validRows = rows.Where(r => r.IsValid && r.Record != null).Select(r => r.Record!).ToList();
|
||||
|
||||
var uniquePaths = FolderStructureService.BuildUniquePaths(_validRows);
|
||||
PreviewSummary = string.Format(TranslationSource.Instance["folderstruct.preview"], uniquePaths.Count);
|
||||
HasPreview = true;
|
||||
ResultSummary = string.Empty;
|
||||
HasFailures = false;
|
||||
}
|
||||
|
||||
protected override async Task RunOperationAsync(CancellationToken ct, IProgress<OperationProgress> progress)
|
||||
{
|
||||
if (_currentProfile == null) throw new InvalidOperationException("No tenant connected.");
|
||||
if (_validRows == null || _validRows.Count == 0)
|
||||
throw new InvalidOperationException("No valid rows. Import a CSV first.");
|
||||
if (string.IsNullOrWhiteSpace(SiteUrl))
|
||||
throw new InvalidOperationException("Site URL is required.");
|
||||
if (string.IsNullOrWhiteSpace(LibraryTitle))
|
||||
throw new InvalidOperationException("Library title is required.");
|
||||
|
||||
var uniquePaths = FolderStructureService.BuildUniquePaths(_validRows);
|
||||
var message = string.Format(TranslationSource.Instance["bulk.confirm.message"],
|
||||
$"{uniquePaths.Count} folders will be created in {LibraryTitle}");
|
||||
if (ShowConfirmDialog != null && !ShowConfirmDialog(message))
|
||||
return;
|
||||
|
||||
var profile = new TenantProfile
|
||||
{
|
||||
Name = _currentProfile.Name,
|
||||
TenantUrl = SiteUrl,
|
||||
ClientId = _currentProfile.ClientId,
|
||||
};
|
||||
var ctx = await _sessionManager.GetOrCreateContextAsync(profile, ct);
|
||||
|
||||
_lastResult = await _folderService.CreateFoldersAsync(ctx, LibraryTitle, _validRows, progress, ct);
|
||||
|
||||
await Application.Current.Dispatcher.InvokeAsync(() =>
|
||||
{
|
||||
HasFailures = _lastResult.HasFailures;
|
||||
ExportFailedCommand.NotifyCanExecuteChanged();
|
||||
|
||||
ResultSummary = _lastResult.HasFailures
|
||||
? string.Format(TranslationSource.Instance["bulk.result.success"],
|
||||
_lastResult.SuccessCount, _lastResult.FailedCount)
|
||||
: string.Format(TranslationSource.Instance["bulk.result.allsuccess"],
|
||||
_lastResult.TotalCount);
|
||||
});
|
||||
}
|
||||
|
||||
private async Task ExportFailedAsync()
|
||||
{
|
||||
if (_lastResult == null || !_lastResult.HasFailures) return;
|
||||
var dlg = new SaveFileDialog { Filter = "CSV Files (*.csv)|*.csv", FileName = "failed_folders.csv" };
|
||||
if (dlg.ShowDialog() == true)
|
||||
{
|
||||
await _exportService.WriteFailedItemsCsvAsync(_lastResult.FailedItems.ToList(), dlg.FileName, CancellationToken.None);
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnTenantSwitched(TenantProfile profile)
|
||||
{
|
||||
_currentProfile = profile;
|
||||
SiteUrl = string.Empty;
|
||||
LibraryTitle = string.Empty;
|
||||
PreviewRows = new();
|
||||
_validRows = null;
|
||||
PreviewSummary = string.Empty;
|
||||
ResultSummary = string.Empty;
|
||||
HasFailures = false;
|
||||
HasPreview = false;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user