Add render for legacy project.

This commit is contained in:
Kolosov Alexandr 2024-06-14 16:02:21 +05:00
parent a06f5c541e
commit 92e3e37bd1
27 changed files with 479 additions and 169 deletions

View File

@ -7,6 +7,9 @@ namespace TUI.Engine.Nodes;
public interface INode : IResizable
{
DrawContext DrawContext { get; set; }
StyleContext StyleContext { get; set; }
}
public record DrawContext(ICanvas Canvas, Position Pencil, Size MaxSize);
public record StyleContext(string? Foreground, string? Background = null);

View File

@ -57,4 +57,6 @@ public abstract class NodeBase : INode
#endregion Resizing
public DrawContext? DrawContext { get; set; }
public StyleContext? StyleContext { get; set; }
}

View File

@ -1,3 +1,4 @@
using Pastel;
using TUI.Engine.Attributes;
using TUI.Engine.Components;
using TUI.Engine.Nodes;
@ -28,7 +29,10 @@ internal sealed class ComponentCraftsman : CraftsmanBase, IDrawable<IComponent>
component.DrawContext = new DrawContext(_canvas, pencil, maxSize);
_canvas.SetPencil(correctedPencil);
_canvas.Paint(line);
_canvas.Paint(component.StyleContext is not null
? line.RemoveColors().Pastel(component.StyleContext.Foreground)
: line);
correctedPencil = correctedPencil with { Top = correctedPencil.Top + 1 };
}

View File

@ -4,12 +4,13 @@ namespace TUI.Engine.Theme;
public static class Palette
{
private const string HoverColor = "292928";
private const string PrimaryColor = "84BA64";
private const string HintColor = "71797E";
private const string ErrorColor = "CA3433";
private const string WarningColor = "EC9706";
private const string InfoColor = "25799F";
public const string HoverColor = "292928";
public const string PrimaryColor = "84BA64";
public const string HintColor = "71797E";
public const string DisableColor = "303030";
public const string ErrorColor = "CA3433";
public const string WarningColor = "EC9706";
public const string InfoColor = "25799F";
public static string Main(this string currentText, bool isFocused = true) =>
isFocused

View File

@ -9,10 +9,12 @@ namespace TUI.Controls.Common;
public class StubComponent : ComponentBase
{
private readonly Size _size;
private readonly string? _text;
public StubComponent(Size size)
public StubComponent(Size size, string? text = null)
{
_size = size;
_text = text;
SetFixed(Orientation.Horizontal, size.Width);
SetFixed(Orientation.Vertical, size.Height);
}
@ -22,12 +24,17 @@ public class StubComponent : ComponentBase
var builder = new StringBuilder();
var height = 0;
while (_size.Height > height)
{
builder.Append(Symbols.Space.Repeat(_size.Width));
builder.Append(Symbols.Space.Repeat(_size.Width - (_text?.GetWidth() ?? 0)));
height++;
}
if (_text is not null)
{
builder.Append(_text);
}
return new Sketch(builder.ToString());
}
}

View File

