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..48fd7c3cf7b 100644 --- a/src/Aspire.Dashboard/Utils/FormatHelpers.cs +++ b/src/Aspire.Dashboard/Utils/FormatHelpers.cs @@ -18,6 +18,11 @@ 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; + 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. // This struct contains required information from the culture that is used in cached format strings. @@ -133,4 +138,19 @@ 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)) + { + return string.Empty; + } + + if (text.Length <= maxLength) + { + return text; + } + + 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..0851d1f6aa1 100644 --- a/tests/Aspire.Dashboard.Tests/FormatHelpersTests.cs +++ b/tests/Aspire.Dashboard.Tests/FormatHelpersTests.cs @@ -82,6 +82,16 @@ 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(null, 5, "")] + [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));