Skip to content

Commit 3bcf24f

Browse files
authored
Show aggregate health status in the dashboard (#5770)
* Added the aggregated health state to the resource server protocol to enable showing it in the dashboard. - Don't show healthy/unhealthy, just use the heath state to show readiness in the dashboard UX. - Use an internal annotation to keep track of DCP resource names for state updates. - Publish health state updates to instances as well as the main resource.
1 parent 0490bcb commit 3bcf24f

37 files changed

+228
-13
lines changed

src/Aspire.Dashboard/Components/Controls/ResourceDetails.razor.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,8 @@ protected override void OnInitialized()
7474
new KnownProperty(KnownProperties.Resource.DisplayName, Loc[Resources.Resources.ResourcesDetailsDisplayNameProperty]),
7575
new KnownProperty(KnownProperties.Resource.State, Loc[Resources.Resources.ResourcesDetailsStateProperty]),
7676
new KnownProperty(KnownProperties.Resource.CreateTime, Loc[Resources.Resources.ResourcesDetailsStartTimeProperty]),
77-
new KnownProperty(KnownProperties.Resource.ExitCode, Loc[Resources.Resources.ResourcesDetailsExitCodeProperty])
77+
new KnownProperty(KnownProperties.Resource.ExitCode, Loc[Resources.Resources.ResourcesDetailsExitCodeProperty]),
78+
new KnownProperty(KnownProperties.Resource.HealthState, Loc[Resources.Resources.ResourcesDetailsHealthStateProperty])
7879
];
7980
_projectProperties =
8081
[

src/Aspire.Dashboard/Components/Pages/Resources.razor

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@
9494
<AspireTemplateColumn ColumnId="@NameColumn" ColumnManager="@_manager" Title="@ControlsStringsLoc[nameof(ControlsStrings.NameColumnHeader)]" Sortable="true" SortBy="@_nameSort" Tooltip="true" TooltipText="@(c => GetResourceName(c))">
9595
<ResourceNameDisplay Resource="context" FilterText="@_filter" FormatName="GetResourceName" />
9696
</AspireTemplateColumn>
97-
<AspireTemplateColumn ColumnId="@StateColumn" ColumnManager="@_manager" Title="@Loc[nameof(Dashboard.Resources.Resources.ResourcesStateColumnHeader)]" Sortable="true" SortBy="@_stateSort" Tooltip="true" TooltipText="@(c => c.State.Humanize())">
97+
<AspireTemplateColumn ColumnId="@StateColumn" ColumnManager="@_manager" Title="@Loc[nameof(Dashboard.Resources.Resources.ResourcesStateColumnHeader)]" Sortable="true" SortBy="@_stateSort" Tooltip="true" TooltipText="@(c => GetResourceStateTooltip(c))">
9898
<StateColumnDisplay Resource="@context" UnviewedErrorCounts="@_applicationUnviewedErrorCounts" />
9999
</AspireTemplateColumn>
100100
<AspireTemplateColumn ColumnId="@StartTimeColumn" ColumnManager="@_manager" Title="@Loc[nameof(Dashboard.Resources.Resources.ResourcesStartTimeColumnHeader)]" Sortable="true" SortBy="@_startTimeSort" TooltipText="@(context => context.CreationTimeStamp != null ? FormatHelpers.FormatDateTime(TimeProvider, context.CreationTimeStamp.Value, MillisecondsDisplay.None, CultureInfo.CurrentCulture) : null)" Tooltip="true">

src/Aspire.Dashboard/Components/Pages/Resources.razor.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
using Aspire.Dashboard.Otlp.Storage;
1212
using Aspire.Dashboard.Resources;
1313
using Aspire.Dashboard.Utils;
14+
using Humanizer;
1415
using Microsoft.AspNetCore.Components;
1516
using Microsoft.AspNetCore.Components.Server.ProtectedBrowserStorage;
1617
using Microsoft.FluentUI.AspNetCore.Components;
@@ -331,6 +332,11 @@ private async Task ExecuteResourceCommandAsync(ResourceViewModel resource, Comma
331332
}
332333
}
333334

