PHP code example of toolbelt / inertia-table

1. Go to this page and download the library: Download toolbelt/inertia-table library. Choose the download type require.

2. Extract the ZIP file and open the index.php.

3. Add this code to the index.php.
    
        
<?php
require_once('vendor/autoload.php');

/* Start to develop here. Best regards https://php-download.com/ */

    

toolbelt / inertia-table example snippets


// config/inertia-table.php
return [
    'per_page' => 25,
    'per_page_options' => [10, 25, 50, 100],
    'debounce' => 300,
    'action_path' => '_inertia-table/actions',
    'export_path' => '_inertia-table/exports',
    'relationship_sorter' => \Musing\InertiaTable\Sorters\PowerJoinsRelationshipSorter::class,
    'queue' => [
        'connection' => null,
        'queue' => null,
        'delay' => 0,
        'disk' => 'local',
        'path' => 'table-exports',
        'expires_after' => 604800,
    ],
    'view_path' => '_inertia-table/views',
    'views' => ['table' => 'table_views'],
];



namespace App\Tables;

use App\Models\Topic;
use Illuminate\Database\Eloquent\Builder;
use Musing\InertiaTable\Actions\Action;
use Musing\InertiaTable\Columns\BadgeColumn;
use Musing\InertiaTable\Columns\NumberColumn;
use Musing\InertiaTable\Columns\TextColumn;
use Musing\InertiaTable\Filters\SetFilter;
use Musing\InertiaTable\Table;
use Musing\InertiaTable\Variant;

final class TopicsTable extends Table
{
    protected ?string $defaultSort = 'name';

    // Optional: override the global per_page / per_page_options config for this table only.
    protected ?int $perPage = 50;

    protected ?array $perPageOptions = [25, 50, 100];

    public function query(): Builder
    {
        return Topic::query()->withCount('quotes');
    }

    public function columns(): array
    {
        return [
            TextColumn::make('name', 'Name')->searchable()->sortable(),
            NumberColumn::make('quotes_count', 'Quotes')->sortable(),
            BadgeColumn::make('is_featured', 'Featured')
                ->mapAs(fn (bool $value) => $value ? 'Featured' : 'Normal')
                ->variant(fn (bool $value) => $value ? Variant::Success : Variant::Default),
        ];
    }

    public function filters(): array
    {
        return [
            SetFilter::make('status', 'Status')->options([
                'published' => 'Published',
                'draft' => 'Draft',
            ]),
        ];
    }

    public function actions(): array
    {
        return [
            Action::make('edit', 'Edit')
                ->row()
                ->icon('Pencil')
                ->hideLabel()
                ->tooltip('Edit topic')
                ->endpoint('get', fn (Topic $topic) => route('topics.edit', $topic)),
        ];
    }
}

return inertia('Admin/Topics/Index', [
    'topics' => TopicsTable::make()
        ->reloadProps(['featuredCount']),
]);

use App\Models\Topic;
use Musing\InertiaTable\Columns\TextColumn;
use Musing\InertiaTable\Filters\BooleanFilter;
use Musing\InertiaTable\Table;

return inertia('Admin/Topics/Index', [
    'topics' => Table::build(
        resource: Topic::query()->where('archived', false),
        columns: [
            TextColumn::make('name')->searchable()->sortable(),
        ],
        filters: [
            BooleanFilter::make('is_featured', 'Featured'),
        ],
        name: 'topics',
        defaultSort: 'name',
        perPageOptions: [25, 50, 100],
        defaultPerPage: 25,
        transformModelUsing: fn (Topic $topic) => [
            ...$topic->toArray(),
            'display_name' => str($topic->name)->headline()->toString(),
        ],
    ),
]);

TextColumn::make('status')
    ->sortable()
    ->mapAs(['pending' => 'Pending', 'approved' => 'Approved'])
    ->sortUsingMap();

TextColumn::make('priority')
    ->sortable()
    ->sortUsingPriority(['urgent', 'normal', 'low']);

TextColumn::make('description')
    ->wrap()
    ->truncate(2)
    ->cellClass('max-w-md');

DateTimeColumn::make('published_at', 'Published')
    ->format('d/m/Y H:i')
    ->centerAligned();

ActionColumn::new()->asDropdown();

final class TopicsTable extends Table
{
    protected ?bool $stickyHeader = true;
}

TopicsTable::make()->stickyHeader();

public function columns(): array
{
    return [
        NumberColumn::make('id')->sticky(),
        TextColumn::make('name')->stickable(),
        TextColumn::make('email')->stickable(),
        ActionColumn::new()->sticky(),
    ];
}

TextColumn::make('score')->sortable()->sortUsing(
    fn (Builder $query, SortDirection $direction) =>
        $query->orderBy('score', $direction->value),
);

BadgeColumn::make('status')
    ->mapAs(['active' => 'Active', 'blocked' => 'Blocked'])
    ->variant(['active' => Variant::Success, 'blocked' => Variant::Danger])
    ->icon(['active' => 'CheckCircle', 'blocked' => 'XCircle']);

TextColumn::make('name')->image('avatar_url', fn (Image $image) => $image
    ->rounded()
    ->large()
    ->alt('User avatar'));

TextColumn::make('name')->url(
    fn (Topic $topic, Url $url) => $url
        ->route('topics.edit', $topic)
        ->openInNewTab(),
);

use Musing\InertiaTable\EmptyState;
use Musing\InertiaTable\Url;
use Musing\InertiaTable\Variant;

