feat: implement dynamic knowledge graph updates and state management services

This commit is contained in:
2026-04-26 14:53:48 +02:00
parent 412320980f
commit 7859c9806f
30 changed files with 668 additions and 153 deletions
@@ -31,13 +31,10 @@
[Parameter] public List<string> Actions { get; set; } = new();
[Parameter] public EventCallback<string> OnActionTriggered { get; set; }
private bool _isQuizMode = false;
private async Task HandleActionClick(string action)
{
if (action.Contains("quiz", StringComparison.OrdinalIgnoreCase))
{
_isQuizMode = true;
QuizState.RequestQuiz(ContextBlockId);
}
@@ -1,5 +1,7 @@
@using NexusReader.UI.Shared.Services
@using NexusReader.Application.Abstractions.Services
@inject IFocusModeService FocusMode
@inject IKnowledgeService KnowledgeService
<aside class="intelligence-toolbar">
<div class="toolbar-top">
@@ -21,6 +23,9 @@
<button class="toolbar-item" title="Search">
<NexusIcon Name="search" Size="20" />
</button>
<button class="toolbar-item danger" @onclick="HandleClearCache" title="Clear AI Cache">
<NexusIcon Name="trash" Size="20" />
</button>
</div>
<div class="toolbar-bottom">
@@ -40,6 +45,17 @@
FocusMode.OnFocusModeChanged += StateHasChanged;
}
private async Task HandleClearCache()
{
// For now, a simple console log confirm or just do it
Console.WriteLine("[IntelligenceToolbar] Requesting cache clear...");
var result = await KnowledgeService.ClearCacheAsync();
if (result.IsSuccess)
{
Console.WriteLine("[IntelligenceToolbar] Cache cleared successfully!");
}
}
public void Dispose()
{
FocusMode.OnFocusModeChanged -= StateHasChanged;
@@ -65,3 +65,8 @@
.rotate-180 {
transform: rotate(180deg);
}
.toolbar-item.danger:hover {
color: #ff4d4d;
background: rgba(255, 77, 77, 0.1);
}
@@ -4,6 +4,7 @@
@using NexusReader.Application.Abstractions.Services
@inject IMediator Mediator
@inject IPlatformService PlatformService
@inject IQuizStateService QuizService
<div class="knowledge-check">
<div class="quiz-header">
@@ -11,14 +12,14 @@
<button class="expand-btn">⌵</button>
</div>
@if (_isLoading)
@if (QuizService.IsHydrating)
{
<div class="loading-state">Pobieranie pytań...</div>
<div class="loading-state shimmer">Skanowanie wiedzy przez AI...</div>
}
else if (_quiz != null)
else if (QuizService.CurrentQuiz != null)
{
<div class="quiz-body">
@foreach (var question in _quiz.Questions)
@foreach (var question in QuizService.CurrentQuiz.Questions)
{
<div class="question-container">
<p class="question-text">@question.Question</p>
@@ -50,21 +51,16 @@
@code {
[Parameter] public string ContextBlockId { get; set; } = string.Empty;
private bool _isLoading = true;
private QuizDto? _quiz;
private Dictionary<QuizQuestionDto, (int SelectedIndex, bool IsCorrect)> _states = new();
protected override async Task OnInitializedAsync()
protected override void OnInitialized()
{
_isLoading = true;
var query = new GetQuizQuestionsQuery(ContextBlockId);
var result = await Mediator.Send(query);
if (result.IsSuccess)
_quiz = result.Value;
_isLoading = false;
QuizService.OnQuizUpdated += () => InvokeAsync(StateHasChanged);
}
public void Dispose()
{
QuizService.OnQuizUpdated -= StateHasChanged;
}
private async Task SelectOptionAsync(QuizQuestionDto question, int index)
@@ -89,7 +85,7 @@
private bool AllQuestionsAnswered()
{
return _quiz != null && _states.Count == _quiz.Questions.Count;
return QuizService.CurrentQuiz != null && _states.Count == QuizService.CurrentQuiz.Questions.Count;
}
@@ -106,3 +106,18 @@
border-color: #ff4444 !important;
background: rgba(255, 68, 68, 0.1) !important;
}
.loading-state.shimmer {
background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.05), transparent);
background-size: 200% 100%;
animation: shimmer 1.5s infinite;
padding: 20px;
text-align: center;
color: var(--nexus-neon);
text-shadow: 0 0 10px var(--nexus-neon);
}
@keyframes shimmer {
0% { background-position: -200% 0; }
100% { background-position: 200% 0; }
}