diff --git a/src/Aspire.Dashboard/Components/Controls/AspireMenuButton.razor b/src/Aspire.Dashboard/Components/Controls/AspireMenuButton.razor index 7c4881dda7a..b60f7831436 100644 --- a/src/Aspire.Dashboard/Components/Controls/AspireMenuButton.razor +++ b/src/Aspire.Dashboard/Components/Controls/AspireMenuButton.razor @@ -21,7 +21,11 @@ else { @Text - + + @if (!HideIcon) + { + + } } @@ -36,10 +40,10 @@ { var additionalMenuItemAttributes = new Dictionary(item.AdditionalAttributes ?? ImmutableDictionary.Empty) { - { "title", item.Tooltip ?? string.Empty } + { "title", item.Tooltip ?? item.Text ?? string.Empty } }; - + @item.Text @if (item.Icon != null) { diff --git a/src/Aspire.Dashboard/Components/Controls/AspireMenuButton.razor.cs b/src/Aspire.Dashboard/Components/Controls/AspireMenuButton.razor.cs index 3463d32d5a7..54c063c8467 100644 --- a/src/Aspire.Dashboard/Components/Controls/AspireMenuButton.razor.cs +++ b/src/Aspire.Dashboard/Components/Controls/AspireMenuButton.razor.cs @@ -43,6 +43,9 @@ public partial class AspireMenuButton : FluentComponentBase [Parameter] public string MenuButtonId { get; set; } = Identifier.NewId(); + [Parameter] + public bool HideIcon { get; set; } + protected override void OnParametersSet() { _icon = Icon ?? s_defaultIcon; diff --git a/src/Aspire.Dashboard/Components/Pages/StructuredLogs.razor b/src/Aspire.Dashboard/Components/Pages/StructuredLogs.razor index 2c129c76319..83709331680 100644 --- a/src/Aspire.Dashboard/Components/Pages/StructuredLogs.razor +++ b/src/Aspire.Dashboard/Components/Pages/StructuredLogs.razor @@ -6,6 +6,7 @@ @using Aspire.Dashboard.Resources @using System.Globalization @using Aspire.Dashboard.Components.Controls.Grid +@using Aspire.Dashboard.Model @inject IJSRuntime JS @implements IDisposable @@ -68,22 +69,17 @@ HandleSelectedLogLevelChangedAsync="@HandleSelectedLogLevelChangedAsync" /> } - @FilterLoc[nameof(StructuredFiltering.Filters)] @if (ViewModel.Filters.Count == 0) { @FilterLoc[nameof(StructuredFiltering.NoFilters)] } else { - for (var i = 0; i < ViewModel.Filters.Count; i++) - { - var filter = ViewModel.Filters[i]; - if (i != 0) - { - - } - @filter.GetDisplayText(FilterLoc) - } +
+ + + +
} @if (ViewportInformation.IsDesktop) diff --git a/src/Aspire.Dashboard/Components/Pages/StructuredLogs.razor.cs b/src/Aspire.Dashboard/Components/Pages/StructuredLogs.razor.cs index 6a914209112..aca17fd1365 100644 --- a/src/Aspire.Dashboard/Components/Pages/StructuredLogs.razor.cs +++ b/src/Aspire.Dashboard/Components/Pages/StructuredLogs.razor.cs @@ -349,6 +349,39 @@ private string GetRowClass(OtlpLogEntry entry) } } + private List GetFilterMenuItems() + { + var filterMenuItems = new List(); + + foreach (var filter in ViewModel.Filters) + { + filterMenuItems.Add(new MenuButtonItem + { + OnClick = () => OpenFilterAsync(filter), + Text = filter.GetDisplayText(FilterLoc), + Class = "filter-menu-item", + }); + } + + filterMenuItems.Add(new MenuButtonItem + { + IsDivider = true + }); + + filterMenuItems.Add(new MenuButtonItem + { + Text = DialogsLoc[nameof(Dashboard.Resources.Dialogs.SettingsRemoveAllButtonText)], + Icon = new Microsoft.FluentUI.AspNetCore.Components.Icons.Regular.Size16.Delete(), + OnClick = () => + { + ViewModel.ClearFilters(); + return this.AfterViewModelChangedAsync(_contentLayout, waitToApplyMobileChange: false); + } + }); + + return filterMenuItems; + } + protected override async Task OnAfterRenderAsync(bool firstRender) { if (_applicationChanged) diff --git a/src/Aspire.Dashboard/Components/Pages/Traces.razor b/src/Aspire.Dashboard/Components/Pages/Traces.razor index 2c76c270189..7984a0c462d 100644 --- a/src/Aspire.Dashboard/Components/Pages/Traces.razor +++ b/src/Aspire.Dashboard/Components/Pages/Traces.razor @@ -47,22 +47,17 @@ title="@Loc[nameof(Dashboard.Resources.Traces.TracesNameFilter)]" slot="end" /> - @FilterLoc[nameof(StructuredFiltering.Filters)] @if (TracesViewModel.Filters.Count == 0) { @FilterLoc[nameof(StructuredFiltering.NoFilters)] } else { - for (var i = 0; i < TracesViewModel.Filters.Count; i++) - { - var filter = TracesViewModel.Filters[i]; - if (i != 0) - { - - } - @filter.GetDisplayText(FilterLoc) - } +
+ + + +
} @if (ViewportInformation.IsDesktop) diff --git a/src/Aspire.Dashboard/Components/Pages/Traces.razor.cs b/src/Aspire.Dashboard/Components/Pages/Traces.razor.cs index 9619c8a9faf..d7ab137de73 100644 --- a/src/Aspire.Dashboard/Components/Pages/Traces.razor.cs +++ b/src/Aspire.Dashboard/Components/Pages/Traces.razor.cs @@ -343,6 +343,39 @@ private Task ClearTraces(ApplicationKey? key) return Task.CompletedTask; } + private List GetFilterMenuItems() + { + var filterMenuItems = new List(); + + foreach (var filter in TracesViewModel.Filters) + { + filterMenuItems.Add(new MenuButtonItem + { + OnClick = () => OpenFilterAsync(filter), + Text = filter.GetDisplayText(FilterLoc), + Class = "filter-menu-item", + }); + } + + filterMenuItems.Add(new MenuButtonItem + { + IsDivider = true + }); + + filterMenuItems.Add(new MenuButtonItem + { + Text = DialogsLoc[nameof(Dashboard.Resources.Dialogs.SettingsRemoveAllButtonText)], + Icon = new Microsoft.FluentUI.AspNetCore.Components.Icons.Regular.Size16.Delete(), + OnClick = () => + { + TracesViewModel.ClearFilters(); + return this.AfterViewModelChangedAsync(_contentLayout, waitToApplyMobileChange: false); + } + }); + + return filterMenuItems; + } + public class TracesPageViewModel { public required SelectViewModel SelectedApplication { get; set; } diff --git a/src/Aspire.Dashboard/Model/MenuButtonItem.cs b/src/Aspire.Dashboard/Model/MenuButtonItem.cs index 174e836636b..57b254733af 100644 --- a/src/Aspire.Dashboard/Model/MenuButtonItem.cs +++ b/src/Aspire.Dashboard/Model/MenuButtonItem.cs @@ -14,5 +14,6 @@ public class MenuButtonItem public Func? OnClick { get; set; } public bool IsDisabled { get; set; } public string Id { get; set; } = Identifier.NewId(); + public string? Class { get; set; } public IReadOnlyDictionary? AdditionalAttributes { get; set; } } diff --git a/src/Aspire.Dashboard/wwwroot/css/app.css b/src/Aspire.Dashboard/wwwroot/css/app.css index 500db7a7ed4..35bcf66b4a8 100644 --- a/src/Aspire.Dashboard/wwwroot/css/app.css +++ b/src/Aspire.Dashboard/wwwroot/css/app.css @@ -535,12 +535,6 @@ fluent-switch.table-switch::part(label) { padding: calc(((var(--design-unit) * 0.5) - var(--stroke-width)) * 1px) calc((var(--design-unit) - var(--stroke-width)) * 1px); } -.telemetry-filter-button::part(content) { - max-width: 350px; - overflow: hidden; - text-overflow: ellipsis -} - .mobile-toolbar { width: 100%; height: max(5vh, 30px); @@ -752,3 +746,7 @@ fluent-switch.table-switch::part(label) { max-height: 400px; overflow-y: auto; } + +.filter-menu-item::part(content) { + max-width: 300px; +} diff --git a/tests/Aspire.Dashboard.Components.Tests/Pages/StructuredLogsTests.cs b/tests/Aspire.Dashboard.Components.Tests/Pages/StructuredLogsTests.cs index 99777f0bf64..d273a4e8e03 100644 --- a/tests/Aspire.Dashboard.Components.Tests/Pages/StructuredLogsTests.cs +++ b/tests/Aspire.Dashboard.Components.Tests/Pages/StructuredLogsTests.cs @@ -189,6 +189,7 @@ private void SetupStructureLogsServices() Services.AddSingleton(); Services.AddSingleton(); Services.AddSingleton(); + Services.AddSingleton(); } private static string GetFluentFile(string filePath, Version version) diff --git a/tests/Shared/AsyncTestHelpers.cs b/tests/Shared/AsyncTestHelpers.cs index 785a9efdc22..62640fc0048 100644 --- a/tests/Shared/AsyncTestHelpers.cs +++ b/tests/Shared/AsyncTestHelpers.cs @@ -182,7 +182,7 @@ public static async Task AssertIsTrueRetryAsync(Func> assert, string { if (i > 0) { - await Task.Delay((i + 1) * (i + 1) * 10); + await Task.Delay((i + 1) * (i + 1) * 10 * 5); } if (await assert())