diff --git a/src/ZB.MOM.WW.ScadaBridge.CentralUI/Components/Shared/ParameterValueForm.razor b/src/ZB.MOM.WW.ScadaBridge.CentralUI/Components/Shared/ParameterValueForm.razor index 24ca8fe8..5117bc64 100644 --- a/src/ZB.MOM.WW.ScadaBridge.CentralUI/Components/Shared/ParameterValueForm.razor +++ b/src/ZB.MOM.WW.ScadaBridge.CentralUI/Components/Shared/ParameterValueForm.razor @@ -48,6 +48,13 @@ else [Parameter] public Dictionary Values { get; set; } = new(); [Parameter] public EventCallback> ValuesChanged { get; set; } + /// + /// Raised after every edit with true when the value tree has no parse or validation errors + /// (Flow Debugger script entry, design 2026-09-08 ยง5: the page gates Run on it). Additive; existing + /// callers ignore it. + /// + [Parameter] public EventCallback ValidChanged { get; set; } + private IReadOnlyList _shapes = Array.Empty(); private IReadOnlyList _topLevelFields = Array.Empty(); private InboundApiSchema? _rootSchema; @@ -620,8 +627,11 @@ else { Validate(); await ValuesChanged.InvokeAsync(Values); + await ValidChanged.InvokeAsync(IsValid); } + private bool IsValid => _parseErrors.Count == 0; + // Validates the whole value tree against the parsed schema and projects each // path-qualified error onto the input that owns it. Raw-text parse failures // (numeric / JSON) are added directly by the setters; schema validation adds diff --git a/tests/ZB.MOM.WW.ScadaBridge.CentralUI.Tests/Design/ParameterValueFormTests.cs b/tests/ZB.MOM.WW.ScadaBridge.CentralUI.Tests/Design/ParameterValueFormTests.cs index f968b3c8..023e2f0e 100644 --- a/tests/ZB.MOM.WW.ScadaBridge.CentralUI.Tests/Design/ParameterValueFormTests.cs +++ b/tests/ZB.MOM.WW.ScadaBridge.CentralUI.Tests/Design/ParameterValueFormTests.cs @@ -282,4 +282,19 @@ public class ParameterValueFormTests : BunitContext Assert.Single(cut.FindAll("button.param-list-remove")); Assert.NotEmpty(cut.FindAll(".text-danger")); } + + [Fact] + public void ValidChanged_ReportsFalseOnAParseError_AndTrueOnceFixed() + { + var valid = new List(); + var cut = Render(p => p + .Add(x => x.ParameterDefinitions, """{"type":"object","properties":{"n":{"type":"integer"}}}""") + .Add(x => x.ValidChanged, v => valid.Add(v))); + + var input = cut.Find("#param-n"); + input.Input("abc"); + Assert.False(valid.Last()); + input.Input("5"); + Assert.True(valid.Last()); + } }