Getting Started

Resources

Author Laravel admin panel resources declaratively and let Flashboard assemble tables, forms, actions, and Nuxt UI-powered screens.

Resources are the declarative core of Flashboard.

Minimal resource

<?php

declare(strict_types=1);

namespace App\Flashboard;

use App\Models\Order;
use Pepperfm\Flashboard\Contracts\Forms\FieldRenderer;
use Pepperfm\Flashboard\Contracts\Resources\Resource;
use Pepperfm\Flashboard\Core\Forms\Fields\Select;
use Pepperfm\Flashboard\Core\Forms\Fields\TextInput;
use Pepperfm\Flashboard\Core\Forms\Fields\Toggle;
use Pepperfm\Flashboard\Contracts\Forms\FormContract;
use Pepperfm\Flashboard\Core\Tables\Columns\BadgeColumn;
use Pepperfm\Flashboard\Core\Tables\Columns\TextColumn;
use Pepperfm\Flashboard\Contracts\Tables\TableContract;
use Pepperfm\Flashboard\Core\Tables\Filters\SelectFilter;
use Pepperfm\Flashboard\Integration\Laravel\FlashboardPanelProvider;

final class OrdersResource extends Resource
{
    public static function model(): string
    {
        return Order::class;
    }

    public static function table(TableContract $table): TableContract
    {
        return $table
            ->columns([
                TextColumn::make('id')
                    ->label('ID')
                    ->sortable(),
                BadgeColumn::make('status')
                    ->label('Status')
                    ->searchable(),
            ])
            ->filters([
                SelectFilter::make('status')
                    ->label('Status'),
            ]);
    }

    public static function form(FormContract $form): FormContract
    {
        return $form
            ->columns(2)
            ->schema([
                Select::make('status')
                    ->label('Status'),
                TextInput::make('name')
                    ->label('Name')
                    ->required(),
                TextInput::make('email')
                    ->label('Email')
                    ->email(),
                TextInput::make('notes')
                    ->label('Notes')
                    ->columnSpan(2)
                    ->renderer(FieldRenderer::Textarea),
                Toggle::make('is_active')
                    ->label('Is active'),
            ]);
    }
}

final class AdminPanelProvider extends FlashboardPanelProvider
{
    public function register(): void
    {
        $this->panelConfig()
            ->discover();
    }
}

Any *Resource class placed in app/Flashboard is picked up automatically by provider discover(). Use ->resource(OrdersResource::class) only when you want explicit registration.

Discovery variants

<?php

public function register(): void
{
    $this->panelConfig()
        ->discoverResources()
        ->except(
            App\Flashboard\Support\DraftResource::class,
            'Support/IgnoredResource.php',
        );
}

Use:

  • discover() to scan both resources and pages
  • discoverResources() to scan only resources
  • discoverPages() to scan only pages
  • except() to exclude helper or draft classes from auto-registration
  • withoutDiscovery() to opt out completely and register resources explicitly

Available resource surfaces

  • table() for list and index behavior
  • form() for create and edit behavior
  • detail() for read-only detail screens
  • infolist() as a concept-aligned alias for detail()
  • actions() for page or record actions
  • relations() for nested relation payloads
  • pages() for resource-owned page declarations

Actions and pages participate in the same package-owned resource surface model as table(), form(), and infolist(). That keeps custom resource pages and resource-level actions from drifting into an ad hoc subsystem.

Form authoring guidance

  • prefer $form->schema([...]) for simple CRUD resources
  • introduce Section, Tabs, and Tab nodes inside schema() when the form has meaningful operator-facing grouping
  • use FieldRenderer overrides when the visual control should differ from the base field type
  • use columns(), gap(), columnSpan(), and fullWidth() to place multiple fields on one row without extra layout nodes
  • keep legacy array definitions only as a migration bridge

Configuration styles

Flashboard currently supports both:

  • typed schema nodes such as TextColumn::make('status')->label('Status')
  • concept-aligned nodes such as TextInput, Section, Tabs, Tab, and SelectFilter
  • legacy compatibility arrays such as ['key' => 'status', 'label' => 'Status']

Typed nodes are the preferred public API going forward.

Common overrides

  • routeBasePath()
  • navigationLabel()
  • navigationGroup()
  • formRules()
  • mutateFormDataBeforeSave()
  • afterSave()
  • policy()

Escape hatches

  • queryExtensions()
  • payloadExtensions()
  • actionExtensions()
  • runtimeHooks()

Use these when the declarative path is not enough.

Generate with prompts

php artisan flashboard:make-resource

The command asks for the resource class, model class, primary fields, and whether to scaffold a detail screen. Generated resources default to typed table, form, and infolist definitions.