From 846ef1fb3fb326d6f53fb0a06bd0c8e0000142bc Mon Sep 17 00:00:00 2001 From: Adam Ratzman Date: Mon, 12 May 2025 17:02:58 -0300 Subject: [PATCH 1/2] Fix visibility updates during resource upserts --- src/Aspire.Dashboard/Components/Pages/Resources.razor.cs | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/Aspire.Dashboard/Components/Pages/Resources.razor.cs b/src/Aspire.Dashboard/Components/Pages/Resources.razor.cs index 339f076d5b2..ac05d337d59 100644 --- a/src/Aspire.Dashboard/Components/Pages/Resources.razor.cs +++ b/src/Aspire.Dashboard/Components/Pages/Resources.razor.cs @@ -244,9 +244,12 @@ async Task SubscribeResourcesAsync() { UpdateFromResource( resource, - t => AreAllTypesVisible, - s => AreAllStatesVisible, - s => AreAllHealthStatesVisible); + // The new type/state/health status should be visible if it's either + // 1) new, or + // 2) previously visible + t => !PageViewModel.ResourceTypesToVisibility.TryGetValue(t, out var value) || value, + s => !PageViewModel.ResourceStatesToVisibility.TryGetValue(s, out var value) || value, + s => !PageViewModel.ResourceHealthStatusesToVisibility.TryGetValue(s, out var value) || value); if (string.Equals(SelectedResource?.Name, resource.Name, StringComparisons.ResourceName)) { From 9fac7708bc7e502cc67e96a7da95ae90b5e57812 Mon Sep 17 00:00:00 2001 From: Adam Ratzman Date: Mon, 12 May 2025 17:19:51 -0300 Subject: [PATCH 2/2] Add unit test --- .../Pages/ResourcesTests.cs | 47 +++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/tests/Aspire.Dashboard.Components.Tests/Pages/ResourcesTests.cs b/tests/Aspire.Dashboard.Components.Tests/Pages/ResourcesTests.cs index 0fe5a9f0208..b1be71d4552 100644 --- a/tests/Aspire.Dashboard.Components.Tests/Pages/ResourcesTests.cs +++ b/tests/Aspire.Dashboard.Components.Tests/Pages/ResourcesTests.cs @@ -305,6 +305,53 @@ private static void AssertResourceFilterListEquals(IRenderedComponent + { + CreateResource("Resource1", "Type1", "Running", null), + CreateResource("Resource2", "Type2", "Stopping", null), + }; + var channel = Channel.CreateUnbounded>(); + var dashboardClient = new TestDashboardClient(isEnabled: true, initialResources: initialResources, resourceChannelProvider: () => channel); + + ResourceSetupHelpers.SetupResourcesPage(this, viewport, dashboardClient); + + var cut = RenderComponent(builder => + { + builder.AddCascadingValue(viewport); + }); + + // Open the resource filter and apply a filter + cut.Find("#resourceFilterButton").Click(); + cut.FindComponents>() + .First(f => f.Instance.Id == "resource-types") + .FindComponents() + .First(checkbox => checkbox.Instance.Label == "Type1") + .Find("fluent-checkbox") + .TriggerEvent("oncheckedchange", new CheckboxChangeEventArgs { Checked = false }); + + cut.WaitForState(() => cut.Instance.GetFilteredResources().Count() == 1); + + // Act + channel.Writer.TryWrite(new[] + { + new ResourceViewModelChange( + ResourceViewModelChangeType.Upsert, + CreateResource("Resource3", "Type3", "Running", null)) + }); + + cut.WaitForState(() => cut.Instance.GetFilteredResources().Count() == 2); + + // Assert + var filteredResources = cut.Instance.GetFilteredResources().ToList(); + Assert.Contains(filteredResources, r => r.Name == "Resource2"); + Assert.Contains(filteredResources, r => r.Name == "Resource3"); + } + private static ResourceViewModel CreateResource(string name, string type, string? state, ImmutableArray? healthReports) { return new ResourceViewModel