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
@@ -1,4 +1,5 @@
using SharepointToolbox.Core.Models;
using SharepointToolbox.Localization;
using System.Text;
namespace SharepointToolbox.Services.Export;
@@ -12,15 +13,16 @@ public class DuplicatesHtmlExportService
{
public string BuildHtml(IReadOnlyList<DuplicateGroup> groups, ReportBranding? branding = null)
{
var T = TranslationSource.Instance;
var sb = new StringBuilder();
sb.AppendLine("<!DOCTYPE html>");
sb.AppendLine("<html lang=\"en\">");
sb.AppendLine("<head>");
sb.AppendLine("<meta charset=\"UTF-8\">");
sb.AppendLine("<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">");
sb.AppendLine($"<title>{T["report.title.duplicates"]}</title>");
sb.AppendLine("""
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>SharePoint Duplicate Detection Report</title>
<style>
body { font-family: 'Segoe UI', Arial, sans-serif; font-size: 13px; margin: 20px; background: #f5f5f5; }
h1 { color: #0078d4; }
@@ -54,11 +56,9 @@ public class DuplicatesHtmlExportService
<body>
""");
sb.Append(BrandingHtmlHelper.BuildBrandingHeader(branding));
sb.AppendLine("""
<h1>Duplicate Detection Report</h1>
""");
sb.AppendLine($"<h1>{T["report.title.duplicates_short"]}</h1>");
sb.AppendLine($"<p class=\"summary\">{groups.Count:N0} duplicate group(s) found.</p>");
sb.AppendLine($"<p class=\"summary\">{groups.Count:N0} {T["report.text.duplicate_groups_found"]}</p>");
for (int i = 0; i < groups.Count; i++)
{
@@ -70,19 +70,19 @@ public class DuplicatesHtmlExportService
<div class="group-card">
<div class="group-header" onclick="toggleGroup({i})">
<span class="group-name">{H(g.Name)}</span>
<span class="badge {badgeClass}">{count} copies</span>
<span class="badge {badgeClass}">{count} {T["report.text.copies"]}</span>
</div>
<div class="group-body" id="gb-{i}">
<table>
<thead>
<tr>
<th>#</th>
<th>Name</th>
<th>Library</th>
<th>Path</th>
<th>Size</th>
<th>Created</th>
<th>Modified</th>
<th>{T["report.col.number"]}</th>
<th>{T["report.col.name"]}</th>
<th>{T["report.col.library"]}</th>
<th>{T["report.col.path"]}</th>
<th>{T["report.col.size"]}</th>
<th>{T["report.col.created"]}</th>
<th>{T["report.col.modified"]}</th>
</tr>
</thead>
<tbody>
@@ -116,7 +116,7 @@ public class DuplicatesHtmlExportService
""");
}
sb.AppendLine($"<p class=\"generated\">Generated: {DateTime.Now:yyyy-MM-dd HH:mm}</p>");
sb.AppendLine($"<p class=\"generated\">{T["report.text.generated_colon"]} {DateTime.Now:yyyy-MM-dd HH:mm}</p>");
sb.AppendLine("</body></html>");
return sb.ToString();