Conversation
Reviewer's GuideImplements JS-to-.NET synchronization for the IpAddress component so that pasting an IP triggers ValueChanged, updates styling class names, and adds corresponding unit tests. Sequence diagram for IpAddress paste synchronization from JS to .NETsequenceDiagram
actor User
participant Browser
participant IpAddressJs
participant IpAddressComponent
User->>Browser: Paste IPv4 string into IpAddress input
Browser->>IpAddressJs: paste event
IpAddressJs->>IpAddressJs: Sanitize input and split into parts
IpAddressJs->>IpAddressJs: Clamp each part to 0-255
IpAddressJs->>Browser: Update .ipv4-cell inputs with clamped values
IpAddressJs->>IpAddressComponent: invoke.invokeMethodAsync(TriggerUpdate, v1, v2, v3, v4)
IpAddressComponent->>IpAddressComponent: TriggerUpdate(v1, v2, v3, v4)
IpAddressComponent->>IpAddressComponent: Set Value1..Value4
IpAddressComponent->>IpAddressComponent: UpdateValue()
IpAddressComponent->>IpAddressComponent: Set CurrentValueAsString
IpAddressComponent-->>Browser: ValueChanged and validation pipeline triggered
Updated class diagram for IpAddress component with JSInvokable TriggerUpdateclassDiagram
class IpAddress {
+string Value1
+string Value2
+string Value3
+string Value4
+string CurrentValueAsString
+bool IsDisabled
+string CssClass
+string ValidCss
+string ClassName
+void ValueChanged1(ChangeEventArgs args)
+void ValueChanged2(ChangeEventArgs args)
+void ValueChanged3(ChangeEventArgs args)
+void ValueChanged4(ChangeEventArgs args)
+void UpdateValue()
+void TriggerUpdate(int v1, int v2, int v3, int v4)
}
class CssBuilder {
+CssBuilder Default(string value)
+CssBuilder AddClass(string value)
+CssBuilder AddClass(string value, bool when)
+string Build()
}
IpAddress --> CssBuilder : 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 and found some issues that need to be addressed.
- In the paste handler,
invoke.invokeMethodAsync("TriggerUpdate", ...args)will fail when fewer than four octets are pasted because the JS interop signature expects four arguments; consider normalizingargsto length 4 (e.g., filling missing positions with existing values or zeros) before invoking. - The new
TriggerUpdatemethod assumes values have already been clamped in JS; if there is any other path that might call it, consider adding basic range validation (0–255) on the C# side to avoid invalid IP state.
Prompt for AI Agents
Please address the comments from this code review:
## Overall Comments
- In the paste handler, `invoke.invokeMethodAsync("TriggerUpdate", ...args)` will fail when fewer than four octets are pasted because the JS interop signature expects four arguments; consider normalizing `args` to length 4 (e.g., filling missing positions with existing values or zeros) before invoking.
- The new `TriggerUpdate` method assumes values have already been clamped in JS; if there is any other path that might call it, consider adding basic range validation (0–255) on the C# side to avoid invalid IP state.
## Individual Comments
### Comment 1
<location> `src/BootstrapBlazor/Components/IpAddress/IpAddress.razor.js:101-110` </location>
<code_context>
const parts = raw.replace(/[^\d.]/g, '').split('.').filter(p => p.length);
const cells = el.querySelectorAll(".ipv4-cell");
let pos = 0;
+ const args = [];
parts.forEach(p => {
if (pos > 3) {
return;
}
const num = Math.max(0, Math.min(255, parseInt(p, 10) || 0));
+ args.push(num);
cells[pos].value = num.toString();
ip.prevValues[pos] = cells[pos].value;
pos++;
});
+
+ invoke.invokeMethodAsync("TriggerUpdate", ...args);
});
})
</code_context>
<issue_to_address>
**issue (bug_risk):** TriggerUpdate expects 4 ints but paste handler can pass fewer or none, which is likely to throw.
Because `TriggerUpdate(int v1, int v2, int v3, int v4)` always requires 4 parameters, calling `invoke.invokeMethodAsync("TriggerUpdate", ...args)` with fewer (e.g. pasting `"127"` → a single element in `args`, or invalid/empty paste → no elements) is likely to throw a JS interop exception. Please ensure 4 arguments are always passed (e.g., fill missing positions with defaults or existing values) or adjust the .NET signature to accept a different shape (e.g., a single string or an array).
</issue_to_address>
### Comment 2
<location> `test/UnitTest/Components/IpAddressTest.cs:49-54` </location>
<code_context>
Assert.Equal("123.123.123.123", cut.Instance.Value);
}
+ [Fact]
+ public async Task TriggerUpdate_Ok()
+ {
+ var cut = Context.Render<IpAddress>();
+ await cut.InvokeAsync(() => cut.Instance.TriggerUpdate(192, 0, 1, 10));
+ Assert.Equal("192.0.1.10", cut.Instance.Value);
+ }
+
</code_context>
<issue_to_address>
**suggestion (testing):** Add a test that verifies `TriggerUpdate` also updates the bound value / triggers `ValueChanged`, not just the internal `Value` property.
This test verifies only the internal `Value` property. Since the PR claims that `TriggerUpdate` also raises `ValueChanged` for consumers, please add a test that renders `IpAddress` with a bound value (e.g., via an `EditForm` or `bind-Value`), calls `TriggerUpdate`, and asserts that the bound model or `ValueChanged` callback receives the updated value (e.g., `"192.0.1.10"`).
</issue_to_address>Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.
| [Fact] | ||
| public async Task TriggerUpdate_Ok() | ||
| { | ||
| var cut = Context.Render<IpAddress>(); | ||
| await cut.InvokeAsync(() => cut.Instance.TriggerUpdate(192, 0, 1, 10)); | ||
| Assert.Equal("192.0.1.10", cut.Instance.Value); |
There was a problem hiding this comment.
suggestion (testing): Add a test that verifies TriggerUpdate also updates the bound value / triggers ValueChanged, not just the internal Value property.
This test verifies only the internal Value property. Since the PR claims that TriggerUpdate also raises ValueChanged for consumers, please add a test that renders IpAddress with a bound value (e.g., via an EditForm or bind-Value), calls TriggerUpdate, and asserts that the bound model or ValueChanged callback receives the updated value (e.g., "192.0.1.10").
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #7280 +/- ##
=========================================
Coverage 100.00% 100.00%
=========================================
Files 745 745
Lines 32621 32628 +7
Branches 4522 4522
=========================================
+ Hits 32621 32628 +7
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:
|
* 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
There was a problem hiding this comment.
Pull request overview
This PR adds support for triggering ValueChanged events when pasting IP addresses into the IpAddress component, along with a CSS class rename for better naming consistency.
- Implements paste event handling in JavaScript to parse and apply pasted IP addresses
- Adds C# method
TriggerUpdatecallable from JavaScript via JSInvokable - Renames CSS class from "ipaddress" to "bb-ip" for consistency with framework conventions
Reviewed changes
Copilot reviewed 6 out of 6 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| test/UnitTest/Components/IpAddressTest.cs | Updates test to use new CSS class name and adds test for TriggerUpdate method |
| src/BootstrapBlazor/Components/IpAddress/IpAddress.razor.scss | Renames CSS class from "ipaddress" to "bb-ip" and removes BOM character |
| src/BootstrapBlazor/Components/IpAddress/IpAddress.razor.js | Adds invoke parameter to init function and implements paste event handler with JavaScript-to-C# callback |
| src/BootstrapBlazor/Components/IpAddress/IpAddress.razor.cs | Updates CSS class name, adds JSInvokable TriggerUpdate method, and removes BOM character |
| src/BootstrapBlazor/Components/IpAddress/IpAddress.razor | Enables JSObjectReference in BootstrapModuleAutoLoader attribute and removes BOM character |
| src/BootstrapBlazor/BootstrapBlazor.csproj | Bumps version from 10.1.2 to 10.1.3 |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| ip.prevValues[pos] = cells[pos].value; | ||
| pos++; | ||
| }); | ||
|
|
There was a problem hiding this comment.
The TriggerUpdate method expects exactly 4 parameters, but the args array may contain fewer than 4 elements if the pasted text has fewer than 4 dot-separated parts (e.g., pasting "192.168"). This will cause the invocation to fail or pass undefined values. Consider either:
- Padding the
argsarray to always have 4 elements (e.g., filling remaining slots with 0) - Only invoking
TriggerUpdatewhen exactly 4 parts are present
Example fix:
while (args.length < 4) {
args.push(0);
}
invoke.invokeMethodAsync("TriggerUpdate", ...args);| while (args.length < 4) { | |
| args.push(0); | |
| } |
| /// 更新 值方法供 JS 调用 | ||
| /// </summary> | ||
| /// <param name="v1"></param> | ||
| /// <param name="v2"></param> | ||
| /// <param name="v3"></param> | ||
| /// <param name="v4"></param> |
There was a problem hiding this comment.
The documentation comment is incomplete. It should describe what the method does and document the parameters. Consider:
/// <summary>
/// Triggers an update to the IP address value from JavaScript. Used when pasting values.
/// </summary>
/// <param name="v1">First octet of the IP address (0-255)</param>
/// <param name="v2">Second octet of the IP address (0-255)</param>
/// <param name="v3">Third octet of the IP address (0-255)</param>
/// <param name="v4">Fourth octet of the IP address (0-255)</param>| /// 更新 值方法供 JS 调用 | |
| /// </summary> | |
| /// <param name="v1"></param> | |
| /// <param name="v2"></param> | |
| /// <param name="v3"></param> | |
| /// <param name="v4"></param> | |
| /// Triggers an update to the IP address value from JavaScript. Used when pasting values. | |
| /// </summary> | |
| /// <param name="v1">First octet of the IP address (0-255).</param> | |
| /// <param name="v2">Second octet of the IP address (0-255).</param> | |
| /// <param name="v3">Third octet of the IP address (0-255).</param> | |
| /// <param name="v4">Fourth octet of the IP address (0-255).</param> |
* feat: 增加 Key 参数 * refactor: 使用回调方法 GetKeyByITem 获得行 Key 值 * chore: bump version 9.6.5 * feat: 增加 PdfOptions 配置项 * chore: bump version 9.6.6 * refactor: 调整 IconTemplate 优先级别 * feat: 增加 ActionButtonTemplate 模板 * refactor: 增加条件 * chore: bump version 9.6.7 * feat(IpAddress): support paste function (#7276) * feat(IpAddress): support paste function * refactor: 代码格式化 # Conflicts: # src/BootstrapBlazor/Components/IpAddress/IpAddress.razor.js * chore: bump version 9.6.8 * feat(IpAddress): trigger ValueChanged on paste event (#7280) * 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 * chore: bump version 9.6.9 * chore: 支持 Interop 参数 * chore: bump version 9.6.10 * feat: 增加 OnBeforeTreeItemClick 方法 * chore: bump version 9.6.11 * refactor: 兼容嵌套问题 * chore: bump version 9.6.12 * feat: 支持端口 * chore: bump version 9.6-13-beta01 * chore: bump version 9.6.13 * feat(ZipArchiveService): add ArchiveDirectoryAsync method # Conflicts: # src/BootstrapBlazor/Services/DefaultZipArchiveService.cs # src/BootstrapBlazor/Services/IZipArchiveService.cs * test: 增加单元测试 # Conflicts: # test/UnitTest/Services/ZipArchiveServiceTest.cs * chore: bump version 9.6.14 * refactor: 增加 Key 参数 * refactor: 取消冗余代码 * revert: 撤销更改 * refactor: 移动 SetKey 位置 * refactor: 调整序号 * test: 增加单元测试
* feat: 增加 Key 参数 * refactor: 使用回调方法 GetKeyByITem 获得行 Key 值 * chore: bump version 9.6.5 * feat: 增加 PdfOptions 配置项 * chore: bump version 9.6.6 * refactor: 调整 IconTemplate 优先级别 * feat: 增加 ActionButtonTemplate 模板 * refactor: 增加条件 * chore: bump version 9.6.7 * feat(IpAddress): support paste function (#7276) * feat(IpAddress): support paste function * refactor: 代码格式化 # Conflicts: # src/BootstrapBlazor/Components/IpAddress/IpAddress.razor.js * chore: bump version 9.6.8 * feat(IpAddress): trigger ValueChanged on paste event (#7280) * 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 * chore: bump version 9.6.9 * chore: 支持 Interop 参数 * chore: bump version 9.6.10 * feat: 增加 OnBeforeTreeItemClick 方法 * chore: bump version 9.6.11 * refactor: 兼容嵌套问题 * chore: bump version 9.6.12 * feat: 支持端口 * chore: bump version 9.6-13-beta01 * chore: bump version 9.6.13 * feat(ZipArchiveService): add ArchiveDirectoryAsync method # Conflicts: # src/BootstrapBlazor/Services/DefaultZipArchiveService.cs # src/BootstrapBlazor/Services/IZipArchiveService.cs * test: 增加单元测试 # Conflicts: # test/UnitTest/Services/ZipArchiveServiceTest.cs * chore: bump version 9.6.14 * refactor: 增加 Key 参数 * refactor: 取消冗余代码 * revert: 撤销更改 * refactor: 移动 SetKey 位置 * refactor: 调整序号 * test: 增加单元测试 * refactor: 更新代码 * refactor: 重构代码 * refactor: 重构代码 * refactor: 重构代码 * refactor: 重构代码 * refactor: 更新代码
Link issues
fixes #7279
Summary By Copilot
Regression?
Risk
Verification
Packaging changes reviewed?
☑️ Self Check before Merge
Summary by Sourcery
Synchronize the IpAddress component value with pasted input via JS interop and align its styling class name.
New Features:
Enhancements:
Tests: