diff --git a/src/Aspire.Dashboard/Components/Controls/ResourceFilters.razor b/src/Aspire.Dashboard/Components/Controls/ResourceFilters.razor new file mode 100644 index 0000000000..5ac8ec06fd --- /dev/null +++ b/src/Aspire.Dashboard/Components/Controls/ResourceFilters.razor @@ -0,0 +1,45 @@ +@using System.Collections.Concurrent + +@inject IStringLocalizer Loc + + +
+
@Loc[nameof(Resources.Resources.ResourcesResourceTypesHeader)]
+ +
+
+
@Loc[nameof(Resources.Resources.ResourcesResourceStatesHeader)]
+ +
+
+
@Loc[nameof(Resources.Resources.ResourcesDetailsHealthStateProperty)]
+ +
+
+ +@code { + + [Parameter, EditorRequired] + public required ConcurrentDictionary ResourceTypes { get; set; } + + [Parameter, EditorRequired] + public required ConcurrentDictionary ResourceStates { get; set; } + + [Parameter, EditorRequired] + public required ConcurrentDictionary ResourceHealthStates { get; set; } + + [Parameter, EditorRequired] + public required Func OnAllFilterVisibilityCheckedChangedAsync { get; set; } + + [Parameter, EditorRequired] + public required Func OnResourceFilterVisibilityChangedAsync { get; set; } +} diff --git a/src/Aspire.Dashboard/Components/Controls/SelectResourceOptions.razor b/src/Aspire.Dashboard/Components/Controls/SelectResourceOptions.razor new file mode 100644 index 0000000000..1a8dece0ea --- /dev/null +++ b/src/Aspire.Dashboard/Components/Controls/SelectResourceOptions.razor @@ -0,0 +1,39 @@ +@namespace Aspire.Dashboard.Components + +@using System.Collections.Concurrent +@using Aspire.Dashboard.Resources + +@inject IStringLocalizer ControlsStringsLoc +@inject IStringLocalizer Loc + +@typeparam TValue where TValue : notnull + + + + + @foreach (var (key, isChecked) in Values.OrderBy(pair => pair.Key.ToString(), StringComparer.OrdinalIgnoreCase)) + { + var label = string.IsNullOrEmpty(key.ToString()) ? Loc[nameof(Resources.ResourceFilterOptionEmpty)] : key.ToString(); + + + } + + +@code { + [Parameter, EditorRequired] + public required ConcurrentDictionary Values { get; set; } + + [Parameter, EditorRequired] + public required Func OnAllValuesCheckedChangedAsync { get; set; } + + [Parameter, EditorRequired] + public required Func OnValueVisibilityChangedAsync { get; set; } +} diff --git a/src/Aspire.Dashboard/Components/Controls/SelectResourceOptions.razor.cs b/src/Aspire.Dashboard/Components/Controls/SelectResourceOptions.razor.cs new file mode 100644 index 0000000000..4baf3b2169 --- /dev/null +++ b/src/Aspire.Dashboard/Components/Controls/SelectResourceOptions.razor.cs @@ -0,0 +1,69 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Collections.Concurrent; + +namespace Aspire.Dashboard.Components; + +public partial class SelectResourceOptions +{ + private async Task OnAllValuesCheckedChangedInternalAsync(bool? newAreAllVisible) + { + SetCheckState(newAreAllVisible, Values); + await OnAllValuesCheckedChangedAsync(); + } + + private Task OnValueVisibilityChangedInternalAsync(TValue value, bool isVisible) + { + Values[value] = isVisible; + return OnValueVisibilityChangedAsync(value, isVisible); + } + + private static void SetCheckState(bool? newAreAllVisible, ConcurrentDictionary values) + { + if (newAreAllVisible is null) + { + return; + } + + foreach (var key in values.Keys) + { + values[key] = newAreAllVisible.Value; + } + } + + private static bool? GetCheckState(ConcurrentDictionary values) + { + if (values.IsEmpty) + { + return true; + } + + var areAllChecked = true; + var areAllUnchecked = true; + + foreach (var value in values.Values) + { + if (value) + { + areAllUnchecked = false; + } + else + { + areAllChecked = false; + } + } + + if (areAllChecked) + { + return true; + } + + if (areAllUnchecked) + { + return false; + } + + return null; + } +} diff --git a/src/Aspire.Dashboard/Components/Controls/SelectResourceTypes.razor b/src/Aspire.Dashboard/Components/Controls/SelectResourceTypes.razor deleted file mode 100644 index 1ba88f3e1e..0000000000 --- a/src/Aspire.Dashboard/Components/Controls/SelectResourceTypes.razor +++ /dev/null @@ -1,39 +0,0 @@ -@namespace Aspire.Dashboard.Components - -@using System.Collections.Concurrent -@using Aspire.Dashboard.Resources - -@inject IStringLocalizer ControlsStringsLoc - - - - @foreach (var (resourceType, _) in AllResourceTypes) - { - var isChecked = VisibleResourceTypes.ContainsKey(resourceType); - - } - -@code { - [Parameter, EditorRequired] - public required ConcurrentDictionary AllResourceTypes { get; set; } - - [Parameter, EditorRequired] - public required Func AreAllTypesVisible { get; set; } - - [Parameter, EditorRequired] - public required ConcurrentDictionary VisibleResourceTypes { get; set; } - - [Parameter, EditorRequired] - public required Func OnAllResourceTypesCheckedChangedAsync { get; set; } - - [Parameter, EditorRequired] - public required Func OnResourceTypeVisibilityChangedAsync { get; set; } -} diff --git a/src/Aspire.Dashboard/Components/Pages/Resources.razor b/src/Aspire.Dashboard/Components/Pages/Resources.razor index 491af2b917..50c916c4ec 100644 --- a/src/Aspire.Dashboard/Components/Pages/Resources.razor +++ b/src/Aspire.Dashboard/Components/Pages/Resources.razor @@ -5,7 +5,6 @@ @using System.Globalization @using Aspire.Dashboard.Components.Controls.Grid @using Aspire.Dashboard.Model -@using Humanizer @inject IStringLocalizer Loc @inject IStringLocalizer ControlsStringsLoc @inject IStringLocalizer ColumnsLoc @@ -33,36 +32,39 @@ @if (ViewportInformation.IsDesktop) { - + @onclick="() => _isFilterPopupVisible = !_isFilterPopupVisible" + Title="@(NoFiltersSet ? Loc[nameof(Dashboard.Resources.Resources.ResourcesNotFiltered)] : Loc[nameof(Dashboard.Resources.Resources.ResourcesFiltered)])" + aria-label="@(NoFiltersSet ? Loc[nameof(Dashboard.Resources.Resources.ResourcesNotFiltered)] : Loc[nameof(Dashboard.Resources.Resources.ResourcesFiltered)])" /> } else {
-
@Loc[nameof(Dashboard.Resources.Resources.ResourcesResourceTypesHeader)]
- - +
} - -
@Loc[nameof(Dashboard.Resources.Resources.ResourcesResourceTypesHeader)]
+ - + diff --git a/src/Aspire.Dashboard/Components/Pages/Resources.razor.cs b/src/Aspire.Dashboard/Components/Pages/Resources.razor.cs index 6a06139d0a..c2472b877d 100644 --- a/src/Aspire.Dashboard/Components/Pages/Resources.razor.cs +++ b/src/Aspire.Dashboard/Components/Pages/Resources.razor.cs @@ -9,6 +9,7 @@ using Aspire.Dashboard.Model; using Aspire.Dashboard.Otlp.Storage; using Aspire.Dashboard.Utils; +using Humanizer; using Microsoft.AspNetCore.Components; using Microsoft.FluentUI.AspNetCore.Components; using Microsoft.JSInterop; @@ -49,6 +50,14 @@ public partial class Resources : ComponentBase, IAsyncDisposable [SupplyParameterFromQuery] public string? VisibleTypes { get; set; } + [Parameter] + [SupplyParameterFromQuery] + public string? VisibleStates { get; set; } + + [Parameter] + [SupplyParameterFromQuery] + public string? VisibleHealthStates { get; set; } + [Parameter] [SupplyParameterFromQuery(Name = "resource")] public string? ResourceName { get; set; } @@ -57,11 +66,9 @@ public partial class Resources : ComponentBase, IAsyncDisposable private readonly CancellationTokenSource _watchTaskCancellationTokenSource = new(); private readonly ConcurrentDictionary _resourceByName = new(StringComparers.ResourceName); - private readonly ConcurrentDictionary _allResourceTypes = []; - private readonly ConcurrentDictionary _visibleResourceTypes = new(StringComparers.ResourceName); private readonly HashSet _expandedResourceNames = []; private string _filter = ""; - private bool _isTypeFilterVisible; + private bool _isFilterPopupVisible; private Task? _resourceSubscriptionTask; private bool _isLoading = true; private string? _elementIdBeforeDetailsViewOpened; @@ -72,80 +79,47 @@ public partial class Resources : ComponentBase, IAsyncDisposable private ColumnResizeLabels _resizeLabels = ColumnResizeLabels.Default; private ColumnSortLabels _sortLabels = ColumnSortLabels.Default; - private bool Filter(ResourceViewModel resource) => _visibleResourceTypes.ContainsKey(resource.ResourceType) && (_filter.Length == 0 || resource.MatchesFilter(_filter)) && !resource.IsHiddenState(); + // Filters in the resource popup + private readonly ConcurrentDictionary _resourceTypesToVisibility = new(StringComparers.ResourceName); + + private readonly ConcurrentDictionary _resourceStatesToVisibility = new(StringComparers.ResourceState); - private async Task OnAllResourceTypesCheckedChangedAsync(bool? areAllTypesVisible) + private readonly ConcurrentDictionary _resourceHealthStatusesToVisibility = new(StringComparer.Ordinal); + + private bool Filter(ResourceViewModel resource) { - AreAllTypesVisible = areAllTypesVisible; - await _dataGrid.SafeRefreshDataAsync(); + return IsKeyValueTrue(resource.ResourceType, _resourceTypesToVisibility) + && IsKeyValueTrue(resource.State, _resourceStatesToVisibility) + && IsKeyValueTrue(resource.HealthStatus?.Humanize(), _resourceHealthStatusesToVisibility) + && (_filter.Length == 0 || resource.MatchesFilter(_filter)) + && !resource.IsHiddenState(); + + static bool IsKeyValueTrue(string? key, IDictionary dictionary) => key is not null && dictionary.TryGetValue(key, out var value) && value; } - private async Task OnResourceTypeVisibilityChangedAsync(string resourceType, bool isVisible) + private async Task OnAllFilterVisibilityCheckedChangedAsync() { - if (isVisible) - { - _visibleResourceTypes[resourceType] = true; - } - else - { - _visibleResourceTypes.TryRemove(resourceType, out _); - } - await ClearSelectedResourceAsync(); await _dataGrid.SafeRefreshDataAsync(); } - private async Task HandleSearchFilterChangedAsync() + private async Task OnResourceFilterVisibilityChangedAsync(string resourceType, bool isVisible) { await ClearSelectedResourceAsync(); await _dataGrid.SafeRefreshDataAsync(); } - private bool? AreAllTypesVisible + private async Task HandleSearchFilterChangedAsync() { - get - { - static bool SetEqualsKeys(ConcurrentDictionary left, ConcurrentDictionary right) - { - // PERF: This is inefficient since Keys locks and copies the keys. - var keysLeft = left.Keys; - var keysRight = right.Keys; - - return keysLeft.Count == keysRight.Count && keysLeft.OrderBy(key => key, StringComparers.ResourceType).SequenceEqual(keysRight.OrderBy(key => key, StringComparers.ResourceType), StringComparers.ResourceType); - } - - return SetEqualsKeys(_visibleResourceTypes, _allResourceTypes) - ? true - : _visibleResourceTypes.IsEmpty - ? false - : null; - } - set - { - static bool UnionWithKeys(ConcurrentDictionary left, ConcurrentDictionary right) - { - // .Keys locks and copies the keys so avoid it here. - foreach (var (key, _) in right) - { - left[key] = true; - } - - return true; - } - - if (value is true) - { - UnionWithKeys(_visibleResourceTypes, _allResourceTypes); - } - else if (value is false) - { - _visibleResourceTypes.Clear(); - } - - StateHasChanged(); - } + await ClearSelectedResourceAsync(); + await _dataGrid.SafeRefreshDataAsync(); } + private bool NoFiltersSet => AreAllTypesVisible && AreAllStatesVisible && AreAllHealthStatesVisible; + private bool AreAllTypesVisible => _resourceTypesToVisibility.Values.All(value => value); + private bool AreAllStatesVisible => _resourceStatesToVisibility.Values.All(value => value); + private bool AreAllHealthStatesVisible => _resourceHealthStatusesToVisibility.Values.All(value => value); + private readonly GridSort _nameSort = GridSort.ByAscending(p => p.Resource, ResourceViewModelNameComparer.Instance); private readonly GridSort _stateSort = GridSort.ByAscending(p => p.Resource.State).ThenAscending(p => p.Resource, ResourceViewModelNameComparer.Instance); private readonly GridSort _startTimeSort = GridSort.ByDescending(p => p.Resource.StartTimeStamp).ThenAscending(p => p.Resource, ResourceViewModelNameComparer.Instance); @@ -188,6 +162,8 @@ protected override async Task OnInitializedAsync() async Task SubscribeResourcesAsync() { var preselectedVisibleResourceTypes = VisibleTypes?.Split(',').ToHashSet(); + var preselectedVisibleResourceStates = VisibleStates?.Split(',').ToHashSet(); + var preselectedVisibleResourceHealthStates = VisibleHealthStates?.Split(',').ToHashSet(); var (snapshot, subscription) = await DashboardClient.SubscribeResourcesAsync(_watchTaskCancellationTokenSource.Token); @@ -195,13 +171,9 @@ async Task SubscribeResourcesAsync() foreach (var resource in snapshot) { var added = _resourceByName.TryAdd(resource.Name, resource); - - _allResourceTypes.TryAdd(resource.ResourceType, true); - - if (preselectedVisibleResourceTypes is null || preselectedVisibleResourceTypes.Contains(resource.ResourceType)) - { - _visibleResourceTypes.TryAdd(resource.ResourceType, true); - } + _resourceTypesToVisibility.TryAdd(resource.ResourceType, preselectedVisibleResourceTypes is null || preselectedVisibleResourceTypes.Contains(resource.ResourceType)); + _resourceStatesToVisibility.TryAdd(resource.State ?? string.Empty, preselectedVisibleResourceStates is null || preselectedVisibleResourceStates.Contains(resource.State ?? string.Empty)); + _resourceHealthStatusesToVisibility.TryAdd(resource.HealthStatus?.Humanize() ?? string.Empty, preselectedVisibleResourceHealthStates is null || preselectedVisibleResourceHealthStates.Contains(resource.HealthStatus?.Humanize() ?? string.Empty)); Debug.Assert(added, "Should not receive duplicate resources in initial snapshot data."); } @@ -226,13 +198,6 @@ async Task SubscribeResourcesAsync() SelectedResource = resource; selectedResourceHasChanged = true; } - - if (_allResourceTypes.TryAdd(resource.ResourceType, true)) - { - // If someone has filtered out a resource type then don't remove filter because an update was received. - // Only automatically set resource type to visible if it is a new resource. - _visibleResourceTypes[resource.ResourceType] = true; - } } else if (changeType == ResourceViewModelChangeType.Delete) { @@ -276,9 +241,10 @@ private ValueTask> GetData(GridIt // Paging visible resources. var query = orderedResources .Skip(request.StartIndex) - .Take(request.Count ?? DashboardUIHelpers.DefaultDataGridResultCount); + .Take(request.Count ?? DashboardUIHelpers.DefaultDataGridResultCount) + .ToList(); - return ValueTask.FromResult(GridItemsProviderResult.From(query.ToList(), orderedResources.Count)); + return ValueTask.FromResult(GridItemsProviderResult.From(query, orderedResources.Count)); } private void UpdateMaxHighlightedCount() diff --git a/src/Aspire.Dashboard/Resources/Resources.Designer.cs b/src/Aspire.Dashboard/Resources/Resources.Designer.cs index 3627dda67e..267e8f38e9 100644 --- a/src/Aspire.Dashboard/Resources/Resources.Designer.cs +++ b/src/Aspire.Dashboard/Resources/Resources.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. @@ -168,6 +167,15 @@ public static string ResourceDetailsViewConsoleLogs { } } + /// + /// Looks up a localized string similar to No state. + /// + public static string ResourceFilterOptionEmpty { + get { + return ResourceManager.GetString("ResourceFilterOptionEmpty", resourceCulture); + } + } + /// /// Looks up a localized string similar to Actions. /// @@ -357,6 +365,15 @@ public static string ResourcesEnvironmentVariablesHeader { } } + /// + /// Looks up a localized string similar to Has filters. + /// + public static string ResourcesFiltered { + get { + return ResourceManager.GetString("ResourcesFiltered", resourceCulture); + } + } + /// /// Looks up a localized string similar to Resources. /// @@ -384,6 +401,15 @@ public static string ResourcesNoResources { } } + /// + /// Looks up a localized string similar to No filters. + /// + public static string ResourcesNotFiltered { + get { + return ResourceManager.GetString("ResourcesNotFiltered", resourceCulture); + } + } + /// /// Looks up a localized string similar to {0} resources. /// @@ -393,6 +419,15 @@ public static string ResourcesPageTitle { } } + /// + /// Looks up a localized string similar to State. + /// + public static string ResourcesResourceStatesHeader { + get { + return ResourceManager.GetString("ResourcesResourceStatesHeader", resourceCulture); + } + } + /// /// Looks up a localized string similar to Resource types. /// @@ -438,24 +473,6 @@ public static string ResourcesTypeColumnHeader { } } - /// - /// Looks up a localized string similar to Type filter: All types visible. - /// - public static string ResourcesTypeFilterAllVisible { - get { - return ResourceManager.GetString("ResourcesTypeFilterAllVisible", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Type filter: Filtered. - /// - public static string ResourcesTypeFiltered { - get { - return ResourceManager.GetString("ResourcesTypeFiltered", resourceCulture); - } - } - /// /// Looks up a localized string similar to Waiting for health data.... /// diff --git a/src/Aspire.Dashboard/Resources/Resources.resx b/src/Aspire.Dashboard/Resources/Resources.resx index 7ecdd3deb7..3fa7027d2e 100644 --- a/src/Aspire.Dashboard/Resources/Resources.resx +++ b/src/Aspire.Dashboard/Resources/Resources.resx @@ -1,17 +1,17 @@ - @@ -124,15 +124,21 @@ Resources - - Type filter: All types visible + + No filters - - Type filter: Filtered + + Has filters Resource types + + State + + + No state + Environment variables for {0} {0} is a resource @@ -262,4 +268,4 @@ No telemetry found for this resource. - \ No newline at end of file + diff --git a/src/Aspire.Dashboard/Resources/xlf/Resources.cs.xlf b/src/Aspire.Dashboard/Resources/xlf/Resources.cs.xlf index b32fc7513b..f5d993c759 100644 --- a/src/Aspire.Dashboard/Resources/xlf/Resources.cs.xlf +++ b/src/Aspire.Dashboard/Resources/xlf/Resources.cs.xlf @@ -62,6 +62,11 @@ Zobrazit protokoly konzoly + + No state + No state + + Actions Akce @@ -162,6 +167,21 @@ Prostředí + + Has filters + Has filters + + + + No filters + No filters + + + + State + State + + Source Zdroj @@ -212,16 +232,6 @@ Typ - - Type filter: All types visible - Filtr typů: Jsou viditelné všechny typy - - - - Type filter: Filtered - Filtr typů: Vyfiltrováno - - Waiting for health data... Čeká se na data o stavu... diff --git a/src/Aspire.Dashboard/Resources/xlf/Resources.de.xlf b/src/Aspire.Dashboard/Resources/xlf/Resources.de.xlf index 11130545b2..41fd849543 100644 --- a/src/Aspire.Dashboard/Resources/xlf/Resources.de.xlf +++ b/src/Aspire.Dashboard/Resources/xlf/Resources.de.xlf @@ -62,6 +62,11 @@ Konsolenprotokolle anzeigen + + No state + No state + + Actions Aktionen @@ -162,6 +167,21 @@ Umgebung + + Has filters + Has filters + + + + No filters + No filters + + + + State + State + + Source Quelle @@ -212,16 +232,6 @@ Typ - - Type filter: All types visible - Typfilter: Alle Typen sichtbar - - - - Type filter: Filtered - Typfilter: Gefiltert - - Waiting for health data... Auf Integritätsdaten wird gewartet... diff --git a/src/Aspire.Dashboard/Resources/xlf/Resources.es.xlf b/src/Aspire.Dashboard/Resources/xlf/Resources.es.xlf index 4e61942137..74d281124d 100644 --- a/src/Aspire.Dashboard/Resources/xlf/Resources.es.xlf +++ b/src/Aspire.Dashboard/Resources/xlf/Resources.es.xlf @@ -62,6 +62,11 @@ Ver registros de consola + + No state + No state + + Actions Acciones @@ -162,6 +167,21 @@ Entorno + + Has filters + Has filters + + + + No filters + No filters + + + + State + State + + Source Origen @@ -212,16 +232,6 @@ Tipo - - Type filter: All types visible - Filtro de tipo: todos los tipos visibles - - - - Type filter: Filtered - Filtro de tipo: filtrado - - Waiting for health data... Esperando datos de estado... diff --git a/src/Aspire.Dashboard/Resources/xlf/Resources.fr.xlf b/src/Aspire.Dashboard/Resources/xlf/Resources.fr.xlf index 67be85e073..84abd8f190 100644 --- a/src/Aspire.Dashboard/Resources/xlf/Resources.fr.xlf +++ b/src/Aspire.Dashboard/Resources/xlf/Resources.fr.xlf @@ -62,6 +62,11 @@ Afficher les journaux de console + + No state + No state + + Actions Actions @@ -162,6 +167,21 @@ Environnement + + Has filters + Has filters + + + + No filters + No filters + + + + State + State + + Source Source @@ -212,16 +232,6 @@ Type - - Type filter: All types visible - Filtre de type : tous les types sont visibles - - - - Type filter: Filtered - Filtre de type : filtré - - Waiting for health data... En attente des données d’intégrité... Merci de patienter. diff --git a/src/Aspire.Dashboard/Resources/xlf/Resources.it.xlf b/src/Aspire.Dashboard/Resources/xlf/Resources.it.xlf index dc8ada6a40..215de0e158 100644 --- a/src/Aspire.Dashboard/Resources/xlf/Resources.it.xlf +++ b/src/Aspire.Dashboard/Resources/xlf/Resources.it.xlf @@ -62,6 +62,11 @@ Visualizza log della console + + No state + No state + + Actions Azioni @@ -162,6 +167,21 @@ Ambiente + + Has filters + Has filters + + + + No filters + No filters + + + + State + State + + Source Origine @@ -212,16 +232,6 @@ Tipo - - Type filter: All types visible - Filtro tipo: tutti i tipi sono visibili - - - - Type filter: Filtered - Filtro tipo: filtro applicato - - Waiting for health data... In attesa dei dati sull'integrità... diff --git a/src/Aspire.Dashboard/Resources/xlf/Resources.ja.xlf b/src/Aspire.Dashboard/Resources/xlf/Resources.ja.xlf index 161e998e01..cfc40c9793 100644 --- a/src/Aspire.Dashboard/Resources/xlf/Resources.ja.xlf +++ b/src/Aspire.Dashboard/Resources/xlf/Resources.ja.xlf @@ -62,6 +62,11 @@ コンソール ログの表示 + + No state + No state + + Actions アクション @@ -162,6 +167,21 @@ 環境 + + Has filters + Has filters + + + + No filters + No filters + + + + State + State + + Source ソース @@ -212,16 +232,6 @@ 種類 - - Type filter: All types visible - 型フィルター: すべての型が表示されます - - - - Type filter: Filtered - 型フィルター: フィルター処理済み - - Waiting for health data... 正常性データを待機しています... diff --git a/src/Aspire.Dashboard/Resources/xlf/Resources.ko.xlf b/src/Aspire.Dashboard/Resources/xlf/Resources.ko.xlf index aaf648268b..991efccee7 100644 --- a/src/Aspire.Dashboard/Resources/xlf/Resources.ko.xlf +++ b/src/Aspire.Dashboard/Resources/xlf/Resources.ko.xlf @@ -62,6 +62,11 @@ 콘솔 로그 보기 + + No state + No state + + Actions 작업 @@ -162,6 +167,21 @@ 환경 + + Has filters + Has filters + + + + No filters + No filters + + + + State + State + + Source 원본 @@ -212,16 +232,6 @@ 형식 - - Type filter: All types visible - 형식 필터: 모든 형식 표시 - - - - Type filter: Filtered - 형식 필터: 필터링됨 - - Waiting for health data... 상태 데이터를 기다리는 중... diff --git a/src/Aspire.Dashboard/Resources/xlf/Resources.pl.xlf b/src/Aspire.Dashboard/Resources/xlf/Resources.pl.xlf index e193efb77d..2e5512cf2f 100644 --- a/src/Aspire.Dashboard/Resources/xlf/Resources.pl.xlf +++ b/src/Aspire.Dashboard/Resources/xlf/Resources.pl.xlf @@ -62,6 +62,11 @@ Wyświetl dzienniki konsoli + + No state + No state + + Actions Akcje @@ -162,6 +167,21 @@ Środowisko + + Has filters + Has filters + + + + No filters + No filters + + + + State + State + + Source Źródło @@ -212,16 +232,6 @@ Typ - - Type filter: All types visible - Filtr typu: wszystkie typy są widoczne - - - - Type filter: Filtered - Filtr typu: filtrowany - - Waiting for health data... Trwa oczekiwanie na dane kondycji... diff --git a/src/Aspire.Dashboard/Resources/xlf/Resources.pt-BR.xlf b/src/Aspire.Dashboard/Resources/xlf/Resources.pt-BR.xlf index b20aaea852..7792930371 100644 --- a/src/Aspire.Dashboard/Resources/xlf/Resources.pt-BR.xlf +++ b/src/Aspire.Dashboard/Resources/xlf/Resources.pt-BR.xlf @@ -62,6 +62,11 @@ Exibir registros do console + + No state + No state + + Actions Ações @@ -162,6 +167,21 @@ Ambiente + + Has filters + Has filters + + + + No filters + No filters + + + + State + State + + Source Origem @@ -212,16 +232,6 @@ Tipo - - Type filter: All types visible - Filtro de tipo: todos os tipos visíveis - - - - Type filter: Filtered - Filtro de tipo: filtrado - - Waiting for health data... Aguardando os dados de integridade... diff --git a/src/Aspire.Dashboard/Resources/xlf/Resources.ru.xlf b/src/Aspire.Dashboard/Resources/xlf/Resources.ru.xlf index b07b233475..fd38b02125 100644 --- a/src/Aspire.Dashboard/Resources/xlf/Resources.ru.xlf +++ b/src/Aspire.Dashboard/Resources/xlf/Resources.ru.xlf @@ -62,6 +62,11 @@ Просмотр журналов консоли + + No state + No state + + Actions Действия @@ -162,6 +167,21 @@ Среда + + Has filters + Has filters + + + + No filters + No filters + + + + State + State + + Source Источник @@ -212,16 +232,6 @@ Тип - - Type filter: All types visible - Фильтр типов: все типы видимы - - - - Type filter: Filtered - Фильтр типов: отфильтрованный - - Waiting for health data... Ожидание данных о работоспособности... diff --git a/src/Aspire.Dashboard/Resources/xlf/Resources.tr.xlf b/src/Aspire.Dashboard/Resources/xlf/Resources.tr.xlf index 70142a7691..122518479c 100644 --- a/src/Aspire.Dashboard/Resources/xlf/Resources.tr.xlf +++ b/src/Aspire.Dashboard/Resources/xlf/Resources.tr.xlf @@ -62,6 +62,11 @@ Konsol günlüklerini görüntüle + + No state + No state + + Actions Eylemler @@ -162,6 +167,21 @@ Ortam + + Has filters + Has filters + + + + No filters + No filters + + + + State + State + + Source Kaynak @@ -212,16 +232,6 @@ Tür - - Type filter: All types visible - Tür filtresi: Tüm türler görünür - - - - Type filter: Filtered - Tür filtresi: Filtrelendi - - Waiting for health data... Sistem durumu verileri bekleniyor... diff --git a/src/Aspire.Dashboard/Resources/xlf/Resources.zh-Hans.xlf b/src/Aspire.Dashboard/Resources/xlf/Resources.zh-Hans.xlf index 50a95557c2..b133a5ac92 100644 --- a/src/Aspire.Dashboard/Resources/xlf/Resources.zh-Hans.xlf +++ b/src/Aspire.Dashboard/Resources/xlf/Resources.zh-Hans.xlf @@ -62,6 +62,11 @@ 查看控制台日志 + + No state + No state + + Actions 操作 @@ -162,6 +167,21 @@ 环境 + + Has filters + Has filters + + + + No filters + No filters + + + + State + State + + Source @@ -212,16 +232,6 @@ 类型 - - Type filter: All types visible - 类型筛选器: 所有类型可见 - - - - Type filter: Filtered - 类型筛选器: 已筛选 - - Waiting for health data... 正在等待运行状况数据... diff --git a/src/Aspire.Dashboard/Resources/xlf/Resources.zh-Hant.xlf b/src/Aspire.Dashboard/Resources/xlf/Resources.zh-Hant.xlf index 374779c317..4323e36311 100644 --- a/src/Aspire.Dashboard/Resources/xlf/Resources.zh-Hant.xlf +++ b/src/Aspire.Dashboard/Resources/xlf/Resources.zh-Hant.xlf @@ -62,6 +62,11 @@ 檢視主機記錄 + + No state + No state + + Actions 動作 @@ -162,6 +167,21 @@ 環境 + + Has filters + Has filters + + + + No filters + No filters + + + + State + State + + Source 來源 @@ -212,16 +232,6 @@ 類型 - - Type filter: All types visible - 類型篩選: 所有類型都可見 - - - - Type filter: Filtered - 類型篩選: 已篩選 - - Waiting for health data... 正在等待健康情況資料... diff --git a/src/Aspire.Dashboard/wwwroot/css/app.css b/src/Aspire.Dashboard/wwwroot/css/app.css index 2bdc0b23f0..fbdc92e2cb 100644 --- a/src/Aspire.Dashboard/wwwroot/css/app.css +++ b/src/Aspire.Dashboard/wwwroot/css/app.css @@ -734,3 +734,8 @@ fluent-switch.table-switch::part(label) { .clear-button::part(control) { padding: 0 calc((10 + (var(--design-unit) * 2 * var(--density))) * 1px); } + +.resources-filter-popup { + max-height: 400px; + overflow-y: auto; +}