From 3d2e95b83710a94e78933ed35cb349cf87187cca Mon Sep 17 00:00:00 2001 From: Adam Ratzman Date: Mon, 14 Apr 2025 14:02:07 -0400 Subject: [PATCH 1/2] Ensure visible trace spans stay sorted by start time --- src/Aspire.Dashboard/Components/Pages/TraceDetail.razor.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Aspire.Dashboard/Components/Pages/TraceDetail.razor.cs b/src/Aspire.Dashboard/Components/Pages/TraceDetail.razor.cs index 195ff568cf9..1ecbb812f0f 100644 --- a/src/Aspire.Dashboard/Components/Pages/TraceDetail.razor.cs +++ b/src/Aspire.Dashboard/Components/Pages/TraceDetail.razor.cs @@ -80,7 +80,7 @@ private ValueTask> GetData(GridI { Debug.Assert(_spanWaterfallViewModels != null); - var visibleViewModels = new HashSet(); + var visibleViewModels = new SortedSet(Comparer.Create((a, b) => a.Span.StartTime.CompareTo(b.Span.StartTime))); foreach (var viewModel in _spanWaterfallViewModels) { if (!viewModel.IsHidden && viewModel.MatchesFilter(_filter, GetResourceName, out var matchedDescendents)) From 3ef09984514f5461a8c250b45729f54e00e9201b Mon Sep 17 00:00:00 2001 From: Adam Ratzman Date: Tue, 15 Apr 2025 12:01:06 -0400 Subject: [PATCH 2/2] Add grid sort order test --- .../Components/Pages/TraceDetail.razor.cs | 3 +- .../Pages/TraceDetailsTests.cs | 56 +++++++++++++++++++ 2 files changed, 58 insertions(+), 1 deletion(-) diff --git a/src/Aspire.Dashboard/Components/Pages/TraceDetail.razor.cs b/src/Aspire.Dashboard/Components/Pages/TraceDetail.razor.cs index 1ecbb812f0f..48218220e22 100644 --- a/src/Aspire.Dashboard/Components/Pages/TraceDetail.razor.cs +++ b/src/Aspire.Dashboard/Components/Pages/TraceDetail.razor.cs @@ -76,7 +76,8 @@ protected override void OnInitialized() } } - private ValueTask> GetData(GridItemsProviderRequest request) + // Internal to be used in unit tests + internal ValueTask> GetData(GridItemsProviderRequest request) { Debug.Assert(_spanWaterfallViewModels != null); diff --git a/tests/Aspire.Dashboard.Components.Tests/Pages/TraceDetailsTests.cs b/tests/Aspire.Dashboard.Components.Tests/Pages/TraceDetailsTests.cs index 9e6ea12175a..53d9f4c64b1 100644 --- a/tests/Aspire.Dashboard.Components.Tests/Pages/TraceDetailsTests.cs +++ b/tests/Aspire.Dashboard.Components.Tests/Pages/TraceDetailsTests.cs @@ -137,6 +137,62 @@ public async Task Render_ChangeTrace_RowsRendered() await AsyncTestHelpers.AssertIsTrueRetryAsync(() => rows.Count == 2, "Expected rows to be rendered."); } + [Fact] + public async Task Render_SpansOrderedByStartTime_RowsRenderedInCorrectOrder() + { + // Arrange + SetupTraceDetailsServices(); + + var viewport = new ViewportInformation(IsDesktop: true, IsUltraLowHeight: false, IsUltraLowWidth: false); + + var dimensionManager = Services.GetRequiredService(); + dimensionManager.InvokeOnViewportInformationChanged(viewport); + + var telemetryRepository = Services.GetRequiredService(); + telemetryRepository.AddTraces(new AddContext(), + new RepeatedField + { + new ResourceSpans + { + Resource = CreateResource(), + ScopeSpans = + { + new ScopeSpans + { + Scope = CreateScope(), + Spans = + { + CreateSpan(traceId: "1", spanId: "1-1", + startTime: s_testTime.AddMinutes(1), + endTime: s_testTime.AddMinutes(10)), + CreateSpan(traceId: "1", spanId: "1-2", + startTime: s_testTime.AddMinutes(5), + endTime: s_testTime.AddMinutes(10), parentSpanId: "1-1"), + CreateSpan(traceId: "1", spanId: "1-3", + startTime: s_testTime.AddMinutes(2), + endTime: s_testTime.AddMinutes(6), parentSpanId: "1-1") + } + } + } + } + }); + + // Act + var traceId = Convert.ToHexString(Encoding.UTF8.GetBytes("1")); + var cut = RenderComponent(builder => + { + builder.Add(p => p.TraceId, traceId); + builder.AddCascadingValue(viewport); + }); + + var data = await cut.Instance.GetData(new GridItemsProviderRequest()); + + Assert.Collection(data.Items, + item => Assert.Equal("Test span. Id: 1-1", item.Span.Name), + item => Assert.Equal("Test span. Id: 1-3", item.Span.Name), + item => Assert.Equal("Test span. Id: 1-2", item.Span.Name)); + } + private void SetupTraceDetailsServices() { var version = typeof(FluentMain).Assembly.GetName().Version!;