[frontend] Bootstrap shared DTOs, API abstractions, SignalR & more
This commit is contained in:
parent
674b34a930
commit
6bc2b8d57c
43 changed files with 327 additions and 42 deletions
|
@ -2,7 +2,7 @@ using System.Diagnostics.CodeAnalysis;
|
|||
using System.Net.Mime;
|
||||
using Iceshrimp.Backend.Controllers.Attributes;
|
||||
using Iceshrimp.Backend.Controllers.Federation;
|
||||
using Iceshrimp.Backend.Controllers.Schemas;
|
||||
using Iceshrimp.Shared.Schemas;
|
||||
using Iceshrimp.Backend.Core.Database;
|
||||
using Iceshrimp.Backend.Core.Database.Tables;
|
||||
using Iceshrimp.Backend.Core.Extensions;
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Net.Mime;
|
||||
using Iceshrimp.Backend.Controllers.Renderers;
|
||||
using Iceshrimp.Backend.Controllers.Schemas;
|
||||
using Iceshrimp.Shared.Schemas;
|
||||
using Iceshrimp.Backend.Core.Database;
|
||||
using Iceshrimp.Backend.Core.Database.Tables;
|
||||
using Iceshrimp.Backend.Core.Helpers;
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
using System.Net;
|
||||
using System.Net.Mime;
|
||||
using Iceshrimp.Backend.Controllers.Schemas;
|
||||
using Iceshrimp.Shared.Schemas;
|
||||
using Iceshrimp.Backend.Core.Middleware;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
using System.Text;
|
||||
using Iceshrimp.Backend.Controllers.Attributes;
|
||||
using Iceshrimp.Backend.Controllers.Federation.Attributes;
|
||||
using Iceshrimp.Backend.Controllers.Schemas;
|
||||
using Iceshrimp.Shared.Schemas;
|
||||
using Iceshrimp.Backend.Core.Configuration;
|
||||
using Iceshrimp.Backend.Core.Database;
|
||||
using Iceshrimp.Backend.Core.Extensions;
|
||||
|
|
|
@ -4,7 +4,7 @@ using System.Text;
|
|||
using System.Xml.Serialization;
|
||||
using Iceshrimp.Backend.Controllers.Federation.Attributes;
|
||||
using Iceshrimp.Backend.Controllers.Federation.Schemas;
|
||||
using Iceshrimp.Backend.Controllers.Schemas;
|
||||
using Iceshrimp.Shared.Schemas;
|
||||
using Iceshrimp.Backend.Core.Configuration;
|
||||
using Iceshrimp.Backend.Core.Database;
|
||||
using Iceshrimp.Backend.Core.Database.Tables;
|
||||
|
|
|
@ -3,7 +3,7 @@ using System.ComponentModel.DataAnnotations;
|
|||
using System.Net.Mime;
|
||||
using Iceshrimp.Backend.Controllers.Attributes;
|
||||
using Iceshrimp.Backend.Controllers.Renderers;
|
||||
using Iceshrimp.Backend.Controllers.Schemas;
|
||||
using Iceshrimp.Shared.Schemas;
|
||||
using Iceshrimp.Backend.Core.Database;
|
||||
using Iceshrimp.Backend.Core.Database.Tables;
|
||||
using Iceshrimp.Backend.Core.Extensions;
|
||||
|
@ -74,7 +74,7 @@ public class NoteController(
|
|||
|
||||
[HttpGet("{id}/descendants")]
|
||||
[Authenticate]
|
||||
[ProducesResponseType(StatusCodes.Status200OK, Type = typeof(NoteResponse))]
|
||||
[ProducesResponseType(StatusCodes.Status200OK, Type = typeof(IEnumerable<NoteResponse>))]
|
||||
[ProducesResponseType(StatusCodes.Status404NotFound, Type = typeof(ErrorResponse))]
|
||||
public async Task<IActionResult> GetNoteDescendants(
|
||||
string id, [FromQuery] [DefaultValue(20)] [Range(1, 100)] int? depth
|
||||
|
|
|
@ -2,6 +2,7 @@ using System.Net.Mime;
|
|||
using Iceshrimp.Backend.Controllers.Attributes;
|
||||
using Iceshrimp.Backend.Controllers.Renderers;
|
||||
using Iceshrimp.Backend.Controllers.Schemas;
|
||||
using Iceshrimp.Shared.Schemas;
|
||||
using Iceshrimp.Backend.Core.Database;
|
||||
using Iceshrimp.Backend.Core.Extensions;
|
||||
using Iceshrimp.Backend.Core.Middleware;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
using Iceshrimp.Backend.Controllers.Schemas;
|
||||
using Iceshrimp.Shared.Schemas;
|
||||
using Iceshrimp.Backend.Core.Database;
|
||||
using Iceshrimp.Backend.Core.Database.Tables;
|
||||
using Iceshrimp.Backend.Core.Extensions;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
using Iceshrimp.Backend.Controllers.Schemas;
|
||||
using Iceshrimp.Shared.Schemas;
|
||||
using Iceshrimp.Backend.Core.Database.Tables;
|
||||
using Iceshrimp.Backend.Core.Extensions;
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
using Iceshrimp.Backend.Controllers.Schemas;
|
||||
using Iceshrimp.Shared.Schemas;
|
||||
using Iceshrimp.Backend.Core.Database;
|
||||
using Iceshrimp.Backend.Core.Database.Tables;
|
||||
using Iceshrimp.Backend.Core.Extensions;
|
||||
|
@ -28,12 +28,19 @@ public class UserProfileRenderer(DatabaseContext db)
|
|||
_ => throw new ArgumentOutOfRangeException()
|
||||
};
|
||||
|
||||
var fields = user.UserProfile?.Fields.Select(p => new UserProfileField
|
||||
{
|
||||
Name = p.Name,
|
||||
Value = p.Value,
|
||||
IsVerified = p.IsVerified
|
||||
});
|
||||
|
||||
return new UserProfileResponse
|
||||
{
|
||||
Id = user.Id,
|
||||
Bio = user.UserProfile?.Description,
|
||||
Birthday = user.UserProfile?.Birthday,
|
||||
Fields = user.UserProfile?.Fields,
|
||||
Fields = fields?.ToList(),
|
||||
Location = user.UserProfile?.Location,
|
||||
Followers = followers,
|
||||
Following = following
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
using Iceshrimp.Backend.Controllers.Schemas;
|
||||
using Iceshrimp.Shared.Schemas;
|
||||
using Iceshrimp.Backend.Core.Configuration;
|
||||
using Iceshrimp.Backend.Core.Database;
|
||||
using Iceshrimp.Backend.Core.Database.Tables;
|
||||
|
|
|
@ -1,15 +0,0 @@
|
|||
using Iceshrimp.Backend.Core.Database.Tables;
|
||||
using J = System.Text.Json.Serialization.JsonPropertyNameAttribute;
|
||||
|
||||
namespace Iceshrimp.Backend.Controllers.Schemas;
|
||||
|
||||
public class UserProfileResponse
|
||||
{
|
||||
[J("id")] public required string Id { get; set; }
|
||||
[J("birthday")] public required string? Birthday { get; set; }
|
||||
[J("location")] public required string? Location { get; set; }
|
||||
[J("fields")] public required UserProfile.Field[]? Fields { get; set; }
|
||||
[J("bio")] public required string? Bio { get; set; }
|
||||
[J("followers")] public required int? Followers { get; set; }
|
||||
[J("following")] public required int? Following { get; set; }
|
||||
}
|
|
@ -2,6 +2,7 @@ using System.Net.Mime;
|
|||
using Iceshrimp.Backend.Controllers.Attributes;
|
||||
using Iceshrimp.Backend.Controllers.Renderers;
|
||||
using Iceshrimp.Backend.Controllers.Schemas;
|
||||
using Iceshrimp.Shared.Schemas;
|
||||
using Iceshrimp.Backend.Core.Database;
|
||||
using Iceshrimp.Backend.Core.Extensions;
|
||||
using Iceshrimp.Backend.Core.Middleware;
|
||||
|
|
|
@ -2,6 +2,7 @@ using System.Net.Mime;
|
|||
using Iceshrimp.Backend.Controllers.Attributes;
|
||||
using Iceshrimp.Backend.Controllers.Renderers;
|
||||
using Iceshrimp.Backend.Controllers.Schemas;
|
||||
using Iceshrimp.Shared.Schemas;
|
||||
using Iceshrimp.Backend.Core.Database;
|
||||
using Iceshrimp.Backend.Core.Extensions;
|
||||
using Iceshrimp.Backend.Core.Middleware;
|
||||
|
|
|
@ -180,8 +180,8 @@ public class UserProfile
|
|||
|
||||
public class Field
|
||||
{
|
||||
[J("name")] public required string Name { get; set; }
|
||||
[J("value")] public required string Value { get; set; }
|
||||
[J("verified")] public bool? IsVerified { get; set; }
|
||||
public required string Name { get; set; }
|
||||
public required string Value { get; set; }
|
||||
public bool? IsVerified { get; set; }
|
||||
}
|
||||
}
|
|
@ -5,6 +5,7 @@ using Iceshrimp.Backend.Controllers.Mastodon.Renderers;
|
|||
using Iceshrimp.Backend.Controllers.Mastodon.Schemas;
|
||||
using Iceshrimp.Backend.Controllers.Mastodon.Schemas.Entities;
|
||||
using Iceshrimp.Backend.Controllers.Schemas;
|
||||
using Iceshrimp.Shared.Schemas;
|
||||
using Iceshrimp.Backend.Core.Database;
|
||||
using Iceshrimp.Backend.Core.Database.Tables;
|
||||
using Iceshrimp.Backend.Core.Middleware;
|
||||
|
|
|
@ -2,7 +2,7 @@ using System.Threading.RateLimiting;
|
|||
using Iceshrimp.Backend.Controllers.Federation;
|
||||
using Iceshrimp.Backend.Controllers.Mastodon.Renderers;
|
||||
using Iceshrimp.Backend.Controllers.Renderers;
|
||||
using Iceshrimp.Backend.Controllers.Schemas;
|
||||
using Iceshrimp.Shared.Schemas;
|
||||
using Iceshrimp.Backend.Core.Configuration;
|
||||
using Iceshrimp.Backend.Core.Database;
|
||||
using Iceshrimp.Backend.Core.Federation.WebFinger;
|
||||
|
|
|
@ -2,7 +2,7 @@ using System.Diagnostics.CodeAnalysis;
|
|||
using System.Net;
|
||||
using Iceshrimp.Backend.Controllers.Mastodon.Attributes;
|
||||
using Iceshrimp.Backend.Controllers.Mastodon.Schemas;
|
||||
using Iceshrimp.Backend.Controllers.Schemas;
|
||||
using Iceshrimp.Shared.Schemas;
|
||||
using Iceshrimp.Backend.Core.Configuration;
|
||||
using Microsoft.Extensions.Options;
|
||||
|
||||
|
|
10
Iceshrimp.Backend/Hubs/ExampleHub.cs
Normal file
10
Iceshrimp.Backend/Hubs/ExampleHub.cs
Normal file
|
@ -0,0 +1,10 @@
|
|||
using Microsoft.AspNetCore.SignalR;
|
||||
namespace Iceshrimp.Backend.Hubs;
|
||||
|
||||
public class ExampleHub : Hub
|
||||
{
|
||||
public async Task SendMessage(string user, string message)
|
||||
{
|
||||
await Clients.All.SendAsync("ReceiveMessage", user, message);
|
||||
}
|
||||
}
|
|
@ -33,6 +33,7 @@
|
|||
<PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="8.0.3" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Mvc.Razor.RuntimeCompilation" Version="8.0.3" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="8.0.3" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.SignalR.Protocols.MessagePack" Version="8.0.3" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="8.0.3">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
|
@ -59,6 +60,7 @@
|
|||
<ItemGroup>
|
||||
<ProjectReference Include="..\Iceshrimp.Frontend\Iceshrimp.Frontend.csproj" />
|
||||
<ProjectReference Include="..\Iceshrimp.Parsing\Iceshrimp.Parsing.fsproj"/>
|
||||
<ProjectReference Include="..\Iceshrimp.Shared\Iceshrimp.Shared.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
using Iceshrimp.Backend.Core.Extensions;
|
||||
using Iceshrimp.Backend.Hubs;
|
||||
|
||||
var builder = WebApplication.CreateBuilder(args);
|
||||
|
||||
|
@ -16,6 +17,8 @@ builder.Services.AddLogging(logging => logging.AddCustomConsoleFormatter());
|
|||
builder.Services.AddDatabaseContext(builder.Configuration);
|
||||
builder.Services.AddSlidingWindowRateLimiter();
|
||||
builder.Services.AddCorsPolicies();
|
||||
builder.Services.AddSignalR().AddMessagePackProtocol();
|
||||
builder.Services.AddResponseCompression();
|
||||
|
||||
if (builder.Environment.IsDevelopment())
|
||||
builder.Services.AddRazorPages().AddRazorRuntimeCompilation();
|
||||
|
@ -31,6 +34,9 @@ var app = builder.Build();
|
|||
var config = await app.Initialize(args);
|
||||
|
||||
// This determines the order of middleware execution in the request pipeline
|
||||
if (!app.Environment.IsDevelopment())
|
||||
app.UseResponseCompression();
|
||||
|
||||
app.UseRouting();
|
||||
app.UseSwaggerWithOptions();
|
||||
app.UseBlazorFrameworkFiles();
|
||||
|
@ -43,6 +49,7 @@ app.UseCustomMiddleware();
|
|||
|
||||
app.MapControllers();
|
||||
app.MapFallbackToController("/api/{**slug}", "FallbackAction", "Fallback");
|
||||
app.MapHub<ExampleHub>("/hubs/example");
|
||||
app.MapRazorPages();
|
||||
app.MapFallbackToPage("/Shared/FrontendSPA");
|
||||
|
||||
|
|
|
@ -0,0 +1,26 @@
|
|||
using System.ComponentModel;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using Iceshrimp.Frontend.Core.Extensions;
|
||||
using Iceshrimp.Shared.Schemas;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
|
||||
namespace Iceshrimp.Frontend.Core.ControllerModels;
|
||||
|
||||
internal class NoteControllerModel(HttpClient api)
|
||||
{
|
||||
public Task<NoteResponse?> GetNote(string id) => api.CallNullable<NoteResponse>(HttpMethod.Get, $"/note/{id}");
|
||||
|
||||
public Task<NoteResponse?> GetNoteAscendants(string id, [DefaultValue(20)] [Range(1, 100)] int? limit)
|
||||
{
|
||||
var query = new QueryString();
|
||||
if (limit.HasValue) query.Add("limit", limit.ToString());
|
||||
return api.CallNullable<NoteResponse>(HttpMethod.Get, $"/note/{id}/ascendants", query);
|
||||
}
|
||||
|
||||
public Task<NoteResponse?> GetNoteDescendants(string id, [DefaultValue(20)] [Range(1, 100)] int? depth)
|
||||
{
|
||||
var query = new QueryString();
|
||||
if (depth.HasValue) query.Add("depth", depth.ToString());
|
||||
return api.CallNullable<NoteResponse>(HttpMethod.Get, $"/note/{id}/descendants", query);
|
||||
}
|
||||
}
|
59
Iceshrimp.Frontend/Core/Extensions/HttpClientExtensions.cs
Normal file
59
Iceshrimp.Frontend/Core/Extensions/HttpClientExtensions.cs
Normal file
|
@ -0,0 +1,59 @@
|
|||
using System.Net.Http.Json;
|
||||
using System.Net.Mime;
|
||||
using System.Text;
|
||||
using Iceshrimp.Frontend.Core.Miscellaneous;
|
||||
using Iceshrimp.Shared.Schemas;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
|
||||
namespace Iceshrimp.Frontend.Core.Extensions;
|
||||
|
||||
internal static class HttpClientExtensions
|
||||
{
|
||||
public static async Task<T> Call<T>(
|
||||
this HttpClient client, HttpMethod method, string path, QueryString? query = null, string? body = null
|
||||
) where T : class
|
||||
{
|
||||
var res = await CallInternal<T>(client, method, path, query, body);
|
||||
if (res.result != null)
|
||||
return res.result;
|
||||
throw new ApiException(res.error ?? throw new Exception("Deserialized API error was null"));
|
||||
}
|
||||
|
||||
public static async Task<T?> CallNullable<T>(
|
||||
this HttpClient client, HttpMethod method, string path, QueryString? query = null, string? body = null
|
||||
) where T : class
|
||||
{
|
||||
var res = await CallInternal<T>(client, method, path, query, body);
|
||||
if (res.result != null)
|
||||
return res.result;
|
||||
|
||||
var err = res.error ?? throw new Exception("Deserialized API error was null");
|
||||
if (err.StatusCode == 404)
|
||||
return null;
|
||||
|
||||
throw new ApiException(err);
|
||||
}
|
||||
|
||||
private static async Task<(T? result, ErrorResponse? error)> CallInternal<T>(
|
||||
this HttpClient client, HttpMethod method, string path, QueryString? query = null, string? body = null
|
||||
) where T : class
|
||||
{
|
||||
var request = new HttpRequestMessage(method, "/api/iceshrimp/" + path.TrimStart('/') + query);
|
||||
request.Headers.Accept.ParseAdd(MediaTypeNames.Application.Json);
|
||||
if (body != null) request.Content = new StringContent(body, Encoding.UTF8, MediaTypeNames.Application.Json);
|
||||
|
||||
var res = await client.SendAsync(request);
|
||||
if (res.IsSuccessStatusCode)
|
||||
{
|
||||
var deserialized = await res.Content.ReadFromJsonAsync<T>();
|
||||
if (deserialized == null)
|
||||
throw new Exception("Deserialized API response was null");
|
||||
return (deserialized, null);
|
||||
}
|
||||
|
||||
var error = await res.Content.ReadFromJsonAsync<ErrorResponse>();
|
||||
if (error == null)
|
||||
throw new Exception("Deserialized API error was null");
|
||||
return (null, error);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
namespace Iceshrimp.Frontend.Core.Extensions;
|
||||
|
||||
public class HttpResponseMessageExtensions
|
||||
{
|
||||
|
||||
}
|
8
Iceshrimp.Frontend/Core/Miscellaneous/ApiException.cs
Normal file
8
Iceshrimp.Frontend/Core/Miscellaneous/ApiException.cs
Normal file
|
@ -0,0 +1,8 @@
|
|||
using Iceshrimp.Shared.Schemas;
|
||||
|
||||
namespace Iceshrimp.Frontend.Core.Miscellaneous;
|
||||
|
||||
internal class ApiException(ErrorResponse error) : Exception
|
||||
{
|
||||
public ErrorResponse Response => error;
|
||||
}
|
8
Iceshrimp.Frontend/Core/Services/ApiService.cs
Normal file
8
Iceshrimp.Frontend/Core/Services/ApiService.cs
Normal file
|
@ -0,0 +1,8 @@
|
|||
using Iceshrimp.Frontend.Core.ControllerModels;
|
||||
|
||||
namespace Iceshrimp.Frontend.Core.Services;
|
||||
|
||||
internal class ApiService(HttpClient client)
|
||||
{
|
||||
internal NoteControllerModel Notes = new(client);
|
||||
}
|
|
@ -5,6 +5,7 @@
|
|||
<Nullable>enable</Nullable>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<PublishTrimmed>true</PublishTrimmed>
|
||||
<NoDefaultLaunchSettingsFile>true</NoDefaultLaunchSettingsFile>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(EnableAOT)' == 'true'">
|
||||
|
@ -13,6 +14,9 @@
|
|||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly" Version="8.0.3" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Http.Abstractions" Version="2.2.0" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.SignalR.Client" Version="8.0.3" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.SignalR.Protocols.MessagePack" Version="8.0.3" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
@ -24,4 +28,9 @@
|
|||
<_ContentIncludedByDefault Remove="wwwroot\assets\transparent.png" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Iceshrimp.Parsing\Iceshrimp.Parsing.fsproj" />
|
||||
<ProjectReference Include="..\Iceshrimp.Shared\Iceshrimp.Shared.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
|
||||
<h1>Counter</h1>
|
||||
|
||||
<p role="status">Current count: @_currentCount</p>
|
||||
<p role="status">Current count (edited): @_currentCount</p>
|
||||
|
||||
<button class="btn btn-primary" @onclick="IncrementCount">Click me</button>
|
||||
|
||||
|
|
72
Iceshrimp.Frontend/Pages/Hub.razor
Normal file
72
Iceshrimp.Frontend/Pages/Hub.razor
Normal file
|
@ -0,0 +1,72 @@
|
|||
@page "/hub"
|
||||
@using Microsoft.AspNetCore.SignalR.Client
|
||||
@inject NavigationManager Navigation
|
||||
@implements IAsyncDisposable
|
||||
|
||||
<PageTitle>Home</PageTitle>
|
||||
|
||||
<div class="form-group">
|
||||
<label>
|
||||
User:
|
||||
<input @bind="userInput" />
|
||||
</label>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>
|
||||
Message:
|
||||
<input @bind="messageInput" size="50" />
|
||||
</label>
|
||||
</div>
|
||||
<button @onclick="Send" disabled="@(!IsConnected)">Send</button>
|
||||
|
||||
<hr>
|
||||
|
||||
<ul id="messagesList">
|
||||
@foreach (var message in messages)
|
||||
{
|
||||
<li>@message</li>
|
||||
}
|
||||
</ul>
|
||||
|
||||
@code {
|
||||
private HubConnection? hubConnection;
|
||||
private List<string> messages = [];
|
||||
private string? userInput;
|
||||
private string? messageInput;
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
hubConnection = new HubConnectionBuilder()
|
||||
.WithUrl(Navigation.ToAbsoluteUri("/hubs/example"))
|
||||
.AddMessagePackProtocol()
|
||||
.Build();
|
||||
|
||||
hubConnection.On<string, string>("ReceiveMessage", (user, message) =>
|
||||
{
|
||||
var encodedMsg = $"{user}: {message}";
|
||||
messages.Add(encodedMsg);
|
||||
InvokeAsync(StateHasChanged);
|
||||
});
|
||||
|
||||
await hubConnection.StartAsync();
|
||||
}
|
||||
|
||||
private async Task Send()
|
||||
{
|
||||
if (hubConnection is not null)
|
||||
{
|
||||
await hubConnection.SendAsync("SendMessage", userInput, messageInput);
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsConnected =>
|
||||
hubConnection?.State == HubConnectionState.Connected;
|
||||
|
||||
public async ValueTask DisposeAsync()
|
||||
{
|
||||
if (hubConnection is not null)
|
||||
{
|
||||
await hubConnection.DisposeAsync();
|
||||
}
|
||||
}
|
||||
}
|
44
Iceshrimp.Frontend/Pages/TestNote.razor
Normal file
44
Iceshrimp.Frontend/Pages/TestNote.razor
Normal file
|
@ -0,0 +1,44 @@
|
|||
@page "/TestNote/{id}"
|
||||
@using Iceshrimp.Frontend.Core.Miscellaneous
|
||||
@using Iceshrimp.Frontend.Core.Services
|
||||
@using Iceshrimp.Shared.Schemas
|
||||
@inject ApiService Api
|
||||
<h3>TestNote</h3>
|
||||
|
||||
@if (_note != null)
|
||||
{
|
||||
<p id="text">@_note.Text</p>
|
||||
}
|
||||
else if (_error != null)
|
||||
{
|
||||
<p>Error!: @_error.Error</p>
|
||||
}
|
||||
else
|
||||
{
|
||||
<p>Fetching note...</p>
|
||||
}
|
||||
|
||||
@code {
|
||||
[Parameter]
|
||||
public string Id { get; set; } = null!;
|
||||
|
||||
private ErrorResponse? _error;
|
||||
private NoteResponse? _note;
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
try
|
||||
{
|
||||
_note = await Api.Notes.GetNote(Id) ?? throw new ApiException(new ErrorResponse
|
||||
{
|
||||
StatusCode = 404,
|
||||
Error = "Note not found",
|
||||
RequestId = "-"
|
||||
});
|
||||
}
|
||||
catch (ApiException e)
|
||||
{
|
||||
_error = e.Response;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,11 +1,13 @@
|
|||
using Microsoft.AspNetCore.Components.Web;
|
||||
using Microsoft.AspNetCore.Components.WebAssembly.Hosting;
|
||||
using Iceshrimp.Frontend;
|
||||
using Iceshrimp.Frontend.Core.Services;
|
||||
|
||||
var builder = WebAssemblyHostBuilder.CreateDefault(args);
|
||||
builder.RootComponents.Add<App>("#app");
|
||||
builder.RootComponents.Add<HeadOutlet>("head::after");
|
||||
|
||||
builder.Services.AddScoped(_ => new HttpClient { BaseAddress = new Uri(builder.HostEnvironment.BaseAddress) });
|
||||
builder.Services.AddScoped<ApiService>();
|
||||
|
||||
await builder.Build().RunAsync();
|
|
@ -8,6 +8,8 @@ Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "Iceshrimp.Parsing", "Iceshr
|
|||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Iceshrimp.Frontend", "Iceshrimp.Frontend\Iceshrimp.Frontend.csproj", "{8BAF3DEB-19A7-4044-A3F3-75C8B9B51863}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Iceshrimp.Shared", "Iceshrimp.Shared\Iceshrimp.Shared.csproj", "{25E8E423-D2F7-437B-8E9B-5277BA5CE3CD}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
|
@ -30,5 +32,9 @@ Global
|
|||
{8BAF3DEB-19A7-4044-A3F3-75C8B9B51863}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{8BAF3DEB-19A7-4044-A3F3-75C8B9B51863}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{8BAF3DEB-19A7-4044-A3F3-75C8B9B51863}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{25E8E423-D2F7-437B-8E9B-5277BA5CE3CD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{25E8E423-D2F7-437B-8E9B-5277BA5CE3CD}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{25E8E423-D2F7-437B-8E9B-5277BA5CE3CD}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{25E8E423-D2F7-437B-8E9B-5277BA5CE3CD}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
|
|
9
Iceshrimp.Shared/Iceshrimp.Shared.csproj
Normal file
9
Iceshrimp.Shared/Iceshrimp.Shared.csproj
Normal file
|
@ -0,0 +1,9 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
</Project>
|
|
@ -1,6 +1,6 @@
|
|||
using J = System.Text.Json.Serialization.JsonPropertyNameAttribute;
|
||||
|
||||
namespace Iceshrimp.Backend.Controllers.Schemas;
|
||||
namespace Iceshrimp.Shared.Schemas;
|
||||
|
||||
public class AuthRequest
|
||||
{
|
|
@ -3,7 +3,7 @@ using System.Text.Json.Serialization;
|
|||
using J = System.Text.Json.Serialization.JsonPropertyNameAttribute;
|
||||
using JE = System.Runtime.Serialization.EnumMemberAttribute;
|
||||
|
||||
namespace Iceshrimp.Backend.Controllers.Schemas;
|
||||
namespace Iceshrimp.Shared.Schemas;
|
||||
|
||||
public class AuthStatusConverter() : JsonStringEnumConverter<AuthStatusEnum>(JsonNamingPolicy.SnakeCaseLower);
|
||||
|
|
@ -2,7 +2,7 @@ using System.Text.Json.Serialization;
|
|||
using J = System.Text.Json.Serialization.JsonPropertyNameAttribute;
|
||||
using JI = System.Text.Json.Serialization.JsonIgnoreAttribute;
|
||||
|
||||
namespace Iceshrimp.Backend.Controllers.Schemas;
|
||||
namespace Iceshrimp.Shared.Schemas;
|
||||
|
||||
public class ErrorResponse
|
||||
{
|
|
@ -1,6 +1,6 @@
|
|||
using J = System.Text.Json.Serialization.JsonPropertyNameAttribute;
|
||||
|
||||
namespace Iceshrimp.Backend.Controllers.Schemas;
|
||||
namespace Iceshrimp.Shared.Schemas;
|
||||
|
||||
public class InviteResponse
|
||||
{
|
|
@ -1,6 +1,6 @@
|
|||
using J = System.Text.Json.Serialization.JsonPropertyNameAttribute;
|
||||
|
||||
namespace Iceshrimp.Backend.Controllers.Schemas;
|
||||
namespace Iceshrimp.Shared.Schemas;
|
||||
|
||||
public class NoteCreateRequest
|
||||
{
|
|
@ -1,7 +1,7 @@
|
|||
using J = System.Text.Json.Serialization.JsonPropertyNameAttribute;
|
||||
using JI = System.Text.Json.Serialization.JsonIgnoreAttribute;
|
||||
|
||||
namespace Iceshrimp.Backend.Controllers.Schemas;
|
||||
namespace Iceshrimp.Shared.Schemas;
|
||||
|
||||
public class NoteResponse : NoteWithQuote
|
||||
{
|
|
@ -1,6 +1,6 @@
|
|||
using J = System.Text.Json.Serialization.JsonPropertyNameAttribute;
|
||||
|
||||
namespace Iceshrimp.Backend.Controllers.Schemas;
|
||||
namespace Iceshrimp.Shared.Schemas;
|
||||
|
||||
public class NotificationResponse
|
||||
{
|
21
Iceshrimp.Shared/Schemas/UserProfileResponse.cs
Normal file
21
Iceshrimp.Shared/Schemas/UserProfileResponse.cs
Normal file
|
@ -0,0 +1,21 @@
|
|||
using J = System.Text.Json.Serialization.JsonPropertyNameAttribute;
|
||||
|
||||
namespace Iceshrimp.Shared.Schemas;
|
||||
|
||||
public class UserProfileResponse
|
||||
{
|
||||
[J("id")] public required string Id { get; set; }
|
||||
[J("birthday")] public required string? Birthday { get; set; }
|
||||
[J("location")] public required string? Location { get; set; }
|
||||
[J("fields")] public required List<UserProfileField>? Fields { get; set; }
|
||||
[J("bio")] public required string? Bio { get; set; }
|
||||
[J("followers")] public required int? Followers { get; set; }
|
||||
[J("following")] public required int? Following { get; set; }
|
||||
}
|
||||
|
||||
public class UserProfileField
|
||||
{
|
||||
[J("name")] public required string Name { get; set; }
|
||||
[J("value")] public required string Value { get; set; }
|
||||
[J("verified")] public bool? IsVerified { get; set; }
|
||||
}
|
|
@ -1,6 +1,6 @@
|
|||
using J = System.Text.Json.Serialization.JsonPropertyNameAttribute;
|
||||
|
||||
namespace Iceshrimp.Backend.Controllers.Schemas;
|
||||
namespace Iceshrimp.Shared.Schemas;
|
||||
|
||||
public class UserResponse
|
||||
{
|
|
@ -1,6 +1,6 @@
|
|||
using J = System.Text.Json.Serialization.JsonPropertyNameAttribute;
|
||||
|
||||
namespace Iceshrimp.Backend.Controllers.Schemas;
|
||||
namespace Iceshrimp.Shared.Schemas;
|
||||
|
||||
public class ValueResponse(long count)
|
||||
{
|
Loading…
Add table
Reference in a new issue