@ -35,7 +35,7 @@ public class ProjectTitle : ComponentBase
return new Sketch(builder);
}
private string GetHub() => _project.Hub == "gitlab" ? GitLab : GitHub;
private string GetHub() => _project.Hub.Type == "gitlab" ? GitLab : GitHub;
private string GetApplicationType()
{

View File

@ -1,4 +1,5 @@
using System.Text;
using TUI.Domain;
using TUI.Engine.Attributes;
using TUI.Engine.Components;
@ -9,18 +10,23 @@ public class VersionComponent : ComponentBase
private readonly VersionType _type;
private readonly string _version;
private readonly Brand? _brand;
private readonly VersionStatus _status;
public VersionComponent(VersionType type, string version, Brand? brand)
public VersionComponent(string version, Brand brand, VersionStatus status = VersionStatus.SoGood,
VersionType type = VersionType.Release)
{
_type = type;
_version = version;
_brand = brand;
_status = status;
_type = type;
}
protected override Sketch DrawComponent(Size minSize)
{
var builder = new StringBuilder();
// builder.Append(_type.ToString());
if (_brand is not null)
{
builder.Append(_brand.ColorLogo());
@ -29,6 +35,6 @@ public class VersionComponent : ComponentBase
builder.Append(_version);
var sketch = builder.ToString();
return new Sketch(_type.Colorize(sketch));
return new Sketch(_status.Colorize(sketch));
}
}

View File

@ -0,0 +1,10 @@
namespace TUI.Controls.Components;
public enum VersionStatus
{
NotFound,
ToNew,
SoGood,
BeNice,
TooOld,
}

View File

@ -3,8 +3,10 @@ namespace TUI.Controls.Components;
public enum VersionType
{
Convention,
ToNew,
SoGood,
BeNice,
TooOld,
Release,
Candidate,
Canary,
Alpha,
Beta,
Next,
}

View File

@ -4,14 +4,13 @@ namespace TUI.Controls.Components;
public static class VersionTypeExtensions
{
public static string Colorize(this VersionType versionType, string value) =>
versionType switch
public static string Colorize(this VersionStatus versionStatus, string value) =>
versionStatus switch
{
VersionType.TooOld => value.Warning(),
VersionType.ToNew => value.Info(),
VersionType.SoGood => value.Hint(),
VersionType.BeNice => value.Main(),
VersionType.Convention => value.Main(),
VersionStatus.TooOld => value.Warning(),
VersionStatus.ToNew => value.Info(),
VersionStatus.SoGood => value.Hint(),
VersionStatus.BeNice => value.Main(),
_ => value
};
}

View File

@ -29,4 +29,6 @@ public class DashboardContainer : ContainerBase
}
public override Nodes GetNodes() => _children;
public Nodes GetContent() => _content.GetNodes();
}

View File

