diff options
author | Rory& <root@rory.gay> | 2024-05-16 11:48:35 +0200 |
---|---|---|
committer | Rory& <root@rory.gay> | 2024-05-16 11:48:35 +0200 |
commit | 1fea7b0aa6ffbd7d87a7d23ef9c642c109697758 (patch) | |
tree | 8a6ce52dc3cbc81e7c31d541fea7603e0bba8fd2 | |
parent | Add local changes (diff) | |
download | BugMine-1fea7b0aa6ffbd7d87a7d23ef9c642c109697758.tar.xz |
Add basic issues, abstract project loading to component in web
-rw-r--r-- | .gitignore | 7 | ||||
-rw-r--r-- | BugMine.DevTools.CLI/Worker.cs | 2 | ||||
-rw-r--r-- | BugMine.Sdk/BugMineClient.cs | 16 | ||||
-rw-r--r-- | BugMine.Sdk/Exceptions/BugMineException.cs | 1 | ||||
-rw-r--r-- | BugMine.Web/Components/ProjectContainer.razor | 152 | ||||
-rw-r--r-- | BugMine.Web/Pages/Projects/Index.razor | 2 | ||||
-rw-r--r-- | BugMine.Web/Pages/Projects/Issues/NewIssue.razor | 15 | ||||
-rw-r--r-- | BugMine.Web/Pages/Projects/NewProject.razor | 28 | ||||
-rw-r--r-- | BugMine.Web/Pages/Projects/ViewProject.razor | 89 | ||||
m--------- | LibMatrix | 0 | ||||
-rw-r--r-- | README.MD | 20 |
11 files changed, 234 insertions, 98 deletions
diff --git a/.gitignore b/.gitignore index 51eecb3..547b140 100644 --- a/.gitignore +++ b/.gitignore @@ -11,9 +11,4 @@ appsettings.Local*.json nixpkgs/ *.DotSettings.user -test.tsv -test-proxy.tsv -homeservers.txt -LoginPayload.txt -LoginPayload.txt.old -BugMine.DevTools.CLI/auth.json +**/auth.json diff --git a/BugMine.DevTools.CLI/Worker.cs b/BugMine.DevTools.CLI/Worker.cs index 900d742..4b3d3f4 100644 --- a/BugMine.DevTools.CLI/Worker.cs +++ b/BugMine.DevTools.CLI/Worker.cs @@ -115,7 +115,7 @@ public class Worker(ILogger<Worker> logger, HomeserverProviderService hsProvider // await proj.SendStateEventAsync(RoomCanonicalAliasEventContent.EventId, new RoomCanonicalAliasEventContent() { // Alias = null // }); - await proj.LeaveAsync("Disbanded room."); + await proj.LeaveAsync("[BugMine.DevTools.CLI] Disbanding project."); // ss.Release(); }); } diff --git a/BugMine.Sdk/BugMineClient.cs b/BugMine.Sdk/BugMineClient.cs index 21be614..d55ff4d 100644 --- a/BugMine.Sdk/BugMineClient.cs +++ b/BugMine.Sdk/BugMineClient.cs @@ -1,3 +1,4 @@ +using System.Text.Json.Serialization; using System.Text.RegularExpressions; using ArcaneLibs.Extensions; using BugMine.Web.Classes.Exceptions; @@ -11,14 +12,14 @@ namespace BugMine.Web.Classes; public class BugMineClient(AuthenticatedHomeserverGeneric homeserver) { public AuthenticatedHomeserverGeneric Homeserver { get; } = homeserver; - public async IAsyncEnumerable<BugMineProject> GetProjects(SemaphoreSlim? semaphore = null) { + public async IAsyncEnumerable<BugMineProject> GetProjects(SemaphoreSlim? semaphore = null, bool ignoreInvalidBoards = false) { List<Task<BugMineProject>> tasks = []; int count = 0; await foreach (var room in homeserver.GetJoinedRoomsByType(BugMineProject.RoomType, 64)) { tasks.Add(room.AsBugMineProject(semaphore)); } - var results = tasks.ToAsyncEnumerable(); + var results = tasks.ToAsyncEnumerable(skipExceptions: ignoreInvalidBoards); await foreach (var result in results) { yield return result; } @@ -75,7 +76,16 @@ public class BugMineClient(AuthenticatedHomeserverGeneric homeserver) { } else { var alias = $"#{projectSlug}"; - var resolveResult = await Homeserver.ResolveRoomAliasAsync(alias); + AliasResult? resolveResult = null; + try { + resolveResult = await Homeserver.ResolveRoomAliasAsync(alias); + } + catch (MatrixException e) { + if (e.ErrorCode == MatrixException.ErrorCodes.M_NOT_FOUND) + throw new BugMineException(BugMineException.ErrorCodes.ProjectNotFound, $"Project with slug {projectSlug} not found"); + throw; + } + if (string.IsNullOrEmpty(resolveResult?.RoomId)) return null; //TODO: fallback to finding via joined rooms' canonical alias event? room = homeserver.GetRoom(resolveResult.RoomId); diff --git a/BugMine.Sdk/Exceptions/BugMineException.cs b/BugMine.Sdk/Exceptions/BugMineException.cs index 7e843b3..5c81e48 100644 --- a/BugMine.Sdk/Exceptions/BugMineException.cs +++ b/BugMine.Sdk/Exceptions/BugMineException.cs @@ -19,5 +19,6 @@ public class BugMineException : MatrixException { public new static class ErrorCodes { public const string UserNotInRoom = "BUGMINE_USER_NOT_IN_ROOM"; + public const string ProjectNotFound = "BUGMINE_PROJECT_NOT_FOUND"; } } \ No newline at end of file diff --git a/BugMine.Web/Components/ProjectContainer.razor b/BugMine.Web/Components/ProjectContainer.razor new file mode 100644 index 0000000..f7621be --- /dev/null +++ b/BugMine.Web/Components/ProjectContainer.razor @@ -0,0 +1,152 @@ +@using System.Text.Json.Serialization +@using ArcaneLibs.Extensions +@using BugMine.Web.Classes.Exceptions +@using LibMatrix +@inject ILogger<ProjectContainer> Logger + +@if (Constants.Debug) { + <p>Debug, beware: here be dragons!</p> + <p>ProjectContainer debug info:</p> + <pre>Slug: @ProjectSlug</pre> + <pre>Progress: @Progress.ToString()</pre> + @if (ProjectContext is null) { + <pre>ProjectContext is null!</pre> + } + else { + <details> + <summary>Context json dump</summary> + <pre>@ProjectContext.ToJson()</pre> + </details> + @if (ProjectContext?.Project?.Room is not null) { + <LinkButton OnClick="@ProjectContext.Project.Room.PermanentlyBrickRoomAsync">Dispose room</LinkButton> + } + } + + <hr/> +} +@if (ProjectContext.Client is null) { + <p>Authenticating</p> +} +else if (ProjectContext?.Project is null) { + @if (Progress == Status.Loading) { + <p>Loading project <SimpleSpinner/></p> + } + else if (Progress == Status.NotInRoom) { + <p>You are not in the project room.</p> + <p>You must join before you can view or interact with this project.</p> + <LinkButton OnClick="TryJoin">Attempt to join</LinkButton> + } + else if (Progress == Status.RoomNotFound) { + <p>Project not found.</p> + <p>If you believe this is an error, please contact the project in order to obtain a new room.</p> + } +} +else { + @ChildContent +} + +@code { + private Status? _progress = Status.Loading; + + [Parameter] + public string ProjectSlug { get; set; } = null!; + + [Parameter] + public ProjectContainerContext? ProjectContext { get; set; } + + [Parameter] + public RenderFragment ChildContent { get; set; } + + [Parameter] + public Func<Task>? Loaded { get; set; } + + private Status? Progress { + get => _progress; + set { + _progress = value; + StateHasChanged(); + } + } + + protected override async Task OnInitializedAsync() { + if (ProjectContext is null) { + Logger.LogError("ProjectContext is null"); + ProjectContext = new(); + } + + if (ProjectContext.Project != null) { + Logger.LogWarning("ProjectContext.Project is not null"); + } + + ProjectContext.Client ??= await BugMineStorage.GetCurrentSessionOrNavigate(); + if (ProjectContext.Client == null) { + return; + } + + Progress = Status.Loading; + + try { + ProjectContext.Project = await ProjectContext.Client.GetProject(ProjectSlug); + } + catch (MatrixException e) { + if (e.ErrorCode == BugMineException.ErrorCodes.UserNotInRoom) { + Progress = Status.NotInRoom; + return; + } + else if (e.ErrorCode == BugMineException.ErrorCodes.ProjectNotFound) { + Progress = Status.RoomNotFound; + return; + } + + throw; + } + + Progress = Status.Done; + if (Loaded != null) { + await Loaded.Invoke(); + } + + + StateHasChanged(); + } + + private async Task TryJoin() { + var room = await ProjectContext.Client.ResolveProjectSlug(ProjectSlug); + bool success = false; + while (!success) { + try { + await room.JoinAsync(); + if (!string.IsNullOrWhiteSpace(room.RoomId)) { + success = true; + } + else { + await Task.Delay(1000); + } + } + catch (MatrixException e) { + // if (e.ErrorCode == MatrixException.ErrorCodes.) { + // await Task.Delay(1000); + // continue; + // } + + throw; + } + } + + await OnInitializedAsync(); + } + + public class ProjectContainerContext { + public BugMineClient? Client { get; set; } + + public BugMineProject? Project { get; set; } + } + + private enum Status { + Loading, + NotInRoom, + RoomNotFound, + Done + } + +} \ No newline at end of file diff --git a/BugMine.Web/Pages/Projects/Index.razor b/BugMine.Web/Pages/Projects/Index.razor index 8f46d02..9755dc3 100644 --- a/BugMine.Web/Pages/Projects/Index.razor +++ b/BugMine.Web/Pages/Projects/Index.razor @@ -46,7 +46,7 @@ else { int count = 0; SemaphoreSlim semaphore = new(16, 16); - await foreach (var project in Client.GetProjects(semaphore)) { + await foreach (var project in Client.GetProjects(semaphore, ignoreInvalidBoards: true)) { Projects ??= []; Projects.Add(project); if(count++ <= 250 || count % 4 == 0) diff --git a/BugMine.Web/Pages/Projects/Issues/NewIssue.razor b/BugMine.Web/Pages/Projects/Issues/NewIssue.razor new file mode 100644 index 0000000..159e20d --- /dev/null +++ b/BugMine.Web/Pages/Projects/Issues/NewIssue.razor @@ -0,0 +1,15 @@ +@page "/Projects/{ProjectSlug}/Issues/New" +<h3>New issue</h3> + +<ProjectContainer ProjectSlug="@ProjectSlug" ProjectContext="@ProjectContext"> + <h1>Hi from NewIssue!</h1> +</ProjectContainer> + +@code { + + [Parameter] + public string ProjectSlug { get; set; } = null!; + + public ProjectContainer.ProjectContainerContext? ProjectContext { get; set; } = new(); + +} \ No newline at end of file diff --git a/BugMine.Web/Pages/Projects/NewProject.razor b/BugMine.Web/Pages/Projects/NewProject.razor index 00b7b21..f8c7dfd 100644 --- a/BugMine.Web/Pages/Projects/NewProject.razor +++ b/BugMine.Web/Pages/Projects/NewProject.razor @@ -1,5 +1,6 @@ @page "/Projects/New" @using ArcaneLibs.Extensions +@using LibMatrix <h3>New project</h3> <span>Project name: </span> @@ -20,10 +21,25 @@ <br/> } -<LinkButton OnClick="@CreateProject">Create project</LinkButton> +@if (!_busy) { + <LinkButton OnClick="@CreateProject">Create project</LinkButton> +} +else { + <p>Powering up the framework... <SimpleSpinner/></p> +} @code { + private bool _busy = false; + + private bool Busy { + get => _busy; + set { + _busy = value; + StateHasChanged(); + } + } + private BugMineClient? Client { get; set; } private readonly ProjectInfo _request = new(); @@ -39,9 +55,15 @@ if (Client == null) { return; } + Busy = true; + try { + var proj = await Client.CreateProject(_request); + NavigationManager.NavigateTo($"/Projects/{proj.ProjectSlug}/"); - var proj = await Client.CreateProject(_request); - NavigationManager.NavigateTo($"/Projects/{proj.ProjectSlug}/"); + } + catch (MatrixException e) { + + } } } \ No newline at end of file diff --git a/BugMine.Web/Pages/Projects/ViewProject.razor b/BugMine.Web/Pages/Projects/ViewProject.razor index ec10d1c..91cc4d0 100644 --- a/BugMine.Web/Pages/Projects/ViewProject.razor +++ b/BugMine.Web/Pages/Projects/ViewProject.razor @@ -5,48 +5,30 @@ <ProgressLog ></ProgressLog> -@if (Client is null) { - <p>Authenticating</p> -} -else if (Project is null) { - @if (Progress == "loading") { - <p>Loading project <SimpleSpinner/></p> - } - else if (Progress == "not-in-room") { - <p>You are not in the project room.</p> - <p>You must join before you can view or interact with this project.</p> - <LinkButton OnClick="TryJoin">Attempt to join</LinkButton> - } -} -else { - <h1>@Project.Info.Name</h1> +<ProjectContainer ProjectSlug="@ProjectSlug" ProjectContext="@ProjectContext" Loaded="@OnProjectLoaded"> + <h1>Hi from ViewProject!</h1> + <h1>@ProjectContext!.Project!.Info.Name</h1> - @if (Constants.Debug) { - <p>Debug, beware: here be dragons!</p> - <LinkButton OnClick="@Project.Room.PermanentlyBrickRoomAsync">Dispose room</LinkButton> - } - @if (Progress == "loading-issues") { <p>Loading issues, got @(Issues?.Count ?? 0) so far... <SimpleSpinner/></p> } + @* <p>@Project.Description</p> *@ @if (Issues != null) { - @foreach(var issue in Issues) { + @foreach (var issue in Issues) { <pre>@issue.Data.RawContent.ToJson()</pre> } } -} +</ProjectContainer> @code { private string? _progress = "loading"; + public ProjectContainer.ProjectContainerContext? ProjectContext { get; set; } = new(); + [Parameter] public string ProjectSlug { get; set; } = null!; - private BugMineClient? Client { get; set; } - - private BugMineProject? Project { get; set; } - private List<BugMineIssue>? Issues { get; set; } private string? Progress { @@ -57,64 +39,15 @@ else { } } - protected override async Task OnInitializedAsync() { - Client ??= await BugMineStorage.GetCurrentSessionOrNavigate(); - if (Client == null) { - return; - } - - Progress = "loading"; - StateHasChanged(); - - try { - Project = await Client.GetProject(ProjectSlug); - } - catch (MatrixException e) { - if (e.ErrorCode == BugMineException.ErrorCodes.UserNotInRoom) { - Progress = "not-in-room"; - StateHasChanged(); - return; - } - - throw; - } - + protected async Task OnProjectLoaded() { Progress = "loading-issues"; - await foreach (var issue in Project.GetIssues()) { + await foreach (var issue in ProjectContext.Project.GetIssues()) { Issues ??= new List<BugMineIssue>(); Issues.Add(issue); StateHasChanged(); } - StateHasChanged(); } - private async Task TryJoin() { - var room = await Client.ResolveProjectSlug(ProjectSlug); - bool success = false; - while (!success) { - try { - await room.JoinAsync(); - if (!string.IsNullOrWhiteSpace(room.RoomId)) { - success = true; - } - else { - await Task.Delay(1000); - } - } - catch (MatrixException e) { - // if (e.ErrorCode == MatrixException.ErrorCodes.) { - // await Task.Delay(1000); - // continue; - // } - - throw; - } - } - - await OnInitializedAsync(); - } - -} - +} \ No newline at end of file diff --git a/LibMatrix b/LibMatrix -Subproject b5860ce2011b96a2919d5306445b0e8bd8408b3 +Subproject e1f99073f3d9788a4b48d2bb7091e3894dcefa1 diff --git a/README.MD b/README.MD index 8a83d25..0566989 100644 --- a/README.MD +++ b/README.MD @@ -1,14 +1,22 @@ -# Rory&::MatrixUtils +# BugMine -Power tools for Matrix. +Decentralised issue tracking system, built on [Matrix](https://matrix.org) using [Rory&::LibMatrix](https://cgit.rory.gay/matrix/LibMatrix.git). -# Installation +# Deploying the web interface +Make sure to follow your web server's instructions to deploy a single-page application. ```sh git clone --recursive $REPO -cd MatrixUtils/MatrixUtils.Web +cd BugMine/BugMine.Web dotnet publish -cp -rv bin/Release/net8.0/publish/wwwroot /var/www/html_rmu +cp -rv bin/Release/net8.0/publish/wwwroot /var/www/html_bugmine +``` + +# Running a project + +```sh +cd $PROJECT +dotnet run ``` # Contributing @@ -25,7 +33,7 @@ git format-patch --output-directory "./patches" @{u}.. Error reporting upon file save: ```sh -inotifywait -rmqe CLOSE_WRITE --include '.*\.cs$' . | while read l; do clear; dotnet build --property WarningLevel=0; done +dotnet watch build --property WarningLevel=0 ``` Hot rebuild on file save: |