| File: Components\Controls\DashboardRunMenu.razor.cs | Web Access |
| Project: src\src\Aspire.Dashboard\Aspire.Dashboard.csproj (Aspire.Dashboard) |
// 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.Model; 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 LayoutResources = Aspire.Dashboard.Resources.Layout; namespace Aspire.Dashboard.Components.Controls; /// <summary> /// The run picker from before recordings had their own panel: a "Live run" dropdown that lists the runs in a popup /// menu. It's shown instead of the recordings icon and panel when the "Recordings" setting is set to the menu. /// </summary> public partial class DashboardRunMenu : ComponentBase { private const string DashboardRunsHelpUrl = "https://aka.ms/aspire/run-persistence"; private static readonly Icon s_checkmarkIcon = new Icons.Regular.Size16.Checkmark(); private static readonly Icon s_helpIcon = new Icons.Regular.Size16.QuestionCircle(); private static readonly Icon s_pinIcon = new Icons.Regular.Size16.Pin(); private static readonly Icon s_pinnedIcon = new Icons.Filled.Size16.Pin(); private readonly string _runMenuItemIdPrefix = $"dashboard-run-{Guid.NewGuid():N}"; private string RunSelectTitle => Loc[nameof(LayoutResources.DashboardRunMenuTitle)]; private string RunSelectAccessibleLabel => Loc[nameof(LayoutResources.DashboardRunMenuAccessibleLabel), SelectedRunText]; private string SelectedRunText => SelectedRunIsCurrent ? Loc[nameof(LayoutResources.DashboardRunMenuCurrent)] : FormatHelpers.FormatTimeWithOptionalDate(TimeProvider, SelectedRunStartedAtUtc.UtcDateTime); [Parameter, EditorRequired] public required string SelectedRunId { get; set; } [Parameter] public bool SelectedRunIsCurrent { get; set; } [Parameter] public DateTimeOffset SelectedRunStartedAtUtc { get; set; } [Parameter] public EventCallback<string?> SelectedRunIdChanged { get; set; } [Inject] public required IStringLocalizer<LayoutResources> Loc { get; init; } [Inject] public required BrowserTimeProvider TimeProvider { get; init; } [Inject] public required IDashboardRunStore RunStore { get; init; } [Inject] public required ILogger<DashboardRunMenu> Logger { get; init; } private IList<MenuButtonItem> LoadRuns() { var runs = DashboardRunSelect.GetSortedRuns(RunStore.GetRuns()); var menuItems = new List<MenuButtonItem>(); foreach (var run in runs) { var isCompatible = run.IsCompatible; var menuItem = new MenuButtonItem { Id = $"{_runMenuItemIdPrefix}-{Uri.EscapeDataString(run.RunId)}", RenderKey = run.RunId, Text = FormatRunOption(run), Role = MenuItemRole.Radio, Checked = string.Equals(run.RunId, SelectedRunId, StringComparison.Ordinal), Icon = s_checkmarkIcon, IsDisabled = !isCompatible, Tooltip = isCompatible ? null : Loc[nameof(LayoutResources.DashboardRunMenuIncompatibleTooltip)].Value, SecondaryActionIcon = run.IsPinned ? s_pinnedIcon : s_pinIcon, SecondaryActionAriaLabel = Loc[run.IsPinned ? nameof(LayoutResources.DashboardRunMenuUnpin) : nameof(LayoutResources.DashboardRunMenuPin)], IsSecondaryActionSelected = run.IsPinned, OnSecondaryActionClick = () => { SetRunPinned(run, !run.IsPinned); return Task.CompletedTask; }, OnClick = () => SelectedRunIdChanged.InvokeAsync(run.IsCurrent ? null : run.RunId) }; menuItems.Add(menuItem); if (run.IsCurrent && runs.Count > 1) { menuItems.Add(new MenuButtonItem { IsDivider = true }); } } menuItems.Add(new MenuButtonItem { IsDivider = true }); menuItems.Add(MenuButtonItem.CreateExternalLink( Loc[nameof(LayoutResources.DashboardRunMenuHelp)], DashboardRunsHelpUrl, s_helpIcon, tooltip: Loc[nameof(LayoutResources.DashboardRunMenuHelpTooltip)])); return menuItems; } private void SetRunPinned(DashboardRunDescriptor run, bool isPinned) { try { RunStore.SetRunPinned(run, isPinned); } catch (Exception exception) { Logger.LogError(exception, "Failed to update the pinned state of dashboard run '{RunId}'.", run.RunId); } } private string FormatRunOption(DashboardRunDescriptor run) { if (run.IsCurrent) { return Loc[nameof(LayoutResources.DashboardRunMenuCurrent)]; } return FormatHelpers.FormatTimeWithOptionalDate(TimeProvider, run.StartedAtUtc.UtcDateTime); } }