Feedback plugin screenshot
Dark mode ready
No multilingual support
Supports v5.x

Feedback by Carl Janzell

Community

In-app feedback for Filament panels: people tag the module they mean and how they feel, the team replies in a thread, and a board shows how a release landed.

Tags: Panels Widget Analytics
Supported versions:
5.x 4.x 3.x
Carl Janzell avatar Author: Carl Janzell

Package health

Automated checks of this plugin's Composer package

100 / 100
Security 100
Maintenance 100
Ecosystem 100
15 checks
  • Passed: GitHub Actions pinned to SHA
  • Skipped: GitLab CI includes pinned to SHA
  • Passed: Open security advisories
  • Passed: Dependabot PR responsiveness — No open Dependabot PRs.
  • Skipped: Renovate MR responsiveness
  • Passed: Dependabot or Renovate configured
  • Passed: Dependency update cooldown configured
  • Passed: Provides a security policy
  • Passed: Abandoned or archived — No consulted source marks the package abandoned (packagist, github).
  • Passed: Commit and release recency — Active: last commit 0 days ago; last release 0 days ago.
  • Passed: composer.lock not committed by library — composer.lock is absent from the released dist archive.
  • Passed: Dist archive is lean
  • Passed: Current Laravel version supported — Package dependencies resolve together with current Laravel 13.0.
  • Passed: Current PHP version supported — Constraint ^8.2 supports current PHP 8.5.
  • Skipped: Current Symfony version supported
Third-party plugin. This is built by the community, not the Filament team. Filament does not review, endorse, or vet the security of plugins outside the filament/ namespace. Review the source and install at your own risk. Found malware or an unresolved security issue the author won't address? Report it .
Powered by Plumb Last scanned 3 days ago

Documentation

In-app feedback for Filament panels. People press Feedback on any page, and a small sheet opens above the button: pick the parts of the app they mean and how they feel, and write. Their threads live on a My feedback page, with the team's replies, reactions and a Sent → Seen → Planned → Done timeline. The team reads every post in an inbox, replies and sets a status. A board shows the mood for each module, so you can see how a release landed.

Latest Version on Packagist Total Downloads Tests License

The Feedback inbox: stats for posts, first-reply time, fixes and mood, and a board of mood per module
  • Works on Filament 3.3, 4 and 5 from one codebase.
  • Four kinds of post: feedback, a question, a problem, or a note for the developers (which can be limited to the dev team and ping its own Chat space).
  • Private by default: a post is seen by its author and the people you let triage.
  • Modules stay compact: the page's module is pre-picked, the rest sit behind a search, and typing #DTR (or #BreakRoom, #dtr, …) in the message tags one with autocomplete.
  • Module chips use your app's own navigation icons.
  • Reactions (Thanks, Same here, Seen, Fixed) and a "Did this fix it?" check once a post is Done.
  • Replies send on Enter (Shift+Enter for a new line), and can be unsent (allowUnsend()).
  • Stats on the inbox: posts, median first-reply time, what got done, and mood against the 30 days before.
  • Motion by anime.js, loaded only when the viewer allows motion.
  • Optional Google Chat ping for every new post.

Full documentation: https://darkify19.github.io/filament-feedback/

Pre-release. See ROADMAP.md for what's in, what's next and what 1.0 means.

#Screenshots

The Feedback sheet: kind, modules with # mentions, mood and message My feedback: an author's threads with the team's replies, reactions and the status timeline A thread in the inbox, with the team's replies and the status buttons

#Install

composer require carljanzell/filament-feedback:^0.4
php artisan migrate
php artisan filament:assets

#Set up

Register the plugin on each panel that needs it. A typical app has one panel everyone uses (the button) and an admin panel (the inbox):

use CarlJanzell\FilamentFeedback\FilamentFeedbackPlugin;

$modules = [
    'dtr' => 'DTR',
    'leave' => 'Leave',
    'design' => ['label' => 'Overall look', 'icon' => 'heroicon-o-swatch'],
];

// The panel staff use: the floating Feedback button and My feedback, no inbox.
$panel->plugin(
    FilamentFeedbackPlugin::make()
        ->modules($modules)
        ->moduleFromRoute(fn (?string $route): ?string => str_contains((string) $route, 'leave') ? 'leave' : null)
        ->inbox(false)
        ->chatWebhook(env('FEEDBACK_CHAT_WEBHOOK')),
);

// The admin panel: the inbox, no button.
$panel->plugin(
    FilamentFeedbackPlugin::make()
        ->modules($modules)
        ->button(false)
        ->canTriage(fn (): bool => auth()->user()?->hasRole('admin') ?? false)
        ->navigationGroup('System'),
);

A one-panel app keeps both on (the default) and only sets canTriage().

Method Default What it does
modules(array|Closure) [] The parts of the app people can tag: slug => label, or slug => ['label' => …, 'icon' => …]. With none, the field is hidden.
moduleFromRoute(Closure) none Pre-selects a module. Receives $route and $url and returns a slug or null.
canTriage(bool|Closure) false Who opens the inbox and replies as the team.
button(bool|Closure) true The floating Feedback button on every page, and the My feedback page. A closure is checked on each page and hides only the button.
inbox(bool) true The Feedback inbox page.
launcherAttributes(array) [] Extra attributes on the button's wrapper, for your own CSS.
impersonateUsing(?Closure $callback, bool|Closure $can = true) off "View as" on an inbox thread: sign in as the author and open the page they wrote from. The callback does the impersonating with the app's own package (no dependency here), gets $author, $post, $url (on this app and still routed, else null: fall back to their home) and $guard, and returns a redirect, or false. $can gets $author; triagers only.
chatWebhook(?string) none A Google Chat space webhook. Each new post sends it one line.
developerPosts(bool $enabled, bool|Closure $canRead, ?string $chatWebhook) on, every triager reads The "For the developers" box. canRead limits who sees those posts in the inbox; chatWebhook pings the dev team's own space.
allowUnsend(team: bool|Closure, authors: bool|Closure) team true, authors false Who may unsend their own replies. An unsent reply stays as "… unsent a message".
navigationGroup(?string) none Where the inbox sits in the navigation.

Set it on the panel that has the button: posts are created there.

#Module icons

A module without an icon borrows one from your navigation: the plugin runs each page's and resource's route through moduleFromRoute(), and the first page that maps to a module lends it its navigation icon. So if moduleFromRoute() maps your DTR resource to dtr, the DTR chip shows the same icon as the DTR item in the sidebar. An 'icon' in modules() wins.

#Moving the button

It sits bottom-left, and the sheet opens just above it. Shift both with CSS variables on :root:

:root { --ffb-launcher-bottom: 5rem; --ffb-launcher-left: 1rem; }

#View as the author

The package doesn't impersonate anyone itself. Wire it to the package your app already uses; for example stechstudio/filament-impersonate:

use STS\FilamentImpersonate\Tables\Actions\Impersonate; // Actions\Impersonate on v4+

FilamentFeedbackPlugin::make()
    ->impersonateUsing(
        fn (Model $author, ?string $url, string $guard) => Impersonate::make()
            ->guard($guard)
            ->redirectTo($url ?? '/')
            ->impersonate($author),
        can: fn (): bool => auth()->user()?->hasRole(['hr', 'super_admin']) ?? false,
    );

The button shows in the thread only for triagers who pass $can, never on their own posts.

While you're signed in as someone, the Feedback button would post as them. Hide it on the author's panel:

FilamentFeedbackPlugin::make()
    ->button(fn (): bool => ! app(\Lab404\Impersonate\Services\ImpersonateManager::class)->isImpersonating())
    // filament-impersonate v4+: ! \STS\FilamentImpersonate\Facades\Impersonation::isImpersonating()

#Google Chat ping

In a Chat space: space name → Apps & integrations → Webhooks → add one, then copy its URL into chatWebhook(). The app only calls out, so this works from a server Google can't reach, and it needs no Cloud project. If the option is missing, your Workspace admin has turned off webhooks.

#Stats

The inbox opens with CarlJanzell\FilamentFeedback\Widgets\FeedbackStats: posts in the last 30 days (with a 14-day sparkline), the median time to the team's first reply, posts done and whether authors confirmed the fix, and the average mood against the 30 days before. Only triagers see it. It is a plain Filament stats widget, so a dashboard can use it too, for example filament-insights' ->widgets([FeedbackStats::class]).

#Hooking in

  • CarlJanzell\FilamentFeedback\Events\FeedbackPosted fires with $post on every new post. Listen to it to notify your triagers.
  • CarlJanzell\FilamentFeedback\Events\ReplyPosted fires with $reply on both sides of a thread. $reply->is_from_team tells you which side.
  • The author gets a Filament database notification when the team replies. Its link opens that thread on My feedback (/my-feedback?post=…). Turn on ->databaseNotifications() on that panel. notifyAuthorUsing() receives the same $url.
  • A link to #feedback on any page of the button's panel opens the sheet.

#Data

Three tables: feedback_posts, feedback_replies and feedback_reactions. Authors are polymorphic (morphs()), so any authenticatable model works, UUID keys included.

#For AI agents

The package ships an agent guide at resources/boost/guidelines/core.blade.php: setup, every plugin method, events, data and common tasks. Apps using Laravel Boost pick it up automatically on php artisan boost:install (or boost:update). Without Boost, point your agent at that file. Working on the plugin itself: AGENTS.md.

#Testing

composer test

#License

MIT. See LICENSE.

The author

Carl Janzell avatar Author: Carl Janzell

Carl Janzell is a full-stack software engineer based in Los Baños, Philippines. He builds the Laravel and Filament applications behind HR operations for more than 4,000 personnel at the University of the Philippines Los Baños, with systems that exchange data over Apache Kafka. He cares most about systems thinking, event-driven architecture, and tools that make admin panels faster to build and nicer to use.

Plugins
2
Stars
14

From the same author