Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Filament Spark Pie Laravel Package

aabosham/filament-spark-pie

A Filament plugin that renders compact pie charts in tables and dashboards using Sparkline, letting you show data distributions at a glance with configurable colors, labels, sizes, and tooltips—ideal for resource lists, widgets, and quick visual summaries.

View on GitHub
Deep Wiki
Context7

Getting Started

1. Check your Filament version first. v2.0.0 targets Filament v3. If your panel still runs Filament v2, stay on 0.0.4 — do not attempt the upgrade.

composer show filament/filament   # must be ^3.0

2. Install.

composer require aabosham/filament-spark-pie:^2.0

If the release ships assets or a config file, publish them in the same commit you add the dependency:

php artisan vendor:publish --tag="filament-spark-pie-config"
php artisan filament:assets

3. Where to look first.

  • README.md — the two entry points you actually need: the dashboard widget class and the infolist entry class.
  • src/ — confirm the namespace and the exact class names before copying snippet code from the README, since the package renamed/moved things across the 0.0.4 → 2.0.0 jump.
  • resources/views/ — this is what you'll override when you need to change sizing, legend, or tooltip behaviour.
  • composer.json of the package — sanity-check the filament/filament, php, and livewire/livewire constraints it enforces.

4. First use case (the one this release is built for). Drop a spark pie into a resource's infolist so an operator can see a small, at-a-glance distribution for a single record — e.g. the split of a customer's orders by status — without leaving the View page.

use AAbosham\FilamentSparkPie\...\SparkPieEntry; // confirm exact name in src/

public static function infolist(Infolist $infolist): Infolist
{
    return $infolist->schema([
        Section::make('Orders')
            ->schema([
                SparkPieEntry::make('order_status_split')
                    ->state(fn (Customer $record) => $record->orders()
                        ->selectRaw('status, count(*) as total')
                        ->groupBy('status')
                        ->pluck('total', 'status')
                        ->all()),
            ]),
    ]);
}

Get one pie rendering with hard-coded array data before wiring real queries. The component's contract is "array of label => numeric value"; everything else in this assessment follows from that.

Implementation Patterns

Pre-aggregate, never pass models. The entry wants a flat label => value map. Do the groupBy/count in SQL and hand over scalars. Passing a Collection of models and hoping the package counts them is the single most common failed first attempt.

Centralise the aggregation behind a method on the model or a dedicated service. You will want the same breakdown in an infolist, a table filter badge, and an export. Keep it in one place so the colour mapping stays consistent:

// app/Models/Customer.php
public function orderStatusSplit(): array
{
    return $this->orders()
        ->selectRaw('status, count(*) as total')
        ->groupBy('status')
        ->pluck('total', 'status')
        ->all();
}

Dashboard widget usage. The widget form is the better fit for panel-wide distributions (all orders by status this month). Register it in Panel::widgets() and give it protected static ?string $pollingInterval = '30s' only if the underlying data is cheap — otherwise poll on a cached key.

Pair with StatsOverviewWidget for scale. A spark pie communicates proportion, not magnitude. Put a Stat::make('Total orders', $count) next to the pie; the pie alone tells an operator "80% pending" without telling them whether that's 8 orders or 80,000.

Colour mapping is your responsibility. Derive the palette from your domain statuses rather than accepting the default sequence, or the same status will be a different colour on different records and the chart becomes unreadable across a page:

->colors([
    'pending'    => 'warning',
    'processing' => 'info',
    'completed'  => 'success',
    'cancelled'  => 'danger',
])

Compose inside a grid when an infolist has several pies. Use Section::make()->columns(3) with three entries; single-column stacks of pies are hard to scan on wide screens.

Cache per-record aggregates on View pages you visit often. Cache::remember("customer:{$record->id}:status-split", 300, fn () => $record->orderStatusSplit()) and bust it from an observer on the Order model. Without this, a View page with three pies issues three aggregate queries per render, per Livewire request.

Testing. Infolist entries are Livewire-rendered, so a Livewire::test(ViewCustomer::class, ['record' => $customer->id]) + assertSee('pending') (or assertSeeHtml) is enough to catch a broken data contract. Assert on the rendered legend text rather than the canvas pixels — the chart body itself is not assertable.

Upgrading from 0.0.4. Treat this as a re-integration, not a bump. Read src/ for renamed classes, replace the old widget usage, and remove any locally published views from the old version before re-publishing — stale Blade files referencing removed methods produce blank charts with no error in the log.

Gotchas and Tips

This is a breaking jump, not a patch. The version goes 0.0.4 → 2.0.0 with a hard cut to Filament v3. Consequences to plan for: PHP 8.1+, Laravel 10+, Livewire 3. If any other panel dependency still pins Filament v2, Composer will fail to resolve and you'll be stuck mid-upgrade — audit composer why filament/filament before starting.

Canvas charts inside collapsible sections render at zero width. If the pie lives in a Section::make()->collapsible()->collapsed(), the chart initialises while hidden and draws nothing. Either default the section open, or dispatch a resize on expand:

->extraAttributes(['x-on:expand.window' => 'window.dispatchEvent(new Event("resize"))'])

Guard the empty and all-zero cases yourself. A record with no orders returns [], and a query returning zeros gives a chart with NaN percentages or a blank circle. Short-circuit before the entry:

->state(fn ($record) => $record->orderStatusSplit() ?: ['No orders' => 1])

N+1 across tables. If you ever render the pie in a table column rather than an infolist, each row triggers the aggregate query. ->modifyQueryUsing(fn ($query) => $query->withCount([...])) and read the counts, or accept the cost knowingly on paginated views only.

SPA mode and wire:navigate. Filament panels with SPA enabled tear down and re-init the DOM; charts mounted on DOMContentLoaded only will render on the first page and disappear on navigation. Re-init on livewire:navigated if the package's script doesn't already.

Dark mode and panel primary colour. Explicit hex colours look correct in light mode and wash out in dark. Use Filament's named colours (success, warning, danger, primary, gray) where possible — they resolve per-theme.

Debugging a blank pie. In order: (1) dd() the closure passed to ->state() — confirm it's an array of scalars; (2) php artisan filament:assets again — missing JS is the silent failure mode; (3) check public/css/public/js for the published files; (4) look for a locally published view from the old version shadowing the new one in resources/views/vendor/.

Extension points. The published Blade view is the intended override surface for sizing and legend layout — prefer it over subclassing. If you need a different data shape, wrap the entry in a small custom class that transforms state before delegating, so package upgrades don't break your call sites.

Maintenance signal. This is a small single-maintainer package. Pin it to ^2.0, keep the aggregation logic in your own code (as above) so the chart layer is swappable, and don't build critical reporting solely on it — a Filament-native ChartWidget or a plain Blade + Chart.js view is a one-file fallback if the package stalls before the next Filament major.

Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
socialdept/atp-orm
cboxdk/laravel-assistant-client
socialdept/atp-resolver
socialdept/tenant-domains
tautvydasr/blade-class-names
socialdept/color-scales
maherelgamil/controller
coleus/widgets
coleus/table
coleus/users
coleus/music
coleus/health
coleus/calendar
coleus/notes
coleus/support
coleus/settings
coleus/apps
seampact/laravel
emmyconceptng/laravel-ng-postcode
jjsquady/round-robin