Skip to content

Commit

Permalink
Alert banner improvements: auto-refresh, fixes & "closeable" (#924)
Browse files Browse the repository at this point in the history
* fix websocket error always displaying

* use livewire component with polling for alert banner container

* add id to alert banner

* cleanup blade file and add "closeable" property
  • Loading branch information
Boy132 authored Jan 17, 2025
1 parent cbacc18 commit 61bdf0d
Show file tree
Hide file tree
Showing 9 changed files with 134 additions and 73 deletions.
11 changes: 11 additions & 0 deletions app/Filament/Server/Widgets/ServerConsole.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
namespace App\Filament\Server\Widgets;

use App\Exceptions\Http\HttpForbiddenException;
use App\Livewire\AlertBanner;
use App\Models\Permission;
use App\Models\Server;
use App\Models\User;
Expand Down Expand Up @@ -113,4 +114,14 @@ public function storeStats(string $data): void
cache()->put($cacheKey, $data, now()->addMinute());
}
}

#[On('websocket-error')]
public function websocketError(): void
{
AlertBanner::make()
->title('Could not connect to websocket!')
->body('Check your browser console for more details.')
->danger()
->send();
}
}
61 changes: 52 additions & 9 deletions app/Livewire/AlertBanner.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,40 +2,83 @@

namespace App\Livewire;

use Closure;
use Filament\Notifications\Concerns;
use Filament\Support\Concerns\EvaluatesClosures;
use Illuminate\Contracts\Support\Arrayable;
use Illuminate\Support\Str;
use Livewire\Wireable;

final class AlertBanner implements Arrayable
final class AlertBanner implements Wireable
{
use Concerns\HasBody;
use Concerns\HasIcon;
use Concerns\HasId;
use Concerns\HasStatus;
use Concerns\HasTitle;
use EvaluatesClosures;

public static function make(): static
protected bool|Closure $closable = false;

public static function make(?string $id = null): AlertBanner
{
return new self();
$static = new self();
$static->id($id ?? Str::orderedUuid());

return $static;
}

public function toArray(): array
public function toLivewire(): array
{
return [
'id' => $this->getId(),
'title' => $this->getTitle(),
'body' => $this->getBody(),
'status' => $this->getStatus(),
'icon' => $this->getIcon(),
'closeable' => $this->isCloseable(),
];
}

public function send(): static
public static function fromLivewire(mixed $value): AlertBanner
{
$alerts = session()->get('alert-banners', []);
$alerts[] = $this->toArray();
$static = AlertBanner::make();

session()->flash('alert-banners', $alerts);
$static->id($value['id']);
$static->title($value['title']);
$static->body($value['body']);
$static->status($value['status']);
$static->icon($value['icon']);
$static->closable($value['closeable']);

return $static;
}

public function closable(bool|Closure $closable = true): AlertBanner
{
$this->closable = $closable;

return $this;
}

public function isCloseable(): bool
{
return $this->evaluate($this->closable);
}

public function send(): AlertBanner
{
session()->push('alert-banners', $this->toLivewire());

return $this;
}

public function getColorClasses(): string
{
return match ($this->getStatus()) {
'success' => 'text-success-600 dark:text-success-500',
'warning' => 'text-warning-600 dark:text-warning-500',
'danger' => 'text-danger-600 dark:text-danger-500',
default => 'text-info-600 dark:text-info-500',
};
}
}
35 changes: 35 additions & 0 deletions app/Livewire/AlertBannerContainer.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
<?php

namespace App\Livewire;

use Illuminate\Contracts\View\View;
use Livewire\Component;

class AlertBannerContainer extends Component
{
public array $alertBanners;

public function mount(): void
{
$this->alertBanners = [];
$this->pullFromSession();
}

public function pullFromSession(): void
{
foreach (session()->pull('alert-banners', []) as $alertBanner) {
$alertBanner = AlertBanner::fromLivewire($alertBanner);
$this->alertBanners[$alertBanner->getId()] = $alertBanner;
}
}

public function remove(string $id): void
{
unset($this->alertBanners[$id]);
}

public function render(): View
{
return view('livewire.alerts.alert-banner-container');
}
}
4 changes: 2 additions & 2 deletions app/Providers/AppServiceProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -118,8 +118,8 @@ public function boot(Application $app, SoftwareVersionService $versionService):
);

FilamentView::registerRenderHook(
PanelsRenderHook::CONTENT_START,
fn () => view('filament.alerts.alert-banner-container'),
PanelsRenderHook::PAGE_START,
fn () => Blade::render('@livewire(\App\Livewire\AlertBannerContainer::class)'),
);

FilamentView::registerRenderHook(
Expand Down
11 changes: 0 additions & 11 deletions resources/views/filament/alerts/alert-banner-container.blade.php

This file was deleted.

40 changes: 0 additions & 40 deletions resources/views/filament/alerts/alert-banner.blade.php

This file was deleted.

13 changes: 2 additions & 11 deletions resources/views/filament/components/server-console.blade.php
Original file line number Diff line number Diff line change
Expand Up @@ -113,17 +113,8 @@ class="w-full focus:outline-none focus:ring-0 border-none dark:bg-gray-900"
const socket = new WebSocket("{{ $this->getSocket() }}");
let token = '{{ $this->getToken() }}';
socket.onerror = function(websocketErrorEvent) {
@php
$alerts = session()->get('alert-banners', []);
$alerts[] = [
'title' => 'Could not connect to websocket!',
'body' => 'Check your browser console for more details.',
'status' => 'danger',
];
session()->flash('alert-banners', $alerts);
@endphp
socket.onerror = (event) => {
$wire.dispatchSelf('websocket-error');
};
socket.onmessage = function(websocketMessageEvent) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<div wire:poll.1s="pullFromSession" id="alert-banner-container" class="flex flex-col gap-4">
@foreach (array_values($alertBanners) as $alertBanner)
@include('livewire.alerts.alert-banner', ['alertBanner' => $alertBanner])
@endforeach
</div>
27 changes: 27 additions & 0 deletions resources/views/livewire/alerts/alert-banner.blade.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
@props(['alertBanner'])

@php
$icon = $alertBanner->getIcon();
$title = $alertBanner->getTitle();
$body = $alertBanner->getBody();
@endphp

<div class="{{$alertBanner->getColorClasses()}} flex p-4 mt-3 rounded-xl shadow-lg bg-white dark:bg-gray-900 ring-1 ring-gray-950/5 dark:ring-white/10">
@if (filled($icon))
<x-filament::icon :icon="$icon" class="h-8 w-8 mr-2" color="{{$alertBanner->getStatus()}}" />
@endif

<div class="flex flex-col flex-grow">
@if (filled($title))
<p class="font-bold">{{str($title)->sanitizeHtml()->toHtmlString()}}</p>
@endif

@if (filled($body))
<p class="font-normal">{{str($body)->sanitizeHtml()->toHtmlString()}}</p>
@endif
</div>

@if ($alertBanner->isCloseable())
<x-filament::icon-button color="gray" icon="tabler-x" wire:click="remove('{{$alertBanner->getID()}}')" />
@endif
</div>

0 comments on commit 61bdf0d

Please sign in to comment.