about summary refs log tree commit diff
diff options
context:
space:
mode:
authorRory& <root@rory.gay>2024-05-16 11:48:35 +0200
committerRory& <root@rory.gay>2024-05-16 11:48:35 +0200
commit1fea7b0aa6ffbd7d87a7d23ef9c642c109697758 (patch)
tree8a6ce52dc3cbc81e7c31d541fea7603e0bba8fd2
parentAdd local changes (diff)
downloadBugMine-1fea7b0aa6ffbd7d87a7d23ef9c642c109697758.tar.xz
Add basic issues, abstract project loading to component in web
-rw-r--r--.gitignore7
-rw-r--r--BugMine.DevTools.CLI/Worker.cs2
-rw-r--r--BugMine.Sdk/BugMineClient.cs16
-rw-r--r--BugMine.Sdk/Exceptions/BugMineException.cs1
-rw-r--r--BugMine.Web/Components/ProjectContainer.razor152
-rw-r--r--BugMine.Web/Pages/Projects/Index.razor2
-rw-r--r--BugMine.Web/Pages/Projects/Issues/NewIssue.razor15
-rw-r--r--BugMine.Web/Pages/Projects/NewProject.razor28
-rw-r--r--BugMine.Web/Pages/Projects/ViewProject.razor89
m---------LibMatrix0
-rw-r--r--README.MD20
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: