diff --git a/playground/Stress/Stress.AppHost/Program.cs b/playground/Stress/Stress.AppHost/Program.cs index 3571dc38361..f4d0627ee2a 100644 --- a/playground/Stress/Stress.AppHost/Program.cs +++ b/playground/Stress/Stress.AppHost/Program.cs @@ -26,6 +26,8 @@ } } +builder.AddParameter("testParameterResource", () => "value", secret: true); + // TODO: OTEL env var can be removed when OTEL libraries are updated to 1.9.0 // See https://github.com/open-telemetry/opentelemetry-dotnet/blob/main/RELEASENOTES.md#1100 var serviceBuilder = builder.AddProject("stress-apiservice", launchProfileName: null) diff --git a/src/Aspire.Dashboard/Components/Pages/ConsoleLogs.razor.cs b/src/Aspire.Dashboard/Components/Pages/ConsoleLogs.razor.cs index 8972c2b28cb..ef8386fd010 100644 --- a/src/Aspire.Dashboard/Components/Pages/ConsoleLogs.razor.cs +++ b/src/Aspire.Dashboard/Components/Pages/ConsoleLogs.razor.cs @@ -393,7 +393,7 @@ internal static ImmutableList> GetConsoleLo var builder = ImmutableList.CreateBuilder>(); foreach (var grouping in resourcesByName - .Where(r => !r.Value.IsHiddenState()) + .Where(r => !r.Value.IsResourceHidden()) .OrderBy(c => c.Value, ResourceViewModelNameComparer.Instance) .GroupBy(r => r.Value.DisplayName, StringComparers.ResourceName)) { diff --git a/src/Aspire.Dashboard/Components/Pages/Resources.razor.cs b/src/Aspire.Dashboard/Components/Pages/Resources.razor.cs index 15de7c1fa58..23af2d5560c 100644 --- a/src/Aspire.Dashboard/Components/Pages/Resources.razor.cs +++ b/src/Aspire.Dashboard/Components/Pages/Resources.razor.cs @@ -118,7 +118,7 @@ private bool Filter(ResourceViewModel resource) && IsKeyValueTrue(resource.State ?? string.Empty, PageViewModel.ResourceStatesToVisibility) && IsKeyValueTrue(resource.HealthStatus?.Humanize() ?? string.Empty, PageViewModel.ResourceHealthStatusesToVisibility) && (_filter.Length == 0 || resource.MatchesFilter(_filter)) - && !resource.IsHiddenState(); + && !resource.IsResourceHidden(); static bool IsKeyValueTrue(string key, IDictionary dictionary) => dictionary.TryGetValue(key, out var value) && value; } @@ -451,7 +451,7 @@ private void UpdateMenuButtons() private bool HasCollapsedResources() { - return _resourceByName.Any(r => !r.Value.IsHiddenState() && _collapsedResourceNames.Contains(r.Key)); + return _resourceByName.Any(r => !r.Value.IsResourceHidden() && _collapsedResourceNames.Contains(r.Key)); } private void UpdateMaxHighlightedCount() @@ -619,7 +619,7 @@ private bool HasMultipleReplicas(ResourceViewModel resource) var count = 0; foreach (var (_, item) in _resourceByName) { - if (item.IsHiddenState()) + if (item.IsResourceHidden()) { continue; } @@ -693,7 +693,7 @@ private async Task OnToggleCollapse(ResourceGridViewModel viewModel) private async Task OnToggleCollapseAll() { var resourcesWithChildren = _resourceByName.Values - .Where(r => !r.IsHiddenState()) + .Where(r => !r.IsResourceHidden()) .Where(r => _resourceByName.Values.Any(nested => nested.GetResourcePropertyValue(KnownProperties.Resource.ParentName) == r.Name)) .ToList(); diff --git a/src/Aspire.Dashboard/Extensions/ResourceViewModelExtensions.cs b/src/Aspire.Dashboard/Extensions/ResourceViewModelExtensions.cs index 625c9becfa9..256c5717062 100644 --- a/src/Aspire.Dashboard/Extensions/ResourceViewModelExtensions.cs +++ b/src/Aspire.Dashboard/Extensions/ResourceViewModelExtensions.cs @@ -7,11 +7,6 @@ namespace Aspire.Dashboard.Extensions; internal static class ResourceViewModelExtensions { - public static bool IsHiddenState(this ResourceViewModel resource) - { - return resource.KnownState is KnownResourceState.Hidden; - } - public static bool IsRunningState(this ResourceViewModel resource) { return resource.KnownState is KnownResourceState.Running; diff --git a/src/Aspire.Dashboard/Model/ResourceGraph/ResourceGraphMapper.cs b/src/Aspire.Dashboard/Model/ResourceGraph/ResourceGraphMapper.cs index 0c73cc195fe..e3381f13115 100644 --- a/src/Aspire.Dashboard/Model/ResourceGraph/ResourceGraphMapper.cs +++ b/src/Aspire.Dashboard/Model/ResourceGraph/ResourceGraphMapper.cs @@ -24,7 +24,7 @@ public static ResourceDto MapResource(ResourceViewModel r, IDictionary string.Equals(r.DisplayName, resourceRelationships.Key, StringComparisons.ResourceName)) - .Where(r => r.KnownState != KnownResourceState.Hidden) + .Where(r => !r.IsResourceHidden()) .ToList(); foreach (var match in matches) diff --git a/src/Aspire.Dashboard/Model/ResourceViewModel.cs b/src/Aspire.Dashboard/Model/ResourceViewModel.cs index 8ab1d2bd5c1..16f49c60395 100644 --- a/src/Aspire.Dashboard/Model/ResourceViewModel.cs +++ b/src/Aspire.Dashboard/Model/ResourceViewModel.cs @@ -6,7 +6,6 @@ using System.Diagnostics.CodeAnalysis; using System.Globalization; using Aspire.Dashboard.Components.Controls; -using Aspire.Dashboard.Extensions; using Aspire.Dashboard.Utils; using Google.Protobuf.WellKnownTypes; using Humanizer; @@ -39,6 +38,7 @@ public sealed class ResourceViewModel public required ImmutableArray Commands { get; init; } /// The health status of the resource. indicates that health status is expected but not yet available. public HealthStatus? HealthStatus { get; private set; } + public bool IsHidden { private get; init; } public required ImmutableArray HealthReports { @@ -79,6 +79,11 @@ internal bool MatchesFilter(string filter) return null; } + public bool IsResourceHidden() + { + return IsHidden || KnownState is KnownResourceState.Hidden; + } + internal static HealthStatus? ComputeHealthStatus(ImmutableArray healthReports, KnownResourceState? state) { if (state != KnownResourceState.Running) @@ -100,7 +105,7 @@ public static string GetResourceName(ResourceViewModel resource, IDictionary vm.Name).ToImmutableArray(), + IsHidden = IsHidden }; } catch (Exception ex) diff --git a/src/Aspire.Hosting/ApplicationModel/CustomResourceSnapshot.cs b/src/Aspire.Hosting/ApplicationModel/CustomResourceSnapshot.cs index 4d0a859fced..7712e7f0737 100644 --- a/src/Aspire.Hosting/ApplicationModel/CustomResourceSnapshot.cs +++ b/src/Aspire.Hosting/ApplicationModel/CustomResourceSnapshot.cs @@ -123,6 +123,11 @@ internal init /// public ImmutableArray Relationships { get; init; } = []; + /// + /// Whether this resource should be hidden in UI. + /// + public bool IsHidden { get; init; } + internal static HealthStatus? ComputeHealthStatus(ImmutableArray healthReports, string? state) { if (state != KnownResourceStates.Running) @@ -337,6 +342,7 @@ public static class KnownResourceStates /// /// The hidden state. Useful for hiding the resource. /// + [Obsolete("Use CustomResourceSnapshot.Hidden instead.")] public static readonly string Hidden = nameof(Hidden); /// diff --git a/src/Aspire.Hosting/ConnectionStringBuilderExtensions.cs b/src/Aspire.Hosting/ConnectionStringBuilderExtensions.cs index a0a5cc5e54b..90e869fc51d 100644 --- a/src/Aspire.Hosting/ConnectionStringBuilderExtensions.cs +++ b/src/Aspire.Hosting/ConnectionStringBuilderExtensions.cs @@ -44,7 +44,9 @@ public static IResourceBuilder AddConnectionString(thi { ResourceType = "ConnectionString", // TODO: We'll hide this until we come up with a sane representation of these in the dashboard +#pragma warning disable CS0618 // Type or member is obsolete State = KnownResourceStates.Hidden, +#pragma warning restore CS0618 // Type or member is obsolete Properties = [] }); } diff --git a/src/Aspire.Hosting/Dashboard/DashboardLifecycleHook.cs b/src/Aspire.Hosting/Dashboard/DashboardLifecycleHook.cs index 2d22a5db2d1..3d14e14317e 100644 --- a/src/Aspire.Hosting/Dashboard/DashboardLifecycleHook.cs +++ b/src/Aspire.Hosting/Dashboard/DashboardLifecycleHook.cs @@ -173,7 +173,9 @@ private void ConfigureAspireDashboardResource(IResource dashboardResource) }, State = configuration.GetBool(KnownConfigNames.ShowDashboardResources, KnownConfigNames.Legacy.ShowDashboardResources) is true ? null +#pragma warning disable CS0618 // Type or member is obsolete : KnownResourceStates.Hidden +#pragma warning restore CS0618 // Type or member is obsolete }; dashboardResource.Annotations.Add(new ResourceSnapshotAnnotation(snapshot)); diff --git a/src/Aspire.Hosting/Dashboard/DashboardServiceData.cs b/src/Aspire.Hosting/Dashboard/DashboardServiceData.cs index 951315bf50d..e4ff8fe10d5 100644 --- a/src/Aspire.Hosting/Dashboard/DashboardServiceData.cs +++ b/src/Aspire.Hosting/Dashboard/DashboardServiceData.cs @@ -49,7 +49,8 @@ static GenericResourceSnapshot CreateResourceSnapshot(IResource resource, string State = snapshot.State?.Text, StateStyle = snapshot.State?.Style, HealthReports = snapshot.HealthReports, - Commands = snapshot.Commands + Commands = snapshot.Commands, + IsHidden = snapshot.IsHidden, }; } diff --git a/src/Aspire.Hosting/Dashboard/ResourceSnapshot.cs b/src/Aspire.Hosting/Dashboard/ResourceSnapshot.cs index 37e6c90b39a..9a7cc0ac0c5 100644 --- a/src/Aspire.Hosting/Dashboard/ResourceSnapshot.cs +++ b/src/Aspire.Hosting/Dashboard/ResourceSnapshot.cs @@ -28,6 +28,7 @@ internal abstract class ResourceSnapshot public required ImmutableArray Relationships { get; init; } public required ImmutableArray HealthReports { get; init; } public required ImmutableArray Commands { get; init; } + public required bool IsHidden { get; init; } protected abstract IEnumerable<(string Key, Value Value, bool IsSensitive)> GetProperties(); diff --git a/src/Aspire.Hosting/Dashboard/proto/Partials.cs b/src/Aspire.Hosting/Dashboard/proto/Partials.cs index c82e4df8661..c25a7b3dce4 100644 --- a/src/Aspire.Hosting/Dashboard/proto/Partials.cs +++ b/src/Aspire.Hosting/Dashboard/proto/Partials.cs @@ -18,6 +18,7 @@ public static Resource FromSnapshot(ResourceSnapshot snapshot) Uid = snapshot.Uid, State = snapshot.State ?? "", StateStyle = snapshot.StateStyle ?? "", + IsHidden = snapshot.IsHidden }; if (snapshot.CreationTimeStamp.HasValue) diff --git a/src/Aspire.Hosting/Dashboard/proto/resource_service.proto b/src/Aspire.Hosting/Dashboard/proto/resource_service.proto index 1ada7c5af89..78fcdb1300f 100644 --- a/src/Aspire.Hosting/Dashboard/proto/resource_service.proto +++ b/src/Aspire.Hosting/Dashboard/proto/resource_service.proto @@ -237,6 +237,9 @@ message Resource { // The list of relationships for this resource. repeated ResourceRelationship relationships = 20; + + // Whether the resource should be visually hidden in the dashboard. + bool is_hidden = 21; } //////////////////////////////////////////// diff --git a/src/Aspire.Hosting/Dcp/ResourceSnapshotBuilder.cs b/src/Aspire.Hosting/Dcp/ResourceSnapshotBuilder.cs index 4a0a97f0975..47f3436e883 100644 --- a/src/Aspire.Hosting/Dcp/ResourceSnapshotBuilder.cs +++ b/src/Aspire.Hosting/Dcp/ResourceSnapshotBuilder.cs @@ -24,7 +24,9 @@ public CustomResourceSnapshot ToSnapshot(Container container, CustomResourceSnap var volumes = GetVolumes(container); var environment = GetEnvironmentVariables(container.Status?.EffectiveEnv ?? container.Spec.Env, container.Spec.Env); +#pragma warning disable CS0618 // Type or member is obsolete var state = container.AppModelInitialState == KnownResourceStates.Hidden ? KnownResourceStates.Hidden : container.Status?.State; +#pragma warning restore CS0618 // Type or member is obsolete var relationships = ImmutableArray.Empty; diff --git a/src/Aspire.Hosting/ParameterResourceBuilderExtensions.cs b/src/Aspire.Hosting/ParameterResourceBuilderExtensions.cs index 7b8cfda9bb4..ab3e1f2db45 100644 --- a/src/Aspire.Hosting/ParameterResourceBuilderExtensions.cs +++ b/src/Aspire.Hosting/ParameterResourceBuilderExtensions.cs @@ -152,17 +152,19 @@ private static string GetParameterValue(ConfigurationManager configuration, stri configurationKey ??= $"Parameters:{name}"; return configuration[configurationKey] ?? parameterDefault?.GetDefaultValue() - ?? throw new DistributedApplicationException($"Parameter resource could not be used because configuration key '{configurationKey}' is missing and the Parameter has no default value."); ; + ?? throw new DistributedApplicationException($"Parameter resource could not be used because configuration key '{configurationKey}' is missing and the Parameter has no default value."); } internal static IResourceBuilder AddParameter(this IDistributedApplicationBuilder builder, T resource) where T : ParameterResource { - var state = new CustomResourceSnapshot() + var state = new CustomResourceSnapshot { ResourceType = "Parameter", // hide parameters by default +#pragma warning disable CS0618 // Type or member is obsolete State = KnownResourceStates.Hidden, +#pragma warning restore CS0618 // Type or member is obsolete Properties = [ new("parameter.secret", resource.Secret.ToString()), new(CustomResourceKnownProperties.Source, resource.ConfigurationKey) diff --git a/tests/Aspire.Dashboard.Components.Tests/Pages/ResourcesTests.cs b/tests/Aspire.Dashboard.Components.Tests/Pages/ResourcesTests.cs index 46dee0f9c9e..0fe5a9f0208 100644 --- a/tests/Aspire.Dashboard.Components.Tests/Pages/ResourcesTests.cs +++ b/tests/Aspire.Dashboard.Components.Tests/Pages/ResourcesTests.cs @@ -328,6 +328,7 @@ private static ResourceViewModel CreateResource(string name, string type, string Relationships = default, Properties = ImmutableDictionary.Empty, Commands = [], + IsHidden = false, }; } } diff --git a/tests/Aspire.Hosting.Tests/Dashboard/ResourcePublisherTests.cs b/tests/Aspire.Hosting.Tests/Dashboard/ResourcePublisherTests.cs index 34d59ca3e8a..9e0f1df4501 100644 --- a/tests/Aspire.Hosting.Tests/Dashboard/ResourcePublisherTests.cs +++ b/tests/Aspire.Hosting.Tests/Dashboard/ResourcePublisherTests.cs @@ -202,7 +202,8 @@ private static GenericResourceSnapshot CreateResourceSnapshot(string name) Environment = [], HealthReports = [], Commands = [], - Relationships = [] + Relationships = [], + IsHidden = false }; } diff --git a/tests/Aspire.Playground.Tests/Infrastructure/DistributedApplicationExtensions.cs b/tests/Aspire.Playground.Tests/Infrastructure/DistributedApplicationExtensions.cs index 83d90d40c8b..448a29d6f32 100644 --- a/tests/Aspire.Playground.Tests/Infrastructure/DistributedApplicationExtensions.cs +++ b/tests/Aspire.Playground.Tests/Infrastructure/DistributedApplicationExtensions.cs @@ -89,6 +89,7 @@ public static Task WaitForResource(this DistributedApplication app, string resou return app.ResourceNotifications.WaitForResourceAsync(resourceName, targetState, cancellationToken); } +#pragma warning disable CS0618 // Type or member is obsolete /// /// Waits for all resources in the application to reach one of the specified states. /// @@ -102,6 +103,7 @@ public static Task WaitForResources(this DistributedApplication app, IEnumerable return Task.WhenAll(applicationModel.Resources.Select(r => app.ResourceNotifications.WaitForResourceAsync(r.Name, targetStates, cancellationToken))); } +#pragma warning restore CS0618 // Type or member is obsolete /// /// Gets the app host and resource logs from the application. diff --git a/tests/Shared/DashboardModel/ModelTestHelpers.cs b/tests/Shared/DashboardModel/ModelTestHelpers.cs index 197107722b4..236c2b21ec9 100644 --- a/tests/Shared/DashboardModel/ModelTestHelpers.cs +++ b/tests/Shared/DashboardModel/ModelTestHelpers.cs @@ -21,7 +21,8 @@ public static ResourceViewModel CreateResource( HealthStatus? reportHealthStatus = null, bool createNullHealthReport = false, ImmutableArray? commands = null, - ImmutableArray? relationships = null) + ImmutableArray? relationships = null, + bool hidden = false) { return new ResourceViewModel { @@ -42,6 +43,7 @@ public static ResourceViewModel CreateResource( HealthReports = reportHealthStatus is null && !createNullHealthReport ? [] : [new HealthReportViewModel("healthcheck", reportHealthStatus, null, null)], Commands = commands ?? [], Relationships = relationships ?? [], + IsHidden = hidden }; } }