Add admin views for quick replies, settings, and ticket details

- Created `quick-replies.blade.php` for managing quick replies.
- Added `settings.blade.php` for admin settings management.
- Implemented `ticket-show.blade.php` to display ticket details.
- Introduced `timeline-card.blade.php` component for displaying timeline information.

Enhance quick reply management functionality

- Developed `quick-reply-manager.blade.php` for creating and editing quick replies.
- Integrated Livewire for dynamic interaction and validation.

Implement settings page for AI configuration

- Created `settings-page.blade.php` for managing AI settings, including prompts and provider instances.
- Added functionality for managing models and embeddings.

Add ticket show functionality with real-time updates

- Implemented ticket details view with processing status and tool call logs.
- Added support for displaying article suggestions and error messages.

Create unit tests for AI classifier and domain info tool

- Added `AIClassifierServiceTest.php` to validate AI classifier functionality.
- Implemented `DomainInfoToolTest.php` for domain parameter validation.
- Created `OxxaClientTest.php` to test API interactions and password hashing.
This commit is contained in:
SitiWeb
2026-04-30 01:50:21 +02:00
parent 01aa115a49
commit f939133fe0
103 changed files with 4721 additions and 245 deletions

View File

@@ -3,6 +3,7 @@
namespace App\Livewire\Admin;
use App\Services\AdminArticleService;
use App\Services\AdminQuickReplyService;
use Livewire\Component;
use Livewire\WithPagination;
@@ -11,26 +12,107 @@ class ArticleManager extends Component
use WithPagination;
public string $title = '';
public string $content = '';
public string $note = '';
public array $allowedActions = [];
public array $articleNotes = [];
public array $articleAllowedActions = [];
public array $articleQuickReplies = [];
public function save(AdminArticleService $service): void
{
$this->validate([
'title' => ['required', 'string', 'max:255'],
'content' => ['required', 'string', 'max:12000'],
'note' => ['nullable', 'string', 'max:12000'],
'allowedActions' => ['array'],
'allowedActions.*' => ['string', 'in:domain_inf'],
]);
$service->create($this->title, $this->content);
$service->create($this->title, $this->content, $this->note, $this->allowedActions);
$this->reset(['title', 'content']);
$this->reset(['title', 'content', 'note', 'allowedActions']);
$this->dispatch('article-saved');
session()->flash('success', 'Article opgeslagen en embedding wordt automatisch verwerkt.');
}
public function render(AdminArticleService $service)
public function deleteArticle(int $articleId, AdminArticleService $service): void
{
$deleted = $service->deleteById($articleId);
if ($deleted) {
session()->flash('success', "Artikel #{$articleId} is verwijderd.");
} else {
session()->flash('success', "Artikel #{$articleId} bestond niet meer.");
}
$this->resetPage();
}
public function saveMetadata(int $articleId, AdminArticleService $service): void
{
$this->validate([
"articleNotes.{$articleId}" => ['nullable', 'string', 'max:12000'],
"articleAllowedActions.{$articleId}" => ['array'],
"articleAllowedActions.{$articleId}.*" => ['string', 'in:domain_inf'],
"articleQuickReplies.{$articleId}" => ['array'],
"articleQuickReplies.{$articleId}.*" => ['integer', 'exists:quick_replies,id'],
]);
$updated = $service->updateMetadata(
$articleId,
$this->articleNotes[$articleId] ?? null,
$this->articleAllowedActions[$articleId] ?? [],
$this->articleQuickReplies[$articleId] ?? []
);
session()->flash('success', $updated
? "Metadata voor artikel #{$articleId} is opgeslagen."
: "Artikel #{$articleId} bestaat niet meer.");
}
public function approveDraft(int $articleId, AdminArticleService $service): void
{
$approved = $service->approveDraft($articleId);
if ($approved) {
session()->flash('success', "Conceptartikel #{$articleId} is gevalideerd en gepubliceerd.");
} else {
session()->flash('success', "Conceptartikel #{$articleId} bestaat niet meer.");
}
}
public function render(AdminArticleService $service, AdminQuickReplyService $quickReplyService)
{
$articles = $service->paginate(10);
$this->hydrateArticleMetadataState($articles->items());
return view('livewire.admin.article-manager', [
'articles' => $service->paginate(10),
'articles' => $articles,
'quickReplyOptions' => $quickReplyService->activeOptions(),
]);
}
private function hydrateArticleMetadataState(array $articles): void
{
foreach ($articles as $article) {
if (! array_key_exists($article->id, $this->articleNotes)) {
$this->articleNotes[$article->id] = $article->note ?? '';
}
if (! array_key_exists($article->id, $this->articleAllowedActions)) {
$this->articleAllowedActions[$article->id] = $article->allowed_actions ?? [];
}
if (! array_key_exists($article->id, $this->articleQuickReplies)) {
$this->articleQuickReplies[$article->id] = $article->quickReplies->pluck('id')->map(fn ($id) => (int) $id)->all();
}
}
}
}