Search by

hibira-io / filament

deflinhec

Live database notifications, an Echo connection light and a live channels widget for Filament panels, on Hibira

v0.2.2 2026-10-29 14:29 UTC

This package is auto-updated.

Last update: 2026-10-29 15:19:14 UTC


README

ci

Live notifications for Filament panels, on Hibira.

Filament can already talk to any Pusher-compatible WebSocket service, once you publish config/filament.php, uncomment its Echo block and fill in the host, port and key. This plugin does that for you from the same HIBIRA_* settings the rest of your app uses, and adds:

  • Live database notifications. The bell updates the moment a notification is sent, instead of every 30 seconds.
  • A connection light next to the user menu, so you can see at a glance whether the browser is connected.
  • A live channels widget for the dashboard: channels in use, presence channels and the members in them.
  • Who's here. Avatars in the page header show who else has the same page open.
  • Edit locks. One person edits a record at a time. Others see who holds it, can ask for it, and get it as soon as the holder hands it over or leaves, with no heartbeat polling and no lock table.
  • Live tables. Resource tables refresh for everyone who has them open when records are saved or deleted, instead of polling.
  • Import and export progress. A progress bar shows how many rows of an import or export are done, chunk by chunk.
  • Team chat. A Chat page for the panel's users, one to one or in groups, with unread counts, online status and message history.

Supports Filament 3, 4 and 5. It builds on hibira-io/laravel, which sets up broadcasting, push notifications and webhooks.

Install

composer require hibira-io/filament
php artisan hibira:install

hibira:install (from hibira-io/laravel) adds the HIBIRA_* settings to .env and sets BROADCAST_CONNECTION=hibira. Copy the app ID, key and secret from your app page on hibira.io/portal (the free plan needs no card):

BROADCAST_CONNECTION=hibira
HIBIRA_APP_ID=your-app-id
HIBIRA_APP_KEY=your-app-key
HIBIRA_APP_SECRET=your-app-secret
HIBIRA_HOST=ws.hibira.io

Check them with php artisan hibira:check.

Then add the plugin to your panel:

use Hibira\Filament\HibiraPlugin;

public function panel(Panel $panel): Panel
{
    return $panel
        // ...
        ->plugin(
            HibiraPlugin::make()
                ->databaseNotifications()
                ->channelsWidget()
        );
}

That's it. Filament's own JavaScript already includes Laravel Echo, so there is nothing to build. You don't need npm run build for the panel, and you don't need to publish config/filament.php.

Until HIBIRA_APP_KEY is set the plugin stays out of the way: the panel loads without Echo and database notifications keep polling.

Live database notifications

->databaseNotifications() turns on the panel's notification bell and turns off its polling. To send a notification that shows up straight away, pass isEventDispatched: true so Filament tells the browser over Hibira:

use Filament\Notifications\Notification;

Notification::make()
    ->title('Order #1024 shipped')
    ->success()
    ->sendToDatabase($user, isEventDispatched: true);

Or send a toast that is not stored, to a user who is online now:

Notification::make()
    ->title('Export ready')
    ->broadcast($user);

Both go out on the user's private channel, so your app needs the broadcasting auth route and the channel authorization Laravel adds with php artisan install:broadcasting --without-reverb --without-node (Laravel 11 and later). routes/channels.php then contains:

Broadcast::channel('App.Models.User.{id}', function ($user, $id) {
    return (int) $user->id === (int) $id;
});

If you'd rather keep polling as a fallback, give it an interval:

HibiraPlugin::make()->databaseNotifications(polling: '60s')

Panels with their own guard

Echo authorizes private channels at /broadcasting/auth, which uses the web guard by default. If your panel signs users in with another guard, register the broadcasting routes with that guard, and point Echo at them if you changed the path:

// bootstrap/app.php
->withBroadcasting(__DIR__.'/../routes/channels.php', [
    'middleware' => ['web', 'auth:admin'],
])
HibiraPlugin::make()->echoOptions(['authEndpoint' => '/admin/broadcasting/auth'])

Connection light

A small dot next to the user menu shows the connection: green when connected, amber while connecting, red when the service can't be reached and grey when disconnected. Hovering shows the state in words.

Move it or turn it off:

use Filament\View\PanelsRenderHook;

HibiraPlugin::make()->connectionStatus(renderHook: PanelsRenderHook::TOPBAR_END)
HibiraPlugin::make()->connectionStatus(false)

Live channels widget

->channelsWidget() adds HibiraChannelsWidget to the dashboard. It shows:

  • Live channels: channels with at least one subscriber
  • Presence channels: channels that track who is online
  • Presence members: members across all presence channels (someone in two rooms counts twice)

It refreshes every 10 seconds through the Channels HTTP API. API calls don't count as messages on your plan.

To place it yourself, for example on a custom page or only for some users, leave ->channelsWidget() off and register the class like any other widget:

