- 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>
95 lines
3.8 KiB
PHP
95 lines
3.8 KiB
PHP
<?php
|
|
|
|
use App\Livewire\Admin\Panel;
|
|
use App\Models\EmailTemplate;
|
|
use App\Notifications\TicketNotification;
|
|
use App\Support\Settings;
|
|
use Livewire\Livewire;
|
|
|
|
test('Settings::renderEmailLayout always wraps content in the fixed box layout, ignoring any stored override', function () {
|
|
// The box is no longer admin-editable — a leftover/stale stored value
|
|
// (e.g. from before this UI was removed) must not be used.
|
|
Settings::set('email_layout_html', '<div class="should-be-ignored">{tresc}</div>');
|
|
Settings::set('email_footer', 'Pozdrawiamy, Wsparcie');
|
|
Settings::set('company_name', 'Acme');
|
|
|
|
$html = Settings::renderEmailLayout('<p>Treść zgłoszenia</p>');
|
|
|
|
expect($html)->not->toContain('should-be-ignored')
|
|
->and($html)->toBe(strtr(Settings::default('email_layout_html'), [
|
|
'{tresc}' => '<p>Treść zgłoszenia</p>',
|
|
'{stopka}' => 'Pozdrawiamy, Wsparcie',
|
|
'{firma}' => 'Acme',
|
|
]));
|
|
});
|
|
|
|
test('the default footer is not empty and its own {firma} placeholder resolves through the layout', function () {
|
|
Settings::set('company_name', 'Acme');
|
|
|
|
$html = Settings::renderEmailLayout('<p>Treść</p>');
|
|
|
|
expect(Settings::default('email_footer'))->not->toBeEmpty()
|
|
->and($html)->toContain('Acme')
|
|
->and($html)->not->toContain('{firma}');
|
|
});
|
|
|
|
test('admin can reset the email footer back to its default, remounting the editor with a fresh key', function () {
|
|
$admin = adminUser();
|
|
|
|
$component = Livewire::actingAs($admin)->test(Panel::class)
|
|
->call('setTab', 'email')
|
|
->call('saveEmailFooter', 'Coś innego')
|
|
->assertSet('emailFooterVersion', 0);
|
|
|
|
$component->call('resetEmailFooter')
|
|
->assertOk()
|
|
->assertSet('emailFooterHtml', Settings::default('email_footer'))
|
|
->assertSet('emailFooterVersion', 1)
|
|
->assertSee('email-footer-1', escape: false);
|
|
|
|
expect(Settings::get('email_footer'))->toBe(Settings::default('email_footer'));
|
|
});
|
|
|
|
test('admin can save the email footer from the E-MAIL tab', function () {
|
|
$admin = adminUser();
|
|
|
|
Livewire::actingAs($admin)->test(Panel::class)
|
|
->call('setTab', 'email')
|
|
->call('saveEmailFooter', '<p>Pozdrawiamy, Zespół Wsparcia</p>')
|
|
->assertOk()
|
|
->assertSet('emailFooterHtml', '<p>Pozdrawiamy, Zespół Wsparcia</p>');
|
|
|
|
expect(Settings::get('email_footer'))->toBe('<p>Pozdrawiamy, Zespół Wsparcia</p>');
|
|
});
|
|
|
|
test('the live example preview reflects the currently saved footer', function () {
|
|
$admin = adminUser();
|
|
|
|
$component = Livewire::actingAs($admin)->test(Panel::class)
|
|
->call('setTab', 'email')
|
|
->call('saveEmailFooter', 'Stopka na żywo');
|
|
|
|
expect($component->instance()->emailPreviewHtml)->toContain('Stopka na żywo')
|
|
->and($component->instance()->emailPreviewHtml)->toContain('#1234');
|
|
});
|
|
|
|
test('there is no more editor for the box layout itself, only for its footer', function () {
|
|
expect(method_exists(Panel::class, 'saveEmailLayout'))->toBeFalse()
|
|
->and(method_exists(Panel::class, 'resetEmailLayout'))->toBeFalse();
|
|
});
|
|
|
|
test('a rendered ticket notification embeds its template body inside the fixed box layout', function () {
|
|
seedStatusesAndPriorities();
|
|
|
|
$template = EmailTemplate::query()->create([
|
|
'key' => 'tpl-layout-test', 'name' => 'x', 'trigger_label' => 'x',
|
|
'subject' => 'S', 'body' => '<p>Zgłoszenie #{numer} zostało utworzone.</p>',
|
|
]);
|
|
$ticket = makeTicket();
|
|
|
|
$mail = (new TicketNotification($ticket, $template->id))->toMail((object) ['routes' => ['mail' => $ticket->email]]);
|
|
|
|
expect($mail->viewData['html'])->toBe(Settings::renderEmailLayout('<p>Zgłoszenie #'.$ticket->number.' zostało utworzone.</p>'))
|
|
->and($mail->view)->toBe('emails.ticket-notification');
|
|
});
|