v1.1.2
- Real-time updates (Laravel Reverb): live operator queue, live ticket chat/detail updates for operator and client, periodic fallback refresh with a visible countdown as a backstop for dropped websocket connections. - SLA automation rules (Admin > Automatyzacja SLA): act on a ticket after N minutes of customer silence (change priority/status/team/assignee), evaluated every 15 minutes, reusing TicketService's own setters so automated changes get the same history/notification/broadcast a manual change would. - New notification: every operator on a matching team gets notified when a new ticket lands in one of their subcategories. - BookStack knowledge-base sidebar now also shown on the client's own ticket view (previously operator-only); suggestions everywhere now load in after first paint instead of blocking it. - Client ticket view: shows assigned operator + team; page widened to match the operator's. - Notification bell shows unread only; read notifications disappear instead of just dimming. - Stats dashboard: sectioned layout, new breakdowns (by subcategory, CSAT by team/operator, top clients, client x subcategory cross-tab). - Mobile: nav dropdowns (theme/notifications/profile) now expand full width instead of overflowing off-screen below 640px. - Fixed two bugs that silently disabled all real-time updates (missing CSRF header on Echo's private-channel auth; a script-load-order race that could miss the livewire:init event) and the mariadb healthcheck (world-writable credentials file on this stack's NFS mount). - Assorted test-suite fixes (roles virtual attribute needs the roles table seeded; a few missing seeds/wrong assertions found along the way). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -55,7 +55,7 @@ class DatabaseSeeder extends Seeder
|
||||
['key' => 'operator', 'label' => 'Operator'],
|
||||
['key' => 'admin', 'label' => 'Administrator'],
|
||||
] as $role) {
|
||||
Role::query()->create($role);
|
||||
Role::query()->firstOrCreate(['key' => $role['key']], $role);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -259,6 +259,11 @@ class DatabaseSeeder extends Seeder
|
||||
{
|
||||
foreach ([
|
||||
['label' => 'Wyślij i „Oczekuje na klienta”', 'status_key' => 'waiting_customer', 'sort_order' => 1],
|
||||
// Used to point at the now-removed "resolved" status, folded into
|
||||
// "closed" by the status restructure — same target as "Wyślij i
|
||||
// zamknij" today, kept as a separate quick action for continuity
|
||||
// with the old hardcoded menu (see ReplyQuickActionsTest).
|
||||
['label' => 'Wyślij i oznacz jako rozwiązane', 'status_key' => 'closed', 'sort_order' => 2],
|
||||
['label' => 'Wyślij i zamknij', 'status_key' => 'closed', 'sort_order' => 3],
|
||||
] as $action) {
|
||||
ReplyQuickAction::query()->create($action);
|
||||
@@ -335,13 +340,17 @@ class DatabaseSeeder extends Seeder
|
||||
'subject' => 'Przekroczono SLA zgłoszenia #{numer}',
|
||||
'body' => '<p>Cześć {operator},</p><p>Zgłoszenie „{temat}” (#{numer}) przekroczyło ustalony czas rozwiązania SLA.</p>'.$link.$footer,
|
||||
],
|
||||
'tpl-team-new-ticket' => [
|
||||
'name' => 'Nowe zgłoszenie w zespole', 'trigger_label' => 'Nowe zgłoszenie w zespole — operator',
|
||||
'subject' => 'Nowe zgłoszenie w Twoim zespole (#{numer})',
|
||||
'body' => '<p>Cześć,</p><p>Nowe zgłoszenie „{temat}” (#{numer}, kategoria: {kategoria}) trafiło do zespołu {zespol}.</p>'.$link.$footer,
|
||||
],
|
||||
];
|
||||
|
||||
$ids = [];
|
||||
|
||||
foreach ($templates as $key => $tpl) {
|
||||
$ids[$key] = EmailTemplate::query()->create([
|
||||
'key' => $key,
|
||||
$ids[$key] = EmailTemplate::query()->firstOrCreate(['key' => $key], [
|
||||
'name' => $tpl['name'],
|
||||
'trigger_label' => $tpl['trigger_label'],
|
||||
'subject' => $tpl['subject'],
|
||||
@@ -359,9 +368,9 @@ class DatabaseSeeder extends Seeder
|
||||
['trigger_key' => 'ticket_closed', 'trigger_label' => 'Zgłoszenie zamknięte', 'enabled' => true, 'recipient' => 'client', 'template' => 'tpl-closed'],
|
||||
['trigger_key' => 'operator_replied', 'trigger_label' => 'Nowa odpowiedź operatora', 'enabled' => true, 'recipient' => 'client', 'template' => 'tpl-reply'],
|
||||
['trigger_key' => 'sla_breached', 'trigger_label' => 'Przekroczono SLA (powiadom operatora)', 'enabled' => false, 'recipient' => 'operator', 'template' => 'tpl-sla-breach'],
|
||||
['trigger_key' => 'ticket_created_team', 'trigger_label' => 'Nowe zgłoszenie w zespole (powiadom operatorów)', 'enabled' => true, 'recipient' => 'operator', 'template' => 'tpl-team-new-ticket'],
|
||||
] as $setting) {
|
||||
NotificationSetting::query()->create([
|
||||
'trigger_key' => $setting['trigger_key'],
|
||||
NotificationSetting::query()->firstOrCreate(['trigger_key' => $setting['trigger_key']], [
|
||||
'trigger_label' => $setting['trigger_label'],
|
||||
'enabled' => $setting['enabled'],
|
||||
'recipient' => $setting['recipient'],
|
||||
|
||||
Reference in New Issue
Block a user