use Hibira\Filament\Widgets\HibiraChannelsWidget;

$panel->widgets([HibiraChannelsWidget::class]);

Who's here

->presence() shows the avatars of everyone else on the same page, next to the page's header actions. Each page path is its own room, so people on the posts list don't show up on a post's edit page.

HibiraPlugin::make()->presence()

The plugin registers the presence channels itself and lets in anyone who may use the panel (the same canAccessPanel() check Filament makes). Echo joins them through /broadcasting/auth, so the broadcasting routes need to be on, as for live notifications. Move the avatars with ->presence(renderHook: PanelsRenderHook::TOPBAR_END).

Edit locks

Add InteractsWithHibiraLock to an edit page:

use Filament\Resources\Pages\EditRecord;
use Hibira\Filament\Concerns\InteractsWithHibiraLock;

class EditPost extends EditRecord
{
    use InteractsWithHibiraLock;

    protected static string $resource = PostResource::class;
}

The first person to open a record holds its lock. Anyone else who opens it sees who is editing, and Save is turned off for them. They can:

  • Ask to edit. The holder gets a prompt with Save and hand over, which saves the holder's changes and passes the lock across.
  • Wait. When the holder closes the page, the next person on it takes the lock within a few seconds.

Everyone on the edit page joins a presence channel for that record. When the holder's connection drops, Hibira tells the others, and the server checks Hibira's member list before moving the lock, so a stale lock never blocks anyone and nothing polls. If Hibira can't be reached, the lock stays where it is.

The holder is kept in your cache store, so use one that supports atomic locks (redis, database, memcached, dynamodb, file or array). Presence for locks works with or without ->presence().

Live tables

->liveTables() refreshes a resource's list page for everyone who has it open, whenever one of its records is created, updated, deleted or restored: in the panel, in a queued job, an API controller or a console command.

HibiraPlugin::make()->liveTables()

Changes are collected and sent once when the request or queued job ends, so an import of a thousand rows refreshes each open table once per chunk, not a thousand times. Browsers wait 300 ms after the last message before refreshing.

The plugin watches the models of the panel's resources. For pages whose table lists another model, pass it:

HibiraPlugin::make()->liveTables(models: [AuditEntry::class])

Only Eloquent model events are seen. After a mass update through the query builder, mark the table yourself:

Post::query()->where('draft', true)->update(['draft' => false]);

app(\Hibira\Filament\LiveTables::class)->touch(Post::class);

Import and export progress

Filament runs imports and exports as queued jobs and tells you when they are finished. ->importProgress() also shows how far along they are: a small card in the corner fills up as each chunk of rows is processed, and goes away a few seconds after the last one.

HibiraPlugin::make()->importProgress()

It works with Filament's own ImportAction and ExportAction, including custom importers and exporters, and picks up imports that were already running when the page loads. The card only goes to the user who started the import.

Team chat

->chat() adds a Chat page and a chat button with the unread count to the top bar. Panel users can message each other one to one or start a group, see who is online, and scroll back through earlier messages.

HibiraPlugin::make()->chat()

Messages are stored by Hibira's Chat API, so there are no tables to migrate and nothing to queue. The Chat API is in beta and is turned on per account: ask us at hibira.io to turn it on. Until then the Chat page says chat is unavailable.

How it fits together:

  • Each browser signs in to Hibira as its panel user, through a route the plugin adds to the panel (/admin/hibira/user-auth). New messages, read receipts and online status arrive over that sign-in, with no channel per conversation.
  • Anyone who may use the panel (canAccessPanel()) can chat. Users are found by name and email; pass other columns with ->chat(searchColumns: ['name', 'username']).
  • Chat users are named <panel>.<user key>, so each panel has its own conversations.
  • A group holds up to 50 people. Messages are up to 4,000 characters.

Hide the page from the navigation with ->chat(navigation: false) (the top bar button still links to it), or move the button with ->chat(buttonRenderHook: PanelsRenderHook::TOPBAR_END).

Every message counts as one message per member toward your plan, like any other event.

Echo options

The plugin builds these Echo options from config/hibira.php:

Option From
key HIBIRA_APP_KEY
wsHost HIBIRA_HOST (default ws.hibira.io)
wsPort, wssPort HIBIRA_PORT (default 443)
forceTLS HIBIRA_SCHEME is https
cluster always hkg; pusher-js requires one but ignores it once wsHost is set

Anything else can be added or replaced with ->echoOptions([...]).

The settings are applied only while the panel with the plugin is being served, so other panels keep their own filament.broadcasting.echo config.

Translations

The connection light and widget come in English, Traditional Chinese, Simplified Chinese, Japanese, Korean, Thai and Vietnamese, following the app locale. To change the wording:

php artisan vendor:publish --tag=hibira-filament-translations

Development

composer install
composer test

License

MIT