@ -1,6 +1,7 @@
using TUI.Controls.Common;
using TUI.Controls.Components;
using TUI.Domain;
using TUI.Engine;
using TUI.Engine.Attributes;
using TUI.Engine.Attributes.Alignments;
using TUI.Engine.Attributes.Orientations;
@ -13,11 +14,23 @@ namespace TUI.Controls.Containers;
public class DependenciesContainer : ContainerBase
{
public readonly Project? Project;
private const int VersionColumnWidth = 10;
private const int TitleColumnWidth = 25;
private readonly Nodes _dependencies = new();
public DependenciesContainer()
{
}
public DependenciesContainer(Project project)
{
Project = project;
}
public void AddTitleStub()
{
var size = new Size(TitleColumnWidth, 1);
@ -33,16 +46,42 @@ public class DependenciesContainer : ContainerBase
title.SetFixed(Orientation.Horizontal, TitleColumnWidth);
title.SetAlignment(Horizontal.Left);
if (Project is not null && Project.Legacy)
{
title.StyleContext = new StyleContext(Palette.DisableColor);
}
_dependencies.Add(title);
}
public void AddDependency(Dependency dependency)
public void AddDependencyStub()
{
var version = new VersionComponent(VersionType.Convention, dependency.Version, dependency.Brand);
var size = new Size(VersionColumnWidth, 1);
var stub = new StubComponent(size, Symbols.NotFound.Hint());
stub.SetPadding(Level.Normal);
stub.SetAlignment(Horizontal.Right);
stub.SetFixed(Orientation.Horizontal, VersionColumnWidth);
if (Project is not null && Project.Legacy)
{
stub.StyleContext = new StyleContext(Palette.DisableColor);
}
_dependencies.Add(stub);
}
public void AddDependency(Dependency dependency, VersionStatus status = VersionStatus.BeNice)
{
var version = new VersionComponent(dependency.Version, dependency.Brand, status, dependency.Type);
version.SetPadding(Level.Normal);
version.SetAlignment(Horizontal.Right);
version.SetFixed(Orientation.Horizontal, VersionColumnWidth);
if (Project is not null && Project.Legacy)
{
version.StyleContext = new StyleContext(Palette.DisableColor);
}
_dependencies.Add(version);
}

View File

@ -10,10 +10,10 @@ public class VersionHints : StaticComponentBase
{
private readonly Dictionary<string, string> _hints = new()
{
{ "󰎔", VersionType.ToNew.Colorize("too new") },
{ "", VersionType.SoGood.Colorize("so good") },
{ "", VersionType.BeNice.Colorize("be nice") },
{ "󰬟", VersionType.TooOld.Colorize("too old") }
{ "󰎔", VersionStatus.ToNew.Colorize("too new") },
{ "", VersionStatus.SoGood.Colorize("so good") },
{ "", VersionStatus.BeNice.Colorize("be nice") },
{ "󰬟", VersionStatus.TooOld.Colorize("too old") }
};
protected override void RenderWithCache(StringBuilder builder)

View File

@ -1,8 +1,8 @@
using Pastel;
namespace TUI.Controls.Components;
namespace TUI.Domain;
public record Brand(string Name, string Logo, string Color)
public record Brand(string Name, string? Logo = null, string? Color = null)
{
public string ColorLogo() => Logo.Pastel(Color);
public string ColorLogo() => Logo?.Pastel(Color) ?? string.Empty;
};

View File

@ -2,4 +2,66 @@ using TUI.Controls.Components;
namespace TUI.Domain;
public record Dependency(string Version, Brand Brand);
public record Dependency()
{
private readonly Version _current;
public readonly Brand Brand;
public VersionType Type { get; private set; }
public string Version => $"{_current.Major}.{_current.Minor}.{_current.Patch}";
public Dependency(string version, Brand brand) : this()
{
_current = new Version(version);
Brand = brand;
}
public VersionStatus Comparison(Dependency outerDependency)
{
// if (string.IsNullOrEmpty(Version) || string.IsNullOrEmpty(outerDependency.Version))
// {
// return VersionStatus.NotFound;
// }
var outer = outerDependency._current;
Type = _current.Type;
if (_current.Major < outer.Major)
{
return VersionStatus.TooOld;
}
if (_current.Major > outer.Major)
{
return VersionStatus.ToNew;
}
if (_current.Minor < outer.Minor)
{
return VersionStatus.BeNice;
}
if (_current.Minor > outer.Minor)
{
return VersionStatus.ToNew;
}
if (_current.Patch < outer.Patch)
{
return VersionStatus.BeNice;
}
if (_current.Patch > outer.Patch)
{
return VersionStatus.ToNew;
}
if (outer.Type != VersionType.Release)
{
return VersionStatus.ToNew;
}
return VersionStatus.SoGood;
}
};

View File

@ -1,6 +1,3 @@
namespace TUI.Domain;
public record Hub
{
}
public record Hub(string Origin, string Type);

View File

@ -1,6 +1,6 @@
namespace TUI.Domain;
public record Project(int Id, string Name, IEnumerable<string> Tags, string Hub)
public record Project(int Id, string Name, IEnumerable<string> Tags, Hub Hub)
{
private IEnumerable<Dependency> Dependencies => new List<Dependency>();
@ -9,4 +9,6 @@ public record Project(int Id, string Name, IEnumerable<string> Tags, string Hub)
public bool HasAuth => Tags.Contains("auth");
public bool SeoDependent => Tags.Contains("seo");
public bool Legacy => Tags.Contains("legacy");
}

32
src/TUI/Domain/Version.cs Normal file
View File

@ -0,0 +1,32 @@
using TUI.Controls.Components;
namespace TUI.Domain;
public class Version
{
public readonly int Major;
public readonly int Minor;
public readonly int Patch;
public readonly VersionType Type;
public Version(string version)
{
var parts = version.Split('.');
Major = Convert.ToInt32(parts[0].Replace("^", "").Replace("~", ""));
Minor = Convert.ToInt32(parts[1]);
Patch = Convert.ToInt32(string.Join("", parts[2].TakeWhile(char.IsDigit)));
var extension = parts[2].Replace(Patch.ToString(), "");
Type = extension switch
{
not null when extension.Contains("rc") => VersionType.Candidate,
not null when extension.Contains("beta") => VersionType.Beta,
not null when extension.Contains("alpha") => VersionType.Alpha,
not null when extension.Contains("canary") => VersionType.Canary,
not null when extension.Contains("next") => VersionType.Next,
_ => VersionType.Release
};
}
}

View File

@ -6,14 +6,16 @@ using TUI.Store;
namespace TUI.Pages;
public record DependenciesState(HeaderContainer Header, DashboardContainer Dashboard, FooterContainer Footer);
public class DependenciesPage : PageBase
{
private DependenciesStore _store;
public override void Render()
{
ICanvas canvas = new ConsoleCanvas();
private DependenciesState _state;
public override void Initial()
{
var header = new HeaderContainer();
var dashboard = new DashboardContainer();
var dependenciesHeader = new DependenciesContainer();
@ -28,18 +30,56 @@ public class DependenciesPage : PageBase
foreach (var project in _store.Projects)
{
var projectDependencies = new DependenciesContainer();
var projectDependencies = new DependenciesContainer(project);
projectDependencies.AddTitle(new ProjectTitle(project));
dashboard.AddChildren(projectDependencies);
}
var breadCrumbs = new BreadCrumbsComponent(" Dependencies", "JavaScript");
var footer = new FooterContainer(breadCrumbs);
var layout = new DashboardLayout(header, dashboard, footer);
canvas.Draw(layout);
// CommandLine = new CommandLine();
// DependenciesView = new DependenciesView();
_state = new DependenciesState(header, dashboard, footer);
}
public override void Render()
{
ICanvas canvas = new ConsoleCanvas();
var layout = new DashboardLayout(_state.Header, _state.Dashboard, _state.Footer);
canvas.Draw(layout);
}
public void LoadDependencies()
{
Initial();
var projects = _state.Dashboard.GetContent();
foreach (var projectDependencies in projects.Cast<DependenciesContainer?>().Skip(1))
{
if (projectDependencies is null)
{
continue;
}
var project = projectDependencies.Project;
var actualDependencies = _store.ActualDependencies(project).ToArray();
foreach (var conventionDependency in _store.ConventionDependencies)
{
var actualDependency = actualDependencies.SingleOrDefault(
dependency => string.Equals(dependency.Brand.Name, conventionDependency.Brand.Name,
StringComparison.CurrentCultureIgnoreCase));
if (actualDependency is null)
{
projectDependencies.AddDependencyStub();
continue;
}
var versionType = actualDependency.Comparison(conventionDependency);
projectDependencies.AddDependency(actualDependency, versionType);
}
Render();
}
}
public override void Bind()

View File

@ -3,6 +3,7 @@ namespace TUI.Pages;
interface IPage
{
void Open();
void Initial();
void Render();
void Bind();
}

View File

@ -8,9 +8,12 @@ public abstract class PageBase : IPage
{
Debugger.Log(0, "Event", $"Open page ${GetType().UnderlyingSystemType.Name}\n");
Bind();
Initial();
Render();
}
public abstract void Initial();
public abstract void Render();
public abstract void Bind();

View File

@ -10,6 +10,10 @@ namespace TUI.Pages;
public class WelcomePage : PageBase
{
public override void Initial()
{
}
public override void Render()
{
ICanvas canvas = new ConsoleCanvas();

View File

@ -13,15 +13,24 @@ Thread.Sleep(500);
var dependenciesPage = new DependenciesPage();
dependenciesPage.Open();
var key = new ConsoleKeyInfo('1', ConsoleKey.NoName, false, false, false);
ConsoleKeyInfo? key = null;
var waitCommand = true;
do
{
// if (key.Key == ConsoleKey.Q && !display.CommandLine.IsFocused)
// {
// waitCommand = false;
// continue;
// }
if (key?.Key == ConsoleKey.Q)
{
waitCommand = false;
continue;
}
if (key?.Key == ConsoleKey.R)
{
dependenciesPage.LoadDependencies();
key = null;
continue;
}
//
// if (display.CommandLine.IsFocused)
// {

View File

@ -1,3 +1,5 @@
using System.Text.Json;
using System.Text.Json.Nodes;
using TUI.Controls.Components;
using TUI.Domain;
using YamlDotNet.Serialization;
@ -53,9 +55,73 @@ public class DependencyRepository
{
projects.AddRange(hub
.Projects
.Select(proj => new Project(proj.Id, proj.Name, proj.Tags, hub.Type)));
.Select(proj => new Project(proj.Id, proj.Name, proj.Tags, new Hub(hub.Origin, hub.Type))));
}
return projects;
}
public IEnumerable<Dependency> ReadActual(Project project)
{
var dependencies = new List<Dependency>();
if (project.Hub.Type == "gitlab")
{
var endpoint = GetGitlabEndpoint(project.Hub.Origin, project.Id);
using HttpClient client = new();
var json = client.GetStringAsync(endpoint).GetAwaiter().GetResult();
var packageJson = JsonSerializer.Deserialize<PackageJson>(json);
dependencies.AddRange(Map(packageJson?.Dependencies));
dependencies.AddRange(Map(packageJson?.DevDependencies));
dependencies.AddRange(Map(packageJson?.Engines));
}
return dependencies;
}
private static string GetGitlabEndpoint(string origin, int projectId)
{
var token = Environment.GetEnvironmentVariable("TLD_GITLAB_PAT");
return $"{origin}/api/v4/projects/{projectId}/repository/files/package.json/raw?" +
$"private_token={token}&ref=dev";
}
private static IEnumerable<Dependency> Map(JsonObject? dependencies)
{
if (dependencies is null)
{
yield break;
}
foreach (var dependency in dependencies)
{
var actualVersion = dependency.Value?.ToString();
var brand = new Brand(dependency.Key);
if (actualVersion is null)
{
continue;
}
yield return new Dependency(actualVersion, brand);
}
}
}
// private static Package DownloadPackage(ProjectDto project)
// {
// // var endpoint = projectDto.Tags.Have("gitlab") ? GetGitlabEndpoint(projectDto) : projectDto.Repo;
// var endpoint = "";
// if (Packages.TryGetValue(endpoint, out var downloadPackage)) return downloadPackage;
//
// using HttpClient client = new();
// var json = client.GetStringAsync(endpoint).GetAwaiter().GetResult();
//
// Packages.Add(endpoint, package);
// return package;
// }
//

View File

@ -4,7 +4,7 @@ using TUI.Engine;
namespace TUI.Providers.Dependencies;
public class Package
public class PackageJson
{
[JsonPropertyName("dependencies")]
public JsonObject? Dependencies { get; set; }

View File

@ -1,5 +1,6 @@
using TUI.Controls.Components;
using TUI.Domain;
using TUI.Engine.Theme;
using TUI.Providers.Dependencies;
namespace TUI.Store;
@ -10,37 +11,28 @@ public class DependenciesStore
public IEnumerable<Project> Projects;
public void Bind()
private DependencyRepository Repository = new();
public IEnumerable<Dependency> ActualDependencies(Project project)
{
var repo = new DependencyRepository();
ConventionDependencies = repo.ReadConventions("javascript");
SpeakerComponent.Instance.Shout("🤔", "Prepare javascript conventions");
Projects = repo.ReadProjects("javascript");
SpeakerComponent.Instance.Shout("🤩", "Prepare javascript projects");
SpeakerComponent.Instance.Shout("", $"Fetch actual dependencies for project {project.Name.Main()}");
try
{
return Repository.ReadActual(project);
}
catch
{
SpeakerComponent.Instance.Shout("", $"Fetch failed for project{project.Name}");
return new List<Dependency>();
}
}
// private readonly static Dictionary<string, Package> Packages = new();
//
// private static Package DownloadPackage(ProjectDto projectDto)
// {
// // var endpoint = projectDto.Tags.Have("gitlab") ? GetGitlabEndpoint(projectDto) : projectDto.Repo;
// var endpoint = "";
// if (Packages.TryGetValue(endpoint, out var downloadPackage)) return downloadPackage;
//
// using HttpClient client = new();
// var json = client.GetStringAsync(endpoint).GetAwaiter().GetResult();
// var package = JsonSerializer.Deserialize<Package>(json);
// Packages.Add(endpoint, package);
// return package;
// }
//
// private static string GetGitlabEndpoint(ProjectDto projectDto)
// {
// var token = Environment.GetEnvironmentVariable("TLD_GITLAB_PAT");
// // return $"{projectDto.Repo}/api/v4/projects/{projectDto.ProjectId}/repository/files/package.json/raw?" +
// // $"private_token={token}&ref=dev";
// return "";
// }
public void Bind()
{
SpeakerComponent.Instance.Shout("🤔", "Prepare javascript conventions");
ConventionDependencies = Repository.ReadConventions("javascript");
SpeakerComponent.Instance.Shout("🤩", "Prepare javascript projects");
Projects = Repository.ReadProjects("javascript");
}
}

View File

@ -1,5 +1,6 @@
using FluentAssertions;
using TUI.Controls.Components;
using TUI.Domain;
using TUI.Engine.Attributes;
using TUI.Engine.Components;
@ -9,19 +10,45 @@ namespace TUI.Engine.Tests
{
[Theory]
[Trait("Category", nameof(Sketch))]
[InlineData(VersionType.Convention, "\u001b[38;2;132;186;100m10.12.33\u001b[0m")]
[InlineData(VersionType.BeNice, "\u001b[38;2;132;186;100m10.12.33\u001b[0m")]
[InlineData(VersionType.SoGood, "\u001b[38;2;113;121;126m10.12.33\u001b[0m")]
[InlineData(VersionType.ToNew, "\u001b[38;2;37;121;159m10.12.33\u001b[0m")]
[InlineData(VersionType.TooOld, "\u001b[38;2;236;151;6m10.12.33\u001b[0m")]
public void DrawSketchVersionTypes(VersionType versionType, string expected)
[InlineData(VersionStatus.BeNice, "\u001b[38;2;132;186;100m10.12.33\u001b[0m")]
[InlineData(VersionStatus.SoGood, "\u001b[38;2;113;121;126m10.12.33\u001b[0m")]
[InlineData(VersionStatus.ToNew, "\u001b[38;2;37;121;159m10.12.33\u001b[0m")]
[InlineData(VersionStatus.TooOld, "\u001b[38;2;236;151;6m10.12.33\u001b[0m")]
public void DrawSketchVersionTypes(VersionStatus versionStatus, string expected)
{
var brand = new Brand("Docker", "󰡨", "#1d63ed");
var version = new VersionComponent(versionType, "10.12.33", brand);
var version = new VersionComponent("10.12.33", brand, versionStatus);
var sketch = (version as IComponent).MakeSketch(new Size(10, 2));
sketch.ToString().Should().Be(expected);
}
[Theory]
[Trait("Category", nameof(Dependency))]
[InlineData("1.0.0", "0.0.1", VersionStatus.ToNew)]
[InlineData("1.0.0", "0.1.1", VersionStatus.ToNew)]
[InlineData("1.0.0", "0.1.0", VersionStatus.ToNew)]
[InlineData("1.2.0", "1.0.0", VersionStatus.ToNew)]
[InlineData("1.2.0", "1.0.1", VersionStatus.ToNew)]
[InlineData("1.2.0", "1.1.0", VersionStatus.ToNew)]
[InlineData("1.0.0", "1.0.0-rc", VersionStatus.ToNew)]
[InlineData("1.0.0", "1.0.0", VersionStatus.SoGood)]
[InlineData("^1.0.0", "1.0.0", VersionStatus.SoGood)]
[InlineData("1.2.0", "1.3.0", VersionStatus.BeNice)]
[InlineData("1.3.1", "1.3.3", VersionStatus.BeNice)]
[InlineData("1.2.0", "2.1.0", VersionStatus.TooOld)]
[InlineData("1.2.0", "2.0.1", VersionStatus.TooOld)]
[InlineData("1.2.0", "2.3.1", VersionStatus.TooOld)]
public void ComparisonDependencies(string actual, string convention, VersionStatus expectedType)
{
var brand = new Brand("Poker", "󱢢", "#1d63ed");
var actualDependency = new Dependency(actual, brand);
var conventionDependency = new Dependency(convention, brand);
var status = actualDependency.Comparison(conventionDependency);
status.Should().Be(expectedType);
}
}
}