journal/Journal.DevTool/Tui/EventsScreen.cs

127 lines
4.8 KiB
C#

using Sdt.Core;
using Spectre.Console;
namespace Sdt.Tui;
public sealed class EventsScreen(string projectRoot, string projectName, string version)
{
private readonly string _projectRoot = projectRoot;
private readonly string _projectName = projectName;
private readonly string _version = version;
private readonly RunEventLogReader _reader = new();
public void Run()
{
while (true)
{
AnsiConsole.Clear();
RenderHeader("EVENTS");
var files = _reader.ListEventFiles(_projectRoot);
if (files.Count == 0)
{
AnsiConsole.MarkupLine(Theme.Warn("No event logs found yet."));
AnsiConsole.MarkupLine(Theme.Faint("Run a workflow/debug action first, then return here."));
AnsiConsole.MarkupLine("\n" + Theme.Faint("Press any key to go back..."));
Console.ReadKey(intercept: true);
return;
}
var table = new Table()
.Border(TableBorder.Rounded)
.BorderStyle(Theme.DimStyle)
.AddColumn(new TableColumn($"[{Theme.Amber}]File[/]"))
.AddColumn(new TableColumn($"[{Theme.Amber}]Updated[/]").Width(21))
.AddColumn(new TableColumn($"[{Theme.Amber}]Size[/]").Width(10));
foreach (var file in files.Take(12))
{
table.AddRow(
Theme.G(file.Name),
Theme.Faint(file.LastWriteTime.ToString("yyyy-MM-dd HH:mm:ss")),
Theme.Faint($"{Math.Max(1, file.SizeBytes / 1024)} KB"));
}
AnsiConsole.Write(table);
AnsiConsole.WriteLine();
var choices = files
.Take(20)
.Select(f => new MenuItem(
$"[{Theme.Green}]{Markup.Escape(f.Name)}[/] [{Theme.GreenDim}]{f.LastWriteTime:yyyy-MM-dd HH:mm:ss}[/]",
f.Path))
.ToList();
choices.Add(new MenuItem(Theme.Faint("← Back"), "__back__"));
var selected = AnsiConsole.Prompt(
new SelectionPrompt<MenuItem>()
.Title($"[{Theme.Green}]Select an event log to view:[/]")
.PageSize(20)
.UseConverter(m => m.Display)
.AddChoices(choices));
if (selected.Value == "__back__")
return;
ShowEventFile(selected.Value);
}
}
private void ShowEventFile(string filePath)
{
var events = _reader.ReadEvents(filePath);
AnsiConsole.Clear();
RenderHeader("EVENTS VIEWER");
AnsiConsole.MarkupLine(Theme.Faint(Path.GetFileName(filePath)));
AnsiConsole.MarkupLine(Theme.Faint(filePath));
AnsiConsole.WriteLine();
if (events.Count == 0)
{
AnsiConsole.MarkupLine(Theme.Warn("No parseable events in selected file."));
AnsiConsole.MarkupLine("\n" + Theme.Faint("Press any key to return..."));
Console.ReadKey(intercept: true);
return;
}
var table = new Table()
.Border(TableBorder.Rounded)
.BorderStyle(Theme.DimStyle)
.AddColumn(new TableColumn($"[{Theme.Amber}]Time[/]").Width(12))
.AddColumn(new TableColumn($"[{Theme.Amber}]Type[/]").Width(26))
.AddColumn(new TableColumn($"[{Theme.Amber}]Message[/]"))
.AddColumn(new TableColumn($"[{Theme.Amber}]Status[/]").Width(10));
foreach (var evt in events.TakeLast(120))
{
var status = evt.Success switch
{
true => Theme.Ok("ok"),
false => Theme.Fail("fail"),
null => Theme.Faint("-"),
};
var message = evt.Message;
if (!string.IsNullOrWhiteSpace(evt.Tool))
message += $" [{evt.Tool}]";
if (evt.ExitCode is not null)
message += $" (exit {evt.ExitCode})";
table.AddRow(
Theme.Faint(evt.OccurredAt.ToString("HH:mm:ss")),
Theme.G(evt.Type.ToString()),
Theme.Faint(message),
status);
}
AnsiConsole.Write(table);
AnsiConsole.MarkupLine("\n" + Theme.Faint("Press any key to return..."));
Console.ReadKey(intercept: true);
}
private void RenderHeader(string section)
{
AnsiConsole.Write(new FigletText("SDT").Color(Theme.GreenColor));
AnsiConsole.Write(
new Rule($"[bold {Theme.GreenBold}]{Markup.Escape(_projectName)}[/] [{Theme.GreenDim}]v{Markup.Escape(_version)}[/] [{Theme.Amber}]{Markup.Escape(section)}[/]")
.RuleStyle(Theme.DimStyle));
AnsiConsole.MarkupLine(Theme.Faint($"root: {_projectRoot}") + "\n");
}
}