diff --git a/src/ZB.MOM.WW.ScadaBridge.CentralUI/Components/Dialogs/NodeBrowserDialog.razor b/src/ZB.MOM.WW.ScadaBridge.CentralUI/Components/Dialogs/NodeBrowserDialog.razor index 5d15697e..d3bee874 100644 --- a/src/ZB.MOM.WW.ScadaBridge.CentralUI/Components/Dialogs/NodeBrowserDialog.razor +++ b/src/ZB.MOM.WW.ScadaBridge.CentralUI/Components/Dialogs/NodeBrowserDialog.razor @@ -211,8 +211,15 @@ { node.Loading = true; StateHasChanged(); - var result = await BrowseService.BrowseChildrenAsync(_runtimeSiteId, _runtimeConnectionName, node.NodeId); - node.Loading = false; + BrowseNodeResult result; + try + { + result = await BrowseService.BrowseChildrenAsync(_runtimeSiteId, _runtimeConnectionName, node.NodeId); + } + finally + { + node.Loading = false; + } if (result.Failure is not null) { @@ -237,9 +244,16 @@ node.Loading = true; StateHasChanged(); - var result = await BrowseService.BrowseChildrenAsync( - _runtimeSiteId, _runtimeConnectionName, node.NodeId, node.ContinuationToken); - node.Loading = false; + BrowseNodeResult result; + try + { + result = await BrowseService.BrowseChildrenAsync( + _runtimeSiteId, _runtimeConnectionName, node.NodeId, node.ContinuationToken); + } + finally + { + node.Loading = false; + } if (result.Failure is not null) { @@ -266,6 +280,8 @@ _searchActive = false; _searchResults = new(); _searchCapReached = false; + _failure = null; + _failureMessage = ""; StateHasChanged(); return; } diff --git a/tests/ZB.MOM.WW.ScadaBridge.CentralUI.Tests/Components/NodeBrowserDialogSearchTests.cs b/tests/ZB.MOM.WW.ScadaBridge.CentralUI.Tests/Components/NodeBrowserDialogSearchTests.cs index 8c7e727b..9ee5c2d5 100644 --- a/tests/ZB.MOM.WW.ScadaBridge.CentralUI.Tests/Components/NodeBrowserDialogSearchTests.cs +++ b/tests/ZB.MOM.WW.ScadaBridge.CentralUI.Tests/Components/NodeBrowserDialogSearchTests.cs @@ -124,4 +124,32 @@ public class NodeBrowserDialogSearchTests : BunitContext cut.Find("[data-test=node-search-button]").Click(); Assert.Empty(cut.FindAll("[data-test=node-search-result]")); } + + [Fact] + public void BlankQueryAfterFailure_ClearsStaleFailureAlert() + { + // First search returns a failure so the alert banner appears. + _browse.SearchAsync( + Arg.Any(), Arg.Any(), Arg.Any(), + Arg.Any(), Arg.Any(), Arg.Any()) + .Returns(new SearchAddressSpaceResult( + Matches: Array.Empty(), + CapReached: false, + Failure: new BrowseFailure(BrowseFailureKind.Timeout, "timed out"))); + + var cut = RenderShown(out _); + + cut.Find("[data-test=node-search-input]").Input("Pump1"); + cut.Find("[data-test=node-search-button]").Click(); + + // The failure alert must be visible after the failed search. + Assert.NotEmpty(cut.FindAll(".alert-danger")); + + // User clears the query and searches again (blank). + cut.Find("[data-test=node-search-input]").Input(""); + cut.Find("[data-test=node-search-button]").Click(); + + // Stale failure alert must be gone. + Assert.Empty(cut.FindAll(".alert-danger")); + } }