From d00f205f1d1bf4a761026561ffa3089f710d31d1 Mon Sep 17 00:00:00 2001 From: James Newton-King Date: Thu, 5 Feb 2026 13:36:13 +0800 Subject: [PATCH] Only export env values with FromSpec --- src/Aspire.Dashboard/Model/ExportHelpers.cs | 2 +- .../Model/ResourceMenuBuilder.cs | 2 +- .../Model/ExportHelpersTests.cs | 11 ++- .../Model/ResourceMenuBuilderTests.cs | 67 +++++++++++++++++++ 4 files changed, 78 insertions(+), 4 deletions(-) diff --git a/src/Aspire.Dashboard/Model/ExportHelpers.cs b/src/Aspire.Dashboard/Model/ExportHelpers.cs index 12d5e277cab..785acc8684c 100644 --- a/src/Aspire.Dashboard/Model/ExportHelpers.cs +++ b/src/Aspire.Dashboard/Model/ExportHelpers.cs @@ -79,7 +79,7 @@ public static ExportResult GetResourceAsJson(ResourceViewModel resource, IDictio /// A result containing the .env file content and suggested file name. public static ExportResult GetEnvironmentVariablesAsEnvFile(ResourceViewModel resource, IDictionary resourceByName) { - var envContent = EnvHelpers.ConvertToEnvFormat(resource.Environment.Select(e => new KeyValuePair(e.Name, e.Value))); + var envContent = EnvHelpers.ConvertToEnvFormat(resource.Environment.Where(e => e.FromSpec).Select(e => new KeyValuePair(e.Name, e.Value))); var fileName = $"{ResourceViewModel.GetResourceName(resource, resourceByName)}.env"; return new ExportResult(envContent, fileName); } diff --git a/src/Aspire.Dashboard/Model/ResourceMenuBuilder.cs b/src/Aspire.Dashboard/Model/ResourceMenuBuilder.cs index 325386ac05e..b8412e42c29 100644 --- a/src/Aspire.Dashboard/Model/ResourceMenuBuilder.cs +++ b/src/Aspire.Dashboard/Model/ResourceMenuBuilder.cs @@ -124,7 +124,7 @@ await TextVisualizerDialog.OpenDialogAsync(new OpenTextVisualizerDialogOptions } }); - if (resource.Environment.Length > 0) + if (resource.Environment.Any(e => e.FromSpec)) { menuItems.Add(new MenuButtonItem { diff --git a/tests/Aspire.Dashboard.Tests/Model/ExportHelpersTests.cs b/tests/Aspire.Dashboard.Tests/Model/ExportHelpersTests.cs index 500242982aa..6e7a3d9f3c8 100644 --- a/tests/Aspire.Dashboard.Tests/Model/ExportHelpersTests.cs +++ b/tests/Aspire.Dashboard.Tests/Model/ExportHelpersTests.cs @@ -42,7 +42,8 @@ public void GetEnvironmentVariablesAsEnvFile_ReturnsExpectedResult() resourceType: "Container", state: KnownResourceState.Running, environment: [ - new EnvironmentVariableViewModel("MY_VAR", "my-value", fromSpec: false) + new EnvironmentVariableViewModel("MY_VAR", "my-value", fromSpec: true), + new EnvironmentVariableViewModel("RUNTIME_VAR", "runtime-value", fromSpec: false) ]); var resourceByName = new Dictionary(StringComparer.OrdinalIgnoreCase) { [resource.Name] = resource }; @@ -52,6 +53,12 @@ public void GetEnvironmentVariablesAsEnvFile_ReturnsExpectedResult() // Assert Assert.Equal("Test Resource.env", result.FileName); - Assert.Contains("MY_VAR=my-value", result.Content); + Assert.Equal( + """ + MY_VAR=my-value + + """, + result.Content, + ignoreLineEndingDifferences: true); } } diff --git a/tests/Aspire.Dashboard.Tests/Model/ResourceMenuBuilderTests.cs b/tests/Aspire.Dashboard.Tests/Model/ResourceMenuBuilderTests.cs index 3decb32518c..62d1ce01296 100644 --- a/tests/Aspire.Dashboard.Tests/Model/ResourceMenuBuilderTests.cs +++ b/tests/Aspire.Dashboard.Tests/Model/ResourceMenuBuilderTests.cs @@ -183,6 +183,73 @@ public void AddMenuItems_HasTelemetry_TelemetryItems() e => Assert.Equal("Localized:ResourceActionMetricsText", e.Text)); } + [Fact] + public void AddMenuItems_WithFromSpecEnvVars_ExportEnvMenuItemShown() + { + // Arrange + var resource = ModelTestHelpers.CreateResource( + environment: [ + new EnvironmentVariableViewModel("SPEC_VAR", "spec-value", fromSpec: true), + new EnvironmentVariableViewModel("RUNTIME_VAR", "runtime-value", fromSpec: false) + ]); + var repository = TelemetryTestHelpers.CreateRepository(); + var aiContextProvider = new TestAIContextProvider(); + var resourceMenuBuilder = CreateResourceMenuBuilder(repository, aiContextProvider); + + // Act + var menuItems = new List(); + resourceMenuBuilder.AddMenuItems( + menuItems, + resource, + new Dictionary(StringComparer.OrdinalIgnoreCase) { [resource.Name] = resource }, + EventCallback.Empty, + EventCallback.Empty, + (_, _) => false, + showViewDetails: true, + showConsoleLogsItem: true, + showUrls: true); + + // Assert + Assert.Collection(menuItems, + e => Assert.Equal("Localized:ActionViewDetailsText", e.Text), + e => Assert.Equal("Localized:ResourceActionConsoleLogsText", e.Text), + e => Assert.Equal("Localized:ExportJson", e.Text), + e => Assert.Equal("Localized:ExportEnv", e.Text)); + } + + [Fact] + public void AddMenuItems_WithoutFromSpecEnvVars_ExportEnvMenuItemNotShown() + { + // Arrange - only runtime env vars (fromSpec: false), no spec env vars + var resource = ModelTestHelpers.CreateResource( + environment: [ + new EnvironmentVariableViewModel("RUNTIME_VAR1", "value1", fromSpec: false), + new EnvironmentVariableViewModel("RUNTIME_VAR2", "value2", fromSpec: false) + ]); + var repository = TelemetryTestHelpers.CreateRepository(); + var aiContextProvider = new TestAIContextProvider(); + var resourceMenuBuilder = CreateResourceMenuBuilder(repository, aiContextProvider); + + // Act + var menuItems = new List(); + resourceMenuBuilder.AddMenuItems( + menuItems, + resource, + new Dictionary(StringComparer.OrdinalIgnoreCase) { [resource.Name] = resource }, + EventCallback.Empty, + EventCallback.Empty, + (_, _) => false, + showViewDetails: true, + showConsoleLogsItem: true, + showUrls: true); + + // Assert - ExportEnv should NOT be in the menu + Assert.Collection(menuItems, + e => Assert.Equal("Localized:ActionViewDetailsText", e.Text), + e => Assert.Equal("Localized:ResourceActionConsoleLogsText", e.Text), + e => Assert.Equal("Localized:ExportJson", e.Text)); + } + private sealed class TestNavigationManager : NavigationManager { }