Skip to content

feat(CardUpload): support ValidateForm validate function#7432

Merged
ArgoZhang merged 7 commits intomainfrom
fix-card-upload
Dec 26, 2025
Merged

feat(CardUpload): support ValidateForm validate function#7432
ArgoZhang merged 7 commits intomainfrom
fix-card-upload

Conversation

@ArgoZhang
Copy link
Copy Markdown
Member

@ArgoZhang ArgoZhang commented Dec 26, 2025

Link issues

fixes #7431

Summary By Copilot

Regression?

  • Yes
  • No

Risk

  • High
  • Medium
  • Low

Verification

  • Manual (required)
  • Automated

Packaging changes reviewed?

  • Yes
  • No
  • N/A

☑️ Self Check before Merge

⚠️ Please check all items below before review. ⚠️

  • Doc is updated/provided or not needed
  • Demo is updated/provided or not needed
  • Merge the latest code from the main branch

Summary by Sourcery

Integrate CardUpload with the validation pipeline and improve upload validation handling and styling.

New Features:

  • Enable CardUpload to participate in ValidateForm validation by wiring file items and the add button into the validation messaging flow.
  • Allow upload components to bind directly to IEnumerable values in addition to IEnumerable.
  • Add explicit visual states for valid and invalid card-style upload items.

Bug Fixes:

  • Correct avatar upload validation logic when validating before any files are added by fixing the invalid-on-add item flag usage.
  • Ensure ValidateForm treats an unselected upload value as null so data-annotations validation runs correctly for required fields.

Copilot AI review requested due to automatic review settings December 26, 2025 06:06
@bb-auto bb-auto Bot added the enhancement New feature or request label Dec 26, 2025
@bb-auto bb-auto Bot added this to the v10.1.0 milestone Dec 26, 2025
@sourcery-ai
Copy link
Copy Markdown
Contributor

sourcery-ai Bot commented Dec 26, 2025

Reviewer's Guide

Implements ValidateForm integration for CardUpload, aligns card upload validation behavior and styling with AvatarUpload, and improves UploadBase value binding and hover/valid/invalid visuals for card-style uploads.

Sequence diagram for ValidateForm integration with CardUpload

sequenceDiagram
actor User
participant ValidateForm
participant CardUpload
participant ValidateModule

User->>ValidateForm: Submit_form
ValidateForm->>CardUpload: ToggleMessage(results)
CardUpload->>CardUpload: _results = results
CardUpload->>CardUpload: IsValid = (results.Count == 0)
CardUpload->>CardUpload: IsInValidOnAddItem check
alt First_item_invalid
  CardUpload->>ValidateModule: LoadValidateModule() if needed
  CardUpload->>ValidateModule: executeUpload([AddId],[{Id=AddId,Error}],null)
else Existing_items_invalid
  CardUpload->>ValidateModule: LoadValidateModule() if needed
  CardUpload->>ValidateModule: executeUpload(fileValidateIds,invalidItems,AddId)
end
ValidateModule-->>User: Update_card_item_valid_invalid_borders
Loading

Class diagram for updated upload validation components

classDiagram
class UploadBase_TValue {
  TValue CurrentValue
  Type ValueType
  Task OnFileChange(InputFileChangeEventArgs args)
}

class CardUpload_TValue {
  bool IsValid
  List~UploadFile~ Files
  object ValidateModule
  IReadOnlyCollection~ValidationResult~ _results
  string ItemClassString
  string AddId
  bool IsInValidOnAddItem
  Task ToggleMessage(IReadOnlyCollection~ValidationResult~ results)
  ValueTask ShowValidResult()
  ValueTask RemoveValidResult(string validateId)
}

class AvatarUpload_TValue {
  bool IsValid
  List~UploadFile~ Files
  object ValidateModule
  IReadOnlyCollection~ValidationResult~ _results
  string AddId
  bool IsInValidOnAddItem
  Task ToggleMessage(IReadOnlyCollection~ValidationResult~ results)
  ValueTask RemoveValidResult(string validateId)
}

class ValidateForm {
  Task ValidateAsync(IValidateComponent validator, ValidationContext context, Dictionary~string, List~string~~ messages)
}

UploadBase_TValue <|-- CardUpload_TValue
UploadBase_TValue <|-- AvatarUpload_TValue

