using System.Text; using SharepointToolbox.Core.Models; using SharepointToolbox.Localization; namespace SharepointToolbox.Services.Export; /// /// Exports VersionCleanupResult list to a self-contained sortable/filterable HTML report. /// Summary header shows totals (files trimmed, versions deleted, bytes freed); a single /// table lists every processed file with sort/filter controls. No external assets. /// public class VersionCleanupHtmlExportService { public string BuildHtml(IReadOnlyList results, ReportBranding? branding = null) { var T = TranslationSource.Instance; var sb = new StringBuilder(); long totalBytes = results.Sum(r => r.BytesFreed); int totalDeleted = results.Sum(r => r.VersionsDeleted); int totalFiles = results.Count(r => r.VersionsDeleted > 0); sb.AppendLine(""); sb.AppendLine(""); sb.AppendLine(""); sb.AppendLine(""); sb.AppendLine(""); sb.AppendLine($"{T["report.title.versions"]}"); sb.AppendLine(""" """); sb.Append(BrandingHtmlHelper.BuildBrandingHeader(branding)); sb.AppendLine($"

{T["report.title.versions_short"]}

"); sb.AppendLine($"""
{T["versions.summary.files"]}{totalFiles:N0}
{T["versions.summary.deleted"]}{totalDeleted:N0}
{T["versions.summary.freed"]}{FormatSize(totalBytes)}
"""); sb.AppendLine($""" """); foreach (var r in results) { string rowClass = string.IsNullOrEmpty(r.Error) ? string.Empty : " class=\"err\""; string errCell = string.IsNullOrEmpty(r.Error) ? string.Empty : $"{H(r.Error)}"; sb.AppendLine($""" """); } sb.AppendLine(" \n
{T["report.col.site"]} {T["versions.col.library"]} {T["versions.col.file"]} {T["versions.col.path"]} {T["versions.col.before"]} {T["versions.col.deleted"]} {T["versions.col.remaining"]} {T["versions.col.freed"]} {T["versions.col.error"]}
{H(r.SiteUrl)} {H(r.Library)} {H(r.FileName)} {H(r.FileServerRelativeUrl)} {r.VersionsBefore:N0} {r.VersionsDeleted:N0} {r.VersionsRemaining:N0} {FormatSize(r.BytesFreed)} {errCell}
"); int count = results.Count; sb.AppendLine($"

{T["report.text.generated_colon"]} {DateTime.Now:yyyy-MM-dd HH:mm} — {count:N0} {T["report.text.results_parens"]}

"); sb.AppendLine($$""" """); return sb.ToString(); } /// Writes the HTML report to as UTF-8. public async Task WriteAsync(IReadOnlyList results, string filePath, CancellationToken ct, ReportBranding? branding = null) { var html = BuildHtml(results, branding); await System.IO.File.WriteAllTextAsync(filePath, html, Encoding.UTF8, ct); } private static string H(string value) => System.Net.WebUtility.HtmlEncode(value ?? string.Empty); private static string FormatSize(long bytes) { if (bytes >= 1_073_741_824L) return $"{bytes / 1_073_741_824.0:F2} GB"; if (bytes >= 1_048_576L) return $"{bytes / 1_048_576.0:F2} MB"; if (bytes >= 1024L) return $"{bytes / 1024.0:F2} KB"; return $"{bytes} B"; } }