chore: release v2.4

- Add theme system (Dark/Light palettes, ModernTheme, ThemeManager)
- Add InputDialog, Spinner common view
- Add DuplicatesCsvExportService
- Refresh views, dialogs, and view models across tabs
- Update localization strings (en/fr)
- Tweak services (transfer, permissions, search, user access, ownership elevation, bulk operations)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Dev
2026-04-20 11:23:11 +02:00
parent 8f30a60d2a
commit f4cc81bb71
64 changed files with 3315 additions and 405 deletions
@@ -29,7 +29,8 @@ public class UserAccessAuditService : IUserAccessAuditService
IReadOnlyList<SiteInfo> sites,
ScanOptions options,
IProgress<OperationProgress> progress,
CancellationToken ct)
CancellationToken ct,
Func<string, CancellationToken, Task<bool>>? onAccessDenied = null)
{
// Normalize target logins for case-insensitive matching.
// Users may be identified by email ("alice@contoso.com") or full claim
@@ -59,10 +60,21 @@ public class UserAccessAuditService : IUserAccessAuditService
};
var ctx = await sessionManager.GetOrCreateContextAsync(profile, ct);
var permEntries = await _permissionsService.ScanSiteAsync(ctx, options, progress, ct);
IReadOnlyList<PermissionEntry> permEntries;
try
{
permEntries = await _permissionsService.ScanSiteAsync(ctx, options, progress, ct);
}
catch (Microsoft.SharePoint.Client.ServerUnauthorizedAccessException) when (onAccessDenied != null)
{
var elevated = await onAccessDenied(site.Url, ct);
if (!elevated)
throw;
var retryCtx = await sessionManager.GetOrCreateContextAsync(profile, ct);
permEntries = await _permissionsService.ScanSiteAsync(retryCtx, options, progress, ct);
}
var userEntries = TransformEntries(permEntries, targets, site);
allEntries.AddRange(userEntries);
allEntries.AddRange(TransformEntries(permEntries, targets, site));
}
progress.Report(new OperationProgress(sites.Count, sites.Count,