Fix notifications and document setup

This commit is contained in:
root
2026-01-31 06:33:19 +02:00
parent fac98a3c61
commit 72221b4a63
8 changed files with 112 additions and 67 deletions

View File

@@ -172,7 +172,7 @@ class Waf extends Page implements HasForms, HasTable
$entries = [];
}
$this->auditEntries = $this->markWhitelisted($entries);
$this->auditEntries = $this->normalizeAuditEntries($this->markWhitelisted($entries));
$this->auditLoaded = true;
if ($notify) {
@@ -254,6 +254,21 @@ class Waf extends Page implements HasForms, HasTable
return $entries;
}
protected function normalizeAuditEntries(array $entries): array
{
return array_map(function (array $entry): array {
$entry['__key'] = md5(implode('|', [
(string) ($entry['timestamp'] ?? ''),
(string) ($entry['rule_id'] ?? ''),
(string) ($entry['uri'] ?? ''),
(string) ($entry['remote_ip'] ?? ''),
(string) ($entry['host'] ?? ''),
]));
return $entry;
}, $entries);
}
protected function matchesWhitelist(array $entry, array $rules): bool
{
$ruleId = (string) ($entry['rule_id'] ?? '');

View File

@@ -15,6 +15,7 @@ use Filament\Forms\Components\TextInput;
use Filament\Forms\Concerns\InteractsWithForms;
use Filament\Forms\Contracts\HasForms;
use Filament\Notifications\Notification;
use Filament\Support\Contracts\TranslatableContentDriver;
use Filament\Tables\Columns\TextColumn;
use Filament\Tables\Concerns\InteractsWithTable;
use Filament\Tables\Contracts\HasTable;
@@ -40,6 +41,11 @@ class WafWhitelistTable extends Component implements HasTable, HasForms, HasActi
return view('livewire.admin.waf-whitelist-table');
}
public function makeFilamentTranslatableContentDriver(): ?TranslatableContentDriver
{
return null;
}
public function table(Table $table): Table
{
return $table

View File

@@ -4,8 +4,8 @@ namespace App\Providers;
use App\Models\Domain;
use App\Observers\DomainObserver;
use Filament\Support\Facades\FilamentView;
use Filament\View\PanelsRenderHook;
use App\Support\Notifications\Notification as LivewireNotification;
use Filament\Notifications\Notification;
use Illuminate\Support\ServiceProvider;
class AppServiceProvider extends ServiceProvider
@@ -15,7 +15,7 @@ class AppServiceProvider extends ServiceProvider
*/
public function register(): void
{
//
$this->app->bind(Notification::class, LivewireNotification::class);
}
/**
@@ -27,10 +27,5 @@ class AppServiceProvider extends ServiceProvider
// Note: AuthEventListener is auto-discovered by Laravel 11+
// Do not manually subscribe - it causes duplicate audit log entries
FilamentView::registerRenderHook(
PanelsRenderHook::SCRIPTS_AFTER,
fn (): string => view('filament.partials.notifications-refresh')->render(),
);
}
}

View File

@@ -0,0 +1,27 @@
<?php
declare(strict_types=1);
namespace App\Support\Notifications;
use Filament\Notifications\Notification as BaseNotification;
use Livewire\Livewire;
class Notification extends BaseNotification
{
public function send(): static
{
$payload = $this->toArray();
if (Livewire::isLivewireRequest()) {
$component = Livewire::current();
if ($component) {
$component->dispatch('notificationSent', $payload);
}
}
session()->push('filament.notifications', $payload);
return $this;
}
}

View File

@@ -36,3 +36,19 @@ After install, systemd services are enabled and started:
- `jabali-agent`
- `jabali-queue`
- `jabali-health-monitor`
## Panel notifications (admin + user)
Jabali ships with a hardened Filament notifications setup that prevents Livewire
success hooks from breaking after the first toast.
What is included:
- `public/js/filament/notifications/notifications.js` is patched to guard the
animation callback (prevents `TypeError: e is not a function`).
- `resources/views/vendor/filament-notifications/notifications.blade.php` adds
a lightweight `wire:poll.2s` so toasts keep flowing even if a Livewire event
is dropped.
If you update or rebuild assets, keep the guard in place and hardrefresh the
browser (Ctrl+Shift+R) after deployment.

File diff suppressed because one or more lines are too long

View File

@@ -1,57 +0,0 @@
<script data-navigate-once>
(function () {
let hookRegistered = false;
const registerHook = () => {
if (hookRegistered || !window.Livewire?.hook || !window.Livewire?.dispatch) {
return;
}
hookRegistered = true;
window.Livewire.hook('commit', ({ component, succeed }) => {
if (component?.name === 'notifications') {
return;
}
succeed(() => {
const livewire = window.Livewire;
const allComponents = typeof livewire?.all === 'function' ? livewire.all() : [];
const notificationsComponent = allComponents.find((component) => {
const name = component?.name ?? '';
return name === 'notifications' || name.includes('notifications');
});
if (notificationsComponent?.$wire?.pullNotificationsFromSession) {
try {
notificationsComponent.$wire.pullNotificationsFromSession();
return;
} catch (error) {
// fall back to dispatch-based refresh
}
}
const dispatchTo = livewire?.dispatchTo;
if (dispatchTo) {
['notifications', 'filament.notifications', 'filament-notifications'].forEach((name) => {
try {
dispatchTo(name, 'notificationsSent');
} catch (error) {
// ignore missing component names
}
});
}
livewire?.dispatch?.('notificationsSent');
});
});
};
document.addEventListener('livewire:init', registerHook);
document.addEventListener('livewire:navigated', registerHook);
if (window.Livewire?.hook) {
registerHook();
}
})();
</script>

View File

@@ -0,0 +1,43 @@
@php
use Filament\Support\Enums\Alignment;
use Filament\Support\Enums\VerticalAlignment;
@endphp
<div wire:poll.2s="pullNotificationsFromSession">
<div
@class([
'fi-no',
'fi-align-' . static::$alignment->value,
'fi-vertical-align-' . static::$verticalAlignment->value,
])
role="status"
>
@foreach ($notifications as $notification)
{{ $notification }}
@endforeach
</div>
@if ($broadcastChannel = $this->getBroadcastChannel())
@script
<script>
window.addEventListener('EchoLoaded', () => {
window.Echo.private(@js($broadcastChannel)).notification(
(notification) => {
setTimeout(
() =>
$wire.handleBroadcastNotification(
notification,
),
500,
)
},
)
})
if (window.Echo) {
window.dispatchEvent(new CustomEvent('EchoLoaded'))
}
</script>
@endscript
@endif
</div>