From 03a23d7cb2035cc1db115bbc7c3e0451cd188649 Mon Sep 17 00:00:00 2001 From: James Newton-King Date: Fri, 8 Aug 2025 10:22:15 +0800 Subject: [PATCH 1/3] Truncate large messages displayed in log grid --- .../Components/Pages/StructuredLogs.razor | 3 ++- .../LogMessageColumnDisplay.razor | 4 +++- src/Aspire.Dashboard/Utils/FormatHelpers.cs | 21 +++++++++++++++++++ 3 files changed, 26 insertions(+), 2 deletions(-) diff --git a/src/Aspire.Dashboard/Components/Pages/StructuredLogs.razor b/src/Aspire.Dashboard/Components/Pages/StructuredLogs.razor index 044d9c6b9bd..2a02d262009 100644 --- a/src/Aspire.Dashboard/Components/Pages/StructuredLogs.razor +++ b/src/Aspire.Dashboard/Components/Pages/StructuredLogs.razor @@ -144,7 +144,8 @@ @FormatHelpers.FormatTimeWithOptionalDate(TimeProvider, context.TimeStamp, MillisecondsDisplay.Truncated) - + + @* Tooltip is displayed by the message GridValue instance *@ diff --git a/src/Aspire.Dashboard/Components/ResourcesGridColumns/LogMessageColumnDisplay.razor b/src/Aspire.Dashboard/Components/ResourcesGridColumns/LogMessageColumnDisplay.razor index 8170fc4be37..f5ff52d18d2 100644 --- a/src/Aspire.Dashboard/Components/ResourcesGridColumns/LogMessageColumnDisplay.razor +++ b/src/Aspire.Dashboard/Components/ResourcesGridColumns/LogMessageColumnDisplay.razor @@ -3,11 +3,13 @@ @using Aspire.Dashboard.Extensions @using Aspire.Dashboard.Otlp.Model @using Aspire.Dashboard.Resources +@using Aspire.Dashboard.Utils @inject IStringLocalizer Loc - diff --git a/src/Aspire.Dashboard/Utils/FormatHelpers.cs b/src/Aspire.Dashboard/Utils/FormatHelpers.cs index 1f04ab39c86..539b87fd779 100644 --- a/src/Aspire.Dashboard/Utils/FormatHelpers.cs +++ b/src/Aspire.Dashboard/Utils/FormatHelpers.cs @@ -18,6 +18,10 @@ public enum MillisecondsDisplay internal static partial class FormatHelpers { + // Limit size of very long data that is written in large grids. + public const int ColumnMaximumTextLength = 250; + public const int TooltipMaximumTextLength = 1500; + // There are an unbound number of CultureInfo instances so we don't want to use it as the key. // Someone could have also customized their culture so we don't want to use the name as the key. // This struct contains required information from the culture that is used in cached format strings. @@ -133,4 +137,21 @@ public static string FormatNumberWithOptionalDecimalPlaces(double value, int max }; return value.ToString(formatString, provider ?? CultureInfo.CurrentCulture); } + + public static string TruncateText(string text, int maxLength) + { + if (string.IsNullOrEmpty(text) || maxLength <= 0) + { + return string.Empty; + } + + if (text.Length <= maxLength) + { + return text; + } + + const string ellipsis = "…"; + + return string.Concat(text.AsSpan(0, maxLength - ellipsis.Length), ellipsis); + } } From b3e5d25ea65beee4a58da984f093954b0d2007d3 Mon Sep 17 00:00:00 2001 From: James Newton-King Date: Fri, 8 Aug 2025 10:35:04 +0800 Subject: [PATCH 2/3] Test --- src/Aspire.Dashboard/Utils/FormatHelpers.cs | 7 +++---- tests/Aspire.Dashboard.Tests/FormatHelpersTests.cs | 9 +++++++++ 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/src/Aspire.Dashboard/Utils/FormatHelpers.cs b/src/Aspire.Dashboard/Utils/FormatHelpers.cs index 539b87fd779..494b22d9f40 100644 --- a/src/Aspire.Dashboard/Utils/FormatHelpers.cs +++ b/src/Aspire.Dashboard/Utils/FormatHelpers.cs @@ -21,6 +21,7 @@ internal static partial class FormatHelpers // Limit size of very long data that is written in large grids. public const int ColumnMaximumTextLength = 250; public const int TooltipMaximumTextLength = 1500; + public const string Ellipsis = "…"; // There are an unbound number of CultureInfo instances so we don't want to use it as the key. // Someone could have also customized their culture so we don't want to use the name as the key. @@ -140,7 +141,7 @@ public static string FormatNumberWithOptionalDecimalPlaces(double value, int max public static string TruncateText(string text, int maxLength) { - if (string.IsNullOrEmpty(text) || maxLength <= 0) + if (string.IsNullOrEmpty(text)) { return string.Empty; } @@ -150,8 +151,6 @@ public static string TruncateText(string text, int maxLength) return text; } - const string ellipsis = "…"; - - return string.Concat(text.AsSpan(0, maxLength - ellipsis.Length), ellipsis); + return string.Concat(text.AsSpan(0, maxLength - Ellipsis.Length), Ellipsis); } } diff --git a/tests/Aspire.Dashboard.Tests/FormatHelpersTests.cs b/tests/Aspire.Dashboard.Tests/FormatHelpersTests.cs index 010fb7af17f..361649a5f7f 100644 --- a/tests/Aspire.Dashboard.Tests/FormatHelpersTests.cs +++ b/tests/Aspire.Dashboard.Tests/FormatHelpersTests.cs @@ -82,6 +82,15 @@ public void FormatDateTime_WithMilliseconds_NewZealandCulture(string expected, M Assert.Equal(expected, FormatHelpers.FormatDateTime(CreateTimeProvider(), date, includeMilliseconds, cultureInfo: CultureInfo.GetCultureInfo("en-NZ")), ignoreWhiteSpaceDifferences: true, ignoreCase: true); } + [Theory] + [InlineData("", 5, "")] + [InlineData("abcdef", 5, "abcd" + FormatHelpers.Ellipsis)] + [InlineData("abcdef", 10, "abcdef")] + public void TruncateText(string initialText, int maxLength, string expected) + { + Assert.Equal(expected, FormatHelpers.TruncateText(initialText, maxLength: maxLength)); + } + private static DateTime GetLocalDateTime(string value) { Assert.True(DateTime.TryParseExact(value, "o", CultureInfo.InvariantCulture, DateTimeStyles.RoundtripKind, out var date)); From 620ce415006316269cc884351dd1c343e60bc04b Mon Sep 17 00:00:00 2001 From: James Newton-King Date: Fri, 8 Aug 2025 10:36:15 +0800 Subject: [PATCH 3/3] Update --- src/Aspire.Dashboard/Utils/FormatHelpers.cs | 2 +- tests/Aspire.Dashboard.Tests/FormatHelpersTests.cs | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/Aspire.Dashboard/Utils/FormatHelpers.cs b/src/Aspire.Dashboard/Utils/FormatHelpers.cs index 494b22d9f40..48fd7c3cf7b 100644 --- a/src/Aspire.Dashboard/Utils/FormatHelpers.cs +++ b/src/Aspire.Dashboard/Utils/FormatHelpers.cs @@ -139,7 +139,7 @@ public static string FormatNumberWithOptionalDecimalPlaces(double value, int max return value.ToString(formatString, provider ?? CultureInfo.CurrentCulture); } - public static string TruncateText(string text, int maxLength) + public static string TruncateText(string? text, int maxLength) { if (string.IsNullOrEmpty(text)) { diff --git a/tests/Aspire.Dashboard.Tests/FormatHelpersTests.cs b/tests/Aspire.Dashboard.Tests/FormatHelpersTests.cs index 361649a5f7f..0851d1f6aa1 100644 --- a/tests/Aspire.Dashboard.Tests/FormatHelpersTests.cs +++ b/tests/Aspire.Dashboard.Tests/FormatHelpersTests.cs @@ -83,10 +83,11 @@ public void FormatDateTime_WithMilliseconds_NewZealandCulture(string expected, M } [Theory] + [InlineData(null, 5, "")] [InlineData("", 5, "")] [InlineData("abcdef", 5, "abcd" + FormatHelpers.Ellipsis)] [InlineData("abcdef", 10, "abcdef")] - public void TruncateText(string initialText, int maxLength, string expected) + public void TruncateText(string? initialText, int maxLength, string expected) { Assert.Equal(expected, FormatHelpers.TruncateText(initialText, maxLength: maxLength)); }