filamentphp / filament

A collection of beautiful full-stack components for Laravel. The perfect starting point for your next app. Using Livewire, Alpine.js and Tailwind CSS.
https://filamentphp.com
MIT License
18.97k stars 2.93k forks source link

Stats overview widget should support any number of columns #13406

Open milenmk opened 4 months ago

milenmk commented 4 months ago

Package

filament/filament

Package Version

v3.2.92

Laravel Version

11.11.1

Livewire Version

v3.5.1

PHP Version

8.2.14

Problem description

When using getHeaderWidgetsColumns() with stats widgets the number of columns remains 3.

The problem is, that for stats widgets the number of columns is hardcoded into the view file:

//vendor/filament/widgets/resources/views/stats-overview-widget.blade.php

<x-filament-widgets::widget class="fi-wi-stats-overview">
    <div
        @if ($pollingInterval = $this->getPollingInterval())
            wire:poll.{{ $pollingInterval }}
        @endif
        @class([
            'fi-wi-stats-overview-stats-ctn grid gap-6',
            'md:grid-cols-1' => $columns === 1,
            'md:grid-cols-2' => $columns === 2,
            'md:grid-cols-3' => $columns === 3,
            'md:grid-cols-2 xl:grid-cols-4' => $columns === 4,
        ])
    >
        @foreach ($this->getCachedStats() as $stat)
            {{ $stat }}
        @endforeach
    </div>
</x-filament-widgets::widget>

Expected behavior

using getHeaderWidgetsColumns() should change the number of columns (widgets per row)

Steps to reproduce

Create a stat widgets and show them on the List page of a resource

Reproduction repository (issue will be closed if this is not valid)

https://github.com/milenmk/filament-issue

Relevant log output

No response

Donate 💰 to fund this issue

Fund with Polar

github-actions[bot] commented 4 months ago

Hey @milenmk! We're sorry to hear that you've hit this issue. 💛

However, it looks like you forgot to fill in the reproduction repository URL. Can you edit your original post and then we'll look at your issue?

We need a public GitHub repository which contains a Laravel app with the minimal amount of Filament code to reproduce the problem. Please do not link to your actual project, what we need instead is a minimal reproduction in a fresh project without any unnecessary code. This means it doesn't matter if your real project is private / confidential, since we want a link to a separate, isolated reproduction. That would allow us to download it and review your bug much easier, so it can be fixed quicker. Please make sure to include a database seeder with everything we need to set the app up quickly.

github-actions[bot] commented 4 months ago

Thank you for providing reproduction steps! Reopening the issue now.

zepfietje commented 4 months ago

This is not a bug, since getHeaderWidgetColumns controls the number of columns of the page header widget area. The entire stats overview widget takes up as many columns as it's configured to. If you want to change the number of grid columns inside the stats overview widget, you may do so using getColumns on the widget class.

milenmk commented 4 months ago

When I put getColumns() { return 5;} or another number, each widget stretches to fill the entire row and I end up with 5 widgets each one above the other i.e. 5 rows. I have followed some examples so:

  1. In my resource class

    public static function getWidgets(): array
    {
        return [
            UsersStats::class,
        ];
    }
  2. In class ListUsers extends ListRecords

    
    use ExposesTableToWidgets;

protected function getHeaderWidgets(): array { return UsersResource::getWidgets(); }


3. In `class UsersStats extends BaseWidget`

use InteractsWithPageTable;

protected static ?string $pollingInterval = null;

protected function getTablePage(): string
{
    return ListUsers::class;
}

protected function getStats(): array
{
    return [
        Stat::make('total_users', User::count())->label(__('Total Users')),
        Stat::make(
            'super_admin',
            $this->getPageTableQuery()->with('roles')->get()->filter(
                fn (User $user) => $user->roles->where('name', 'SuperAdmin')->toArray()
            )->count()
        )
            ->label(__('Super Administrator')),
        Stat::make(
            'administrator',
            $this->getPageTableQuery()->with('roles')->get()->filter(
                fn (User $user) => $user->roles->where('name', 'Administrator')->toArray()
            )->count()
        )
            ->label(__('Administrator')),
        Stat::make(
            'moderator',
            $this->getPageTableQuery()->with('roles')->get()->filter(
                fn (User $user) => $user->roles->where('name', 'Moderator')->toArray()
            )->count()
        )
            ->label(__('Moderator')),
        Stat::make(
            'project_owner',
            $this->getPageTableQuery()->with('roles')->get()->filter(
                fn (User $user) => $user->roles->where('name', 'ProjectOwner')->toArray()
            )->count()
        )
            ->label(__('Project Owner')),
    ];
}

As I've said, there are 5 widgets and I'd like to have them in 1 row thus I presume I have to use `getHeaderWidgetColumns` but it doesn't work no matter where I put it: inside ListUsers or inside UsersStats.

As stated in my previous post, the reason is that the columns are hardcoded in `/vendor/filament/widgets/resources/views/stats-overview-widget.blade.php`
zepfietje commented 4 months ago

Please carefully read my previous comment. The stats overview widget is just a single widget, so you will have to configure the number of columns on the stats overview widget.

mariomeyer commented 5 days ago

I'm getting the same error mentioned by @milenmk .

When using:

class TopStats extends BaseWidget
{
    protected function getColumns(): int
    {
        return 5; // Sets 5 columns for the stats
    }

    protected function getStats(): array
    {
        return [
            Stat::make('# of Vendors', User::where('status', Config('constant.status.active'))->whereRelation('roles', 'name', 'VENDOR')->count()),
            Stat::make('# of Products', Product::active()->count()),
            Stat::make('Today\'s Orders', Order::whereDate('created_at', Carbon::today())->count()),
            Stat::make('Total Sales', Order::sum('order_total')),
            Stat::make('Orders Till Date', Order::count())
        ];
    }
}

Each of the stats take the full line

image

mariomeyer commented 5 days ago

It seems stats-overview-widget.blade.php doesn't support anything over 4 columns:

@class([
            'fi-wi-stats-overview-stats-ctn grid gap-6',
            'md:grid-cols-1' => $columns === 1,
            'md:grid-cols-2' => $columns === 2,
            'md:grid-cols-3' => $columns === 3,
            'md:grid-cols-2 xl:grid-cols-4' => $columns === 4,
        ])

Can someone change this on the core?

zepfietje commented 5 days ago

Thanks for clarifying, @mariomeyer. Sorry if I missed your point earlier, @milenmk.

Would you be open to create a PR for this improvement, @mariomeyer? Have a look at the existing grid component to see how that's approached using CSS variables.

mariomeyer commented 4 days ago

@zepfietje I created #14668 but @danharrin said 3.x is closed for new features.