Previewer: sending details about layout overflow exception

This commit is contained in:
MarcinZiabek
2022-11-20 15:28:56 +01:00
parent 57e68e293d
commit baa0feb5e6
11 changed files with 178 additions and 172 deletions
@@ -10,7 +10,7 @@
<ItemGroup>
<PackageReference Include="BenchmarkDotNet" Version="0.13.1" />
<PackageReference Include="nunit" Version="3.13.3" />
<PackageReference Include="NUnit3TestAdapter" Version="4.3.0" />
<PackageReference Include="NUnit3TestAdapter" Version="4.3.1" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.4.0" />
<PackageReference Include="SkiaSharp" Version="2.88.3" />
</ItemGroup>
+7 -4
View File
@@ -6,6 +6,7 @@ using NUnit.Framework;
using QuestPDF.Drawing;
using QuestPDF.Fluent;
using QuestPDF.Infrastructure;
using QuestPDF.Previewer;
using QuestPDF.ReportSample.Layouts;
namespace QuestPDF.ReportSample
@@ -24,11 +25,13 @@ namespace QuestPDF.ReportSample
[Test]
public void GenerateAndShowPdf()
{
Report.ShowInPreviewer();
//ImagePlaceholder.Solid = true;
var path = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, $"test_result.pdf");
Report.GeneratePdf(path);
Process.Start("explorer.exe", path);
//
// var path = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, $"test_result.pdf");
// Report.GeneratePdf(path);
// Process.Start("explorer.exe", path);
}
[Test]
+1 -1
View File
@@ -135,7 +135,7 @@ namespace QuestPDF.Drawing
$"2) The layout configuration of your document is invalid. Some of the elements require more space than is provided." +
$"Please analyze your documents structure to detect this element and fix its size constraints.";
var elementTrace = debuggingState?.BuildTrace() ?? "Debug trace is available only in the DEBUG mode.";
var elementTrace = debuggingState?.BuildTrace(); // ?? "Debug trace is available only in the DEBUG mode.";
throw new DocumentLayoutException(message, elementTrace);
}
@@ -1,12 +1,13 @@
using System;
using QuestPDF.Previewer;
namespace QuestPDF.Drawing.Exceptions
{
public class DocumentLayoutException : Exception
{
public string? ElementTrace { get; }
internal LayoutRenderingTrace? ElementTrace { get; }
internal DocumentLayoutException(string message, string? elementTrace = null) : base(message)
internal DocumentLayoutException(string message, LayoutRenderingTrace? elementTrace = null) : base(message)
{
ElementTrace = elementTrace;
}
+28 -35
View File
@@ -6,6 +6,8 @@ using System.Text;
using QuestPDF.Elements;
using QuestPDF.Helpers;
using QuestPDF.Infrastructure;
using QuestPDF.Previewer;
using Size = QuestPDF.Infrastructure.Size;
namespace QuestPDF.Drawing.Proxy
{
@@ -57,48 +59,35 @@ namespace QuestPDF.Drawing.Proxy
item.SpacePlan = spacePlan;
}
public string BuildTrace()
public LayoutRenderingTrace BuildTrace()
{
var builder = new StringBuilder();
var nestingLevel = 0;
return Traverse(Root);
Traverse(Root);
return builder.ToString();
void Traverse(DebugStackItem item)
LayoutRenderingTrace Traverse(DebugStackItem item)
{
var indent = new string(' ', nestingLevel * 4);
var title = item.Element.GetType().Name;
if (item.Element is DebugPointer debugPointer)
return new LayoutRenderingTrace
{
title = debugPointer.Target;
title += debugPointer.Highlight ? " 🌟" : string.Empty;
}
if (item.SpacePlan.Type != SpacePlanType.FullRender)
title = "🔥 " + title;
builder.AppendLine(indent + title);
builder.AppendLine(indent + new string('-', title.Length));
builder.AppendLine(indent + "Available space: " + item.AvailableSpace);
builder.AppendLine(indent + "Requested space: " + item.SpacePlan);
foreach (var configuration in GetElementConfiguration(item.Element))
builder.AppendLine(indent + configuration);
builder.AppendLine();
nestingLevel++;
item.Stack.ToList().ForEach(Traverse);
nestingLevel--;
ElementType = item.Element.GetType().Name,
ElementProperties = GetElementConfiguration(item.Element).ToList(),
AvailableSpace = new QuestPDF.Previewer.Size()
{
Width = item.AvailableSpace.Width,
Height = item.AvailableSpace.Height
},
SpacePlan = new QuestPDF.Previewer.SpacePlan()
{
Width = item.SpacePlan.Width,
Height = item.SpacePlan.Height,
Type = item.SpacePlan.Type
},
Children = item.Stack.Select(Traverse).ToList()
};
}
static IEnumerable<string> GetElementConfiguration(IElement element)
static IEnumerable<DocumentElementProperty> GetElementConfiguration(IElement element)
{
if (element is DebugPointer)
return Enumerable.Empty<string>();
return Enumerable.Empty<DocumentElementProperty>();
return element
.GetType()
@@ -111,7 +100,11 @@ namespace QuestPDF.Drawing.Proxy
.Where(x => !(x.Value is IElement))
.Where(x => x.Value is string || !(x.Value is IEnumerable))
.Where(x => !(x.Value is TextStyle))
.Select(x => $"{x.Property}: {FormatValue(x.Value)}");
.Select(x => new DocumentElementProperty
{
Label = x.Property,
Value = FormatValue(x.Value)
});
string FormatValue(object value)
{
+5 -2
View File
@@ -1,4 +1,5 @@
using System;
#if NETCOREAPP3_0_OR_GREATER
using System.Net.Http;
using System.Text;
using System.Text.Json;
@@ -16,4 +17,6 @@ internal static class Helpers
return client.PostAsync(requestUri, jsonContent, cancellationToken);
}
}
}
#endif
+33
View File
@@ -0,0 +1,33 @@
using System.Collections.Generic;
using QuestPDF.Drawing;
using QuestPDF.Infrastructure;
namespace QuestPDF.Previewer;
internal sealed class DocumentElementProperty
{
public string Label { get; set; }
public string Value { get; set; }
}
internal sealed class Size
{
public float Width { get; set; }
public float Height { get; set; }
}
internal sealed class SpacePlan
{
public float Width { get; set; }
public float Height { get; set; }
public SpacePlanType Type { get; set; }
}
internal sealed class LayoutRenderingTrace
{
public string ElementType { get; set; }
public IReadOnlyCollection<DocumentElementProperty> ElementProperties { get; set; }
public Size AvailableSpace { get; set; }
public SpacePlan SpacePlan { get; set; }
public IReadOnlyCollection<LayoutRenderingTrace> Children { get; set; }
}
+21 -16
View File
@@ -5,6 +5,7 @@ using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using QuestPDF.Drawing;
using QuestPDF.Drawing.Exceptions;
using QuestPDF.Infrastructure;
namespace QuestPDF.Previewer
@@ -16,8 +17,10 @@ namespace QuestPDF.Previewer
document.ShowInPreviewerAsync(port).ConfigureAwait(true).GetAwaiter().GetResult();
}
public static async Task ShowInPreviewerAsync(this IDocument document, int port = 5000)
public static async Task ShowInPreviewerAsync(this IDocument document, int port = 5000, CancellationToken cancellationToken = default)
{
QuestPDF.Settings.EnableDebugging = true;
var previewerService = new PreviewerService(port);
using var cancellationTokenSource = new CancellationTokenSource();
@@ -26,10 +29,19 @@ namespace QuestPDF.Previewer
await previewerService.Connect();
await RefreshPreview();
//
// //HotReloadManager.UpdateApplicationRequested += (_, _) => RefreshPreview();
//
// await WaitForPreviewerExit(cancellationTokenSource.Token);
#if NET6_0_OR_GREATER
HotReloadManager.UpdateApplicationRequested += (_, _) => RefreshPreview();
#endif
while (true)
{
//if (cancellationToken.IsCancellationRequested)
// break;
await Task.Delay(TimeSpan.FromMilliseconds(1000));
}
//await previewerService.Disconnect();
Task RefreshPreview()
{
@@ -38,22 +50,15 @@ namespace QuestPDF.Previewer
var pictures = DocumentGenerator.GeneratePreviewerPictures(document);
return previewerService.ShowDocumentPreview(pictures);
}
catch (DocumentLayoutException exception)
{
return previewerService.ShowLayoutError(exception);
}
catch (Exception exception)
{
return previewerService.ShowGenericError(exception);
}
}
//
// async Task WaitForPreviewerExit(CancellationToken cancellationToken)
// {
// while (true)
// {
// if (cancellationToken.IsCancellationRequested)
// return;
//
// await Task.Delay(TimeSpan.FromSeconds(1), cancellationToken);
// }
// }
}
}
}
@@ -1,23 +0,0 @@
using System;
using System.Collections.Generic;
using QuestPDF.Infrastructure;
#if NETCOREAPP3_0_OR_GREATER
namespace QuestPDF.Previewer
{
internal class PreviewerRefreshCommand
{
public ICollection<Page> Pages { get; set; }
public class Page
{
public string Id { get; } = Guid.NewGuid().ToString("N");
public float Width { get; set; }
public float Height { get; set; }
}
}
}
#endif
+79 -87
View File
@@ -2,11 +2,13 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Net.Http;
using System.Text;
using System.Text.Json;
using System.Threading.Tasks;
using QuestPDF.Drawing;
using QuestPDF.Drawing.Exceptions;
namespace QuestPDF.Previewer
{
@@ -20,10 +22,15 @@ namespace QuestPDF.Previewer
public GenericError? InnerException { get; set; }
}
internal sealed class ShowLayoutErrorApiRequestVersion
internal sealed class ShowGenericErrorApiRequest
{
public GenericError? Error { get; set; }
}
internal sealed class ShowLayoutErrorApiRequest
{
public LayoutRenderingTrace? Trace { get; set; }
}
internal sealed class UpdateDocumentPreviewApiRequest
@@ -62,6 +69,62 @@ namespace QuestPDF.Previewer
};
}
private void StartPreviewer()
{
try
{
var process = new Process
{
StartInfo = new()
{
FileName = "questpdf-previewer",
Arguments = $"{Port}",
UseShellExecute = false,
CreateNoWindow = true
}
};
process.Start();
}
catch
{
throw new Exception("Cannot start the QuestPDF Previewer tool. " +
"Please install it by executing in terminal the following command: 'dotnet tool install --global QuestPDF.Previewer'.");
}
}
public async Task Connect()
{
var isAvailable = await IsPreviewerAvailable();
if (!isAvailable)
{
//StartPreviewer();
//await WaitForConnection();
}
//var previewerVersion = await GetPreviewerVersion();
//CheckVersionCompatibility(previewerVersion);
}
public async Task Disconnect()
{
await HttpClient.GetAsync("/v1/disconnect");
}
private async Task<bool> IsPreviewerAvailable()
{
try
{
using var result = await HttpClient.GetAsync("/ping");
return result.IsSuccessStatusCode;
}
catch
{
return false;
}
}
public async Task ShowDocumentPreview(ICollection<PreviewerPicture> pictures)
{
using var multipartContent = new MultipartFormDataContent();
@@ -100,7 +163,7 @@ namespace QuestPDF.Previewer
public async Task ShowGenericError(Exception exception)
{
var payload = new ShowLayoutErrorApiRequestVersion
var payload = new ShowGenericErrorApiRequest
{
Error = MapException(exception)
};
@@ -122,32 +185,19 @@ namespace QuestPDF.Previewer
}
}
public async Task Connect()
public async Task ShowLayoutError(DocumentLayoutException exception)
{
var isAvailable = await IsPreviewerAvailable();
if (!isAvailable)
var payload = new ShowLayoutErrorApiRequest
{
//StartPreviewer();
//await WaitForConnection();
}
//var previewerVersion = await GetPreviewerVersion();
//CheckVersionCompatibility(previewerVersion);
Trace = exception.ElementTrace
};
await HttpClient.PostAsJsonAsync("/v1/update/error/layout", payload);
}
private async Task<bool> IsPreviewerAvailable()
{
try
{
using var result = await HttpClient.GetAsync("/ping");
return result.IsSuccessStatusCode;
}
catch
{
return false;
}
}
//
// private async Task<Version> GetPreviewerVersion()
// {
@@ -155,36 +205,11 @@ namespace QuestPDF.Previewer
// return await result.Content.ReadFromJsonAsync<Version>();
// }
//
// private void StartPreviewer()
// {
// try
// {
// var process = new Process
// {
// StartInfo = new()
// {
// FileName = "questpdf-previewer",
// Arguments = $"{Port}",
// UseShellExecute = false,
// CreateNoWindow = true
// }
// };
//
// process.Start();
//
// Task.Run(async () =>
// {
// await process.WaitForExitAsync();
// process.Dispose();
// OnPreviewerStopped?.Invoke();
// });
// }
// catch
// {
// throw new Exception("Cannot start the QuestPDF Previewer tool. " +
// "Please install it by executing in terminal the following command: 'dotnet tool install --global QuestPDF.Previewer'.");
// }
// }
//
// private void CheckVersionCompatibility(Version version)
// {
@@ -216,39 +241,6 @@ namespace QuestPDF.Previewer
// break;
// }
// }
//
// public async Task RefreshPreview(ICollection<PreviewerPicture> pictures)
// {
// using var multipartContent = new MultipartFormDataContent();
//
// var pages = new List<PreviewerRefreshCommand.Page>();
//
// foreach (var picture in pictures)
// {
// var page = new PreviewerRefreshCommand.Page
// {
// Width = picture.Size.Width,
// Height = picture.Size.Height
// };
//
// pages.Add(page);
//
// var pictureStream = picture.Picture.Serialize().AsStream();
// multipartContent.Add(new StreamContent(pictureStream), page.Id, page.Id);
// }
//
// var command = new PreviewerRefreshCommand
// {
// Pages = pages
// };
//
// multipartContent.Add(JsonContent.Create(command), "command");
//
// using var _ = await HttpClient.PostAsync("/update/preview", multipartContent);
//
// foreach (var picture in pictures)
// picture.Picture.Dispose();
// }
}
}
-1
View File
@@ -18,7 +18,6 @@
<PackageLicenseExpression>MIT</PackageLicenseExpression>
<Nullable>enable</Nullable>
<TargetFrameworks>net462;netstandard2.0;netcoreapp2.0;netcoreapp3.0;net6.0</TargetFrameworks>
<TargetFrameworks>netcoreapp3.0;</TargetFrameworks>
<IncludeSymbols>true</IncludeSymbols>
<SymbolPackageFormat>snupkg</SymbolPackageFormat>
</PropertyGroup>