335+
private static string GetResourceStateTooltip(ResourceViewModel resource) =>
336+
resource.ShowReadinessState() ?
337+
$"{resource.State.Humanize()} ({resource.ReadinessState.Humanize()})"
338+
: resource.State.Humanize();
339+
334340
private static (string Value, string? ContentAfterValue, string ValueToCopy, string Tooltip)? GetSourceColumnValueAndTooltip(ResourceViewModel resource)
335341
{
336342
// NOTE projects are also executables, so we have to check for projects first

src/Aspire.Dashboard/Components/ResourcesGridColumns/StateColumnDisplay.razor

Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
@using Aspire.Dashboard.Otlp.Model
44
@using Aspire.Dashboard.Otlp.Storage
55
@using Aspire.Dashboard.Resources
6+
@using Microsoft.Extensions.Diagnostics.HealthChecks
67
@using Humanizer
78

89
@inject IStringLocalizer<Columns> Loc
@@ -78,9 +79,20 @@ else if (!string.IsNullOrEmpty(Resource.StateStyle))
7879
}
7980
else
8081
{
81-
<FluentIcon Icon="Icons.Filled.Size16.CheckmarkCircle"
82-
Color="Color.Success"
83-
Class="severity-icon" />
82+
switch (Resource.ReadinessState)
83+
{
84+
// Unknown state is treated as ready state (we don't know if it's ready or not)
85+
case ReadinessState.Unknown or ReadinessState.Ready:
86+
<FluentIcon Icon="Icons.Filled.Size16.CheckmarkCircle"
87+
Color="Color.Success"
88+
Class="severity-icon" />
89+
break;
90+
default:
91+
<FluentIcon Icon="Icons.Regular.Size16.CheckmarkCircleWarning"
92+
Color="Color.Neutral"
93+
Class="severity-icon" />
94+
break;
95+
}
8496
}
8597

8698
@if (Resource.HasNoState())
@@ -89,7 +101,14 @@ else
89101
}
90102
else
91103
{
92-
<span>@Resource.State.Humanize()</span>
104+
if (Resource.ShowReadinessState())
105+
{
106+
<span>@Resource.State.Humanize() (@Resource.ReadinessState.Humanize())</span>
107+
}
108+
else
109+
{
110+
<span>@Resource.State.Humanize()</span>
111+
}
93112
}
94113

95114
<UnreadLogErrorsBadge UnviewedErrorCounts="UnviewedErrorCounts" Resource="@Resource" />

src/Aspire.Dashboard/Extensions/ResourceViewModelExtensions.cs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,4 +33,8 @@ public static bool IsStartingOrBuildingOrWaiting(this ResourceViewModel resource
3333
}
3434

3535
public static bool HasNoState(this ResourceViewModel resource) => string.IsNullOrEmpty(resource.State);
36+
37+
// We only care about the readiness state if the resource is running
38+
public static bool ShowReadinessState(this ResourceViewModel resource) =>
39+
resource.IsRunningState() && resource.ReadinessState is ReadinessState.NotReady;
3640
}

src/Aspire.Dashboard/Model/ResourceViewModel.cs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ public sealed class ResourceViewModel
2020
public required string Uid { get; init; }
2121
public required string? State { get; init; }
2222
public required string? StateStyle { get; init; }
23+
public required ReadinessState ReadinessState { get; init; }
2324
public required DateTime? CreationTimeStamp { get; init; }
2425
public required ImmutableArray<EnvironmentVariableViewModel> Environment { get; init; }
2526
public required ImmutableArray<UrlViewModel> Urls { get; init; }
@@ -60,6 +61,13 @@ public static string GetResourceName(ResourceViewModel resource, IDictionary<str
6061
}
6162
}
6263

64+
public enum ReadinessState
65+
{
66+
Unknown,
67+
NotReady,
68+
Ready
69+
}
70+
6371
[DebuggerDisplay("CommandType = {CommandType}, DisplayName = {DisplayName}")]
6472
public sealed class CommandViewModel
6573
{

src/Aspire.Dashboard/ResourceService/Partials.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,11 @@ public ResourceViewModel ToViewModel()
3131
State = HasState ? State : null,
3232
KnownState = HasState ? Enum.TryParse(State, out KnownResourceState knownState) ? knownState : null : null,
3333
StateStyle = HasStateStyle ? StateStyle : null,
34+
ReadinessState = HasHealthState ? HealthState switch
35+
{
36+
HealthStateKind.Healthy => ReadinessState.Ready,
37+
_ => ReadinessState.NotReady,
38+
} : ReadinessState.Unknown,
3439
Commands = GetCommands()
3540
};
3641
}

src/Aspire.Dashboard/Resources/Resources.Designer.cs

Lines changed: 9 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/Aspire.Dashboard/Resources/Resources.resx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -232,4 +232,7 @@
232232
<data name="ResourceDetailsViewConsoleLogs" xml:space="preserve">
233233
<value>View console logs</value>
234234
</data>
235+
<data name="ResourcesDetailsHealthStateProperty" xml:space="preserve">
236+
<value>Health State</value>
237+
</data>
235238
</root>

src/Aspire.Dashboard/Resources/xlf/Resources.cs.xlf

Lines changed: 5 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)