public function emptyState(): ?EmptyState
{
    return EmptyState::make('No topics yet', 'Create the first topic.')
        ->dataAttributes(['kind' => 'topics'])
        ->action(
            label: 'Create topic',
            url: fn (Url $url) => $url->route('topics.create'),
            variant: Variant::Info,
            icon: 'Plus',
        );
}

public function dataAttributesForModel(Model $model, array $data): array
{
    return [
        'record-id' => $model->getKey(),
        'status' => $data['status_label'],
    ];
}

protected array|string|null $search = ['name', 'email'];

// Explicitly disable global search, even if a column is searchable.
protected array|string|null $search = [];

TextFilter::make('name', 'Name')->clauses([
    'contains', 'starts_with', 'equals', 'not_equals',
]);

SetFilter::make('category_id', 'Category')->options(
    Category::query()->orderBy('name')->pluck('name', 'id')->all(),
);

DateFilter::make('created_at', 'Created at');

SetFilter::make('status')->options([
    'empty' => 'Without quotes',
    'featured' => 'Featured',
])->applyUsing(function (Builder $query, string|array $value, string $clause) {
    $values = (array) $value;

    if ($clause === 'equals' && $values[0] === 'empty') {
        $query->doesntHave('quotes');
    }
});

public function columns(): array
{
    return [
        TextColumn::make('author.name', 'Author')->searchable()->sortable(),
        TextColumn::make('author.company.name', 'Company')->searchable(),
        NumberColumn::make('comments.score', 'Comment score')->sortable(),
    ];
}

public function filters(): array
{
    return [
        TextFilter::make('author.company.name', 'Company'),
        NumericFilter::make('comments.score', 'Comment score'),
    ];
}

use Spatie\QueryBuilder\QueryBuilder;

protected function withQueryBuilder(QueryBuilder $query): QueryBuilder
{
    $query->where('topics.tenant_id', tenant()->id);

    return $query;
}

use Illuminate\Http\Request;
use Illuminate\Support\Facades\Log;
use Musing\InertiaTable\Selection;

Action::make('delete', 'Delete')
    ->row()
    ->destructive()
    ->icon('Trash2')
    ->hideLabel()
    ->tooltip('Delete topic')
    ->authorized(fn (Topic $topic) => auth()->user()->can('delete', $topic))
    ->handle(fn (Topic $topic) => $topic->delete())
    ->confirm('Delete topic?', 'This cannot be undone.', 'Delete', 'Cancel');

Action::make('archive', 'Archive')
    ->bulk()
    ->authorize(fn (Request $request) => $request->user()->can('update', Topic::class))
    ->before(fn (Selection $selection) => Log::info('Archiving topics', [
        'count' => $selection->count(),
    ]))
    ->handleSelection(fn (Selection $selection) => $selection
        ->query()
        ->update(['archived_at' => now()]))
    ->after(fn () => session()->flash('success', 'Topics archived'));

public function selectableQuery(Builder $query): Builder
{
    return $query->whereNull('locked_at');
}

public function isSelectable(Model $model): bool
{
    return $model->locked_at === null;
}

Action::make('edit')
    ->row()
    ->endpoint('get', fn (Topic $topic) => route('topics.edit', $topic));

Action::make('delete', 'Delete')
    ->bulk()
    ->destructive()
    ->confirm(
        'Delete :count selected topics?',
        'You selected :count matching topics to move to trash.',
        'Delete :count',
);

->confirm(
    [
        'Delete :count topic?',
        'Delete :count topics?',
        'Delete all :count matching topics?',
    ],
    [
        'This topic will be deleted.',
        ':count topics will be deleted.',
        'All :count matching topics will be deleted.',
    ],
    'Delete :count',
);

use Illuminate\Http\Request;
use Musing\InertiaTable\Exports\Export;

public function exports(): array
{
    return [
        Export::make('all', 'All topics'),
        Export::make('filtered', 'Filtered topics')->filtered(),
        Export::make('selected', 'Selected topics')->selected(),
        Export::make('excel', 'Excel', type: 'xlsx')
            ->filtered()
            ->authorize(fn (Request $request) => $request->user()->can('export')),
    ];
}

TextColumn::make('reference')
    ->exportAs(fn (string $value, Topic $topic) => "#{$value}");

TextColumn::make('internal_notes')->dontExport();

NumberColumn::make('amount')
    ->exportFormat('#,##0.00')
    ->exportMeta(['style' => ['font' => ['bold' => true]]]);

use Illuminate\Support\Facades\Storage;
use Musing\InertiaTable\Exports\QueuedExportSnapshot;

Export::make('archive', 'Export archive')
    ->filtered()
    ->queue(
        connection: 'redis',
        queue: 'exports',
        delay: 5,
        disk: 's3',
        expiresAfter: 86_400,
    )
    ->redirectAfterDispatch('/exports')
    ->deliveryUrlUsing(
        fn (QueuedExportSnapshot $snapshot) => Storage::disk($snapshot->disk)
            ->temporaryUrl($snapshot->path, now()->addHour()),
    )
    ->onReady(fn (QueuedExportSnapshot $snapshot, ?string $url) => /* notify */ null)
    ->onFailure(fn (QueuedExportSnapshot $snapshot, \Throwable $exception) => /* report */ null);

NumericFilter::make('source_id', 'Source')->withoutClause();

use Musing\InertiaTable\Views;

public function views(): ?Views
{
    return Views::make();
}

public function views(): ?Views
{
    return Views::make()
        ->' => tenant()->id]);
}
bash
php artisan vendor:publish --tag=inertia-table-config
bash
php artisan vendor:publish --tag=inertia-table-migrations
php artisan migrate
bash
php artisan vendor:publish --tag=inertia-table-translations