note for UploadBase_TValue "OnFileChange now sets CurrentValue to IEnumerable UploadFile when TValue is IEnumerable UploadFile, and to IEnumerable IBrowserFile when TValue is IEnumerable IBrowserFile"
note for CardUpload_TValue "Implements ToggleMessage integration with ValidateForm and JS validate module, plus no-op ShowValidResult and guarded RemoveValidResult"
note for AvatarUpload_TValue "Aligns naming IsInValidOnAddItem and its use in ToggleMessage and disposal logic"
Loading

File-Level Changes

Change Details Files
Add full ValidateForm validation support to CardUpload, mirroring AvatarUpload behavior.
  • Override ToggleMessage in CardUpload to store validation results, compute validity, and call the JS validation module with upload item IDs and error messages.
  • Introduce IsInValidOnAddItem and AddId helpers to handle the special case where validation errors occur before any files are uploaded.
  • Override ShowValidResult as a no-op and constrain RemoveValidResult to only forward non-empty validate IDs to the base implementation.
  • Expose per-item and add-card element IDs in the CardUpload markup so validation can target specific DOM elements.
  • Refine item CSS class construction for CardUpload to ensure valid/invalid state classes are applied consistently.
src/BootstrapBlazor/Components/Upload/CardUpload.razor.cs
src/BootstrapBlazor/Components/Upload/CardUpload.razor
Fix and align AvatarUpload validation state naming and disposal logic.
  • Rename IsInValiadOnAddItem to IsInValidOnAddItem and update all references for correct spelling and consistency.
  • Ensure DisposeAsync uses the corrected IsInValidOnAddItem flag when computing items to pass to the validation module.
src/BootstrapBlazor/Components/Upload/AvatarUpload.razor.cs
Adjust card upload styling to visually distinguish valid, invalid, and hover states.
  • Update card upload hover selector so it only applies when an item is neither valid nor invalid to avoid overriding validation styles.
  • Change invalid card item border styling to target the whole .upload-item rather than only the body container.
  • Add new styles to give valid card upload items a success border color.
src/BootstrapBlazor/Components/Upload/InputUpload.razor.scss
Improve UploadBase value binding to support binding to UploadFile collections directly.
  • When the bound TValue is assignable to IEnumerable, set CurrentValue to the list of UploadFile items produced during file change handling.
  • Fallback to the existing behavior of binding IEnumerable when applicable.
src/BootstrapBlazor/Components/Upload/UploadBase.cs
Ensure ValidateForm treats empty uploads as null for validation purposes.
  • When no file is selected in ValidateForm's file validation path, explicitly set propertyValue to null before running data annotations validation so required-like attributes behave correctly.
src/BootstrapBlazor/Components/ValidateForm/ValidateForm.razor.cs

Assessment against linked issues

Issue Objective Addressed Explanation
#7431 Enable the CardUpload component to fully support ValidateForm's validate function, including triggering and displaying validation results correctly.

Possibly linked issues


Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@ArgoZhang ArgoZhang merged commit 8a9748e into main Dec 26, 2025
3 of 5 checks passed
@ArgoZhang ArgoZhang deleted the fix-card-upload branch December 26, 2025 06:07
Copy link
Copy Markdown
Contributor

@sourcery-ai sourcery-ai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey - I've left some high level feedback:

  • In CardUpload.ToggleMessage, the anonymous object initializer new { Id = AddId, _results.First().ErrorMessage } is not valid C# and likely should be new { Id = AddId, ErrorMessage = _results.First().ErrorMessage } to name the second property explicitly.
  • The CSS change from .upload .upload-body.is-card .is-invalid .upload-item-body to .upload .upload-body.is-card .upload-item.is-invalid sets border-color on the container rather than .upload-item-body; double-check that the border is actually applied on the element that owns the border to avoid the invalid/valid styles not showing.
  • The override of RemoveValidResult in CardUpload only calls base.RemoveValidResult when validateId is non-empty, which changes the behavior for a null/empty validateId (previously used to clear all); verify that this restriction is intentional and that you don’t need to support clearing all validation results for this component.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- In `CardUpload.ToggleMessage`, the anonymous object initializer `new { Id = AddId, _results.First().ErrorMessage }` is not valid C# and likely should be `new { Id = AddId, ErrorMessage = _results.First().ErrorMessage }` to name the second property explicitly.
