- Triggers (Admin > Wyzwalacze): event-driven rules that fire immediately on a ticket lifecycle event (created/updated/status/priority/assignee/team/ category changed, new reply), with AND-conditions and ordered actions (set status/priority/team/assignee, send e-mail). Ships its own dedicated, freely add/edit/delete-able e-mail templates, kept separate from the fixed system templates. - Ticket watching: operators can star/"Obserwuj" any ticket to follow it regardless of assignment/team. - Real-time notification bell (private per-user broadcast channel, 30s fallback poll) with an opt-in in-tab browser push notification. - Per-user notification preferences (/settings/notifications): scope (mine/unassigned/watched/all) and e-mail toggle per event category. - Admin > Integracje: new tab for LDAP/AD + BookStack config, split out of Konfiguracja. - Operator queue: Podkategoria/Zespół/Utworzono columns (off by default). - Obserwuj button moved next to the auto-refresh countdown; trigger condition builder shows subcategory/zgłaszający as name dropdowns instead of raw IDs; /settings/notifications got a back link, full-width push card, and a bordered table container; admin panel tab and operator queue view now persist across a plain page refresh. - Docs: README/ARCHITECTURE/wiki updated for all of the above. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
73 lines
3.0 KiB
PHP
73 lines
3.0 KiB
PHP
<?php
|
|
|
|
use App\Livewire\Operator\Queue;
|
|
use Livewire\Livewire;
|
|
|
|
test('search filters tickets by subject, number, customer name or email', function () {
|
|
seedStatusesAndPriorities();
|
|
$operator = operatorUser('search-1@example.com');
|
|
makeTicket(['number' => '1001', 'subject' => 'VPN nie działa', 'name' => 'Jan Kowalski', 'email' => 'jan@example.com']);
|
|
makeTicket(['number' => '1002', 'subject' => 'Reset hasła', 'name' => 'Anna Nowak', 'email' => 'anna@example.com']);
|
|
|
|
$component = Livewire::actingAs($operator)->test(Queue::class)->set('search', 'VPN');
|
|
expect($component->instance()->filteredTickets)->toHaveCount(1);
|
|
expect($component->instance()->filteredTickets->first()->number)->toBe('1001');
|
|
|
|
$component->set('search', 'Nowak');
|
|
expect($component->instance()->filteredTickets)->toHaveCount(1);
|
|
expect($component->instance()->filteredTickets->first()->number)->toBe('1002');
|
|
|
|
$component->set('search', '');
|
|
expect($component->instance()->filteredTickets)->toHaveCount(2);
|
|
});
|
|
|
|
test('clicking a sortable column header sorts ascending, then descending on a second click', function () {
|
|
seedStatusesAndPriorities();
|
|
$operator = operatorUser('sort-1@example.com');
|
|
makeTicket(['number' => '1001', 'subject' => 'Zebra']);
|
|
makeTicket(['number' => '1002', 'subject' => 'Alfa']);
|
|
makeTicket(['number' => '1003', 'subject' => 'Mango']);
|
|
|
|
$component = Livewire::actingAs($operator)->test(Queue::class)
|
|
->call('sortByColumn', 'subject');
|
|
|
|
expect($component->get('sortDir'))->toBe('asc');
|
|
expect($component->instance()->filteredTickets->pluck('subject')->all())->toBe(['Alfa', 'Mango', 'Zebra']);
|
|
|
|
$component->call('sortByColumn', 'subject');
|
|
|
|
expect($component->get('sortDir'))->toBe('desc');
|
|
expect($component->instance()->filteredTickets->pluck('subject')->all())->toBe(['Zebra', 'Mango', 'Alfa']);
|
|
});
|
|
|
|
test('sla is not a clickable sortable column', function () {
|
|
$operator = operatorUser('sort-2@example.com');
|
|
|
|
Livewire::actingAs($operator)->test(Queue::class)
|
|
->call('sortByColumn', 'sla')
|
|
->assertSet('sortBy', 'updated_at');
|
|
});
|
|
|
|
test('columns can be hidden and shown again, but at least one must stay visible', function () {
|
|
$operator = operatorUser('columns-1@example.com');
|
|
|
|
$component = Livewire::actingAs($operator)->test(Queue::class)
|
|
->call('toggleColumn', 'sla')
|
|
->assertSet('visibleColumns', fn ($cols) => ! in_array('sla', $cols, true));
|
|
|
|
$component->call('toggleColumn', 'sla')
|
|
->assertSet('visibleColumns', fn ($cols) => in_array('sla', $cols, true));
|
|
|
|
// Hide every visible-by-default column except one, then try to hide the last one too.
|
|
foreach ((new Queue)->visibleColumns as $key) {
|
|
if ($key !== 'number') {
|
|
$component->call('toggleColumn', $key);
|
|
}
|
|
}
|
|
|
|
expect($component->get('visibleColumns'))->toBe(['number']);
|
|
|
|
$component->call('toggleColumn', 'number');
|
|
expect($component->get('visibleColumns'))->toBe(['number']);
|
|
});
|