/ src / modules / cmdpal / Microsoft.CmdPal.UI / ViewModels / LogEntryViewModel.cs
LogEntryViewModel.cs
 1  // Copyright (c) Microsoft Corporation
 2  // The Microsoft Corporation licenses this file to you under the MIT license.
 3  // See the LICENSE file in the project root for more information.
 4  
 5  using System.Globalization;
 6  using CommunityToolkit.Mvvm.ComponentModel;
 7  
 8  namespace Microsoft.CmdPal.UI.ViewModels;
 9  
10  internal sealed partial class LogEntryViewModel : ObservableObject
11  {
12      private const int HeaderMaxLength = 80;
13      private const string WarningGlyph = "\uE7BA";
14      private const string ErrorGlyph = "\uEA39";
15      private const string TimestampFormat = "HH:mm:ss";
16  
17      private DateTimeOffset Timestamp { get; }
18  
19      private string Severity { get; }
20  
21      private string Message { get; }
22  
23      private string FormattedTimestamp { get; }
24  
25      public string SeverityGlyph { get; }
26  
27      [ObservableProperty]
28      public partial string Header { get; private set; }
29  
30      [ObservableProperty]
31      public partial string Description { get; private set; }
32  
33      [ObservableProperty]
34      public partial string Details { get; private set; }
35  
36      public LogEntryViewModel(DateTimeOffset timestamp, string severity, string message, string details)
37      {
38          Timestamp = timestamp;
39          Severity = severity;
40          Message = message;
41          Details = details;
42  
43          SeverityGlyph = severity.ToUpperInvariant() switch
44          {
45              "WARNING" => WarningGlyph,
46              "ERROR" => ErrorGlyph,
47              _ => string.Empty,
48          };
49  
50          FormattedTimestamp = timestamp.ToString(TimestampFormat, CultureInfo.CurrentCulture);
51          Description = $"{FormattedTimestamp} • {Message}";
52          Header = Message;
53      }
54  
55      public void AppendDetails(string? message)
56      {
57          if (string.IsNullOrEmpty(message))
58          {
59              return;
60          }
61  
62          Details += Environment.NewLine + message;
63  
64          // Make header the second line of details (because that's actually the message itself):
65          var detailsLines = Details.Split([Environment.NewLine], StringSplitOptions.None);
66          if (detailsLines.Length < 2)
67          {
68              return;
69          }
70  
71          Header = detailsLines[1].Trim();
72          if (Header.Length > HeaderMaxLength)
73          {
74              Header = Header[..(HeaderMaxLength - 1)] + "…";
75          }
76      }
77  }