diff --git a/src/Aspire.Dashboard/Components/Controls/Chart/ChartContainer.razor b/src/Aspire.Dashboard/Components/Controls/Chart/ChartContainer.razor index 68758ebe08..eb4262ae75 100644 --- a/src/Aspire.Dashboard/Components/Controls/Chart/ChartContainer.razor +++ b/src/Aspire.Dashboard/Components/Controls/Chart/ChartContainer.razor @@ -31,7 +31,7 @@ else Id="@($"tab-{Metrics.MetricViewKind.Table}")" Label="@Loc[nameof(ControlsStrings.ChartContainerTableTab)]" Icon="@(new Icons.Regular.Size24.Table())"> -
+
diff --git a/src/Aspire.Dashboard/Components/Controls/Chart/MetricTable.razor b/src/Aspire.Dashboard/Components/Controls/Chart/MetricTable.razor index 9deef0382e..ac621677f4 100644 --- a/src/Aspire.Dashboard/Components/Controls/Chart/MetricTable.razor +++ b/src/Aspire.Dashboard/Components/Controls/Chart/MetricTable.razor @@ -18,7 +18,7 @@ } } -
+
@* ItemKey is to preserve row focus by associating rows with their associated time *@
- + + Label="@Loc[nameof(ControlsStrings.MetricTableShowOnlyValueChanges)]" /> diff --git a/src/Aspire.Dashboard/Components/Controls/Chart/PlotlyChart.razor b/src/Aspire.Dashboard/Components/Controls/Chart/PlotlyChart.razor index 6673a1674f..6063419298 100644 --- a/src/Aspire.Dashboard/Components/Controls/Chart/PlotlyChart.razor +++ b/src/Aspire.Dashboard/Components/Controls/Chart/PlotlyChart.razor @@ -1,6 +1,5 @@ -@using Aspire.Dashboard.Resources -@namespace Aspire.Dashboard.Components +@namespace Aspire.Dashboard.Components @inherits Aspire.Dashboard.Components.Controls.Chart.ChartBase; -
+
diff --git a/src/Aspire.Dashboard/Components/Controls/Chart/PlotlyChart.razor.cs b/src/Aspire.Dashboard/Components/Controls/Chart/PlotlyChart.razor.cs index d15e5db4d2..8f4652bd0c 100644 --- a/src/Aspire.Dashboard/Components/Controls/Chart/PlotlyChart.razor.cs +++ b/src/Aspire.Dashboard/Components/Controls/Chart/PlotlyChart.razor.cs @@ -5,6 +5,7 @@ using System.Globalization; using System.Web; using Aspire.Dashboard.Components.Controls.Chart; +using Aspire.Dashboard.Components.Resize; using Aspire.Dashboard.Extensions; using Aspire.Dashboard.Model; using Aspire.Dashboard.Model.Otlp; @@ -32,6 +33,9 @@ public partial class PlotlyChart : ChartBase public string ChartDivId { get; } = $"plotly-chart-container-{Interlocked.Increment(ref s_nextChartId)}"; + [CascadingParameter] + public required ViewportInformation ViewportInformation { get; init; } + private DotNetObjectReference? _chartInteropReference; private IJSObjectReference? _jsModule; diff --git a/src/Aspire.Dashboard/Components/Controls/Grid/AspirePropertyColumn.cs b/src/Aspire.Dashboard/Components/Controls/Grid/AspirePropertyColumn.cs index 87845231de..eb2aa08986 100644 --- a/src/Aspire.Dashboard/Components/Controls/Grid/AspirePropertyColumn.cs +++ b/src/Aspire.Dashboard/Components/Controls/Grid/AspirePropertyColumn.cs @@ -1,14 +1,39 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. + +using Microsoft.AspNetCore.Components; using Microsoft.FluentUI.AspNetCore.Components; namespace Aspire.Dashboard.Components.Controls.Grid; -public class AspirePropertyColumn : PropertyColumn +public class AspirePropertyColumn : PropertyColumn, IAspireColumn { + [Parameter] + public GridColumnManager? ColumnManager { get; set; } + + [Parameter] + public string? ColumnId { get; set; } + + [Parameter] + public bool UseCustomHeaderTemplate { get; set; } = true; + protected override void OnParametersSet() { - HeaderCellItemTemplate = AspireFluentDataGridHeaderCell.RenderHeaderContent(Grid); base.OnParametersSet(); + + if (UseCustomHeaderTemplate) + { + HeaderCellItemTemplate = AspireFluentDataGridHeaderCell.RenderHeaderContent(Grid); + } + } + + protected override bool ShouldRender() + { + if (ColumnManager is not null && ColumnId is not null && !ColumnManager.IsColumnVisible(ColumnId)) + { + return false; + } + + return base.ShouldRender(); } } diff --git a/src/Aspire.Dashboard/Components/Controls/Grid/AspireTemplateColumn.cs b/src/Aspire.Dashboard/Components/Controls/Grid/AspireTemplateColumn.cs index 959cd2691a..cbb3c55acb 100644 --- a/src/Aspire.Dashboard/Components/Controls/Grid/AspireTemplateColumn.cs +++ b/src/Aspire.Dashboard/Components/Controls/Grid/AspireTemplateColumn.cs @@ -1,14 +1,39 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. + +using Microsoft.AspNetCore.Components; using Microsoft.FluentUI.AspNetCore.Components; namespace Aspire.Dashboard.Components.Controls.Grid; -public class AspireTemplateColumn : TemplateColumn +public class AspireTemplateColumn : TemplateColumn, IAspireColumn { + [Parameter] + public GridColumnManager? ColumnManager { get; set; } + + [Parameter] + public string? ColumnId { get; set; } + + [Parameter] + public bool UseCustomHeaderTemplate { get; set; } = true; + protected override void OnParametersSet() { - HeaderCellItemTemplate = AspireFluentDataGridHeaderCell.RenderHeaderContent(Grid); base.OnParametersSet(); + + if (UseCustomHeaderTemplate) + { + HeaderCellItemTemplate = AspireFluentDataGridHeaderCell.RenderHeaderContent(Grid); + } + } + + protected override bool ShouldRender() + { + if (ColumnManager is not null && ColumnId is not null && !ColumnManager.IsColumnVisible(ColumnId)) + { + return false; + } + + return base.ShouldRender(); } } diff --git a/src/Aspire.Dashboard/Components/Controls/Grid/IAspireColumn.cs b/src/Aspire.Dashboard/Components/Controls/Grid/IAspireColumn.cs new file mode 100644 index 0000000000..667649c1ae --- /dev/null +++ b/src/Aspire.Dashboard/Components/Controls/Grid/IAspireColumn.cs @@ -0,0 +1,13 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +namespace Aspire.Dashboard.Components.Controls.Grid; + +internal interface IAspireColumn +{ + public GridColumnManager? ColumnManager { get; set; } + + public string? ColumnId { get; set; } + + public bool UseCustomHeaderTemplate { get; set; } +} diff --git a/src/Aspire.Dashboard/Components/Controls/GridValue.razor.cs b/src/Aspire.Dashboard/Components/Controls/GridValue.razor.cs index aa40adfaa3..8e7e9280af 100644 --- a/src/Aspire.Dashboard/Components/Controls/GridValue.razor.cs +++ b/src/Aspire.Dashboard/Components/Controls/GridValue.razor.cs @@ -75,7 +75,7 @@ public partial class GridValue public required IJSRuntime JS { get; init; } [CascadingParameter] - public required ViewportInformation ViewportInformation { get; init; } + public required ViewportInformation ViewportInformation { get; set; } private readonly Icon _maskIcon = new Icons.Regular.Size16.EyeOff(); private readonly Icon _unmaskIcon = new Icons.Regular.Size16.Eye(); diff --git a/src/Aspire.Dashboard/Components/Controls/TreeMetricSelector.razor b/src/Aspire.Dashboard/Components/Controls/TreeMetricSelector.razor new file mode 100644 index 0000000000..44db1aaf44 --- /dev/null +++ b/src/Aspire.Dashboard/Components/Controls/TreeMetricSelector.razor @@ -0,0 +1,23 @@ +@using Aspire.Dashboard.Components.Pages + + + + @foreach (var meterGroup in PageViewModel.Instruments!.GroupBy(i => i.Parent).OrderBy(g => g.Key.MeterName)) + { + + @foreach (var instrument in meterGroup.OrderBy(i => i.Name)) + { + + } + + } + + + +@code { + [Parameter, EditorRequired] + public required Func HandleSelectedTreeItemChangedAsync { get; set; } + + [Parameter, EditorRequired] + public required Metrics.MetricsViewModel PageViewModel { get; set; } +} diff --git a/src/Aspire.Dashboard/Components/Layout/AspirePageContentLayout.razor b/src/Aspire.Dashboard/Components/Layout/AspirePageContentLayout.razor index 49f60eeb8c..7ab2daf931 100644 --- a/src/Aspire.Dashboard/Components/Layout/AspirePageContentLayout.razor +++ b/src/Aspire.Dashboard/Components/Layout/AspirePageContentLayout.razor @@ -7,7 +7,7 @@ @if (ViewportInformation.IsDesktop) { -
+
@if (AddNewlineOnToolbar) { @PageTitleSection @@ -27,7 +27,7 @@ } else if (!IsSummaryDetailsViewOpen) { -
+
@PageTitleSection @@ -39,7 +39,7 @@ @if (AddNewlineOnToolbar) { -
@MobilePageTitleToolbarSection
+
@MobilePageTitleToolbarSection
}
} diff --git a/src/Aspire.Dashboard/Components/Layout/AspirePageContentLayout.razor.cs b/src/Aspire.Dashboard/Components/Layout/AspirePageContentLayout.razor.cs index c5ff2cbd12..b014e459c7 100644 --- a/src/Aspire.Dashboard/Components/Layout/AspirePageContentLayout.razor.cs +++ b/src/Aspire.Dashboard/Components/Layout/AspirePageContentLayout.razor.cs @@ -77,7 +77,7 @@ private string GetMobileMainStyle() return style; } - private async Task OpenMobileToolbarAsync() + public async Task OpenMobileToolbarAsync() { _toolbarPanel = await DialogService.ShowPanelAsync( new MobileToolbar( diff --git a/src/Aspire.Dashboard/Components/Layout/AspirePageContentLayout.razor.css b/src/Aspire.Dashboard/Components/Layout/AspirePageContentLayout.razor.css index 43ca0f72b9..ffb80f5276 100644 --- a/src/Aspire.Dashboard/Components/Layout/AspirePageContentLayout.razor.css +++ b/src/Aspire.Dashboard/Components/Layout/AspirePageContentLayout.razor.css @@ -11,6 +11,15 @@ grid-template-rows: auto 1fr auto; } +::deep.content-header { + /* + Long titles inside a header don't add an ellipsis when trimmed. + Improve here could be to add that feature + */ + grid-area: page-header; + white-space: nowrap; +} + ::deep .title-toolbar-inline { padding-left: 0px; padding-top: 0px; diff --git a/src/Aspire.Dashboard/Components/Pages/ConsoleLogs.razor b/src/Aspire.Dashboard/Components/Pages/ConsoleLogs.razor index b8fcfcd842..d2ae3d70fa 100644 --- a/src/Aspire.Dashboard/Components/Pages/ConsoleLogs.razor +++ b/src/Aspire.Dashboard/Components/Pages/ConsoleLogs.razor @@ -12,7 +12,8 @@ + MainContentStyle="margin-top: 10px;" + MobileToolbarButtonText="@Loc[nameof(Dashboard.Resources.ConsoleLogs.ConsoleLogsSelectResourceToolbar)]">

@Loc[nameof(Dashboard.Resources.ConsoleLogs.ConsoleLogsHeader)]

diff --git a/src/Aspire.Dashboard/Components/Pages/Metrics.razor b/src/Aspire.Dashboard/Components/Pages/Metrics.razor index 5c8d5a8450..d79258653f 100644 --- a/src/Aspire.Dashboard/Components/Pages/Metrics.razor +++ b/src/Aspire.Dashboard/Components/Pages/Metrics.razor @@ -5,8 +5,8 @@ @using Aspire.Dashboard.Components.Controls.Grid @using Aspire.Dashboard.Model.Otlp -@using Aspire.Dashboard.Resources @using Aspire.Dashboard.Otlp.Model +@using Aspire.Dashboard.Resources @using Aspire.Dashboard.Utils @inject IStringLocalizer Loc @inject IStringLocalizer ControlsStringsLoc @@ -17,7 +17,8 @@ + HeaderStyle="margin-bottom: calc(var(--design-unit) * 2px);" + MobileToolbarButtonText="@Loc[nameof(Dashboard.Resources.Metrics.MetricsViewAttributesToolbar)]">

@Loc[nameof(Dashboard.Resources.Metrics.MetricsHeader)]

@@ -27,33 +28,44 @@ @bind-SelectedResource="PageViewModel.SelectedApplication" @bind-SelectedResource:after="HandleSelectedApplicationChangedAsync" CanSelectGrouping="true" /> - + @if (!ViewportInformation.IsDesktop) + { + + } + + + @if (!ViewportInformation.IsDesktop && PageViewModel.Instruments?.Count > 0) + { + // Show metric selector in the toolbar for mobile, since we don't have enough room to show both + // panels on a mobile viewport. + + + }
@if (PageViewModel.Instruments?.Count > 0) { - + // Collapsed property only allows us to show Panel1 (which is the metric selector) + // but we want to only show Panel2 on mobile. So, hide the bar handle and reduce width to 0 + // on mobile. + - - - @foreach (var meterGroup in PageViewModel.Instruments.GroupBy(i => i.Parent).OrderBy(g => g.Key.MeterName)) - { - - @foreach (var instrument in meterGroup.OrderBy(i => i.Name)) - { - - } - - } - - +
@@ -65,13 +77,13 @@ MeterName="@(PageViewModel.SelectedMeter.MeterName)" InstrumentName="@(PageViewModel.SelectedInstrument.Name)" Duration="PageViewModel.SelectedDuration.Id" - ActiveView="@(PageViewModel.SelectedViewKind ?? MetricViewKind.Graph)" + ActiveView="@(PageViewModel.SelectedViewKind ?? Metrics.MetricViewKind.Graph)" OnViewChangedAsync="@OnViewChangedAsync" - Applications="_applications" /> + Applications="@_applications" /> } else if (PageViewModel.SelectedMeter != null) { -

@PageViewModel.SelectedMeter.MeterName

+

@PageViewModel.SelectedMeter.MeterName

@Loc[nameof(Dashboard.Resources.Metrics.MetricsSelectInstrument)]

+ @if (ViewportInformation.IsDesktop) + { +

@Loc[nameof(Dashboard.Resources.Metrics.MetricsSelectInstrument)]

+ } + else + { + // class needed to prevent color from being removed from reboot style + + @Loc[nameof(Dashboard.Resources.Metrics.MetricsSelectInstrument)] + + } }
@@ -101,7 +123,16 @@ else if (PageViewModel.Instruments == null) {
-  @Loc[nameof(Dashboard.Resources.Metrics.MetricsSelectAResource)] + @if (ViewportInformation.IsDesktop) + { + @:  + @Loc[nameof(Dashboard.Resources.Metrics.MetricsSelectAResource)] + } + else + { + @:  + @Loc[nameof(Dashboard.Resources.Metrics.MetricsSelectAResource)] + }
} else diff --git a/src/Aspire.Dashboard/Components/Pages/Metrics.razor.cs b/src/Aspire.Dashboard/Components/Pages/Metrics.razor.cs index 1ea3236f07..e971771ac3 100644 --- a/src/Aspire.Dashboard/Components/Pages/Metrics.razor.cs +++ b/src/Aspire.Dashboard/Components/Pages/Metrics.razor.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. using Aspire.Dashboard.Components.Layout; +using Aspire.Dashboard.Components.Resize; using Aspire.Dashboard.Model; using Aspire.Dashboard.Model.Otlp; using Aspire.Dashboard.Otlp.Model; @@ -60,6 +61,9 @@ public partial class Metrics : IDisposable, IPageWithSessionAndUrlState Logger { get; init; } + [CascadingParameter] + public required ViewportInformation ViewportInformation { get; init; } + protected override Task OnInitializedAsync() { _durations = new List> @@ -160,7 +164,10 @@ private Task HandleSelectedApplicationChangedAsync() } } - return this.AfterViewModelChangedAsync(_contentLayout, isChangeInToolbar: true); + // On mobile, we actually *do* want to update the selected application immediately, since it will affect the tree of possible + // metrics to select from. So, we must also immediately close the window since the closing behavior is necessary if the url has changed. + var isChangeInToolbar = ViewportInformation.IsDesktop; + return this.AfterViewModelChangedAsync(_contentLayout, isChangeInToolbar: isChangeInToolbar); } private bool ShouldClearSelectedMetrics(List instruments) @@ -226,7 +233,7 @@ private Task HandleSelectedTreeItemChangedAsync() PageViewModel.SelectedInstrument = null; } - return this.AfterViewModelChangedAsync(_contentLayout, isChangeInToolbar: false); + return this.AfterViewModelChangedAsync(_contentLayout, isChangeInToolbar: !ViewportInformation.IsDesktop); } public string GetUrlFromSerializableViewModel(MetricsPageState serializable) diff --git a/src/Aspire.Dashboard/Components/Pages/Metrics.razor.css b/src/Aspire.Dashboard/Components/Pages/Metrics.razor.css index 9daf9ce751..ec1fc3e48b 100644 --- a/src/Aspire.Dashboard/Components/Pages/Metrics.razor.css +++ b/src/Aspire.Dashboard/Components/Pages/Metrics.razor.css @@ -7,6 +7,12 @@ font-weight: 600; } +::deep .meter-name-title { + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + /* Metrics chart SVG */ ::deep .yaxislayer-above { transform: translate(-10px,0px); @@ -24,11 +30,23 @@ "chart"; width: 100%; gap: calc(var(--design-unit) * 4px); - padding-left: 40px; +} + +@media (min-width: 768px) { + ::deep .metrics-chart { + padding-left: 40px; + } } ::deep .metrics-chart-header { grid-area: header; + overflow-x: hidden; +} + +::deep .metrics-chart-header h3 { + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; } ::deep .metrics-chart-container { @@ -71,7 +89,21 @@ } ::deep .plotly-chart-container { - margin-left: -40px; + width: 100%; + max-width: 650px; + aspect-ratio: 13 / 9; +} + +@media (min-width: 768px) { + ::deep .plotly-chart-container { + margin-left: -40px; + } +} + +@media (max-width: 768px) { + ::deep .plotly-chart-container { + margin-left: -20px; + } } ::deep .metric-info-icon { diff --git a/src/Aspire.Dashboard/Components/Pages/Resources.razor b/src/Aspire.Dashboard/Components/Pages/Resources.razor index 119d43c5ee..227c78e5d9 100644 --- a/src/Aspire.Dashboard/Components/Pages/Resources.razor +++ b/src/Aspire.Dashboard/Components/Pages/Resources.razor @@ -1,10 +1,10 @@ @page "/" @using Aspire.Dashboard.Components.ResourcesGridColumns -@using Aspire.Dashboard.Model @using Aspire.Dashboard.Resources @using Aspire.Dashboard.Utils @using System.Globalization @using Aspire.Dashboard.Components.Controls.Grid +@using Aspire.Dashboard.Model @using Humanizer @inject IStringLocalizer Loc @inject IStringLocalizer ControlsStringsLoc @@ -37,11 +37,12 @@
@Loc[nameof(Dashboard.Resources.Resources.ResourcesResourceTypesHeader)]
- +
} @@ -57,11 +58,12 @@
@Loc[nameof(Dashboard.Resources.Resources.ResourcesResourceTypesHeader)]
- +
@@ -81,7 +83,7 @@ ItemSize="46" Items="@FilteredResources" ResizableColumns="true" - GridTemplateColumns="@gridTemplateColumns" + GridTemplateColumns="@_manager.GetGridTemplateColumns()" RowClass="GetRowClass" Loading="_isLoading" ShowHover="true" @@ -89,32 +91,32 @@ OnRowClick="@(r => r.ExecuteOnDefault(d => ShowResourceDetailsAsync(d, buttonId: null)))" Class="enable-row-click"> - - + + - + - + - + @if (GetSourceColumnValueAndTooltip(context) is { } columnDisplay) { } - + - + @ControlsStringsLoc[ControlsStrings.ViewAction] - + @{ var id = $"details-button-{context.Uid}"; } @@ -125,15 +127,12 @@ OnClick="@(() => ShowResourceDetailsAsync(context, id))">@ControlsStringsLoc[nameof(ControlsStrings.ViewAction)]
- @if (HasResourcesWithCommands) - { - -
- -
-
- } + +
+ +
+
 @Loc[nameof(Dashboard.Resources.Resources.ResourcesNoResources)] diff --git a/src/Aspire.Dashboard/Components/Pages/Resources.razor.cs b/src/Aspire.Dashboard/Components/Pages/Resources.razor.cs index 87dc9f448a..1210907ee9 100644 --- a/src/Aspire.Dashboard/Components/Pages/Resources.razor.cs +++ b/src/Aspire.Dashboard/Components/Pages/Resources.razor.cs @@ -21,6 +21,16 @@ namespace Aspire.Dashboard.Components.Pages; public partial class Resources : ComponentBase, IAsyncDisposable { + private const string TypeColumn = nameof(TypeColumn); + private const string NameColumn = nameof(NameColumn); + private const string StateColumn = nameof(StateColumn); + private const string StartTimeColumn = nameof(StartTimeColumn); + private const string SourceColumn = nameof(SourceColumn); + private const string EndpointsColumn = nameof(EndpointsColumn); + private const string LogsColumn = nameof(LogsColumn); + private const string DetailsColumn = nameof(DetailsColumn); + private const string CommandsColumn = nameof(CommandsColumn); + private Subscription? _logsSubscription; private Dictionary? _applicationUnviewedErrorCounts; @@ -40,9 +50,11 @@ public partial class Resources : ComponentBase, IAsyncDisposable public required IJSRuntime JS { get; init; } [Inject] public required ProtectedSessionStorage SessionStorage { get; init; } + [Inject] + public required DimensionManager DimensionManager { get; init; } [CascadingParameter] - public required ViewportInformation ViewportInformation { get; init; } + public required ViewportInformation ViewportInformation { get; set; } [Parameter] [SupplyParameterFromQuery] @@ -59,6 +71,7 @@ public partial class Resources : ComponentBase, IAsyncDisposable private Task? _resourceSubscriptionTask; private bool _isLoading = true; private string? _elementIdBeforeDetailsViewOpened; + private GridColumnManager _manager = null!; private bool Filter(ResourceViewModel resource) => _visibleResourceTypes.ContainsKey(resource.ResourceType) && (_filter.Length == 0 || resource.MatchesFilter(_filter)) && !resource.IsHiddenState(); @@ -136,6 +149,18 @@ static bool UnionWithKeys(ConcurrentDictionary left, ConcurrentDic protected override async Task OnInitializedAsync() { + _manager = new GridColumnManager([ + new GridColumn(Name: TypeColumn, DesktopWidth: "1fr", MobileWidth: "1fr"), + new GridColumn(Name: NameColumn, DesktopWidth: "1.5fr", MobileWidth: "1.5fr"), + new GridColumn(Name: StateColumn, DesktopWidth: "1.25fr"), + new GridColumn(Name: StartTimeColumn, DesktopWidth: "1.5fr"), + new GridColumn(Name: SourceColumn, DesktopWidth: "2.5fr"), + new GridColumn(Name: EndpointsColumn, DesktopWidth: "2.5fr", MobileWidth: "2fr"), + new GridColumn(Name: LogsColumn, DesktopWidth: "1fr"), + new GridColumn(Name: DetailsColumn, DesktopWidth: "1fr", MobileWidth: "1fr"), + new GridColumn(Name: CommandsColumn, DesktopWidth: "1fr", IsVisible: () => HasResourcesWithCommands) + ], DimensionManager); + _applicationUnviewedErrorCounts = TelemetryRepository.GetApplicationUnviewedErrorLogsCount(); if (DashboardClient.IsEnabled) @@ -276,7 +301,7 @@ private bool HasMultipleReplicas(ResourceViewModel resource) return false; } - private string? GetRowClass(ResourceViewModel resource) + private string GetRowClass(ResourceViewModel resource) => resource == SelectedResource ? "selected-row resource-row" : "resource-row"; private async Task ExecuteResourceCommandAsync(ResourceViewModel resource, CommandViewModel command) diff --git a/src/Aspire.Dashboard/Components/Pages/StructuredLogs.razor b/src/Aspire.Dashboard/Components/Pages/StructuredLogs.razor index 03fd41938f..e8d467175a 100644 --- a/src/Aspire.Dashboard/Components/Pages/StructuredLogs.razor +++ b/src/Aspire.Dashboard/Components/Pages/StructuredLogs.razor @@ -1,10 +1,8 @@ @page "/structuredlogs" @page "/structuredlogs/resource/{applicationName}" -@using Aspire.Dashboard.Model.Otlp @using Aspire.Dashboard.Otlp.Model @using Aspire.Dashboard.Utils -@using Microsoft.Extensions.Logging @using Aspire.Dashboard.Resources @using System.Globalization @using Aspire.Dashboard.Components.Controls.Grid @@ -85,15 +83,16 @@ - + @{ var eventName = OtlpHelpers.GetValue(context!.LogEntry.Attributes, "event.name") - ?? OtlpHelpers.GetValue(context!.LogEntry.Attributes, "logrecord.event.name") - ?? Loc[nameof(Dashboard.Resources.StructuredLogs.StructuredLogsEntryDetails)]; + ?? OtlpHelpers.GetValue(context!.LogEntry.Attributes, "logrecord.event.name") + ?? Loc[nameof(Dashboard.Resources.StructuredLogs.StructuredLogsEntryDetails)]; }
@@ -113,26 +112,26 @@ ResizableColumns="true" ItemsProvider="@GetData" TGridItem="OtlpLogEntry" - GridTemplateColumns="1fr 1fr 1fr 5fr 0.8fr 0.8fr" + GridTemplateColumns="@_manager.GetGridTemplateColumns()" ShowHover="true" OnRowClick="@(r => r.ExecuteOnDefault(d => OnShowPropertiesAsync(d, buttonId: null)))" Class="enable-row-click"> - + @GetResourceName(context.Application) - + - + @FormatHelpers.FormatTimeWithOptionalDate(TimeProvider, context.TimeStamp, MillisecondsDisplay.Truncated) - + - + @if (!string.IsNullOrEmpty(context.TraceId)) { @@ -140,7 +139,7 @@ } - + @{ var id = $"details-button-{context.InternalId}"; } diff --git a/src/Aspire.Dashboard/Components/Pages/StructuredLogs.razor.cs b/src/Aspire.Dashboard/Components/Pages/StructuredLogs.razor.cs index 4e59a0f014..ec1db4e147 100644 --- a/src/Aspire.Dashboard/Components/Pages/StructuredLogs.razor.cs +++ b/src/Aspire.Dashboard/Components/Pages/StructuredLogs.razor.cs @@ -21,6 +21,13 @@ namespace Aspire.Dashboard.Components.Pages; public partial class StructuredLogs : IPageWithSessionAndUrlState { + private const string ResourceColumn = nameof(ResourceColumn); + private const string LogLevelColumn = nameof(LogLevelColumn); + private const string TimestampColumn = nameof(TimestampColumn); + private const string MessageColumn = nameof(MessageColumn); + private const string TraceColumn = nameof(TraceColumn); + private const string DetailsColumn = nameof(DetailsColumn); + private SelectViewModel _allApplication = default!; private TotalItemsFooter _totalItemsFooter = default!; @@ -34,6 +41,7 @@ public partial class StructuredLogs : IPageWithSessionAndUrlState DashboardUrls.StructuredLogsBasePath; public string SessionStorageKey => "StructuredLogs_PageState"; @@ -124,6 +132,15 @@ await MessageService.ShowMessageBarAsync(options => protected override Task OnInitializedAsync() { + _manager = new GridColumnManager([ + new GridColumn(Name: ResourceColumn, DesktopWidth: "2fr", MobileWidth: "1fr"), + new GridColumn(Name: LogLevelColumn, DesktopWidth: "1fr"), + new GridColumn(Name: TimestampColumn, DesktopWidth: "1.5fr"), + new GridColumn(Name: MessageColumn, DesktopWidth: "5fr", "2.5fr"), + new GridColumn(Name: TraceColumn, DesktopWidth: "1fr"), + new GridColumn(Name: DetailsColumn, DesktopWidth: "1fr", MobileWidth: "0.8fr") + ], DimensionManager); + if (!string.IsNullOrEmpty(TraceId)) { ViewModel.AddFilter(new LogFilter diff --git a/src/Aspire.Dashboard/Components/Pages/TraceDetail.razor b/src/Aspire.Dashboard/Components/Pages/TraceDetail.razor index 468e3dc492..fd96398fcd 100644 --- a/src/Aspire.Dashboard/Components/Pages/TraceDetail.razor +++ b/src/Aspire.Dashboard/Components/Pages/TraceDetail.razor @@ -14,9 +14,10 @@
@if (_trace is { } trace) { - + @{ var headerSpan = trace.RootSpan ?? trace.FirstSpan; @@ -49,14 +50,13 @@ @ControlStringsLoc[nameof(ControlsStrings.ViewLogsLink)] - + - @{ - var shortedSpanId = OtlpHelpers.ToShortenedId(context!.Span.SpanId); - } + @{ var shortedSpanId = OtlpHelpers.ToShortenedId(context!.Span.SpanId); }
@context!.Title @shortedSpanId @@ -65,15 +65,15 @@ - +
@{ var isServerOrConsumer = context.Span.Kind == OtlpSpanKind.Server || context.Span.Kind == OtlpSpanKind.Consumer; @@ -112,12 +112,12 @@ + Value="@GetSpanIcon(context.Span)"/> } @if (context.IsError) { - + } @GetResourceName(context.Span.Source) @if (context.HasUninstrumentedPeer) @@ -139,9 +139,10 @@ icon = new Icons.Filled.Size16.ArrowCircleRight(); } } - + @context.UninstrumentedPeer } @@ -149,8 +150,8 @@
-
- + +
@* First column starts at 0. We don't want to display the smallest unit (0μs) because that looks odd. Use the unit from the next column *@ @@ -166,7 +167,7 @@
@DurationFormatter.FormatDuration(trace.Duration / 4 * 3) - @DurationFormatter.FormatDuration(trace.Duration) + @DurationFormatter.FormatDuration(trace.Duration)
@@ -186,19 +187,20 @@
- - + + @{ var id = context.Span.SpanId; }
- @ControlStringsLoc[nameof(ControlsStrings.ViewAction)] + @ControlStringsLoc[nameof(ControlsStrings.ViewAction)]
-
+
diff --git a/src/Aspire.Dashboard/Components/Pages/TraceDetail.razor.cs b/src/Aspire.Dashboard/Components/Pages/TraceDetail.razor.cs index a393f3f9f1..b2319dbdd1 100644 --- a/src/Aspire.Dashboard/Components/Pages/TraceDetail.razor.cs +++ b/src/Aspire.Dashboard/Components/Pages/TraceDetail.razor.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. using System.Diagnostics; +using Aspire.Dashboard.Components.Resize; using Aspire.Dashboard.Model; using Aspire.Dashboard.Model.Otlp; using Aspire.Dashboard.Otlp.Model; @@ -15,6 +16,10 @@ namespace Aspire.Dashboard.Components.Pages; public partial class TraceDetail : ComponentBase { + private const string NameColumn = nameof(NameColumn); + private const string TicksColumn = nameof(TicksColumn); + private const string DetailsColumn = nameof(DetailsColumn); + private readonly List _peerChangesSubscriptions = new(); private OtlpTrace? _trace; private Subscription? _tracesSubscription; @@ -23,6 +28,7 @@ public partial class TraceDetail : ComponentBase private List _applications = default!; private readonly List _collapsedSpanIds = []; private string? _elementIdBeforeDetailsViewOpened; + private GridColumnManager _manager = null!; [Parameter] public required string TraceId { get; set; } @@ -46,8 +52,20 @@ public partial class TraceDetail : ComponentBase [Inject] public required NavigationManager NavigationManager { get; init; } + [Inject] + public required DimensionManager DimensionManager { get; init; } + + [CascadingParameter] + public required ViewportInformation ViewportInformation { get; set; } + protected override void OnInitialized() { + _manager = new GridColumnManager([ + new GridColumn(Name: NameColumn, DesktopWidth: "4fr", MobileWidth: "4fr"), + new GridColumn(Name: TicksColumn, DesktopWidth: "12fr", MobileWidth: "12fr"), + new GridColumn(Name: DetailsColumn, DesktopWidth: "85px", MobileWidth: null) + ], DimensionManager); + foreach (var resolver in OutgoingPeerResolvers) { _peerChangesSubscriptions.Add(resolver.OnPeerChanges(async () => diff --git a/src/Aspire.Dashboard/Components/Pages/Traces.razor b/src/Aspire.Dashboard/Components/Pages/Traces.razor index 438d51288c..c64c254524 100644 --- a/src/Aspire.Dashboard/Components/Pages/Traces.razor +++ b/src/Aspire.Dashboard/Components/Pages/Traces.razor @@ -41,18 +41,21 @@ ResizableColumns="true" ItemsProvider="@GetData" TGridItem="OtlpTrace" - GridTemplateColumns="2fr 3fr 0.8fr 0.8fr 0.5fr" + GridTemplateColumns="@_manager.GetGridTemplateColumns()" ShowHover="true" OnRowClick="@(r => r.ExecuteOnDefault(d => NavigationManager.NavigateTo(DashboardUrls.TraceDetailUrl(d.TraceId))))" Class="enable-row-click"> - + + @FormatHelpers.FormatTimeWithOptionalDate(TimeProvider, context.FirstSpan.StartTime, MillisecondsDisplay.Truncated) + + @OtlpHelpers.ToShortenedId(context.TraceId) - + @foreach (var item in context.Spans.GroupBy(s => s.Source).OrderBy(g => g.Min(s => s.StartTime))) @@ -88,10 +91,7 @@ - - @FormatHelpers.FormatTimeWithOptionalDate(TimeProvider, context.FirstSpan.StartTime, MillisecondsDisplay.Truncated) - - +
@if (ViewportInformation.IsDesktop) { @@ -110,8 +110,7 @@ }
- - + @ControlsStringsLoc[nameof(ControlsStrings.ViewAction)]
diff --git a/src/Aspire.Dashboard/Components/Pages/Traces.razor.cs b/src/Aspire.Dashboard/Components/Pages/Traces.razor.cs index 93806ecd65..8a1fd0064a 100644 --- a/src/Aspire.Dashboard/Components/Pages/Traces.razor.cs +++ b/src/Aspire.Dashboard/Components/Pages/Traces.razor.cs @@ -21,6 +21,12 @@ namespace Aspire.Dashboard.Components.Pages; public partial class Traces : IPageWithSessionAndUrlState { + private const string TimestampColumn = nameof(TimestampColumn); + private const string NameColumn = nameof(NameColumn); + private const string SpansColumn = nameof(SpansColumn); + private const string DurationColumn = nameof(DurationColumn); + private const string DetailsColumn = nameof(DetailsColumn); + private SelectViewModel _allApplication = null!; private TotalItemsFooter _totalItemsFooter = default!; @@ -32,6 +38,7 @@ public partial class Traces : IPageWithSessionAndUrlState "Traces_PageState"; public string BasePath => DashboardUrls.TracesBasePath; @@ -68,7 +75,7 @@ public partial class Traces : IPageWithSessionAndUrlState protected override Task OnInitializedAsync() { - _allApplication = new SelectViewModel { Id = null, Name = ControlsStringsLoc[nameof(ControlsStrings.All)] }; + _manager = new GridColumnManager([ + new GridColumn(Name: TimestampColumn, DesktopWidth: "0.8fr", MobileWidth: "0.8fr"), + new GridColumn(Name: NameColumn, DesktopWidth: "2fr", MobileWidth: "2fr"), + new GridColumn(Name: SpansColumn, DesktopWidth: "3fr"), + new GridColumn(Name: DurationColumn, DesktopWidth: "0.8fr"), + new GridColumn(Name: DetailsColumn, DesktopWidth: "0.5fr", MobileWidth: "1fr") + ], DimensionManager); + + _allApplication = new SelectViewModel { Id = null, Name = ControlsStringsLoc[name: nameof(ControlsStrings.All)] }; PageViewModel = new TracesPageViewModel { SelectedApplication = _allApplication }; UpdateApplications(); - _applicationsSubscription = TelemetryRepository.OnNewApplications(() => InvokeAsync(() => + _applicationsSubscription = TelemetryRepository.OnNewApplications(callback: () => InvokeAsync(workItem: () => { UpdateApplications(); StateHasChanged(); diff --git a/src/Aspire.Dashboard/Components/Resize/BrowserDimensionWatcher.razor.cs b/src/Aspire.Dashboard/Components/Resize/BrowserDimensionWatcher.razor.cs index b2f590097e..fc1d9e025f 100644 --- a/src/Aspire.Dashboard/Components/Resize/BrowserDimensionWatcher.razor.cs +++ b/src/Aspire.Dashboard/Components/Resize/BrowserDimensionWatcher.razor.cs @@ -8,6 +8,15 @@ namespace Aspire.Dashboard.Components.Resize; public class BrowserDimensionWatcher : ComponentBase { + // Set our mobile cutoff at 768 pixels, which is ~medium tablet size + private const int MobileCutoffPixelWidth = 768; + + // A small enough height that the filters button takes up too much of the vertical space on screen + private const int LowHeightCutoffPixelWidth = 400; + + // Very close to the minimum width we need to support (320px) + private const int LowWidthCutoffPixelWidth = 350; + [Parameter] public ViewportInformation? ViewportInformation { get; set; } @@ -26,6 +35,7 @@ protected override async Task OnAfterRenderAsync(bool firstRender) { var viewport = await JS.InvokeAsync("window.getWindowDimensions"); ViewportInformation = GetViewportInformation(viewport); + DimensionManager.InvokeOnBrowserDimensionsChanged(ViewportInformation); await ViewportInformationChanged.InvokeAsync(ViewportInformation); await JS.InvokeVoidAsync("window.listenToWindowResize", DotNetObjectReference.Create(this)); @@ -39,27 +49,28 @@ public async Task OnResizeAsync(ViewportSize viewportSize) { var newViewportInformation = GetViewportInformation(viewportSize); - if (newViewportInformation.IsDesktop != ViewportInformation!.IsDesktop || newViewportInformation.IsUltraLowHeight != ViewportInformation.IsUltraLowHeight) + if (newViewportInformation.IsDesktop != ViewportInformation!.IsDesktop + || newViewportInformation.IsUltraLowHeight != ViewportInformation.IsUltraLowHeight + || newViewportInformation.IsUltraLowWidth != ViewportInformation.IsUltraLowWidth) { ViewportInformation = newViewportInformation; DimensionManager.IsResizing = true; - + // A re-render happens on components after ViewportInformationChanged is invoked + // we should invoke OnBrowserDimensionsChanged first so that listeners of it + // that are outside of the UI tree have the current viewport kind internally when components + // call them + DimensionManager.InvokeOnBrowserDimensionsChanged(newViewportInformation); await ViewportInformationChanged.InvokeAsync(newViewportInformation); - DimensionManager.InvokeOnBrowserDimensionsChanged(); - DimensionManager.IsResizing = false; } } private static ViewportInformation GetViewportInformation(ViewportSize viewportSize) { - return new ViewportInformation(IsDesktop: viewportSize.Width > 768, IsUltraLowHeight: viewportSize.Height < 400); + return new ViewportInformation( + IsDesktop: viewportSize.Width > MobileCutoffPixelWidth, + IsUltraLowHeight: viewportSize.Height < LowHeightCutoffPixelWidth, + IsUltraLowWidth: viewportSize.Width < LowWidthCutoffPixelWidth); } - - public static ViewportInformation Create(int height, int width) - { - return new ViewportInformation(IsDesktop: width > 768, IsUltraLowHeight: height < 400); - } - public record ViewportSize(int Width, int Height); } diff --git a/src/Aspire.Dashboard/Components/Resize/DimensionManager.cs b/src/Aspire.Dashboard/Components/Resize/DimensionManager.cs index f6a558e1e7..7b5758d150 100644 --- a/src/Aspire.Dashboard/Components/Resize/DimensionManager.cs +++ b/src/Aspire.Dashboard/Components/Resize/DimensionManager.cs @@ -5,12 +5,22 @@ namespace Aspire.Dashboard.Components.Resize; public class DimensionManager { - public event EventHandler? OnBrowserDimensionsChanged; + private ViewportInformation? _viewportInformation; + public event BrowserDimensionsChangedEventHandler? OnBrowserDimensionsChanged; public bool IsResizing { get; set; } + public ViewportInformation ViewportInformation => _viewportInformation ?? throw new ArgumentNullException(nameof(_viewportInformation)); - internal void InvokeOnBrowserDimensionsChanged() + internal void InvokeOnBrowserDimensionsChanged(ViewportInformation newViewportInformation) { - OnBrowserDimensionsChanged?.Invoke(this, EventArgs.Empty); + _viewportInformation = newViewportInformation; + OnBrowserDimensionsChanged?.Invoke(this, new BrowserDimensionsChangedEventArgs(newViewportInformation)); } } + +public delegate void BrowserDimensionsChangedEventHandler(object sender, BrowserDimensionsChangedEventArgs e); + +public class BrowserDimensionsChangedEventArgs(ViewportInformation viewportInformation) : EventArgs +{ + public ViewportInformation ViewportInformation { get; } = viewportInformation; +} diff --git a/src/Aspire.Dashboard/Components/Resize/ViewportInformation.cs b/src/Aspire.Dashboard/Components/Resize/ViewportInformation.cs index 95921a5dae..40bae76388 100644 --- a/src/Aspire.Dashboard/Components/Resize/ViewportInformation.cs +++ b/src/Aspire.Dashboard/Components/Resize/ViewportInformation.cs @@ -3,9 +3,12 @@ namespace Aspire.Dashboard.Components.Resize; -/// Set our mobile cutoff at 768 pixels, which is ~medium tablet size +/// Whether the viewport is desktop-sized /// Ultra low height is users with very high zooms and/or very low resolutions, /// where the height is significantly constrained. In these cases, the users need the entire main page content /// (toolbar, title, main content, footer) to be scrollable, rather than just the main content. /// -public record ViewportInformation(bool IsDesktop, bool IsUltraLowHeight); +/// Ultra low width means users with extremely constricted viewport widths, requiring +/// the disabling of horizontal space-intensive non-essential features such as the copy button in GridValue, so as +/// to preserve maximum space for content. +public record ViewportInformation(bool IsDesktop, bool IsUltraLowHeight, bool IsUltraLowWidth); diff --git a/src/Aspire.Dashboard/Components/ResourcesGridColumns/GridColumnManager.cs b/src/Aspire.Dashboard/Components/ResourcesGridColumns/GridColumnManager.cs new file mode 100644 index 0000000000..c63760b301 --- /dev/null +++ b/src/Aspire.Dashboard/Components/ResourcesGridColumns/GridColumnManager.cs @@ -0,0 +1,54 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using Aspire.Dashboard.Components.Resize; +using Aspire.Dashboard.Model; + +namespace Aspire.Dashboard.Components; + +public class GridColumnManager +{ + private readonly GridColumn[] _columns; + private readonly DimensionManager _dimensionManager; + + public GridColumnManager(GridColumn[] columns, DimensionManager dimensionManager) + { + if (columns.DistinctBy(c => c.Name, StringComparers.GridColumn).Count() != columns.Length) + { + throw new InvalidOperationException("There are duplicate columns"); + } + + _columns = columns; + _dimensionManager = dimensionManager; + } + + public bool IsColumnVisible(string columnId) + { + return GetColumnWidth(_columns.First(column => column.Name == columnId)) is not null; + } + + private string? GetColumnWidth(GridColumn column) + { + if (column.IsVisible is not null && !column.IsVisible()) + { + return null; + } + + if (_dimensionManager.ViewportInformation.IsDesktop) + { + return column.DesktopWidth; + } + + return column.MobileWidth; + } + + public string GetGridTemplateColumns() + { + var visibleColumns = _columns + .Select(GetColumnWidth) + .Where(s => s is not null) + .Select(s => s!); + + return string.Join(" ", visibleColumns); + } +} diff --git a/src/Aspire.Dashboard/Model/GridColumn.cs b/src/Aspire.Dashboard/Model/GridColumn.cs new file mode 100644 index 0000000000..76126685fc --- /dev/null +++ b/src/Aspire.Dashboard/Model/GridColumn.cs @@ -0,0 +1,6 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +namespace Aspire.Dashboard.Model; + +public record GridColumn(string Name, string? DesktopWidth, string? MobileWidth = null, Func? IsVisible = null); diff --git a/src/Aspire.Dashboard/Resources/ConsoleLogs.Designer.cs b/src/Aspire.Dashboard/Resources/ConsoleLogs.Designer.cs index 2e9f0775bb..7a432d8905 100644 --- a/src/Aspire.Dashboard/Resources/ConsoleLogs.Designer.cs +++ b/src/Aspire.Dashboard/Resources/ConsoleLogs.Designer.cs @@ -11,46 +11,32 @@ namespace Aspire.Dashboard.Resources { using System; - /// - /// A strongly-typed resource class, for looking up localized strings, etc. - /// - // This class was auto-generated by the StronglyTypedResourceBuilder - // class via a tool like ResGen or Visual Studio. - // To add or remove a member, edit your .ResX file then rerun ResGen - // with the /str option, or rebuild your VS project. - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")] - [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] - [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")] + [System.Diagnostics.DebuggerNonUserCodeAttribute()] + [System.Runtime.CompilerServices.CompilerGeneratedAttribute()] public class ConsoleLogs { - private static global::System.Resources.ResourceManager resourceMan; + private static System.Resources.ResourceManager resourceMan; - private static global::System.Globalization.CultureInfo resourceCulture; + private static System.Globalization.CultureInfo resourceCulture; - [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] internal ConsoleLogs() { } - /// - /// Returns the cached ResourceManager instance used by this class. - /// - [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] - public static global::System.Resources.ResourceManager ResourceManager { + [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Advanced)] + public static System.Resources.ResourceManager ResourceManager { get { - if (object.ReferenceEquals(resourceMan, null)) { - global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Aspire.Dashboard.Resources.ConsoleLogs", typeof(ConsoleLogs).Assembly); + if (object.Equals(null, resourceMan)) { + System.Resources.ResourceManager temp = new System.Resources.ResourceManager("Aspire.Dashboard.Resources.ConsoleLogs", typeof(ConsoleLogs).Assembly); resourceMan = temp; } return resourceMan; } } - /// - /// Overrides the current thread's CurrentUICulture property for all - /// resource lookups using this strongly typed resource class. - /// - [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] - public static global::System.Globalization.CultureInfo Culture { + [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Advanced)] + public static System.Globalization.CultureInfo Culture { get { return resourceCulture; } @@ -59,99 +45,72 @@ internal ConsoleLogs() { } } - /// - /// Looks up a localized string similar to Failed to initialize. - /// - public static string ConsoleLogsFailedToInitialize { + public static string ConsoleLogsHeader { get { - return ResourceManager.GetString("ConsoleLogsFailedToInitialize", resourceCulture); + return ResourceManager.GetString("ConsoleLogsHeader", resourceCulture); } } - /// - /// Looks up a localized string similar to Finished watching logs. - /// - public static string ConsoleLogsFinishedWatchingLogs { + public static string ConsoleLogsSelectResourceToolbar { get { - return ResourceManager.GetString("ConsoleLogsFinishedWatchingLogs", resourceCulture); + return ResourceManager.GetString("ConsoleLogsSelectResourceToolbar", resourceCulture); } } - /// - /// Looks up a localized string similar to Console logs. - /// - public static string ConsoleLogsHeader { + public static string ConsoleLogsPageTitle { get { - return ResourceManager.GetString("ConsoleLogsHeader", resourceCulture); + return ResourceManager.GetString("ConsoleLogsPageTitle", resourceCulture); } } - /// - /// Looks up a localized string similar to Initializing log viewer.... - /// public static string ConsoleLogsInitializingLogViewer { get { return ResourceManager.GetString("ConsoleLogsInitializingLogViewer", resourceCulture); } } - /// - /// Looks up a localized string similar to Loading resources .... - /// - public static string ConsoleLogsLoadingResources { + public static string ConsoleLogsLogsNotYetAvailable { get { - return ResourceManager.GetString("ConsoleLogsLoadingResources", resourceCulture); + return ResourceManager.GetString("ConsoleLogsLogsNotYetAvailable", resourceCulture); } } - /// - /// Looks up a localized string similar to Logs not yet available. - /// - public static string ConsoleLogsLogsNotYetAvailable { + public static string ConsoleLogsWatchingLogs { get { - return ResourceManager.GetString("ConsoleLogsLogsNotYetAvailable", resourceCulture); + return ResourceManager.GetString("ConsoleLogsWatchingLogs", resourceCulture); } } - /// - /// Looks up a localized string similar to No resource selected. - /// - public static string ConsoleLogsNoResourceSelected { + public static string ConsoleLogsFailedToInitialize { get { - return ResourceManager.GetString("ConsoleLogsNoResourceSelected", resourceCulture); + return ResourceManager.GetString("ConsoleLogsFailedToInitialize", resourceCulture); } } - /// - /// Looks up a localized string similar to {0} console logs. - /// - public static string ConsoleLogsPageTitle { + public static string ConsoleLogsFinishedWatchingLogs { get { - return ResourceManager.GetString("ConsoleLogsPageTitle", resourceCulture); + return ResourceManager.GetString("ConsoleLogsFinishedWatchingLogs", resourceCulture); } } - /// - /// Looks up a localized string similar to Unknown state. - /// - public static string ConsoleLogsUnknownState { + public static string ConsoleLogsLoadingResources { get { - return ResourceManager.GetString("ConsoleLogsUnknownState", resourceCulture); + return ResourceManager.GetString("ConsoleLogsLoadingResources", resourceCulture); } } - /// - /// Looks up a localized string similar to Watching logs.... - /// - public static string ConsoleLogsWatchingLogs { + public static string ConsoleLogsNoResourceSelected { get { - return ResourceManager.GetString("ConsoleLogsWatchingLogs", resourceCulture); + return ResourceManager.GetString("ConsoleLogsNoResourceSelected", resourceCulture); + } + } + + public static string ConsoleLogsUnknownState { + get { + return ResourceManager.GetString("ConsoleLogsUnknownState", resourceCulture); } } - /// - /// Looks up a localized string similar to Service log status. - /// public static string LogStatusLabel { get { return ResourceManager.GetString("LogStatusLabel", resourceCulture); diff --git a/src/Aspire.Dashboard/Resources/ConsoleLogs.resx b/src/Aspire.Dashboard/Resources/ConsoleLogs.resx index 4075a77470..7adec95a31 100644 --- a/src/Aspire.Dashboard/Resources/ConsoleLogs.resx +++ b/src/Aspire.Dashboard/Resources/ConsoleLogs.resx @@ -101,6 +101,9 @@ Console logs + + Select resource + {0} console logs {0} is an application name diff --git a/src/Aspire.Dashboard/Resources/Layout.resx b/src/Aspire.Dashboard/Resources/Layout.resx index 6334ad62be..37aa54cb09 100644 --- a/src/Aspire.Dashboard/Resources/Layout.resx +++ b/src/Aspire.Dashboard/Resources/Layout.resx @@ -169,6 +169,6 @@ Telemetry endpoint is unsecured - View Filters + View filters diff --git a/src/Aspire.Dashboard/Resources/Metrics.Designer.cs b/src/Aspire.Dashboard/Resources/Metrics.Designer.cs index ead368c287..1dff7713ac 100644 --- a/src/Aspire.Dashboard/Resources/Metrics.Designer.cs +++ b/src/Aspire.Dashboard/Resources/Metrics.Designer.cs @@ -1,7 +1,6 @@ //------------------------------------------------------------------------------ // // This code was generated by a tool. -// Runtime Version:4.0.30319.42000 // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. @@ -12,46 +11,32 @@ namespace Aspire.Dashboard.Resources { using System; - /// - /// A strongly-typed resource class, for looking up localized strings, etc. - /// - // This class was auto-generated by the StronglyTypedResourceBuilder - // class via a tool like ResGen or Visual Studio. - // To add or remove a member, edit your .ResX file then rerun ResGen - // with the /str option, or rebuild your VS project. - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")] - [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] - [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")] + [System.Diagnostics.DebuggerNonUserCodeAttribute()] + [System.Runtime.CompilerServices.CompilerGeneratedAttribute()] public class Metrics { - private static global::System.Resources.ResourceManager resourceMan; + private static System.Resources.ResourceManager resourceMan; - private static global::System.Globalization.CultureInfo resourceCulture; + private static System.Globalization.CultureInfo resourceCulture; - [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] internal Metrics() { } - /// - /// Returns the cached ResourceManager instance used by this class. - /// - [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] - public static global::System.Resources.ResourceManager ResourceManager { + [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Advanced)] + public static System.Resources.ResourceManager ResourceManager { get { - if (object.ReferenceEquals(resourceMan, null)) { - global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Aspire.Dashboard.Resources.Metrics", typeof(Metrics).Assembly); + if (object.Equals(null, resourceMan)) { + System.Resources.ResourceManager temp = new System.Resources.ResourceManager("Aspire.Dashboard.Resources.Metrics", typeof(Metrics).Assembly); resourceMan = temp; } return resourceMan; } } - /// - /// Overrides the current thread's CurrentUICulture property for all - /// resource lookups using this strongly typed resource class. - /// - [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] - public static global::System.Globalization.CultureInfo Culture { + [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Advanced)] + public static System.Globalization.CultureInfo Culture { get { return resourceCulture; } @@ -60,156 +45,111 @@ internal Metrics() { } } - /// - /// Looks up a localized string similar to Metrics. - /// - public static string MetricsHeader { + public static string MetricsPageTitle { get { - return ResourceManager.GetString("MetricsHeader", resourceCulture); + return ResourceManager.GetString("MetricsPageTitle", resourceCulture); } } - /// - /// Looks up a localized string similar to Description. - /// - public static string MetricsInsturementDescriptionGridNameColumnHeader { + public static string MetricsHeader { get { - return ResourceManager.GetString("MetricsInsturementDescriptionGridNameColumnHeader", resourceCulture); + return ResourceManager.GetString("MetricsHeader", resourceCulture); } } - /// - /// Looks up a localized string similar to Instrument. - /// - public static string MetricsInsturementNameGridNameColumnHeader { + public static string MetricsSelectADuration { get { - return ResourceManager.GetString("MetricsInsturementNameGridNameColumnHeader", resourceCulture); + return ResourceManager.GetString("MetricsSelectADuration", resourceCulture); } } - /// - /// Looks up a localized string similar to Last 15 minutes. - /// - public static string MetricsLastFifteenMinutes { + public static string MetricsSelectInstrument { get { - return ResourceManager.GetString("MetricsLastFifteenMinutes", resourceCulture); + return ResourceManager.GetString("MetricsSelectInstrument", resourceCulture); } } - /// - /// Looks up a localized string similar to Last 5 minutes. - /// - public static string MetricsLastFiveMinutes { + public static string MetricsSelectAResource { get { - return ResourceManager.GetString("MetricsLastFiveMinutes", resourceCulture); + return ResourceManager.GetString("MetricsSelectAResource", resourceCulture); } } - /// - /// Looks up a localized string similar to Last hour. - /// - public static string MetricsLastHour { + public static string MetricsNoMetricsForResource { get { - return ResourceManager.GetString("MetricsLastHour", resourceCulture); + return ResourceManager.GetString("MetricsNoMetricsForResource", resourceCulture); } } - /// - /// Looks up a localized string similar to Last 1 minute. - /// public static string MetricsLastOneMinute { get { return ResourceManager.GetString("MetricsLastOneMinute", resourceCulture); } } - /// - /// Looks up a localized string similar to Last 6 hours. - /// - public static string MetricsLastSixHours { + public static string MetricsLastFiveMinutes { get { - return ResourceManager.GetString("MetricsLastSixHours", resourceCulture); + return ResourceManager.GetString("MetricsLastFiveMinutes", resourceCulture); + } + } + + public static string MetricsLastFifteenMinutes { + get { + return ResourceManager.GetString("MetricsLastFifteenMinutes", resourceCulture); } } - /// - /// Looks up a localized string similar to Last 30 minutes. - /// public static string MetricsLastThirtyMinutes { get { return ResourceManager.GetString("MetricsLastThirtyMinutes", resourceCulture); } } - /// - /// Looks up a localized string similar to Last 3 hours. - /// - public static string MetricsLastThreeHours { + public static string MetricsLastHour { get { - return ResourceManager.GetString("MetricsLastThreeHours", resourceCulture); + return ResourceManager.GetString("MetricsLastHour", resourceCulture); } } - /// - /// Looks up a localized string similar to Last 12 hours. - /// - public static string MetricsLastTwelveHours { + public static string MetricsLastThreeHours { get { - return ResourceManager.GetString("MetricsLastTwelveHours", resourceCulture); + return ResourceManager.GetString("MetricsLastThreeHours", resourceCulture); } } - /// - /// Looks up a localized string similar to Last 24 hours. - /// - public static string MetricsLastTwentyFourHours { + public static string MetricsLastSixHours { get { - return ResourceManager.GetString("MetricsLastTwentyFourHours", resourceCulture); + return ResourceManager.GetString("MetricsLastSixHours", resourceCulture); } } - /// - /// Looks up a localized string similar to No metrics for the selected resource. - /// - public static string MetricsNoMetricsForResource { + public static string MetricsLastTwelveHours { get { - return ResourceManager.GetString("MetricsNoMetricsForResource", resourceCulture); + return ResourceManager.GetString("MetricsLastTwelveHours", resourceCulture); } } - /// - /// Looks up a localized string similar to {0} metrics. - /// - public static string MetricsPageTitle { + public static string MetricsLastTwentyFourHours { get { - return ResourceManager.GetString("MetricsPageTitle", resourceCulture); + return ResourceManager.GetString("MetricsLastTwentyFourHours", resourceCulture); } } - /// - /// Looks up a localized string similar to Select a duration. - /// - public static string MetricsSelectADuration { + public static string MetricsInsturementDescriptionGridNameColumnHeader { get { - return ResourceManager.GetString("MetricsSelectADuration", resourceCulture); + return ResourceManager.GetString("MetricsInsturementDescriptionGridNameColumnHeader", resourceCulture); } } - /// - /// Looks up a localized string similar to Select a resource to view metrics. - /// - public static string MetricsSelectAResource { + public static string MetricsInsturementNameGridNameColumnHeader { get { - return ResourceManager.GetString("MetricsSelectAResource", resourceCulture); + return ResourceManager.GetString("MetricsInsturementNameGridNameColumnHeader", resourceCulture); } } - /// - /// Looks up a localized string similar to Select instrument.. - /// - public static string MetricsSelectInstrument { + public static string MetricsViewAttributesToolbar { get { - return ResourceManager.GetString("MetricsSelectInstrument", resourceCulture); + return ResourceManager.GetString("MetricsViewAttributesToolbar", resourceCulture); } } } diff --git a/src/Aspire.Dashboard/Resources/Metrics.resx b/src/Aspire.Dashboard/Resources/Metrics.resx index 0ac6b0191a..b64912cef5 100644 --- a/src/Aspire.Dashboard/Resources/Metrics.resx +++ b/src/Aspire.Dashboard/Resources/Metrics.resx @@ -1,17 +1,17 @@  - @@ -169,4 +169,7 @@ Instrument - \ No newline at end of file + + View attributes + + diff --git a/src/Aspire.Dashboard/Resources/TraceDetail.Designer.cs b/src/Aspire.Dashboard/Resources/TraceDetail.Designer.cs index 81936250d4..c3c568d089 100644 --- a/src/Aspire.Dashboard/Resources/TraceDetail.Designer.cs +++ b/src/Aspire.Dashboard/Resources/TraceDetail.Designer.cs @@ -11,46 +11,32 @@ namespace Aspire.Dashboard.Resources { using System; - /// - /// A strongly-typed resource class, for looking up localized strings, etc. - /// - // This class was auto-generated by the StronglyTypedResourceBuilder - // class via a tool like ResGen or Visual Studio. - // To add or remove a member, edit your .ResX file then rerun ResGen - // with the /str option, or rebuild your VS project. - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")] - [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] - [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")] + [System.Diagnostics.DebuggerNonUserCodeAttribute()] + [System.Runtime.CompilerServices.CompilerGeneratedAttribute()] public class TraceDetail { - private static global::System.Resources.ResourceManager resourceMan; + private static System.Resources.ResourceManager resourceMan; - private static global::System.Globalization.CultureInfo resourceCulture; + private static System.Globalization.CultureInfo resourceCulture; - [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] internal TraceDetail() { } - /// - /// Returns the cached ResourceManager instance used by this class. - /// - [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] - public static global::System.Resources.ResourceManager ResourceManager { + [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Advanced)] + public static System.Resources.ResourceManager ResourceManager { get { - if (object.ReferenceEquals(resourceMan, null)) { - global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Aspire.Dashboard.Resources.TraceDetail", typeof(TraceDetail).Assembly); + if (object.Equals(null, resourceMan)) { + System.Resources.ResourceManager temp = new System.Resources.ResourceManager("Aspire.Dashboard.Resources.TraceDetail", typeof(TraceDetail).Assembly); resourceMan = temp; } return resourceMan; } } - /// - /// Overrides the current thread's CurrentUICulture property for all - /// resource lookups using this strongly typed resource class. - /// - [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] - public static global::System.Globalization.CultureInfo Culture { + [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Advanced)] + public static System.Globalization.CultureInfo Culture { get { return resourceCulture; } @@ -59,75 +45,57 @@ internal TraceDetail() { } } - /// - /// Looks up a localized string similar to Depth. - /// - public static string TraceDetailDepthHeader { + public static string TraceDetailPageTitle { get { - return ResourceManager.GetString("TraceDetailDepthHeader", resourceCulture); + return ResourceManager.GetString("TraceDetailPageTitle", resourceCulture); } } - /// - /// Looks up a localized string similar to Duration. - /// - public static string TraceDetailDurationHeader { + public static string TraceDetailTraceStartHeader { get { - return ResourceManager.GetString("TraceDetailDurationHeader", resourceCulture); + return ResourceManager.GetString("TraceDetailTraceStartHeader", resourceCulture); } } - /// - /// Looks up a localized string similar to Trace details. - /// - public static string TraceDetailMobileToolbarButtonText { + public static string TraceDetailDurationHeader { get { - return ResourceManager.GetString("TraceDetailMobileToolbarButtonText", resourceCulture); + return ResourceManager.GetString("TraceDetailDurationHeader", resourceCulture); } } - /// - /// Looks up a localized string similar to {0} trace. - /// - public static string TraceDetailPageTitle { + public static string TraceDetailResourcesHeader { get { - return ResourceManager.GetString("TraceDetailPageTitle", resourceCulture); + return ResourceManager.GetString("TraceDetailResourcesHeader", resourceCulture); } } - /// - /// Looks up a localized string similar to Resources. - /// - public static string TraceDetailResourcesHeader { + public static string TraceDetailDepthHeader { get { - return ResourceManager.GetString("TraceDetailResourcesHeader", resourceCulture); + return ResourceManager.GetString("TraceDetailDepthHeader", resourceCulture); } } - /// - /// Looks up a localized string similar to Total spans. - /// public static string TraceDetailTotalSpansHeader { get { return ResourceManager.GetString("TraceDetailTotalSpansHeader", resourceCulture); } } - /// - /// Looks up a localized string similar to Trace "{0}" not found. - /// public static string TraceDetailTraceNotFound { get { return ResourceManager.GetString("TraceDetailTraceNotFound", resourceCulture); } } - /// - /// Looks up a localized string similar to Trace detail. - /// - public static string TraceDetailTraceStartHeader { + public static string TraceDetailMobileToolbarButtonText { get { - return ResourceManager.GetString("TraceDetailTraceStartHeader", resourceCulture); + return ResourceManager.GetString("TraceDetailMobileToolbarButtonText", resourceCulture); + } + } + + public static string TraceDetailNameHeader { + get { + return ResourceManager.GetString("TraceDetailNameHeader", resourceCulture); } } } diff --git a/src/Aspire.Dashboard/Resources/TraceDetail.resx b/src/Aspire.Dashboard/Resources/TraceDetail.resx index 83d6fa0d07..72941eb65e 100644 --- a/src/Aspire.Dashboard/Resources/TraceDetail.resx +++ b/src/Aspire.Dashboard/Resources/TraceDetail.resx @@ -143,4 +143,7 @@ Trace details + + Name + diff --git a/src/Aspire.Dashboard/Resources/xlf/ConsoleLogs.cs.xlf b/src/Aspire.Dashboard/Resources/xlf/ConsoleLogs.cs.xlf index dc747c725b..71ff710e05 100644 --- a/src/Aspire.Dashboard/Resources/xlf/ConsoleLogs.cs.xlf +++ b/src/Aspire.Dashboard/Resources/xlf/ConsoleLogs.cs.xlf @@ -42,6 +42,11 @@ Protokoly konzoly aplikace {0} {0} is an application name + + Select resource + Select resource + + Unknown state Neznámý stav diff --git a/src/Aspire.Dashboard/Resources/xlf/ConsoleLogs.de.xlf b/src/Aspire.Dashboard/Resources/xlf/ConsoleLogs.de.xlf index ce1eff95a8..1d478a3c1e 100644 --- a/src/Aspire.Dashboard/Resources/xlf/ConsoleLogs.de.xlf +++ b/src/Aspire.Dashboard/Resources/xlf/ConsoleLogs.de.xlf @@ -42,6 +42,11 @@ {0} Konsolenprotokolle {0} is an application name + + Select resource + Select resource + + Unknown state Unbekannter Status diff --git a/src/Aspire.Dashboard/Resources/xlf/ConsoleLogs.es.xlf b/src/Aspire.Dashboard/Resources/xlf/ConsoleLogs.es.xlf index bbc079e07d..12e8eedd7e 100644 --- a/src/Aspire.Dashboard/Resources/xlf/ConsoleLogs.es.xlf +++ b/src/Aspire.Dashboard/Resources/xlf/ConsoleLogs.es.xlf @@ -42,6 +42,11 @@ Registros de consola de {0} {0} is an application name + + Select resource + Select resource + + Unknown state Estado desconocido diff --git a/src/Aspire.Dashboard/Resources/xlf/ConsoleLogs.fr.xlf b/src/Aspire.Dashboard/Resources/xlf/ConsoleLogs.fr.xlf index 96e8a0ebcf..92ca1d99be 100644 --- a/src/Aspire.Dashboard/Resources/xlf/ConsoleLogs.fr.xlf +++ b/src/Aspire.Dashboard/Resources/xlf/ConsoleLogs.fr.xlf @@ -42,6 +42,11 @@ Journaux de console {0} {0} is an application name + + Select resource + Select resource + + Unknown state État inconnu diff --git a/src/Aspire.Dashboard/Resources/xlf/ConsoleLogs.it.xlf b/src/Aspire.Dashboard/Resources/xlf/ConsoleLogs.it.xlf index 889560e104..ffe6d72831 100644 --- a/src/Aspire.Dashboard/Resources/xlf/ConsoleLogs.it.xlf +++ b/src/Aspire.Dashboard/Resources/xlf/ConsoleLogs.it.xlf @@ -42,6 +42,11 @@ {0} log della console {0} is an application name + + Select resource + Select resource + + Unknown state Stato sconosciuto diff --git a/src/Aspire.Dashboard/Resources/xlf/ConsoleLogs.ja.xlf b/src/Aspire.Dashboard/Resources/xlf/ConsoleLogs.ja.xlf index 72247b7c62..6f9f9144b3 100644 --- a/src/Aspire.Dashboard/Resources/xlf/ConsoleLogs.ja.xlf +++ b/src/Aspire.Dashboard/Resources/xlf/ConsoleLogs.ja.xlf @@ -42,6 +42,11 @@ {0} のコンソール ログ {0} is an application name + + Select resource + Select resource + + Unknown state 不明な状態 diff --git a/src/Aspire.Dashboard/Resources/xlf/ConsoleLogs.ko.xlf b/src/Aspire.Dashboard/Resources/xlf/ConsoleLogs.ko.xlf index 0efc83b96a..e4beb729a4 100644 --- a/src/Aspire.Dashboard/Resources/xlf/ConsoleLogs.ko.xlf +++ b/src/Aspire.Dashboard/Resources/xlf/ConsoleLogs.ko.xlf @@ -42,6 +42,11 @@ {0} 콘솔 로그 {0} is an application name + + Select resource + Select resource + + Unknown state 알 수 없는 상태 diff --git a/src/Aspire.Dashboard/Resources/xlf/ConsoleLogs.pl.xlf b/src/Aspire.Dashboard/Resources/xlf/ConsoleLogs.pl.xlf index c3ed26dd39..16f00fe21f 100644 --- a/src/Aspire.Dashboard/Resources/xlf/ConsoleLogs.pl.xlf +++ b/src/Aspire.Dashboard/Resources/xlf/ConsoleLogs.pl.xlf @@ -42,6 +42,11 @@ Dzienniki konsoli: {0} {0} is an application name + + Select resource + Select resource + + Unknown state Nieznany stan diff --git a/src/Aspire.Dashboard/Resources/xlf/ConsoleLogs.pt-BR.xlf b/src/Aspire.Dashboard/Resources/xlf/ConsoleLogs.pt-BR.xlf index 606808b219..ec00ab58a0 100644 --- a/src/Aspire.Dashboard/Resources/xlf/ConsoleLogs.pt-BR.xlf +++ b/src/Aspire.Dashboard/Resources/xlf/ConsoleLogs.pt-BR.xlf @@ -42,6 +42,11 @@ {0} logs do console {0} is an application name + + Select resource + Select resource + + Unknown state Estado desconhecido diff --git a/src/Aspire.Dashboard/Resources/xlf/ConsoleLogs.ru.xlf b/src/Aspire.Dashboard/Resources/xlf/ConsoleLogs.ru.xlf index 940dcd238f..2e9293f689 100644 --- a/src/Aspire.Dashboard/Resources/xlf/ConsoleLogs.ru.xlf +++ b/src/Aspire.Dashboard/Resources/xlf/ConsoleLogs.ru.xlf @@ -42,6 +42,11 @@ Журналов консоли: {0} {0} is an application name + + Select resource + Select resource + + Unknown state Неизвестное состояние diff --git a/src/Aspire.Dashboard/Resources/xlf/ConsoleLogs.tr.xlf b/src/Aspire.Dashboard/Resources/xlf/ConsoleLogs.tr.xlf index dc66f8bf0a..32920cbbb0 100644 --- a/src/Aspire.Dashboard/Resources/xlf/ConsoleLogs.tr.xlf +++ b/src/Aspire.Dashboard/Resources/xlf/ConsoleLogs.tr.xlf @@ -42,6 +42,11 @@ {0} konsol günlükleri {0} is an application name + + Select resource + Select resource + + Unknown state Bilinmeyen durum diff --git a/src/Aspire.Dashboard/Resources/xlf/ConsoleLogs.zh-Hans.xlf b/src/Aspire.Dashboard/Resources/xlf/ConsoleLogs.zh-Hans.xlf index 28b7c3eaf9..52a5f279b5 100644 --- a/src/Aspire.Dashboard/Resources/xlf/ConsoleLogs.zh-Hans.xlf +++ b/src/Aspire.Dashboard/Resources/xlf/ConsoleLogs.zh-Hans.xlf @@ -42,6 +42,11 @@ {0} 控制台日志 {0} is an application name + + Select resource + Select resource + + Unknown state 未知状态 diff --git a/src/Aspire.Dashboard/Resources/xlf/ConsoleLogs.zh-Hant.xlf b/src/Aspire.Dashboard/Resources/xlf/ConsoleLogs.zh-Hant.xlf index 6889615f68..0504acd6e2 100644 --- a/src/Aspire.Dashboard/Resources/xlf/ConsoleLogs.zh-Hant.xlf +++ b/src/Aspire.Dashboard/Resources/xlf/ConsoleLogs.zh-Hant.xlf @@ -42,6 +42,11 @@ {0} 主控台記錄 {0} is an application name + + Select resource + Select resource + + Unknown state 未知狀態 diff --git a/src/Aspire.Dashboard/Resources/xlf/Layout.cs.xlf b/src/Aspire.Dashboard/Resources/xlf/Layout.cs.xlf index f03f21573a..d2f6cfd03a 100644 --- a/src/Aspire.Dashboard/Resources/xlf/Layout.cs.xlf +++ b/src/Aspire.Dashboard/Resources/xlf/Layout.cs.xlf @@ -88,8 +88,8 @@ - View Filters - View Filters + View filters + View filters diff --git a/src/Aspire.Dashboard/Resources/xlf/Layout.de.xlf b/src/Aspire.Dashboard/Resources/xlf/Layout.de.xlf index 759680a397..51a57e6467 100644 --- a/src/Aspire.Dashboard/Resources/xlf/Layout.de.xlf +++ b/src/Aspire.Dashboard/Resources/xlf/Layout.de.xlf @@ -88,8 +88,8 @@ - View Filters - View Filters + View filters + View filters diff --git a/src/Aspire.Dashboard/Resources/xlf/Layout.es.xlf b/src/Aspire.Dashboard/Resources/xlf/Layout.es.xlf index 508d18bc88..fbd3feec68 100644 --- a/src/Aspire.Dashboard/Resources/xlf/Layout.es.xlf +++ b/src/Aspire.Dashboard/Resources/xlf/Layout.es.xlf @@ -88,8 +88,8 @@ - View Filters - View Filters + View filters + View filters diff --git a/src/Aspire.Dashboard/Resources/xlf/Layout.fr.xlf b/src/Aspire.Dashboard/Resources/xlf/Layout.fr.xlf index a44645354b..ff3e3b9ba1 100644 --- a/src/Aspire.Dashboard/Resources/xlf/Layout.fr.xlf +++ b/src/Aspire.Dashboard/Resources/xlf/Layout.fr.xlf @@ -88,8 +88,8 @@ - View Filters - View Filters + View filters + View filters diff --git a/src/Aspire.Dashboard/Resources/xlf/Layout.it.xlf b/src/Aspire.Dashboard/Resources/xlf/Layout.it.xlf index c5b4a65a4b..22ca6ca16f 100644 --- a/src/Aspire.Dashboard/Resources/xlf/Layout.it.xlf +++ b/src/Aspire.Dashboard/Resources/xlf/Layout.it.xlf @@ -88,8 +88,8 @@ - View Filters - View Filters + View filters + View filters diff --git a/src/Aspire.Dashboard/Resources/xlf/Layout.ja.xlf b/src/Aspire.Dashboard/Resources/xlf/Layout.ja.xlf index a4f75adf57..7baf997364 100644 --- a/src/Aspire.Dashboard/Resources/xlf/Layout.ja.xlf +++ b/src/Aspire.Dashboard/Resources/xlf/Layout.ja.xlf @@ -88,8 +88,8 @@ - View Filters - View Filters + View filters + View filters diff --git a/src/Aspire.Dashboard/Resources/xlf/Layout.ko.xlf b/src/Aspire.Dashboard/Resources/xlf/Layout.ko.xlf index 8feadae7a3..0cdefb46ac 100644 --- a/src/Aspire.Dashboard/Resources/xlf/Layout.ko.xlf +++ b/src/Aspire.Dashboard/Resources/xlf/Layout.ko.xlf @@ -88,8 +88,8 @@ - View Filters - View Filters + View filters + View filters diff --git a/src/Aspire.Dashboard/Resources/xlf/Layout.pl.xlf b/src/Aspire.Dashboard/Resources/xlf/Layout.pl.xlf index e3a0358a37..ab3c906ef1 100644 --- a/src/Aspire.Dashboard/Resources/xlf/Layout.pl.xlf +++ b/src/Aspire.Dashboard/Resources/xlf/Layout.pl.xlf @@ -88,8 +88,8 @@ - View Filters - View Filters + View filters + View filters diff --git a/src/Aspire.Dashboard/Resources/xlf/Layout.pt-BR.xlf b/src/Aspire.Dashboard/Resources/xlf/Layout.pt-BR.xlf index 0f9e740750..d7c2b152db 100644 --- a/src/Aspire.Dashboard/Resources/xlf/Layout.pt-BR.xlf +++ b/src/Aspire.Dashboard/Resources/xlf/Layout.pt-BR.xlf @@ -88,8 +88,8 @@ - View Filters - View Filters + View filters + View filters diff --git a/src/Aspire.Dashboard/Resources/xlf/Layout.ru.xlf b/src/Aspire.Dashboard/Resources/xlf/Layout.ru.xlf index e38dbb7fbd..4268300fdf 100644 --- a/src/Aspire.Dashboard/Resources/xlf/Layout.ru.xlf +++ b/src/Aspire.Dashboard/Resources/xlf/Layout.ru.xlf @@ -88,8 +88,8 @@ - View Filters - View Filters + View filters + View filters diff --git a/src/Aspire.Dashboard/Resources/xlf/Layout.tr.xlf b/src/Aspire.Dashboard/Resources/xlf/Layout.tr.xlf index 7a08267ba7..18d6cfb3d7 100644 --- a/src/Aspire.Dashboard/Resources/xlf/Layout.tr.xlf +++ b/src/Aspire.Dashboard/Resources/xlf/Layout.tr.xlf @@ -88,8 +88,8 @@ - View Filters - View Filters + View filters + View filters diff --git a/src/Aspire.Dashboard/Resources/xlf/Layout.zh-Hans.xlf b/src/Aspire.Dashboard/Resources/xlf/Layout.zh-Hans.xlf index a056973143..41688ad06c 100644 --- a/src/Aspire.Dashboard/Resources/xlf/Layout.zh-Hans.xlf +++ b/src/Aspire.Dashboard/Resources/xlf/Layout.zh-Hans.xlf @@ -88,8 +88,8 @@ - View Filters - View Filters + View filters + View filters diff --git a/src/Aspire.Dashboard/Resources/xlf/Layout.zh-Hant.xlf b/src/Aspire.Dashboard/Resources/xlf/Layout.zh-Hant.xlf index 47e681e2da..29af91b964 100644 --- a/src/Aspire.Dashboard/Resources/xlf/Layout.zh-Hant.xlf +++ b/src/Aspire.Dashboard/Resources/xlf/Layout.zh-Hant.xlf @@ -88,8 +88,8 @@ - View Filters - View Filters + View filters + View filters diff --git a/src/Aspire.Dashboard/Resources/xlf/Metrics.cs.xlf b/src/Aspire.Dashboard/Resources/xlf/Metrics.cs.xlf index 0e32713602..ac30c34979 100644 --- a/src/Aspire.Dashboard/Resources/xlf/Metrics.cs.xlf +++ b/src/Aspire.Dashboard/Resources/xlf/Metrics.cs.xlf @@ -87,6 +87,11 @@ Vyberte nástroj. + + View attributes + View attributes + + \ No newline at end of file diff --git a/src/Aspire.Dashboard/Resources/xlf/Metrics.de.xlf b/src/Aspire.Dashboard/Resources/xlf/Metrics.de.xlf index 0e1eb15975..ecd95453ab 100644 --- a/src/Aspire.Dashboard/Resources/xlf/Metrics.de.xlf +++ b/src/Aspire.Dashboard/Resources/xlf/Metrics.de.xlf @@ -87,6 +87,11 @@ Instrument auswählen. + + View attributes + View attributes + + \ No newline at end of file diff --git a/src/Aspire.Dashboard/Resources/xlf/Metrics.es.xlf b/src/Aspire.Dashboard/Resources/xlf/Metrics.es.xlf index 8432b66020..7a07dd4ed5 100644 --- a/src/Aspire.Dashboard/Resources/xlf/Metrics.es.xlf +++ b/src/Aspire.Dashboard/Resources/xlf/Metrics.es.xlf @@ -87,6 +87,11 @@ Seleccione el instrumento. + + View attributes + View attributes + + \ No newline at end of file diff --git a/src/Aspire.Dashboard/Resources/xlf/Metrics.fr.xlf b/src/Aspire.Dashboard/Resources/xlf/Metrics.fr.xlf index 35ffec3754..1238413ac9 100644 --- a/src/Aspire.Dashboard/Resources/xlf/Metrics.fr.xlf +++ b/src/Aspire.Dashboard/Resources/xlf/Metrics.fr.xlf @@ -87,6 +87,11 @@ Sélectionnez un instrument. + + View attributes + View attributes + + \ No newline at end of file diff --git a/src/Aspire.Dashboard/Resources/xlf/Metrics.it.xlf b/src/Aspire.Dashboard/Resources/xlf/Metrics.it.xlf index 13a27db7b4..9b660c15ee 100644 --- a/src/Aspire.Dashboard/Resources/xlf/Metrics.it.xlf +++ b/src/Aspire.Dashboard/Resources/xlf/Metrics.it.xlf @@ -87,6 +87,11 @@ Seleziona uno strumento. + + View attributes + View attributes + + \ No newline at end of file diff --git a/src/Aspire.Dashboard/Resources/xlf/Metrics.ja.xlf b/src/Aspire.Dashboard/Resources/xlf/Metrics.ja.xlf index 42a9564018..f255deac0f 100644 --- a/src/Aspire.Dashboard/Resources/xlf/Metrics.ja.xlf +++ b/src/Aspire.Dashboard/Resources/xlf/Metrics.ja.xlf @@ -87,6 +87,11 @@ インストルメントを選択します。 + + View attributes + View attributes + + \ No newline at end of file diff --git a/src/Aspire.Dashboard/Resources/xlf/Metrics.ko.xlf b/src/Aspire.Dashboard/Resources/xlf/Metrics.ko.xlf index 9b190f929f..8081a2470b 100644 --- a/src/Aspire.Dashboard/Resources/xlf/Metrics.ko.xlf +++ b/src/Aspire.Dashboard/Resources/xlf/Metrics.ko.xlf @@ -87,6 +87,11 @@ 계측을 선택합니다. + + View attributes + View attributes + + \ No newline at end of file diff --git a/src/Aspire.Dashboard/Resources/xlf/Metrics.pl.xlf b/src/Aspire.Dashboard/Resources/xlf/Metrics.pl.xlf index d6a42f4785..36d6cdd33c 100644 --- a/src/Aspire.Dashboard/Resources/xlf/Metrics.pl.xlf +++ b/src/Aspire.Dashboard/Resources/xlf/Metrics.pl.xlf @@ -87,6 +87,11 @@ Wybierz instrument. + + View attributes + View attributes + + \ No newline at end of file diff --git a/src/Aspire.Dashboard/Resources/xlf/Metrics.pt-BR.xlf b/src/Aspire.Dashboard/Resources/xlf/Metrics.pt-BR.xlf index be08ecd831..bf272a4e4f 100644 --- a/src/Aspire.Dashboard/Resources/xlf/Metrics.pt-BR.xlf +++ b/src/Aspire.Dashboard/Resources/xlf/Metrics.pt-BR.xlf @@ -87,6 +87,11 @@ Selecionar instrumento. + + View attributes + View attributes + + \ No newline at end of file diff --git a/src/Aspire.Dashboard/Resources/xlf/Metrics.ru.xlf b/src/Aspire.Dashboard/Resources/xlf/Metrics.ru.xlf index 0d76acd777..f42ba59309 100644 --- a/src/Aspire.Dashboard/Resources/xlf/Metrics.ru.xlf +++ b/src/Aspire.Dashboard/Resources/xlf/Metrics.ru.xlf @@ -87,6 +87,11 @@ Выберите инструмент. + + View attributes + View attributes + + \ No newline at end of file diff --git a/src/Aspire.Dashboard/Resources/xlf/Metrics.tr.xlf b/src/Aspire.Dashboard/Resources/xlf/Metrics.tr.xlf index d6b0007810..fe58e75274 100644 --- a/src/Aspire.Dashboard/Resources/xlf/Metrics.tr.xlf +++ b/src/Aspire.Dashboard/Resources/xlf/Metrics.tr.xlf @@ -87,6 +87,11 @@ Aracı seçin. + + View attributes + View attributes + + \ No newline at end of file diff --git a/src/Aspire.Dashboard/Resources/xlf/Metrics.zh-Hans.xlf b/src/Aspire.Dashboard/Resources/xlf/Metrics.zh-Hans.xlf index 64baa11f1d..5547b2a992 100644 --- a/src/Aspire.Dashboard/Resources/xlf/Metrics.zh-Hans.xlf +++ b/src/Aspire.Dashboard/Resources/xlf/Metrics.zh-Hans.xlf @@ -87,6 +87,11 @@ 选择检测。 + + View attributes + View attributes + + \ No newline at end of file diff --git a/src/Aspire.Dashboard/Resources/xlf/Metrics.zh-Hant.xlf b/src/Aspire.Dashboard/Resources/xlf/Metrics.zh-Hant.xlf index 70209fcd7f..06f94881d6 100644 --- a/src/Aspire.Dashboard/Resources/xlf/Metrics.zh-Hant.xlf +++ b/src/Aspire.Dashboard/Resources/xlf/Metrics.zh-Hant.xlf @@ -87,6 +87,11 @@ 選取檢測。 + + View attributes + View attributes + + \ No newline at end of file diff --git a/src/Aspire.Dashboard/Resources/xlf/TraceDetail.cs.xlf b/src/Aspire.Dashboard/Resources/xlf/TraceDetail.cs.xlf index c84580c3bd..02c792b03c 100644 --- a/src/Aspire.Dashboard/Resources/xlf/TraceDetail.cs.xlf +++ b/src/Aspire.Dashboard/Resources/xlf/TraceDetail.cs.xlf @@ -17,6 +17,11 @@ Trace details + + Name + Name + + {0} trace Trasa {0} diff --git a/src/Aspire.Dashboard/Resources/xlf/TraceDetail.de.xlf b/src/Aspire.Dashboard/Resources/xlf/TraceDetail.de.xlf index c279aa7aaf..fddb0a5826 100644 --- a/src/Aspire.Dashboard/Resources/xlf/TraceDetail.de.xlf +++ b/src/Aspire.Dashboard/Resources/xlf/TraceDetail.de.xlf @@ -17,6 +17,11 @@ Trace details + + Name + Name + + {0} trace {0}-Ablaufverfolgung diff --git a/src/Aspire.Dashboard/Resources/xlf/TraceDetail.es.xlf b/src/Aspire.Dashboard/Resources/xlf/TraceDetail.es.xlf index 3c331025f7..3bb6a19082 100644 --- a/src/Aspire.Dashboard/Resources/xlf/TraceDetail.es.xlf +++ b/src/Aspire.Dashboard/Resources/xlf/TraceDetail.es.xlf @@ -17,6 +17,11 @@ Trace details + + Name + Name + + {0} trace Seguimiento de {0} diff --git a/src/Aspire.Dashboard/Resources/xlf/TraceDetail.fr.xlf b/src/Aspire.Dashboard/Resources/xlf/TraceDetail.fr.xlf index 516b7ddbae..8297729c43 100644 --- a/src/Aspire.Dashboard/Resources/xlf/TraceDetail.fr.xlf +++ b/src/Aspire.Dashboard/Resources/xlf/TraceDetail.fr.xlf @@ -17,6 +17,11 @@ Trace details + + Name + Name + + {0} trace Trace {0} diff --git a/src/Aspire.Dashboard/Resources/xlf/TraceDetail.it.xlf b/src/Aspire.Dashboard/Resources/xlf/TraceDetail.it.xlf index 12bf106e1f..8cbebc9dc2 100644 --- a/src/Aspire.Dashboard/Resources/xlf/TraceDetail.it.xlf +++ b/src/Aspire.Dashboard/Resources/xlf/TraceDetail.it.xlf @@ -17,6 +17,11 @@ Trace details + + Name + Name + + {0} trace Traccia {0} diff --git a/src/Aspire.Dashboard/Resources/xlf/TraceDetail.ja.xlf b/src/Aspire.Dashboard/Resources/xlf/TraceDetail.ja.xlf index 2ae3a81934..058c3e7a42 100644 --- a/src/Aspire.Dashboard/Resources/xlf/TraceDetail.ja.xlf +++ b/src/Aspire.Dashboard/Resources/xlf/TraceDetail.ja.xlf @@ -17,6 +17,11 @@ Trace details + + Name + Name + + {0} trace {0} のトレース diff --git a/src/Aspire.Dashboard/Resources/xlf/TraceDetail.ko.xlf b/src/Aspire.Dashboard/Resources/xlf/TraceDetail.ko.xlf index 5523d0b2bf..89e2373377 100644 --- a/src/Aspire.Dashboard/Resources/xlf/TraceDetail.ko.xlf +++ b/src/Aspire.Dashboard/Resources/xlf/TraceDetail.ko.xlf @@ -17,6 +17,11 @@ Trace details + + Name + Name + + {0} trace {0} 추적 diff --git a/src/Aspire.Dashboard/Resources/xlf/TraceDetail.pl.xlf b/src/Aspire.Dashboard/Resources/xlf/TraceDetail.pl.xlf index acaf801924..2d76d8ebb7 100644 --- a/src/Aspire.Dashboard/Resources/xlf/TraceDetail.pl.xlf +++ b/src/Aspire.Dashboard/Resources/xlf/TraceDetail.pl.xlf @@ -17,6 +17,11 @@ Trace details + + Name + Name + + {0} trace Ślad {0} diff --git a/src/Aspire.Dashboard/Resources/xlf/TraceDetail.pt-BR.xlf b/src/Aspire.Dashboard/Resources/xlf/TraceDetail.pt-BR.xlf index bec75d25ed..08c472d973 100644 --- a/src/Aspire.Dashboard/Resources/xlf/TraceDetail.pt-BR.xlf +++ b/src/Aspire.Dashboard/Resources/xlf/TraceDetail.pt-BR.xlf @@ -17,6 +17,11 @@ Trace details + + Name + Name + + {0} trace Rastreamento de{0} diff --git a/src/Aspire.Dashboard/Resources/xlf/TraceDetail.ru.xlf b/src/Aspire.Dashboard/Resources/xlf/TraceDetail.ru.xlf index fa1eb4170d..54383254a5 100644 --- a/src/Aspire.Dashboard/Resources/xlf/TraceDetail.ru.xlf +++ b/src/Aspire.Dashboard/Resources/xlf/TraceDetail.ru.xlf @@ -17,6 +17,11 @@ Trace details + + Name + Name + + {0} trace Трассировка {0} diff --git a/src/Aspire.Dashboard/Resources/xlf/TraceDetail.tr.xlf b/src/Aspire.Dashboard/Resources/xlf/TraceDetail.tr.xlf index f77111cbfb..026c478c15 100644 --- a/src/Aspire.Dashboard/Resources/xlf/TraceDetail.tr.xlf +++ b/src/Aspire.Dashboard/Resources/xlf/TraceDetail.tr.xlf @@ -17,6 +17,11 @@ Trace details + + Name + Name + + {0} trace {0} izleme diff --git a/src/Aspire.Dashboard/Resources/xlf/TraceDetail.zh-Hans.xlf b/src/Aspire.Dashboard/Resources/xlf/TraceDetail.zh-Hans.xlf index e123eb3288..80f1436619 100644 --- a/src/Aspire.Dashboard/Resources/xlf/TraceDetail.zh-Hans.xlf +++ b/src/Aspire.Dashboard/Resources/xlf/TraceDetail.zh-Hans.xlf @@ -17,6 +17,11 @@ Trace details + + Name + Name + + {0} trace {0} 跟踪 diff --git a/src/Aspire.Dashboard/Resources/xlf/TraceDetail.zh-Hant.xlf b/src/Aspire.Dashboard/Resources/xlf/TraceDetail.zh-Hant.xlf index 8883c00140..4c6cc9cfa3 100644 --- a/src/Aspire.Dashboard/Resources/xlf/TraceDetail.zh-Hant.xlf +++ b/src/Aspire.Dashboard/Resources/xlf/TraceDetail.zh-Hant.xlf @@ -17,6 +17,11 @@ Trace details + + Name + Name + + {0} trace {0} 追蹤 diff --git a/src/Aspire.Dashboard/wwwroot/css/app.css b/src/Aspire.Dashboard/wwwroot/css/app.css index 441e3ef881..dcf6a8f1ef 100644 --- a/src/Aspire.Dashboard/wwwroot/css/app.css +++ b/src/Aspire.Dashboard/wwwroot/css/app.css @@ -174,6 +174,10 @@ h1 { .page-header { padding: calc(var(--design-unit) * 1.5px) calc(var(--design-unit) * 0.5px) 0; } + + .hidden-on-mobile { + visibility: collapse; + } } @media (min-width: 768px) { diff --git a/src/Aspire.Dashboard/wwwroot/js/app-metrics.js b/src/Aspire.Dashboard/wwwroot/js/app-metrics.js index e25facab28..7948cc8319 100644 --- a/src/Aspire.Dashboard/wwwroot/js/app-metrics.js +++ b/src/Aspire.Dashboard/wwwroot/js/app-metrics.js @@ -50,16 +50,8 @@ export function initializeChart(id, traces, exemplarTrace, rangeStartTime, range }; data.push(points); - // Explicitly set the width and height based on the container div. - // If there is no explicit width and height, Plotly will use the rendered container size. - // However, if the container isn't visible then it uses a default size. - // Being explicit ensures the chart is always the correct size. - var width = parseInt(chartContainerDiv.style.width); - var height = parseInt(chartContainerDiv.style.height); - + // Width and height are set using ResizeObserver + ploty resize call. var layout = { - width: width, - height: height, paper_bgcolor: themeColors.backgroundColor, plot_bgcolor: themeColors.backgroundColor, margin: { t: 0, r: 0, b: 40, l: 50 }, @@ -90,7 +82,7 @@ export function initializeChart(id, traces, exemplarTrace, rangeStartTime, range var options = { scrollZoom: false, displayModeBar: false }; - Plotly.newPlot(chartDiv, data, layout, options); + var plot = Plotly.newPlot(chartDiv, data, layout, options); fixTraceLineRendering(chartDiv); @@ -106,7 +98,6 @@ export function initializeChart(id, traces, exemplarTrace, rangeStartTime, range var point = data.points[0]; if (point.fullData.name == exemplarTrace.name) { currentPoint = point; - var pointTraceData = point.data.traceData[point.pointIndex]; dragLayer.style.cursor = 'pointer'; } }); @@ -125,6 +116,15 @@ export function initializeChart(id, traces, exemplarTrace, rangeStartTime, range chartInterop.invokeMethodAsync('ViewSpan', pointTraceData.traceId, pointTraceData.spanId); } }); + + const resizeObserver = new ResizeObserver(entries => { + for (let entry of entries) { + Plotly.Plots.resize(entry.target); + } + }); + plot.then(plotyDiv => { + resizeObserver.observe(plotyDiv); + }); } export function updateChart(id, traces, exemplarTrace, rangeStartTime, rangeEndTime) { diff --git a/src/Shared/StringComparers.cs b/src/Shared/StringComparers.cs index 15ac86e0c7..31cc291d48 100644 --- a/src/Shared/StringComparers.cs +++ b/src/Shared/StringComparers.cs @@ -16,6 +16,7 @@ internal static class StringComparers public static StringComparer UrlPath => StringComparer.OrdinalIgnoreCase; public static StringComparer UrlHost => StringComparer.OrdinalIgnoreCase; public static StringComparer Attribute => StringComparer.Ordinal; + public static StringComparer GridColumn => StringComparer.Ordinal; } internal static class StringComparisons diff --git a/tests/Aspire.Dashboard.Components.Tests/Controls/PlotlyChartTests.cs b/tests/Aspire.Dashboard.Components.Tests/Controls/PlotlyChartTests.cs index 5806442c04..dc59fde132 100644 --- a/tests/Aspire.Dashboard.Components.Tests/Controls/PlotlyChartTests.cs +++ b/tests/Aspire.Dashboard.Components.Tests/Controls/PlotlyChartTests.cs @@ -1,6 +1,7 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using Aspire.Dashboard.Components.Resize; using Aspire.Dashboard.Components.Tests.Shared; using Aspire.Dashboard.Configuration; using Aspire.Dashboard.Model; @@ -16,7 +17,7 @@ namespace Aspire.Dashboard.Components.Tests.Controls; [UseCulture("en-US")] public class PlotlyChartTests : TestContext { - private static string GetContainerHtml(string divId) => $"""
"""; + private static string GetContainerHtml(string divId) => $"""
"""; [Fact] public void Render_NoInstrument_NoPlotlyInvocations() @@ -30,6 +31,7 @@ public void Render_NoInstrument_NoPlotlyInvocations() var cut = RenderComponent(builder => { builder.Add(p => p.InstrumentViewModel, model); + builder.Add(p => p.ViewportInformation, new ViewportInformation(IsDesktop: true, IsUltraLowHeight: false, IsUltraLowWidth: false)); }); // Assert @@ -82,6 +84,7 @@ public async Task Render_HasInstrument_InitializeChartInvocation() { builder.Add(p => p.InstrumentViewModel, model); builder.Add(p => p.Duration, TimeSpan.FromSeconds(1)); + builder.Add(p => p.ViewportInformation, new ViewportInformation(IsDesktop: true, IsUltraLowHeight: false, IsUltraLowWidth: false)); }); // Assert diff --git a/tests/Aspire.Dashboard.Components.Tests/GridColumnManagerTests.cs b/tests/Aspire.Dashboard.Components.Tests/GridColumnManagerTests.cs new file mode 100644 index 0000000000..6567304db5 --- /dev/null +++ b/tests/Aspire.Dashboard.Components.Tests/GridColumnManagerTests.cs @@ -0,0 +1,61 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using Aspire.Dashboard.Components.Resize; +using Aspire.Dashboard.Model; +using Xunit; + +namespace Aspire.Dashboard.Components.Tests; + +public class GridColumnManagerTests +{ + [Fact] + public void Returns_Correct_TemplateColumn_String() + { + var dimensionManager = new DimensionManager(); + dimensionManager.InvokeOnBrowserDimensionsChanged(new ViewportInformation(IsDesktop: true, IsUltraLowHeight: false, IsUltraLowWidth: false)); + + var manager = new GridColumnManager([ + new GridColumn("NoMobile", "1fr", null), + new GridColumn("Both1", "1fr", "1fr"), + new GridColumn("Both2", "3fr", "0.5fr"), + new GridColumn("NoDesktop", null, "2fr"), + new GridColumn("NoDesktopWithIsVisibleFalse", null, "2fr", IsVisible: () => false), + new GridColumn("NoDesktopWithIsVisibleTrue", null, "4fr", IsVisible: () => true) + ], dimensionManager); + + Assert.Equal("1fr 1fr 3fr", manager.GetGridTemplateColumns()); + + dimensionManager.InvokeOnBrowserDimensionsChanged(new ViewportInformation(IsDesktop: false, IsUltraLowHeight: true, IsUltraLowWidth: false)); + Assert.Equal("1fr 0.5fr 2fr 4fr", manager.GetGridTemplateColumns()); + } + + [Fact] + public void Returns_Right_Columns_IsVisible() + { + var dimensionManager = new DimensionManager(); + dimensionManager.InvokeOnBrowserDimensionsChanged(new ViewportInformation(IsDesktop: true, IsUltraLowHeight: false, IsUltraLowWidth: false)); + + var manager = new GridColumnManager([ + new GridColumn("NoMobile", "1fr", null), + new GridColumn("Both1", "1fr", "1fr"), + new GridColumn("Both2", "3fr", "0.5fr"), + new GridColumn("NoDesktop", null, "2fr"), + new GridColumn("NoDesktopWithIsVisibleFalse", null, "2fr", IsVisible: () => false), + new GridColumn("NoDesktopWithIsVisibleTrue", null, "4fr", IsVisible: () => true) + ], dimensionManager); + + Assert.True(manager.IsColumnVisible("NoMobile")); + Assert.True(manager.IsColumnVisible("Both1")); + Assert.True(manager.IsColumnVisible("Both2")); + Assert.False(manager.IsColumnVisible("NoDesktop")); + + dimensionManager.InvokeOnBrowserDimensionsChanged(new ViewportInformation(IsDesktop: false, IsUltraLowHeight: true, IsUltraLowWidth: false)); + Assert.False(manager.IsColumnVisible("NoMobile")); + Assert.True(manager.IsColumnVisible("Both1")); + Assert.True(manager.IsColumnVisible("Both2")); + Assert.True(manager.IsColumnVisible("NoDesktop")); + Assert.False(manager.IsColumnVisible("NoDesktopWithIsVisibleFalse")); + Assert.True(manager.IsColumnVisible("NoDesktopWithIsVisibleTrue")); + } +} diff --git a/tests/Aspire.Dashboard.Components.Tests/Pages/MetricsTests.cs b/tests/Aspire.Dashboard.Components.Tests/Pages/MetricsTests.cs index d9a26a551d..75d3787bab 100644 --- a/tests/Aspire.Dashboard.Components.Tests/Pages/MetricsTests.cs +++ b/tests/Aspire.Dashboard.Components.Tests/Pages/MetricsTests.cs @@ -88,7 +88,7 @@ private void ChangeResourceAndAssertInstrument(string app1InstrumentName, string var cut = RenderComponent(builder => { builder.Add(m => m.ApplicationName, "TestApp"); - builder.AddCascadingValue(new ViewportInformation(IsDesktop: true, IsUltraLowHeight: false)); + builder.AddCascadingValue(new ViewportInformation(IsDesktop: true, IsUltraLowHeight: false, IsUltraLowWidth: false)); }); var viewModel = cut.Instance.PageViewModel; diff --git a/tests/Aspire.Dashboard.Components.Tests/Pages/StructuredLogsTests.cs b/tests/Aspire.Dashboard.Components.Tests/Pages/StructuredLogsTests.cs index 41ace4e000..8861dcdd71 100644 --- a/tests/Aspire.Dashboard.Components.Tests/Pages/StructuredLogsTests.cs +++ b/tests/Aspire.Dashboard.Components.Tests/Pages/StructuredLogsTests.cs @@ -37,7 +37,10 @@ public void Render_TraceIdAndSpanId_FilterAdded() }); navigationManager.NavigateTo(uri); - var viewport = new ViewportInformation(IsDesktop: true, IsUltraLowHeight: false); + var viewport = new ViewportInformation(IsDesktop: true, IsUltraLowHeight: false, IsUltraLowWidth: false); + + var dimensionManager = Services.GetRequiredService(); + dimensionManager.InvokeOnBrowserDimensionsChanged(viewport); // Act var cut = RenderComponent(builder =>