mcpField
B
bagisto-datagrid-development

bagisto-datagrid-development

github.com/bagistoDevelopment13122 installsUpdated 2w ago
Repository

About bagisto-datagrid-development

A development skill for building Bagisto admin listing pages with the DataGrid engine. It explains query and column setup, controller and view wiring, and guidance for actions, filters, and export.

Key features

  1. 01DataGrid subclass structure
  2. 02Query builder and column setup
  3. 03AJAX controller and view wiring
  4. 04ACL-gated row and bulk actions
  5. 05Filtering, sorting, and export guidance

Use cases

  1. 01Building an admin listing page
  2. 02Adding columns and filters to a grid
  3. 03Configuring row or bulk actions

Install

Copy the command and run it in a terminal.

$npx skills add https://github.com/bagisto/agent-skills --skill bagisto-datagrid-development

After installing, type/bagisto-datagrid-developmentin Claude Code to confirm it loaded.

Bundled filesactions.mdcolumns.md

Details

From the project README

DataGrid Development

An admin listing page is a DataGrid subclass plus three lines of wiring. The engine (packages/Webkul/DataGrid) owns paging, search, filtering, sorting, saved filters and export; the subclass supplies a query and describes its columns. There are 51 of them in the codebase — copy the closest one rather than inventing a shape.

The four methods

Webkul\DataGrid\DataGrid declares two abstract methods and two optional hooks:

MethodRequiredPurpose
prepareQueryBuilder()yesReturn a query builder, not a collection
prepareColumns()yesaddColumn([...]) per column
prepareActions()noPer-row actions, each ACL-gated
prepareMassActions()noCheckbox actions, each ACL-gated

Tunable properties, overridden only when the default is wrong: $primaryColumn (default 'id'), $sortColumn, $sortOrder ('desc'), $itemsPerPage (10), $perPageOptions.

The shape

class CurrencyDataGrid extends DataGrid
{
    /**
     * Prepare query builder.
     *
     * @return Builder
     */
    public function prepareQueryBuilder()
    {
        return DB::table('currencies')
            ->select('id', 'name', 'code');
    }

    /**
     * Add Columns.
     *
     * @return void
     */
    public function prepareColumns()
    {
        $this->addColumn([
            'index'      => 'name',
            'label'      => trans('admin::app.settings.currencies.index.datagrid.name'),
            'type'       => 'string',
            'searchable' => true,
            'filterable' => true,
            'sortable'   => true,
        ]);
    }

    /**
     * Prepare actions.
     *
     * @return void
     */
    public function prepareActions()
    {
        if (bouncer()->hasPermission('settings.currencies.edit')) {
            $this->addAction([
                'index'  => 'edit',
                'icon'   => 'icon-edit',
                'title'  => trans('admin::app.settings.currencies.index.datagrid.edit'),
                'method' => 'GET',
                'url'    => fn ($row) => route('admin.settings.currencies.edit', $row->id),
            ]);
        }
    }
}

Align the => inside an addColumn/addAction array only if the file you are editing already does; Pint does not enforce alignment either way, and the codebase has both.

Wiring

The controller serves JSON on an AJAX hit and the view otherwise — one route, two responses:

public function index()
{
    if (request()->ajax()) {
        return datagrid(CurrencyDataGrid::class)->process();
    }

    return view('admin::settings.currencies.index');
}

The Blade side is one tag pointing at that same route:

<x-admin::datagrid :src="route('admin.settings.currencies.index')" />

datagrid() throws InvalidDataGridException unless the class extends DataGrid, so the class name is the only contract.

Reference files

FileLoad when
columns.mdColumn types, search/filter/sort flags, dropdown options, closures, joins and addFilter
actions.mdRow actions, mass actions, ACL gating, export

Non-negotiables

  • prepareQueryBuilder() returns a builder. Calling ->get(), ->paginate() or mapping to a collection breaks paging, filtering and export, because the engine appends to the query you return.
  • The query builder is the one place DB:: is expected. Everywhere else in Bagisto goes through a repository; a DataGrid is built on the query builder by design.
  • Every action and mass action is wrapped in bouncer()->hasPermission(...). An ungated action renders for admins who cannot perform it, and the grid is the most common place this is forgotten.
  • Every label goes through trans(), with the key added to all 23 locales.
  • A joined query needs addFilter() for every aliased column — see columns.md. Without it, filtering and sorting on that column produce an ambiguous-column SQL error.
  • Escape whatever a closure interpolates. Cells render through v-html. The engine strips tags from raw values first, but not quotes — so a value placed inside an attribute can break out. See columns.md.

REQUIRED SUB-SKILL: Use bagisto-change-verification before calling any change done.

Comments

Markdown supported