- The CSS change from `.upload .upload-body.is-card .is-invalid .upload-item-body` to `.upload .upload-body.is-card .upload-item.is-invalid` sets `border-color` on the container rather than `.upload-item-body`; double-check that the border is actually applied on the element that owns the border to avoid the invalid/valid styles not showing.
- The override of `RemoveValidResult` in `CardUpload` only calls `base.RemoveValidResult` when `validateId` is non-empty, which changes the behavior for a `null`/empty `validateId` (previously used to clear all); verify that this restriction is intentional and that you don’t need to support clearing all validation results for this component.

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR adds validation support for the CardUpload component, bringing it to feature parity with AvatarUpload. The changes enable CardUpload to work properly within ValidateForm contexts by implementing the necessary validation methods and visual feedback.

Key changes:

  • Implements validation lifecycle methods (ToggleMessage, ShowValidResult, RemoveValidResult) in CardUpload
  • Adds support for IEnumerable<UploadFile> value type binding in UploadBase
  • Fixes CSS styling for validation states (valid/invalid) on card upload items
  • Corrects a typo in AvatarUpload (IsInValiadOnAddItemIsInValidOnAddItem)

Reviewed changes

Copilot reviewed 7 out of 7 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
src/BootstrapBlazor/Components/ValidateForm/ValidateForm.razor.cs Sets property value to null when no files are selected for upload validation
src/BootstrapBlazor/Components/Upload/UploadBase.cs Adds support for IEnumerable<UploadFile> value type binding before the existing IEnumerable<IBrowserFile> check
src/BootstrapBlazor/Components/Upload/InputUpload.razor.scss Fixes CSS selectors for validation states and prevents hover styling from overriding valid/invalid states
src/BootstrapBlazor/Components/Upload/CardUpload.razor.cs Implements validation methods (ToggleMessage, ShowValidResult, RemoveValidResult) for form validation support
src/BootstrapBlazor/Components/Upload/CardUpload.razor Adds id attributes to upload items and add button for validation targeting
src/BootstrapBlazor/Components/Upload/AvatarUpload.razor.cs Fixes spelling of IsInValidOnAddItem property name (was IsInValiadOnAddItem)
src/BootstrapBlazor/BootstrapBlazor.csproj Bumps version from 10.1.5-beta03 to 10.1.5-beta04

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

}

private string? AddId => $"{Id}_new";

Copy link

Copilot AI Dec 26, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The CardUpload component is missing a DisposeAsync override to clean up validation resources, unlike AvatarUpload which implements it at lines 230-250 in AvatarUpload.razor.cs. This override should call ValidateModule.InvokeVoidAsync("disposeUpload", items) to properly clean up JavaScript validation resources when the component is disposed. Consider adding it after the AddId property.

Suggested change
/// <summary>
/// <inheritdoc/>
/// </summary>
/// <returns></returns>
public override async ValueTask DisposeAsync()
{
if (ValidateModule != null)
{
await ValidateModule.InvokeVoidAsync("disposeUpload", items);
}
await base.DisposeAsync();
}

Copilot uses AI. Check for mistakes.
Comment on lines +172 to +189
public override async Task ToggleMessage(IReadOnlyCollection<ValidationResult> results)
{
_results = results;
IsValid = results.Count == 0;

ValidateModule ??= await LoadValidateModule();

var invalidItems = IsInValidOnAddItem
? [new { Id = AddId, _results.First().ErrorMessage }]
: _results.Select(i => new { Id = i.MemberNames.FirstOrDefault(), i.ErrorMessage }).ToList();

var items = IsInValidOnAddItem
? [AddId]
: Files.Select(i => i.ValidateId).ToList();

var addId = IsInValidOnAddItem ? null : AddId;
await ValidateModule.InvokeVoidAsync("executeUpload", items, invalidItems, addId);
}
Copy link

Copilot AI Dec 26, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The new validation functionality added to CardUpload (ToggleMessage, ShowValidResult, RemoveValidResult methods) lacks test coverage. Similar functionality in AvatarUpload has comprehensive test coverage in test/UnitTest/Components/UploadAvatarTest.cs (lines 224-287). Consider adding similar tests to ensure the validation features work correctly.

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat(CardUpload): support ValidateForm validate function

2 participants