feat: Release v1.2.0 - Concepts Map, RAG Search & Core Consolidations #59
@@ -46,6 +46,9 @@
|
||||
case "arrow-right":
|
||||
<path d="M5 12h14M12 5l7 7-7 7" />
|
||||
break;
|
||||
case "log-out":
|
||||
<path d="M9 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h4M16 17l5-5-5-5M21 12H9" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" />
|
||||
break;
|
||||
default:
|
||||
<!-- Fallback circle -->
|
||||
<circle cx="12" cy="12" r="10" />
|
||||
|
||||
|
Before Width: | Height: | Size: 3.4 KiB After Width: | Height: | Size: 3.6 KiB |
@@ -2,6 +2,8 @@
|
||||
@using NexusReader.Application.Abstractions.Services
|
||||
@inject IFocusModeService FocusMode
|
||||
@inject IKnowledgeService KnowledgeService
|
||||
@inject IIdentityService IdentityService
|
||||
@inject NavigationManager NavigationManager
|
||||
|
||||
<aside class="intelligence-toolbar">
|
||||
<div class="toolbar-top">
|
||||
@@ -36,6 +38,9 @@
|
||||
<button class="toolbar-item" title="Global Settings">
|
||||
<NexusIcon Name="settings" Size="20" />
|
||||
</button>
|
||||
<button class="toolbar-item logout-item" @onclick="HandleLogout" title="Logout">
|
||||
<NexusIcon Name="log-out" Size="20" />
|
||||
</button>
|
||||
</div>
|
||||
</aside>
|
||||
|
||||
@@ -56,6 +61,12 @@
|
||||
}
|
||||
}
|
||||
|
||||
private async Task HandleLogout()
|
||||
{
|
||||
await IdentityService.LogoutAsync();
|
||||
NavigationManager.NavigateTo("/", true);
|
||||
}
|
||||
|
||||
private Task HandleUpdate() => InvokeAsync(StateHasChanged);
|
||||
|
||||
public void Dispose()
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
.intelligence-toolbar {
|
||||
width: 50px;
|
||||
height: 100%;
|
||||
background: #080808;
|
||||
border-right: 1px solid rgba(255, 255, 255, 0.03);
|
||||
background: #0D0D0D;
|
||||
border-right: 1px solid rgba(255, 255, 255, 0.08);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: space-between;
|
||||
@@ -10,6 +10,7 @@
|
||||
align-items: center;
|
||||
z-index: 20;
|
||||
box-shadow: inset -2px 0 10px rgba(0,0,0,0.5);
|
||||
backdrop-filter: blur(10px);
|
||||
}
|
||||
|
||||
|
||||
@@ -22,7 +23,7 @@
|
||||
.toolbar-item {
|
||||
background: none;
|
||||
border: none;
|
||||
color: #444;
|
||||
color: #555;
|
||||
cursor: pointer;
|
||||
width: 34px;
|
||||
height: 34px;
|
||||
@@ -37,11 +38,15 @@
|
||||
.toolbar-item:hover {
|
||||
color: var(--nexus-neon);
|
||||
background: rgba(0, 255, 153, 0.05);
|
||||
box-shadow: 0 0 15px rgba(0, 255, 153, 0.15);
|
||||
filter: drop-shadow(0 0 5px var(--nexus-neon));
|
||||
}
|
||||
|
||||
.toolbar-item.active {
|
||||
color: var(--nexus-neon);
|
||||
background: rgba(0, 255, 153, 0.08);
|
||||
box-shadow: 0 0 20px rgba(0, 255, 153, 0.25);
|
||||
filter: drop-shadow(0 0 8px var(--nexus-neon));
|
||||
}
|
||||
|
||||
.toolbar-item.active::after {
|
||||
|
||||
@@ -35,10 +35,7 @@
|
||||
<span>Asystent AI</span>
|
||||
</div>
|
||||
|
||||
<div class="user-profile">
|
||||
<span class="user-email">@context.User.Identity?.Name</span>
|
||||
<button class="logout-btn" @onclick="HandleLogout">Logout</button>
|
||||
</div>
|
||||
|
||||
|
||||
<button class="close-btn">×</button>
|
||||
</div>
|
||||
@@ -93,11 +90,7 @@
|
||||
}
|
||||
}
|
||||
|
||||
private async Task HandleLogout()
|
||||
{
|
||||
await IdentityService.LogoutAsync();
|
||||
NavigationManager.NavigateTo("/", true);
|
||||
}
|
||||
|
||||
|
||||
protected override async Task OnAfterRenderAsync(bool firstRender)
|
||||
{
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
using System.Net.Http.Headers;
|
||||
using NexusReader.Application.Abstractions.Services;
|
||||
|
||||
namespace NexusReader.Web.Client.Handlers;
|
||||
|
||||
public class AuthenticationHeaderHandler : DelegatingHandler
|
||||
{
|
||||
private readonly INativeStorageService _storageService;
|
||||
private const string TokenKey = "nexus_auth_token";
|
||||
|
||||
public AuthenticationHeaderHandler(INativeStorageService storageService)
|
||||
{
|
||||
_storageService = storageService;
|
||||
}
|
||||
|
||||
protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
|
||||
{
|
||||
var tokenResult = await _storageService.GetSecureString(TokenKey);
|
||||
|
||||
if (tokenResult.IsSuccess && !string.IsNullOrEmpty(tokenResult.Value))
|
||||
{
|
||||
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", tokenResult.Value);
|
||||
}
|
||||
|
||||
return await base.SendAsync(request, cancellationToken);
|
||||
}
|
||||
}
|
||||
@@ -12,6 +12,7 @@
|
||||
<ItemGroup>
|
||||
<PackageReference Include="MediatR" Version="12.1.1" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly" Version="10.0.7" />
|
||||
<PackageReference Include="Microsoft.Extensions.Http" Version="10.0.7" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
@@ -33,7 +33,14 @@ builder.Services.AddCascadingAuthenticationState();
|
||||
|
||||
// AI & Content Services
|
||||
builder.Services.AddScoped<IKnowledgeService, WasmKnowledgeService>();
|
||||
builder.Services.AddScoped(sp => new HttpClient { BaseAddress = new Uri(builder.HostEnvironment.BaseAddress) });
|
||||
|
||||
builder.Services.AddTransient<NexusReader.Web.Client.Handlers.AuthenticationHeaderHandler>();
|
||||
builder.Services.AddHttpClient("NexusAPI", client =>
|
||||
{
|
||||
client.BaseAddress = new Uri(builder.HostEnvironment.BaseAddress);
|
||||
}).AddHttpMessageHandler<NexusReader.Web.Client.Handlers.AuthenticationHeaderHandler>();
|
||||
|
||||
builder.Services.AddScoped(sp => sp.GetRequiredService<IHttpClientFactory>().CreateClient("NexusAPI"));
|
||||
|
||||
// Dummy registrations for server-only handlers to satisfy DI validation
|
||||
builder.Services.AddSingleton<IDbContextFactory<AppDbContext>>(new ThrowingDbContextFactory());
|
||||
|
||||
@@ -96,6 +96,18 @@ builder.Services.ConfigureApplicationCookie(options =>
|
||||
options.Cookie.HttpOnly = true;
|
||||
options.ExpireTimeSpan = TimeSpan.FromDays(30);
|
||||
options.SlidingExpiration = true;
|
||||
options.Events.OnRedirectToLogin = context =>
|
||||
{
|
||||
if (context.Request.Path.StartsWithSegments("/api"))
|
||||
{
|
||||
context.Response.StatusCode = 401;
|
||||
}
|
||||
else
|
||||
{
|
||||
context.Response.Redirect(context.RedirectUri);
|
||||
}
|
||||
return Task.CompletedTask;
|
||||
};
|
||||
});
|
||||
|
||||
builder.Services.Configure<IdentityOptions>(options =>
|
||||
|
||||
Reference in New Issue
Block a user