-
Notifications
You must be signed in to change notification settings - Fork 658
Add "Collapse All"/"Expand All" buttons in the trace page #9474
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
0b57fc7
0fb3044
deb0de6
18c03a6
332b6b1
d5b5c90
34b388e
a14c166
4aa3b14
91db72a
90020cf
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -8,8 +8,10 @@ | |
using Aspire.Dashboard.Model.Otlp; | ||
using Aspire.Dashboard.Otlp.Model; | ||
using Aspire.Dashboard.Otlp.Storage; | ||
using Aspire.Dashboard.Resources; | ||
using Aspire.Dashboard.Utils; | ||
using Microsoft.AspNetCore.Components; | ||
using Microsoft.Extensions.Localization; | ||
using Microsoft.FluentUI.AspNetCore.Components; | ||
using Icons = Microsoft.FluentUI.AspNetCore.Components.Icons; | ||
using Microsoft.JSInterop; | ||
|
@@ -35,6 +37,7 @@ public partial class TraceDetail : ComponentBase, IComponentWithTelemetry, IDisp | |
private GridColumnManager _manager = null!; | ||
private IList<GridColumn> _gridColumns = null!; | ||
private string _filter = string.Empty; | ||
private readonly List<MenuButtonItem> _traceActionsMenuItems = new(); | ||
|
||
[Parameter] | ||
public required string TraceId { get; set; } | ||
|
@@ -64,6 +67,9 @@ public partial class TraceDetail : ComponentBase, IComponentWithTelemetry, IDisp | |
[Inject] | ||
public required ComponentTelemetryContextProvider TelemetryContextProvider { get; init; } | ||
|
||
[Inject] | ||
public required IStringLocalizer<ControlsStrings> ControlsLoc { get; init; } | ||
|
||
protected override void OnInitialized() | ||
{ | ||
_gridColumns = [ | ||
|
@@ -82,8 +88,31 @@ protected override void OnInitialized() | |
})); | ||
} | ||
|
||
UpdateTraceActionsMenu(); | ||
|
||
TelemetryContextProvider.Initialize(TelemetryContext); | ||
} | ||
|
||
private void UpdateTraceActionsMenu() | ||
{ | ||
_traceActionsMenuItems.Clear(); | ||
|
||
_traceActionsMenuItems.Add(new MenuButtonItem | ||
{ | ||
Text = ControlsLoc[nameof(ControlsStrings.ExpandAllSpansText)], | ||
Icon = new Icons.Regular.Size16.ArrowExpandAll(), | ||
OnClick = ExpandAllSpansAsync, | ||
IsDisabled = !HasCollapsedSpans() | ||
}); | ||
|
||
_traceActionsMenuItems.Add(new MenuButtonItem | ||
{ | ||
Text = ControlsLoc[nameof(ControlsStrings.CollapseAllSpansText)], | ||
Icon = new Icons.Regular.Size16.ArrowCollapseAll(), | ||
OnClick = CollapseAllSpansAsync, | ||
IsDisabled = !HasExpandedSpans() | ||
}); | ||
} | ||
|
||
// Internal to be used in unit tests | ||
internal ValueTask<GridItemsProviderResult<SpanWaterfallViewModel>> GetData(GridItemsProviderRequest<SpanWaterfallViewModel> request) | ||
|
@@ -192,6 +221,7 @@ private void UpdateDetailViewData() | |
_spanWaterfallViewModels = null; | ||
_maxDepth = 0; | ||
_resourceCount = 0; | ||
UpdateTraceActionsMenu(); // Update menu when no trace | ||
return; | ||
} | ||
|
||
|
@@ -209,6 +239,8 @@ private void UpdateDetailViewData() | |
} | ||
} | ||
_resourceCount = apps.Count; | ||
|
||
UpdateTraceActionsMenu(); // Update menu whenever view data changes | ||
} | ||
|
||
private async Task HandleAfterFilterBindAsync() | ||
|
@@ -253,21 +285,30 @@ private string GetRowClass(SpanWaterfallViewModel viewModel) | |
public SpanDetailsViewModel? SelectedSpan { get; set; } | ||
|
||
private async Task OnToggleCollapse(SpanWaterfallViewModel viewModel) | ||
{ | ||
SetSpanCollapsedState(viewModel, !viewModel.IsCollapsed); | ||
await RefreshSpanViewAsync(); | ||
} | ||
|
||
private void SetSpanCollapsedState(SpanWaterfallViewModel viewModel, bool isCollapsed) | ||
{ | ||
// View model data is recreated if the trace updates. | ||
// Persist the collapsed state in a separate list. | ||
if (viewModel.IsCollapsed) | ||
viewModel.IsCollapsed = isCollapsed; | ||
if (isCollapsed) | ||
{ | ||
viewModel.IsCollapsed = false; | ||
_collapsedSpanIds.Remove(viewModel.Span.SpanId); | ||
_collapsedSpanIds.Add(viewModel.Span.SpanId); | ||
} | ||
else | ||
{ | ||
viewModel.IsCollapsed = true; | ||
_collapsedSpanIds.Add(viewModel.Span.SpanId); | ||
_collapsedSpanIds.Remove(viewModel.Span.SpanId); | ||
} | ||
} | ||
|
||
private async Task RefreshSpanViewAsync() | ||
{ | ||
UpdateDetailViewData(); | ||
UpdateTraceActionsMenu(); | ||
await _dataGrid.SafeRefreshDataAsync(); | ||
} | ||
|
||
|
@@ -333,6 +374,62 @@ private async Task ClearSelectedSpanAsync(bool causedByUserAction = false) | |
_elementIdBeforeDetailsViewOpened = null; | ||
} | ||
|
||
private bool HasCollapsedSpans() | ||
{ | ||
if (_spanWaterfallViewModels is null) | ||
{ | ||
return false; | ||
} | ||
|
||
return _spanWaterfallViewModels.Any(vm => vm.IsCollapsed); | ||
} | ||
|
||
private bool HasExpandedSpans() | ||
{ | ||
if (_spanWaterfallViewModels is null) | ||
{ | ||
return false; | ||
} | ||
|
||
return _spanWaterfallViewModels.Any(vm => !vm.IsCollapsed && vm.Children.Count > 0); | ||
} | ||
|
||
private async Task CollapseAllSpansAsync() | ||
{ | ||
if (_spanWaterfallViewModels is null) | ||
{ | ||
return; | ||
} | ||
|
||
foreach (var viewModel in _spanWaterfallViewModels) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You should be using OnToggleCollapse There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Updated to follow the same state management pattern as OnToggleCollapse - manually updating both viewModel.IsCollapsed and _collapsedSpanIds list (commit 91db72a). |
||
{ | ||
if (viewModel.Children.Count > 0 && !viewModel.IsCollapsed) | ||
{ | ||
SetSpanCollapsedState(viewModel, true); | ||
} | ||
} | ||
|
||
await RefreshSpanViewAsync(); | ||
} | ||
|
||
private async Task ExpandAllSpansAsync() | ||
{ | ||
if (_spanWaterfallViewModels is null) | ||
{ | ||
return; | ||
} | ||
|
||
foreach (var viewModel in _spanWaterfallViewModels) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You should be using OnToggleCollapse There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Updated to follow the same state management pattern as OnToggleCollapse - manually updating both viewModel.IsCollapsed and _collapsedSpanIds list (commit 91db72a). There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. No, extract this logic and the logic in OnToggleCollapse into a helper function There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Extracted the common logic into helper functions |
||
{ | ||
if (viewModel.IsCollapsed) | ||
{ | ||
SetSpanCollapsedState(viewModel, false); | ||
} | ||
} | ||
|
||
await RefreshSpanViewAsync(); | ||
} | ||
|
||
private string GetResourceName(OtlpApplicationView app) => OtlpApplication.GetResourceName(app, _applications); | ||
|
||
public void Dispose() | ||
|
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The expand all button should only be enabled when there is a trace span that is collapsed. Likewise, the collapse all button should only be enabled if there is a trace span that is NOT collapsed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Implemented conditional enabling: "Expand All" is only enabled when there are collapsed spans, and "Collapse All" is only enabled when there are spans that can be collapsed (have children and are not already collapsed). The menu state updates dynamically as spans are toggled (commit 91db72a).