Conversation
Reviewer's GuideThis pull request adds asynchronous PDF export and download capabilities to the Mermaid component by injecting HTML-to-PDF and download services, refactoring the rendering API, and extending the JavaScript interop to support SVG extraction. Sequence diagram for DownloadPdfAsync method in Mermaid componentsequenceDiagram
participant Mermaid
participant Html2PdfService
participant DownloadService
participant JSInterop
Mermaid->>JSInterop: getSvgHtml(id)
JSInterop-->>Mermaid: SVG HTML string
Mermaid->>Html2PdfService: PdfStreamFromHtmlAsync(html)
Html2PdfService-->>Mermaid: PDF stream
Mermaid->>DownloadService: DownloadFromStreamAsync(fileName, stream)
DownloadService-->>Mermaid: (download complete)
Sequence diagram for Render method replacing MermaidChangedsequenceDiagram
participant Mermaid
participant JSInterop
Mermaid->>JSInterop: render(id, BuildDiagramText())
JSInterop-->>Mermaid: (diagram rendered)
Class diagram for updated Mermaid component with PDF export and downloadclassDiagram
class Mermaid {
+string? Title
+Task<string?> ExportBase64MermaidAsync()
+Task<Stream?> ExportPdfAsync(CancellationToken token = default)
+Task DownloadPdfAsync(string fileName, CancellationToken token = default)
+Task Render()
-IHtml2Pdf Html2PdfService
-DownloadService DownloadService
}
class IHtml2Pdf {
+Task<Stream?> PdfStreamFromHtmlAsync(string html)
}
class DownloadService {
+Task DownloadFromStreamAsync(string fileName, Stream stream)
}
Mermaid --> IHtml2Pdf : uses
Mermaid --> DownloadService : uses
File-Level Changes
Assessment against linked issues
Possibly linked issues
Tips and commandsInteracting with Sourcery
Customizing Your ExperienceAccess your dashboard to:
Getting Help
|
There was a problem hiding this comment.
Hey there - I've reviewed your changes - here's some feedback:
- Ensure addScript is idempotent so that mermaid.min.js isn’t re-loaded on every Render call and to avoid redundant network requests.
- In ExportPdfAsync, consider throwing or logging a clear exception when getSvgHtml returns null or empty instead of returning a null Stream to surface failures sooner.
- Propagate the CancellationToken into DownloadService.DownloadFromStreamAsync (or extend its API) so that long‐running downloads can be cancelled.
Prompt for AI Agents
Please address the comments from this code review:
## Overall Comments
- Ensure addScript is idempotent so that mermaid.min.js isn’t re-loaded on every Render call and to avoid redundant network requests.
- In ExportPdfAsync, consider throwing or logging a clear exception when getSvgHtml returns null or empty instead of returning a null Stream to surface failures sooner.
- Propagate the CancellationToken into DownloadService.DownloadFromStreamAsync (or extend its API) so that long‐running downloads can be cancelled.
## Individual Comments
### Comment 1
<location> `src/components/BootstrapBlazor.Mermaid/Mermaid.razor.cs:88-93` </location>
<code_context>
+ /// 导出图为 Pdf 文档流
/// </summary>
- /// <returns></returns>
+ public async Task<Stream?> ExportPdfAsync(CancellationToken token = default)
+ {
+ Stream? stream = null;
+ var html = await InvokeAsync<string?>("getSvgHtml", token, Id);
+ if (html != null)
+ {
</code_context>
<issue_to_address>
**suggestion:** Check for null or empty HTML before passing to PDF service.
Also check for string.IsNullOrWhiteSpace(html) to avoid unnecessary PDF service calls with empty content.
```suggestion
public async Task<Stream?> ExportPdfAsync(CancellationToken token = default)
{
Stream? stream = null;
var html = await InvokeAsync<string?>("getSvgHtml", token, Id);
if (!string.IsNullOrWhiteSpace(html))
{
```
</issue_to_address>
### Comment 2
<location> `src/components/BootstrapBlazor.Mermaid/Mermaid.razor.cs:106-112` </location>
<code_context>
+ /// <returns>base64 string of the diagram</returns>
+ public async Task DownloadPdfAsync(string fileName, CancellationToken token = default)
+ {
+ ArgumentNullException.ThrowIfNull(fileName);
+
+ var stream = await ExportPdfAsync(token);
</code_context>
<issue_to_address>
**suggestion (bug_risk):** Consider validating fileName for empty or whitespace values.
Also check for empty or whitespace-only fileName values using string.IsNullOrWhiteSpace(fileName).
```suggestion
ArgumentNullException.ThrowIfNull(fileName);
if (string.IsNullOrWhiteSpace(fileName))
{
throw new ArgumentException("fileName cannot be empty or whitespace.", nameof(fileName));
}
var stream = await ExportPdfAsync(token);
if (stream != null)
{
await DownloadService.DownloadFromStreamAsync(fileName, stream);
}
```
</issue_to_address>
### Comment 3
<location> `src/components/BootstrapBlazor.Mermaid/Mermaid.razor.js:3-7` </location>
<code_context>
+import { addScript } from '../BootstrapBlazor/modules/utility.js'
export async function init(id, content) {
+ await addScript('./_content/BootstrapBlazor.Mermaid/mermaid.min.js');
+
+ await render(id, content);
</code_context>
<issue_to_address>
**suggestion (bug_risk):** Consider handling addScript errors to avoid silent failures.
If addScript fails, later mermaid calls may throw. Wrap in try/catch or verify script load success.
```suggestion
export async function init(id, content) {
try {
await addScript('./_content/BootstrapBlazor.Mermaid/mermaid.min.js');
} catch (error) {
console.error('Failed to load mermaid script:', error);
return;
}
await render(id, content);
}
```
</issue_to_address>Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.
| ArgumentNullException.ThrowIfNull(fileName); | ||
|
|
||
| var stream = await ExportPdfAsync(token); | ||
| if (stream != null) | ||
| { | ||
| await DownloadService.DownloadFromStreamAsync(fileName, stream); | ||
| } |
There was a problem hiding this comment.
suggestion (bug_risk): Consider validating fileName for empty or whitespace values.
Also check for empty or whitespace-only fileName values using string.IsNullOrWhiteSpace(fileName).
| ArgumentNullException.ThrowIfNull(fileName); | |
| var stream = await ExportPdfAsync(token); | |
| if (stream != null) | |
| { | |
| await DownloadService.DownloadFromStreamAsync(fileName, stream); | |
| } | |
| ArgumentNullException.ThrowIfNull(fileName); | |
| if (string.IsNullOrWhiteSpace(fileName)) | |
| { | |
| throw new ArgumentException("fileName cannot be empty or whitespace.", nameof(fileName)); | |
| } | |
| var stream = await ExportPdfAsync(token); | |
| if (stream != null) | |
| { | |
| await DownloadService.DownloadFromStreamAsync(fileName, stream); | |
| } |
There was a problem hiding this comment.
Pull Request Overview
This PR adds the ability to download Mermaid diagrams as PDF documents by introducing new export and download methods that leverage the IHtml2Pdf service.
Key Changes:
- Added
DownloadPdfAsyncmethod to enable direct PDF downloads of Mermaid diagrams - Refactored JavaScript initialization to support dynamic script loading and separate rendering logic
- Deprecated the
MermaidChangedmethod in favor of a newRendermethod
Reviewed Changes
Copilot reviewed 3 out of 4 changed files in this pull request and generated 7 comments.
| File | Description |
|---|---|
| Mermaid.razor.js | Refactored to use dynamic script loading, added new render and getSvgHtml functions to support PDF export functionality |
| Mermaid.razor.cs | Added ExportPdfAsync and DownloadPdfAsync methods with IHtml2Pdf and DownloadService injections; deprecated MermaidChanged in favor of Render |
| BootstrapBlazor.Mermaid.csproj | Updated version to 10.0.1 |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Link issues
fixes #704
Summary By Copilot
Regression?
Risk
Verification
Packaging changes reviewed?
☑️ Self Check before Merge
Summary by Sourcery
Enable PDF export and download for Mermaid diagrams, refactor the rendering API, and enhance the JavaScript integration by dynamically loading scripts and providing helper methods.
New Features:
Enhancements:
Chores: