Conversation
* feat(IpAddress): support paste function * refactor: 代码格式化 # Conflicts: # src/BootstrapBlazor/Components/IpAddress/IpAddress.razor.js
* refactor: 增加 JSInvoke 能力 * refactor: 更改样式 * refactor: 增加客户端更改 IP 回调方法 * test: 更新单元测试 * chore: bump version 10.1.3 # Conflicts: # src/BootstrapBlazor/BootstrapBlazor.csproj # src/BootstrapBlazor/Components/IpAddress/IpAddress.razor.scss # test/UnitTest/Components/IpAddressTest.cs
# Conflicts: # src/BootstrapBlazor/Services/DefaultZipArchiveService.cs # src/BootstrapBlazor/Services/IZipArchiveService.cs
# Conflicts: # test/UnitTest/Services/ZipArchiveServiceTest.cs
# Conflicts: # src/BootstrapBlazor/BootstrapBlazor.csproj # src/BootstrapBlazor/Components/BaseComponents/BootstrapModuleComponentBase.cs # src/BootstrapBlazor/Components/BaseComponents/DynamicElement.cs # src/BootstrapBlazor/Components/Drawer/Drawer.razor.js # src/BootstrapBlazor/Components/IpAddress/IpAddress.razor.cs # src/BootstrapBlazor/Components/IpAddress/IpAddress.razor.scss # src/BootstrapBlazor/Components/Table/Table.razor # src/BootstrapBlazor/Components/Table/Table.razor.cs # src/BootstrapBlazor/Components/TreeView/TreeView.razor.cs # src/BootstrapBlazor/Components/Upload/CardUpload.razor # src/BootstrapBlazor/Components/Upload/CardUpload.razor.cs # src/BootstrapBlazor/Options/PdfOptions.cs # src/BootstrapBlazor/Services/DefaultZipArchiveService.cs # src/BootstrapBlazor/Services/IZipArchiveService.cs # test/UnitTest/Components/IpAddressTest.cs # test/UnitTest/Services/ZipArchiveServiceTest.cs
Reviewer's GuideAdds key support to DynamicElement rendering and fixes/improves directory handling when creating ZIP archives, including explicit entry creation for directories and stream cleanup. Class diagram for DynamicElement and DefaultZipArchiveService changesclassDiagram
class DynamicElement {
+bool GenerateElement
+object Key
+RenderFragment ChildContent
+bool IsTriggerClick()
+bool IsTriggerDoubleClick()
+void BuildRenderTree(RenderTreeBuilder builder)
}
class DefaultZipArchiveService {
+Task ArchiveFilesAsync(Stream stream, IEnumerable_ArchiveEntryInfo_ files, ZipArchiveOptions options, CancellationToken cancellationToken)
}
class ArchiveEntryInfo {
+string SourceFileName
+string EntryName
+CompressionLevel CompressionLevel
}
class ZipArchiveOptions {
+CompressionLevel CompressionLevel
+Task~Stream~ ReadStreamAsync(string sourceFileName)
}
DefaultZipArchiveService --> ArchiveEntryInfo : uses
DefaultZipArchiveService --> ZipArchiveOptions : uses
DynamicElement --> RenderTreeBuilder : uses
DynamicElement --> RenderFragment : uses
Flow diagram for updated ArchiveFilesAsync directory and file handlingflowchart TD
A["Start ArchiveFilesAsync"] --> B["For each ArchiveEntryInfo f"]
B --> C{"File.Exists(f.SourceFileName)?"}
C -- "Yes" --> D["Create file entry in archive
archive.CreateEntry(f.EntryName, compressionLevel)"]
D --> E["Read content stream via options.ReadStreamAsync"]
E --> F["Open entry stream"]
F --> G["CopyToAsync from content to entry stream"]
G --> H["entryStream.Close()"]
H --> I["Next file"]
C -- "No" --> J{"Directory.Exists(f.SourceFileName)?"}
J -- "Yes" --> K{"Is f.EntryName null or empty?"}
K -- "No" --> L{"Does f.EntryName end with directory separator?"}
L -- "No" --> M["Append Path.DirectorySeparatorChar to f.EntryName"]
M --> N["Create directory entry in archive
archive.CreateEntry(entryName, compressionLevel)"]
L -- "Yes" --> N
N --> I
K -- "Yes" --> I
J -- "No" --> I
I --> O["End loop"]
O --> P["End ArchiveFilesAsync"]
File-Level Changes
Tips and commandsInteracting with Sourcery
Customizing Your ExperienceAccess your dashboard to:
Getting Help
|
There was a problem hiding this comment.
Hey - I've found 1 issue, and left some high level feedback:
- The new
else if (Directory.Exists(f.SourceFileName))block inArchiveFilesAsyncmakes the existingelse if (Directory.Exists(f.SourceFileName))immediately below it unreachable; consolidate these into a single directory-handling branch. - In
ArchiveFilesAsync,entryStreamis already wrapped inawait using, so the explicitentryStream.Close()call is redundant and can be removed to avoid confusion about ownership/disposal.
Prompt for AI Agents
Please address the comments from this code review:
## Overall Comments
- The new `else if (Directory.Exists(f.SourceFileName))` block in `ArchiveFilesAsync` makes the existing `else if (Directory.Exists(f.SourceFileName))` immediately below it unreachable; consolidate these into a single directory-handling branch.
- In `ArchiveFilesAsync`, `entryStream` is already wrapped in `await using`, so the explicit `entryStream.Close()` call is redundant and can be removed to avoid confusion about ownership/disposal.
## Individual Comments
### Comment 1
<location> `src/BootstrapBlazor/Components/BaseComponents/DynamicElement.cs:141-143` </location>
<code_context>
builder.AddContent(8, ChildContent);
+ if (Key != null)
+ {
+ builder.SetKey(Key);
+ }
+
</code_context>
<issue_to_address>
**suggestion:** Consider calling `builder.SetKey(Key)` immediately after `OpenElement` instead of after `AddContent`.
This will work, but the usual Blazor pattern is to call `SetKey` immediately after `OpenElement`/`OpenRegion` so the key clearly applies to the element rather than any content frames. Placing it there makes the intent clearer and reduces the risk of subtle issues if the render sequence changes later.
Suggested implementation:
```csharp
if (Key != null)
{
builder.SetKey(Key);
}
builder.AddContent(8, ChildContent);
/// <summary>
```
If `BuildRenderTree` contains a call like `builder.OpenElement(sequence, tagName)` or `builder.OpenRegion(sequence)` above this snippet, the ideal pattern in Blazor is:
```csharp
builder.OpenElement(0, "some-tag");
if (Key != null)
{
builder.SetKey(Key);
}
builder.AddContent(8, ChildContent);
// ...
builder.CloseElement();
```
So you may want to further adjust the method to ensure the `SetKey` block appears *immediately after* `OpenElement`/`OpenRegion` and before any other content is added, following the usual Blazor pattern.
</issue_to_address>Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.
src/BootstrapBlazor/Components/BaseComponents/DynamicElement.cs
Outdated
Show resolved
Hide resolved
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #7636 +/- ##
=========================================
Coverage 100.00% 100.00%
=========================================
Files 749 749
Lines 33105 33109 +4
Branches 4593 4593
=========================================
+ Hits 33105 33109 +4
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
There was a problem hiding this comment.
Pull request overview
This PR updates BootstrapBlazor internals around ZIP archive creation and dynamic element rendering, adding support for keyed rendering and adjusting how directory entries are handled when archiving.
Changes:
- Added directory-entry handling logic during ZIP creation and explicitly closed the ZIP entry stream after copying.
- Added a new
Keyparameter toDynamicElementand applied it viaRenderTreeBuilder.SetKey.
Reviewed changes
Copilot reviewed 1 out of 1 changed files in this pull request and generated 1 comment.
| File | Description |
|---|---|
| src/BootstrapBlazor/Services/DefaultZipArchiveService.cs | Adjusts ZIP entry writing/closing and introduces directory-entry creation logic. |
| src/BootstrapBlazor/Components/BaseComponents/DynamicElement.cs | Adds a Key parameter and applies keyed rendering in BuildRenderTree. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Link issues
fixes #7637
Summary By Copilot
Regression?
Risk
Verification
Packaging changes reviewed?
☑️ Self Check before Merge
Summary by Sourcery
Add support for element keys in dynamic components and improve ZIP archive handling for files and directories.
New Features:
Bug Fixes: