fix(core): replace archived Blazored.FluentValidation with Blazilla - #993
Conversation
Blazored.FluentValidation is unlisted on NuGet at every version and its repository is archived, so Elsa.Studio.Core handed every consumer a dependency that can never be fixed and that fails restore wherever unlisted packages are disallowed. Blazilla is the maintained, MIT-licensed equivalent and depends on exactly the FluentValidation 12.1.1 this repository already pins. Blazilla only executes asynchronous rules when AsyncMode is set, and it starts them from EditContext.Validate(), which returns before they finish. The create and clone workflow dialogs hold the only asynchronous rule in the solution - the workflow name uniqueness check - so both now submit through OnSubmit and await EditContext.ValidateAsync() there, which is what their Ok button already did. A native form submission (Enter in the name field) would otherwise create or clone a workflow under a name the uniqueness rule was about to reject. The other four forms validate synchronously and keep OnValidSubmit. Refs #934 Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…er the output dialog; align the input dialog validator setup Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…newline Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
There was a problem hiding this comment.
🟡 Changes recommended
Validator initialization, replaceable edit contexts, and stale asynchronous submissions can bypass validation or fail during rerenders.
Once you've addressed the issues Copilot identified, you can request another Copilot review.
Pull request overview
Replaces the archived FluentValidation integration with Blazilla and updates workflow and label forms to preserve synchronous and asynchronous validation behavior.
Changes:
- Replaces package references and Razor imports.
- Migrates six dialogs to
FluentValidator. - Adds workflow-dialog and metadata validation tests.
File summaries
| File | Description |
|---|---|
Directory.Packages.props |
Pins Blazilla 2.3.0. |
Elsa.Studio.sln.DotSettings |
Adds Blazilla to the dictionary. |
src/framework/Elsa.Studio.Core/Elsa.Studio.Core.csproj |
Replaces the archived dependency. |
src/modules/Elsa.Studio.Labels/_Imports.razor |
Imports Blazilla. |
src/modules/Elsa.Studio.Labels/UI/Components/CreateLabelDialog.razor |
Migrates the label validator component. |
src/modules/Elsa.Studio.Labels/UI/Components/CreateLabelDialog.razor.cs |
Uses EditContext.ValidateAsync. |
src/modules/Elsa.Studio.Workflows/_Imports.razor |
Imports Blazilla. |
src/modules/Elsa.Studio.Workflows/Components/WorkflowDefinitionList/CreateWorkflowDialog.razor |
Migrates create-form validation. |
src/modules/Elsa.Studio.Workflows/Components/WorkflowDefinitionList/CreateWorkflowDialog.razor.cs |
Awaits asynchronous submission validation. |
src/modules/Elsa.Studio.Workflows/Components/WorkflowDefinitionList/CloneWorkflowDialog.razor |
Migrates clone-form validation. |
src/modules/Elsa.Studio.Workflows/Components/WorkflowDefinitionList/CloneWorkflowDialog.razor.cs |
Awaits asynchronous submission validation. |
src/modules/Elsa.Studio.Workflows/Components/WorkflowDefinitionEditor/Components/WorkflowProperties/Tabs/InputOutput/Components/Inputs/EditInputDialog.razor |
Migrates input validation. |
src/modules/Elsa.Studio.Workflows/Components/WorkflowDefinitionEditor/Components/WorkflowProperties/Tabs/InputOutput/Components/Inputs/EditInputDialog.razor.cs |
Initializes validation earlier and validates via EditContext. |
src/modules/Elsa.Studio.Workflows/Components/WorkflowDefinitionEditor/Components/WorkflowProperties/Tabs/InputOutput/Components/Outputs/EditOutputDialog.razor |
Migrates output validation. |
src/modules/Elsa.Studio.Workflows/Components/WorkflowDefinitionEditor/Components/WorkflowProperties/Tabs/InputOutput/Components/Outputs/EditOutputDialog.razor.cs |
Validates through EditContext. |
src/modules/Elsa.Studio.Workflows/Components/WorkflowDefinitionEditor/Components/WorkflowProperties/Tabs/Variables/Components/EditVariableDialog.razor |
Migrates variable validation. |
src/modules/Elsa.Studio.Workflows/Components/WorkflowDefinitionEditor/Components/WorkflowProperties/Tabs/Variables/Components/EditVariableDialog.razor.cs |
Validates through EditContext. |
src/modules/Elsa.Studio.Workflows.Tests/WorkflowDialogValidationTests.cs |
Covers dialog submission paths. |
src/modules/Elsa.Studio.Workflows.Tests/WorkflowDefinitionMetadataTests.cs |
Adds metadata validation regressions. |
src/modules/Elsa.Studio.Workflows.Tests/Support/ControlledWorkflowDefinitionService.cs |
Provides controlled asynchronous test behavior. |
Review details
- Files reviewed: 20/20 changed files
- Comments generated: 8
- Review effort level: Balanced
💡 Add a code-review agent skill for context-aware, tailored reviews. Learn more in the docs.
…stale asynchronous submissions Guard CreateLabelDialog's form so it never renders before its validator is assigned, key the five affected dialogs' EditForm by their EditContext to match the metadata form's precedent for replaceable contexts, and make the create/clone workflow dialogs discard a submission if the bound name changes while the asynchronous uniqueness check is still pending. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
There was a problem hiding this comment.
🟡 Changes recommended
Label submission can bypass validation while initialization is pending, and input-dialog rerenders now repeat remote descriptor requests.
Once you've addressed the issues Copilot identified, you can request another Copilot review.
Review details
- Files reviewed: 20/20 changed files
- Comments generated: 2
- Review effort level: Balanced
… load input descriptors once CreateLabelDialog's Ok button stayed clickable while its FluentValidator was still loading, letting an empty label through since ValidateAsync() found no attached validator. EditInputDialog moved its descriptor loads into OnParametersSetAsync, causing the storage-driver and variable-type services to be re-fetched on every parent parameter update instead of once. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
There was a problem hiding this comment.
🟡 Changes recommended
Async validation races can bypass uniqueness checks, and the input dialog permits submission before required descriptors finish loading.
Once you've addressed the issues Copilot identified, you can request another Copilot review.
Review details
- Files reviewed: 20/20 changed files
- Comments generated: 3
- Review effort level: Balanced
…gate the input dialog on loaded descriptors Guard the input dialog's submit paths behind a flag that only flips once the descriptor lookups have populated the model, closing the window where a non-empty name could reach OnValidSubmit before Type/StorageDriver/UIHint were set. Make the create and clone workflow dialogs decide submission from a component-owned validator call instead of EditContext.ValidateAsync(), whose shared message store could be overwritten by a stale Blazilla field-change validation resolving after the submit's own check. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
There was a problem hiding this comment.
🟡 Changes recommended
The custom validation store can retain or publish stale workflow-name errors after the field changes.
Once you've addressed the issues Copilot identified, you can request another Copilot review.
Review details
- Files reviewed: 21/21 changed files
- Comments generated: 1
- Review effort level: Balanced
…hen the name changes Turn the static WorkflowMetadataValidation helper into an instance-scoped WorkflowMetadataSubmitValidator owned by each dialog's edit context. It now discards a validation result whose name no longer matches the model (instead of publishing it and letting the caller check afterward), and it clears its own message store on EditContext.OnFieldChanged so a duplicate-name message does not linger once the user edits the field, since Blazilla's field-change handler only clears its own store. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Purpose
Remove the unlisted, archived
Blazored.FluentValidationdependency fromElsa.Studio.Coreand migrate every form that used it to a maintained FluentValidation integration for Blazor, without weakening validation.Scope
Description
Problem
Elsa.Studio.Core(and transitively the WebAssembly core package) depended onBlazored.FluentValidation2.2.0. Every version of that package is unlisted on NuGet and its repository is archived, so consumers inherit an unfixable dependency and may fail restore where unlisted packages are disallowed.Replacement
Blazilla2.3.0 from LoreSoft: listed on NuGet, MIT, actively maintained (repository pushed this week, releases through 2.4.1), targets net8.0, net9.0, and net10.0, and depends on exactly the FluentValidation version this repo pins. 2.3.0 rather than 2.4.1 on purpose: 2.3.1 and later raise theMicrosoft.AspNetCore.Components.Webfloor above what this repo pins, which would force a Blazor runtime bump across all three target frameworks that this issue does not ask for. The diff between 2.3.0 and 2.4.1 is AOT and trimming annotations, an internal activation change, an extra overload, and dependency bumps; nothing used here changes. Upgrading later is a one-line dependency bump alongside the Components packages.Forms
Six forms used the old validator component: the create and clone workflow dialogs, the input, output, and variable dialogs, and the create label dialog. Each now uses
<FluentValidator>with a validator instance that exists before the validator component initializes. The old wrapper had an assembly-scanning fallback; the new one validates only through the supplied instance, so a missing instance would pass silently. That is why every form supplies one explicitly, and why the input dialog now constructs its edit context and validator before any await, as its sibling dialogs already did.The create and clone dialogs hold the solution's only asynchronous rule, the workflow-name uniqueness check. Blazor decides
OnValidSubmitfrom the synchronous validation result, which cannot see an in-flight async rule, so a native form submission (Enter in the name field) could create or clone before uniqueness resolved. Those two dialogs now submit throughOnSubmitand awaitEditContext.ValidateAsync()on both the form and the button path. The other four forms have purely synchronous rules and keepOnValidSubmit; if an async rule is ever added to them FluentValidation throws rather than skipping it.The metadata section of the workflow editor no longer references the old package on
main(it constructs its validator directly and keys its form since #991); two tests pin that it enforces the required name and survives a parent re-render. The draft PR #935 explored this migration; its four review findings are addressed here, and it also bumped the whole Components family, which this change avoids.Tests
WorkflowDialogValidationTests(16 tests): create and clone are blocked when the uniqueness rule resolves false and proceed when it resolves true, driven through both the form submission and the button, with the dialog asserted still open while validation is in flight; the input and output dialogs block an empty name and close on a valid one on both paths. Reverting the create and clone dialogs toOnValidSubmitfails exactly the two form-path cases. A shared controlled workflow-definition service stub serves these and the metadata tests.Verification
dotnet build Elsa.Studio.sln: 0 errors, 0 new warnings.dotnet test Elsa.Studio.sln: 1016 passed at the first commit;Elsa.Studio.Workflows.Testsnow 225 passed.git grepfor the old package and its component name returns nothing across the tree, including hosts and docs.Consumers that relied on the old package flowing transitively must switch to Blazilla's
<FluentValidator>, which is the intent of this change.Fixes #934
🤖 Generated with Claude Code