Generate Table Livewire components

This commit is contained in:
Dan Harrin
2024-11-24 18:15:29 +00:00
parent baf07c6fd1
commit fbc6ce7141
22 changed files with 667 additions and 439 deletions
@@ -16,7 +16,7 @@ use function Laravel\Prompts\text;
#[AsCommand(name: 'make:filament-livewire-form', aliases: [
'make:livewire-form',
])]
class MakeFormCommand extends Command
class MakeLivewireFormCommand extends Command
{
use CanGenerateForms;
use CanIndentStrings;
+1 -1
View File
@@ -20,7 +20,7 @@ class FormsServiceProvider extends PackageServiceProvider
->name('filament-forms')
->hasCommands([
Commands\MakeFieldCommand::class,
Commands\MakeFormCommand::class,
Commands\MakeLivewireFormCommand::class,
])
->hasTranslations()
->hasViews();
@@ -19,19 +19,19 @@ use Filament\Actions\ForceDeleteBulkAction;
use Filament\Actions\RestoreAction;
use Filament\Actions\RestoreBulkAction;
use Filament\Actions\ViewAction;
use Filament\Tables\Columns\IconColumn;
use Filament\Tables\Columns\ImageColumn;
use Filament\Tables\Columns\TextColumn;
use Filament\Tables\Commands\FileGenerators\Concerns\CanGenerateTables;
use Filament\Tables\Filters\BaseFilter;
use Filament\Tables\Filters\TrashedFilter;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletingScope;
use Illuminate\Support\Str;
use Nette\PhpGenerator\Literal;
trait CanGenerateResourceTables
{
use CanGenerateTables;
/**
* @param ?class-string<Model> $model
*/
@@ -91,154 +91,6 @@ trait CanGenerateResourceTables
PHP;
}
/**
* @param ?class-string<Model> $model
* @return array<string>
*/
public function getTableColumns(?string $model = null): array
{
if (! $this->isGenerated()) {
return [];
}
if (blank($model)) {
return [];
}
if (! class_exists($model)) {
return [];
}
$schema = $this->getModelSchema($model);
$table = $this->getModelTable($model);
$columns = [];
foreach ($schema->getColumns($table) as $column) {
if ($column['auto_increment']) {
continue;
}
$type = $this->parseColumnType($column);
if (in_array($type['name'], [
'json',
'text',
])) {
continue;
}
$columnName = $column['name'];
if (str($columnName)->endsWith([
'_token',
])) {
continue;
}
if (str($columnName)->contains([
'password',
])) {
continue;
}
if (str($columnName)->endsWith('_id')) {
$guessedRelationshipName = $this->guessBelongsToRelationshipName($columnName, $model);
if (filled($guessedRelationshipName)) {
$guessedRelationshipTitleColumnName = $this->guessBelongsToRelationshipTitleColumnName($columnName, app($model)->{$guessedRelationshipName}()->getModel()::class);
$columnName = "{$guessedRelationshipName}.{$guessedRelationshipTitleColumnName}";
}
}
$columnData = [];
if (in_array($columnName, [
'id',
'sku',
'uuid',
])) {
$columnData['label'] = [Str::upper($columnName)];
}
if ($type['name'] === 'boolean') {
$columnData['type'] = IconColumn::class;
$columnData['boolean'] = [];
} else {
$columnData['type'] = match (true) {
$columnName === 'image', str($columnName)->startsWith('image_'), str($columnName)->contains('_image_'), str($columnName)->endsWith('_image') => ImageColumn::class,
default => TextColumn::class,
};
if (in_array($type['name'], [
'string',
'char',
]) && ($columnData['type'] === TextColumn::class)) {
$columnData['searchable'] = [];
}
if (in_array($type['name'], [
'date',
])) {
$columnData['date'] = [];
$columnData['sortable'] = [];
}
if (in_array($type['name'], [
'datetime',
'timestamp',
])) {
$columnData['dateTime'] = [];
$columnData['sortable'] = [];
}
if (in_array($type['name'], [
'integer',
'decimal',
'float',
'double',
'money',
])) {
$columnData[in_array($columnName, [
'cost',
'money',
'price',
]) || $type['name'] === 'money' ? 'money' : 'numeric'] = [];
$columnData['sortable'] = [];
}
}
if (in_array($columnName, [
'created_at',
'updated_at',
'deleted_at',
])) {
$columnData['toggleable'] = ['isToggledHiddenByDefault' => true];
}
$this->importUnlessPartial($columnData['type']);
$columns[$columnName] = $columnData;
}
return array_map(
function (array $columnData, string $columnName): string {
$column = (string) new Literal("{$this->simplifyFqn($columnData['type'])}::make(?)", [$columnName]);
unset($columnData['type']);
foreach ($columnData as $methodName => $parameters) {
$column .= new Literal(PHP_EOL . " ->{$methodName}(...?:)", [$parameters]);
}
return "{$column},";
},
$columns,
array_keys($columns),
);
}
/**
* @param ?class-string<Model> $model
*/
@@ -116,7 +116,7 @@ class MakeResourceCommand extends Command
{
return [
new InputArgument(
name: 'name',
name: 'model',
mode: InputArgument::OPTIONAL,
description: 'The name of the model to generate the resource for, optionally prefixed with directories',
),
@@ -275,7 +275,7 @@ class MakeResourceCommand extends Command
->map(fn (string $class): string => str($class)->after("{$modelNamespace}\\"))
->all();
$this->modelFqnEnd = (string) str($this->argument('name') ?? suggest(
$this->modelFqnEnd = (string) str($this->argument('model') ?? suggest(
label: 'What is the model name?',
options: function (string $search) use ($modelFqns): array {
$search = str($search)->trim()->replace(['\\', '/'], '');
+21
View File
@@ -9,6 +9,11 @@ class CliManager
*/
protected array $componentLocations = [];
/**
* @var array<string, array{path: string, viewNamespace: ?string}>
*/
protected array $livewireComponentLocations = [];
public function registerComponentLocation(string $path, string $namespace, ?string $viewNamespace): void
{
$this->componentLocations[$namespace] = [
@@ -24,4 +29,20 @@ class CliManager
{
return $this->componentLocations;
}
public function registerLivewireComponentLocation(string $path, string $namespace, ?string $viewNamespace): void
{
$this->livewireComponentLocations[$namespace] = [
'path' => $path,
'viewNamespace' => $viewNamespace,
];
}
/**
* @return array<string, array{path: string, viewNamespace: ?string}>
*/
public function getLivewireComponentLocations(): array
{
return $this->livewireComponentLocations;
}
}
@@ -25,7 +25,7 @@ trait CanAskForComponentLocation
return [
"App\\{$pathNamespace}",
app_path($path),
null,
'',
];
}
@@ -0,0 +1,57 @@
<?php
namespace Filament\Support\Commands\Concerns;
use Filament\Support\Facades\FilamentCli;
use function Laravel\Prompts\select;
trait CanAskForLivewireComponentLocation
{
/**
* @return array{
* 0: string,
* 1: string,
* 2: ?string,
* }
*/
protected function askForLivewireComponentLocation(string $question = 'Where would you like to create the Livewire component?'): array
{
$locations = FilamentCli::getLivewireComponentLocations();
if (blank($locations)) {
return [
'App\\Livewire',
app_path('Livewire'),
'',
];
}
$options = [
null => 'App\\Livewire',
...array_combine(
array_keys($locations),
array_keys($locations),
),
];
$namespace = select(
label: $question,
options: $options,
);
if (blank($namespace)) {
return [
'App\\Livewire',
app_path('Livewire'),
'',
];
}
return [
$namespace,
$locations[$namespace]['path'],
$locations[$namespace]['viewNamespace'] ?? null,
];
}
}
+3 -1
View File
@@ -6,8 +6,10 @@ use Filament\Support\CliManager;
use Illuminate\Support\Facades\Facade;
/**
* @method static void registerComponentLocation(string $directory, string $namespace, ?string $viewNamespace = null)
* @method static array<string, array{path: string, viewNamespace: ?string}> getComponentLocations()
* @method static array<string, array{path: string, viewNamespace: ?string}> getLivewireComponentLocations()
* @method static void registerComponentLocation(string $directory, string $namespace, ?string $viewNamespace = null)
* @method static void registerLivewireComponentLocation(string $directory, string $namespace, ?string $viewNamespace = null)
*
* @see CliManager
*/
@@ -1,22 +1,64 @@
<?php
namespace Filament\Tables\Commands\Concerns;
namespace Filament\Tables\Commands\FileGenerators\Concerns;
use Filament\Tables;
use Filament\Actions\BulkActionGroup;
use Filament\Tables\Columns\IconColumn;
use Filament\Tables\Columns\ImageColumn;
use Filament\Tables\Columns\TextColumn;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Str;
use Nette\PhpGenerator\Literal;
trait CanGenerateTables
{
/**
* @param string|class-string<Model> $model
* @param ?class-string<Model> $model
*/
protected function getResourceTableColumns(string $model): string
public function generateTableMethodBody(?string $model = null): string
{
$model = $this->parseModel($model);
$this->importUnlessPartial(BulkActionGroup::class);
return <<<PHP
return \$table
->query(fn (): {$this->simplifyFqn(Builder::class)} => {$this->simplifyFqn($model)}::query())
->columns([
{$this->outputTableColumns($model)}
])
->filters([
//
])
->headerActions([
//
])
->actions([
//
])
->bulkActions([
{$this->simplifyFqn(BulkActionGroup::class)}::make([
//
]),
]);
PHP;
}
/**
* @param ?class-string<Model> $model
* @return array<string>
*/
public function getTableColumns(?string $model = null): array
{
if (! $this->isGenerated()) {
return [];
}
if (blank($model)) {
return '//';
return [];
}
if (! class_exists($model)) {
return [];
}
$schema = $this->getModelSchema($model);
@@ -73,18 +115,18 @@ trait CanGenerateTables
}
if ($type['name'] === 'boolean') {
$columnData['type'] = Tables\Columns\IconColumn::class;
$columnData['type'] = IconColumn::class;
$columnData['boolean'] = [];
} else {
$columnData['type'] = match (true) {
$columnName === 'image', str($columnName)->startsWith('image_'), str($columnName)->contains('_image_'), str($columnName)->endsWith('_image') => Tables\Columns\ImageColumn::class,
default => Tables\Columns\TextColumn::class,
$columnName === 'image', str($columnName)->startsWith('image_'), str($columnName)->contains('_image_'), str($columnName)->endsWith('_image') => ImageColumn::class,
default => TextColumn::class,
};
if (in_array($type['name'], [
'string',
'char',
]) && ($columnData['type'] === Tables\Columns\TextColumn::class)) {
]) && ($columnData['type'] === TextColumn::class)) {
$columnData['searchable'] = [];
}
@@ -127,55 +169,39 @@ trait CanGenerateTables
$columnData['toggleable'] = ['isToggledHiddenByDefault' => true];
}
$this->importUnlessPartial($columnData['type']);
$columns[$columnName] = $columnData;
}
$output = count($columns) ? '' : '//';
return array_map(
function (array $columnData, string $columnName): string {
$column = (string) new Literal("{$this->simplifyFqn($columnData['type'])}::make(?)", [$columnName]);
foreach ($columns as $columnName => $columnData) {
// Constructor
$output .= (string) str($columnData['type'])->after('Filament\\');
$output .= '::make(\'';
$output .= $columnName;
$output .= '\')';
unset($columnData['type']);
unset($columnData['type']);
foreach ($columnData as $methodName => $parameters) {
$column .= new Literal(PHP_EOL . " ->{$methodName}(...?:)", [$parameters]);
}
// Configuration
foreach ($columnData as $methodName => $parameters) {
$output .= PHP_EOL;
$output .= ' ->';
$output .= $methodName;
$output .= '(';
$output .= collect($parameters)
->map(function (mixed $parameterValue, int | string $parameterName): string {
$parameterValue = match (true) {
/** @phpstan-ignore-next-line */
is_bool($parameterValue) => $parameterValue ? 'true' : 'false',
/** @phpstan-ignore-next-line */
is_null($parameterValue) => 'null',
is_numeric($parameterValue) => $parameterValue,
default => "'{$parameterValue}'",
};
return "{$column},";
},
$columns,
array_keys($columns),
);
}
if (is_numeric($parameterName)) {
return $parameterValue;
}
/**
* @param ?class-string<Model> $model
*/
public function outputTableColumns(?string $model = null): string
{
$columns = $this->getTableColumns($model);
return "{$parameterName}: {$parameterValue}";
})
->implode(', ');
$output .= ')';
}
// Termination
$output .= ',';
if (! (array_key_last($columns) === $columnName)) {
$output .= PHP_EOL;
}
if (empty($columns)) {
return '//';
}
return $output;
return implode(PHP_EOL . ' ', $columns);
}
}
@@ -0,0 +1,172 @@
<?php
namespace Filament\Tables\Commands\FileGenerators;
use Filament\Actions\Concerns\InteractsWithActions;
use Filament\Actions\Contracts\HasActions;
use Filament\Schema\Concerns\InteractsWithSchemas;
use Filament\Schema\Contracts\HasSchemas;
use Filament\Support\Commands\Concerns\CanReadModelSchemas;
use Filament\Support\Commands\FileGenerators\ClassGenerator;
use Filament\Tables\Commands\FileGenerators\Concerns\CanGenerateTables;
use Filament\Tables\Concerns\InteractsWithTable;
use Filament\Tables\Contracts\HasTable;
use Filament\Tables\Table;
use Illuminate\Contracts\View\View;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Model;
use Livewire\Component;
use Nette\PhpGenerator\ClassType;
use Nette\PhpGenerator\Literal;
use Nette\PhpGenerator\Method;
use Nette\PhpGenerator\TraitUse;
class LivewireTableClassGenerator extends ClassGenerator
{
use CanGenerateTables;
use CanReadModelSchemas;
/**
* @param class-string<Model> $modelFqn
*/
final public function __construct(
protected string $fqn,
protected string $modelFqn,
protected bool $isGenerated,
protected string $view,
) {}
public function getNamespace(): string
{
return $this->extractNamespace($this->getFqn());
}
/**
* @return array<string>
*/
public function getImports(): array
{
return [
$this->getExtends(),
...$this->getImplements(),
InteractsWithActions::class,
InteractsWithTable::class,
InteractsWithSchemas::class,
Table::class,
...($this->hasPartialImports() ? ['Filament\Tables'] : []),
Builder::class,
$this->getModelFqn(),
View::class,
];
}
public function getBasename(): string
{
return class_basename($this->getFqn());
}
public function getExtends(): string
{
return Component::class;
}
/**
* @return array<class-string>
*/
public function getImplements(): array
{
return [
HasActions::class,
HasSchemas::class,
HasTable::class,
];
}
protected function addTraitsToClass(ClassType $class): void
{
$this->addInteractsWithActionsTraitToClass($class);
$this->addInteractsWithTableTraitToClass($class);
$this->addInteractsWithSchemasTraitToClass($class);
}
protected function addMethodsToClass(ClassType $class): void
{
$this->addTableMethodToClass($class);
$this->addRenderMethodToClass($class);
}
protected function addInteractsWithActionsTraitToClass(ClassType $class): void
{
$trait = $class->addTrait(InteractsWithActions::class);
$this->configureInteractsWithActionsTrait($trait);
}
protected function configureInteractsWithActionsTrait(TraitUse $trait): void {}
protected function addInteractsWithTableTraitToClass(ClassType $class): void
{
$trait = $class->addTrait(InteractsWithTable::class);
$this->configureInteractsWithTableTrait($trait);
}
protected function configureInteractsWithTableTrait(TraitUse $trait): void {}
protected function addInteractsWithSchemasTraitToClass(ClassType $class): void
{
$trait = $class->addTrait(InteractsWithSchemas::class);
$this->configureInteractsWithSchemasTrait($trait);
}
protected function configureInteractsWithSchemasTrait(TraitUse $trait): void {}
protected function addTableMethodToClass(ClassType $class): void
{
$method = $class->addMethod('table')
->setPublic()
->setReturnType(Table::class)
->setBody($this->generateTableMethodBody($this->getModelFqn()));
$method->addParameter('table')
->setType(Table::class);
$this->configureTableMethod($method);
}
protected function configureTableMethod(Method $method): void {}
protected function addRenderMethodToClass(ClassType $class): void
{
$method = $class->addMethod('render')
->setPublic()
->setReturnType(View::class)
->setBody(new Literal(<<<'PHP'
return view(?);
PHP, [$this->getView()]));
$this->configureRenderMethod($method);
}
protected function configureRenderMethod(Method $method): void {}
public function getFqn(): string
{
return $this->fqn;
}
/**
* @return ?class-string<Model>
*/
public function getModelFqn(): ?string
{
return $this->modelFqn;
}
public function isGenerated(): bool
{
return $this->isGenerated;
}
public function getView(): string
{
return $this->view;
}
}
@@ -154,8 +154,8 @@ class MakeColumnCommand extends Command
$this->viewPath,
] = $this->askForViewLocation(
str($this->fqn)
->afterLast('Filament\\Tables\\Columns')
->prepend('Filament\\Tables\\Columns')
->afterLast('\\Filament\\Tables\\Columns\\')
->prepend('Filament\\Tables\\Columns\\')
->replace('\\', '/')
->explode('/')
->map(Str::kebab(...))
@@ -0,0 +1,246 @@
<?php
namespace Filament\Tables\Commands;
use Filament\Support\Commands\Concerns\CanAskForLivewireComponentLocation;
use Filament\Support\Commands\Concerns\CanAskForViewLocation;
use Filament\Support\Commands\Concerns\CanManipulateFiles;
use Filament\Support\Commands\Exceptions\InvalidCommandOutput;
use Filament\Tables\Commands\FileGenerators\LivewireTableClassGenerator;
use Illuminate\Console\Command;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Str;
use Symfony\Component\Console\Attribute\AsCommand;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputOption;
use function Laravel\Prompts\confirm;
use function Laravel\Prompts\suggest;
use function Laravel\Prompts\text;
#[AsCommand(name: 'make:filament-livewire-table', aliases: [
'make:livewire-table',
])]
class MakeLivewireTableCommand extends Command
{
use CanAskForLivewireComponentLocation;
use CanAskForViewLocation;
use CanManipulateFiles;
protected $description = 'Create a new Livewire component containing a Filament table';
protected $name = 'make:filament-livewire-table';
/**
* @var array<string>
*/
protected $aliases = [
'make:livewire-table',
];
/**
* @var class-string
*/
protected string $fqn;
protected string $fqnEnd;
protected string $path;
/**
* @var class-string<Model>
*/
protected string $modelFqn;
protected string $modelFqnEnd;
protected bool $isGenerated;
protected ?string $view = null;
protected ?string $viewPath = null;
/**
* @return array<InputArgument>
*/
protected function getArguments(): array
{
return [
new InputArgument(
name: 'name',
mode: InputArgument::OPTIONAL,
description: 'The name of the Livewire component to generate, optionally prefixed with directories',
),
new InputArgument(
name: 'model',
mode: InputArgument::OPTIONAL,
description: 'The name of the model to generate the table for, optionally prefixed with directories',
),
];
}
/**
* @return array<InputOption>
*/
protected function getOptions(): array
{
return [
new InputOption(
name: 'generate',
shortcut: 'G',
mode: InputOption::VALUE_NONE,
description: 'Generate the table columns based on the attributes of a model',
),
new InputOption(
name: 'model-namespace',
shortcut: null,
mode: InputOption::VALUE_REQUIRED,
description: 'The namespace of the model class, [App\\Models] by default',
),
new InputOption(
name: 'force',
shortcut: 'F',
mode: InputOption::VALUE_NONE,
description: 'Overwrite the contents of the files if they already exist',
),
];
}
public function handle(): int
{
try {
$this->configureFqnEnd();
$this->configureModel();
$this->configureIsGenerated();
$this->configureLocation();
$this->createLivewireComponent();
$this->createView();
} catch (InvalidCommandOutput) {
return static::INVALID;
}
$this->components->info("Livewire component [{$this->fqn}] created successfully.");
return static::SUCCESS;
}
protected function configureFqnEnd(): void
{
$this->fqnEnd = (string) str($this->argument('name') ?? text(
label: 'What is the Livewire component name?',
placeholder: 'BlogPostsTable',
required: true,
))
->trim('/')
->trim('\\')
->trim(' ')
->studly()
->replace('/', '\\');
}
protected function configureModel(): void
{
$modelNamespace = $this->option('model-namespace') ?? 'App\\Models';
$modelFqns = collect(get_declared_classes())
->filter(fn (string $class): bool => is_subclass_of($class, Model::class) &&
str($class)->startsWith("{$modelNamespace}\\"))
->map(fn (string $class): string => str($class)->after("{$modelNamespace}\\"))
->all();
$this->modelFqnEnd = (string) str($this->argument('model') ?? suggest(
label: 'What is the model name?',
options: function (string $search) use ($modelFqns): array {
$search = str($search)->trim()->replace(['\\', '/'], '');
if (blank($search)) {
return $modelFqns;
}
return array_filter(
$modelFqns,
fn (string $class): bool => str($class)->replace(['\\', '/'], '')->contains($search, ignoreCase: true),
);
},
placeholder: 'BlogPost',
))
->trim('/')
->trim('\\')
->trim(' ')
->studly()
->replace('/', '\\');
if (blank($this->modelFqnEnd)) {
$this->modelFqnEnd = 'Resource';
}
$this->modelFqn = "{$modelNamespace}\\{$this->modelFqnEnd}";
}
protected function configureIsGenerated(): void
{
$this->isGenerated = $this->option('generate') || confirm(
label: 'Would you like to generate the table columns based on the attributes of the model?',
default: false,
);
}
protected function configureLocation(): void
{
[
$namespace,
$path,
$viewNamespace,
] = $this->askForLivewireComponentLocation(
question: 'Where would you like to create the table?',
);
$this->fqn = "{$namespace}\\{$this->fqnEnd}";
$this->path = (string) str("{$path}\\{$this->fqnEnd}.php")
->replace('\\', '/')
->replace('//', '/');
[
$this->view,
$this->viewPath,
] = $this->askForViewLocation(
str($this->fqn)
->afterLast('\\Livewire\\')
->prepend('Livewire\\')
->replace('\\', '/')
->explode('/')
->map(Str::kebab(...))
->implode('.'),
defaultNamespace: $viewNamespace,
);
}
protected function createLivewireComponent(): void
{
if (! $this->option('force') && $this->checkForCollision($this->path)) {
throw new InvalidCommandOutput;
}
$this->writeFile($this->path, app(LivewireTableClassGenerator::class, [
'fqn' => $this->fqn,
'modelFqn' => $this->modelFqn,
'isGenerated' => $this->isGenerated,
'view' => $this->view,
]));
}
protected function createView(): void
{
if (blank($this->view)) {
return;
}
if (! $this->option('force') && $this->checkForCollision($this->viewPath)) {
throw new InvalidCommandOutput;
}
$this->copyStubToApp('LivewireTableView', $this->viewPath);
}
}
@@ -1,102 +0,0 @@
<?php
namespace Filament\Tables\Commands;
use Filament\Support\Commands\Concerns\CanIndentStrings;
use Filament\Support\Commands\Concerns\CanManipulateFiles;
use Filament\Support\Commands\Concerns\CanReadModelSchemas;
use Filament\Tables\Commands\Concerns\CanGenerateTables;
use Illuminate\Console\Command;
use Illuminate\Support\Str;
use Symfony\Component\Console\Attribute\AsCommand;
use function Laravel\Prompts\text;
#[AsCommand(name: 'make:filament-livewire-table', aliases: [
'make:livewire-table',
])]
class MakeTableCommand extends Command
{
use CanGenerateTables;
use CanIndentStrings;
use CanManipulateFiles;
use CanReadModelSchemas;
protected $description = 'Create a new Livewire component containing a Filament table';
protected $signature = 'make:filament-livewire-table {name?} {model?} {--G|generate} {--F|force}';
/**
* @var array<string>
*/
protected $aliases = [
'make:livewire-table',
];
public function handle(): int
{
$component = (string) str($this->argument('name') ?? text(
label: 'What is the table name?',
placeholder: 'Products/ListProducts',
required: true,
))
->trim('/')
->trim('\\')
->trim(' ')
->replace('/', '\\');
$componentClass = (string) str($component)->classBasename();
$componentNamespace = str($component)->contains('\\') ?
(string) str($component)->beforeLast('\\') :
'';
$view = str($component)
->replace('\\', '/')
->prepend('Livewire/')
->explode('/')
->map(fn ($segment) => Str::lower(Str::kebab($segment)))
->implode('.');
$model = (string) str($this->argument('model') ?? text(
label: 'What is the model name?',
placeholder: 'Product',
required: true,
))
->replace('/', '\\');
$modelClass = (string) str($model)->classBasename();
$path = (string) str($component)
->prepend('/')
->prepend(app_path('Livewire/'))
->replace('\\', '/')
->replace('//', '/')
->append('.php');
$viewPath = resource_path(
(string) str($view)
->replace('.', '/')
->prepend('views/')
->append('.blade.php'),
);
if ((! $this->option('force')) && $this->checkForCollision([$path, $viewPath])) {
return static::INVALID;
}
$this->copyStubToApp('Table', $path, [
'class' => $componentClass,
'columns' => $this->indentString($this->option('generate') ? $this->getResourceTableColumns(
'App\\Models\\' . $model,
) : '//', 4),
'model' => $model,
'modelClass' => $modelClass,
'namespace' => 'App\\Livewire' . ($componentNamespace !== '' ? "\\{$componentNamespace}" : ''),
'view' => $view,
]);
$this->copyStubToApp('TableView', $viewPath);
$this->components->info("Filament table [{$path}] created successfully.");
return static::SUCCESS;
}
}
@@ -23,7 +23,7 @@ class TablesServiceProvider extends PackageServiceProvider
->name('filament-tables')
->hasCommands([
Commands\MakeColumnCommand::class,
Commands\MakeTableCommand::class,
Commands\MakeLivewireTableCommand::class,
])
->hasTranslations()
->hasViews();
-46
View File
@@ -1,46 +0,0 @@
<?php
namespace {{ namespace }};
use App\Models\{{ model }};
use Filament\Actions;
use Filament\Forms\Concerns\InteractsWithForms;
use Filament\Forms\Contracts\HasForms;
use Filament\Tables;
use Filament\Tables\Concerns\InteractsWithTable;
use Filament\Tables\Contracts\HasTable;
use Filament\Tables\Table;
use Livewire\Component;
use Illuminate\Contracts\View\View;
use Illuminate\Database\Eloquent\Builder;
class {{ class }} extends Component implements HasForms, HasTable
{
use InteractsWithForms;
use InteractsWithTable;
public function table(Table $table): Table
{
return $table
->query({{ modelClass }}::query())
->columns([
{{ columns }}
])
->filters([
//
])
->actions([
//
])
->bulkActions([
Actions\BulkActionGroup::make([
//
]),
]);
}
public function render(): View
{
return view('{{ view }}');
}
}
@@ -133,7 +133,7 @@ it('can generate a page class in a resource', function () {
$this->withoutMockingConsoleOutput();
$this->artisan('make:filament-resource', [
'name' => 'User',
'model' => 'User',
'--panel' => 'admin',
'--no-interaction' => true,
]);
@@ -165,7 +165,7 @@ it('can generate a page view in a resource', function () {
$this->withoutMockingConsoleOutput();
$this->artisan('make:filament-resource', [
'name' => 'User',
'model' => 'User',
'--panel' => 'admin',
'--no-interaction' => true,
]);
@@ -197,7 +197,7 @@ it('can generate a create page class in a resource', function () {
$this->withoutMockingConsoleOutput();
$this->artisan('make:filament-resource', [
'name' => 'User',
'model' => 'User',
'--panel' => 'admin',
'--no-interaction' => true,
]);
@@ -231,7 +231,7 @@ it('can generate an edit page class in a resource', function () {
$this->withoutMockingConsoleOutput();
$this->artisan('make:filament-resource', [
'name' => 'User',
'model' => 'User',
'--panel' => 'admin',
'--no-interaction' => true,
]);
@@ -265,7 +265,7 @@ it('can generate a view page class in a resource', function () {
$this->withoutMockingConsoleOutput();
$this->artisan('make:filament-resource', [
'name' => 'User',
'model' => 'User',
'--panel' => 'admin',
'--no-interaction' => true,
]);
@@ -297,7 +297,7 @@ it('can generate a view page class in a resource', function () {
$runGenerateManageRelatedRecordsPageCommand = function (TestCase $testCase): PendingCommand {
$testCase->artisan('make:filament-resource', [
'name' => 'Team',
'model' => 'Team',
'--view' => true,
'--panel' => 'admin',
'--no-interaction' => true,
@@ -306,7 +306,7 @@ $runGenerateManageRelatedRecordsPageCommand = function (TestCase $testCase): Pen
->expectsQuestion('Does the model use soft deletes?', false);
$testCase->artisan('make:filament-resource', [
'name' => 'User',
'model' => 'User',
'--panel' => 'admin',
'--no-interaction' => true,
])
@@ -21,7 +21,7 @@ beforeEach(function () {
$this->withoutMockingConsoleOutput();
$this->artisan('make:filament-resource', [
'name' => 'Team',
'model' => 'Team',
'--model-namespace' => 'Filament\\Tests\\Models',
'--view' => true,
'--panel' => 'admin',
@@ -29,7 +29,7 @@ beforeEach(function () {
]);
$this->artisan('make:filament-resource', [
'name' => 'User',
'model' => 'User',
'--panel' => 'admin',
'--no-interaction' => true,
]);
@@ -25,7 +25,7 @@ beforeEach(function () {
it('can generate a resource class', function () {
$this->artisan('make:filament-resource', [
'name' => 'Post',
'model' => 'Post',
'--model-namespace' => 'Filament\Tests\Models',
'--panel' => 'admin',
'--no-interaction' => true,
@@ -39,7 +39,7 @@ it('can generate a resource class', function () {
it('can generate a resource list page', function () {
$this->artisan('make:filament-resource', [
'name' => 'Post',
'model' => 'Post',
'--model-namespace' => 'Filament\Tests\Models',
'--panel' => 'admin',
'--no-interaction' => true,
@@ -52,7 +52,7 @@ it('can generate a resource list page', function () {
it('can generate a resource create page', function () {
$this->artisan('make:filament-resource', [
'name' => 'Post',
'model' => 'Post',
'--model-namespace' => 'Filament\Tests\Models',
'--panel' => 'admin',
'--no-interaction' => true,
@@ -65,7 +65,7 @@ it('can generate a resource create page', function () {
it('can generate a resource edit page', function () {
$this->artisan('make:filament-resource', [
'name' => 'Post',
'model' => 'Post',
'--model-namespace' => 'Filament\Tests\Models',
'--panel' => 'admin',
'--no-interaction' => true,
@@ -78,7 +78,7 @@ it('can generate a resource edit page', function () {
it('can generate a resource view page', function () {
$this->artisan('make:filament-resource', [
'name' => 'Post',
'model' => 'Post',
'--view' => true,
'--model-namespace' => 'Filament\Tests\Models',
'--panel' => 'admin',
@@ -92,7 +92,7 @@ it('can generate a resource view page', function () {
it('can generate the form and table of a resource class', function () {
$this->artisan('make:filament-resource', [
'name' => 'Post',
'model' => 'Post',
'--generate' => true,
'--model-namespace' => 'Filament\Tests\Models',
'--panel' => 'admin',
@@ -106,7 +106,7 @@ it('can generate the form and table of a resource class', function () {
it('can generate a resource class with soft deletes', function () {
$this->artisan('make:filament-resource', [
'name' => 'Post',
'model' => 'Post',
'--soft-deletes' => true,
'--model-namespace' => 'Filament\Tests\Models',
'--panel' => 'admin',
@@ -120,7 +120,7 @@ it('can generate a resource class with soft deletes', function () {
it('can generate a resource edit page with soft deletes', function () {
$this->artisan('make:filament-resource', [
'name' => 'Post',
'model' => 'Post',
'--soft-deletes' => true,
'--model-namespace' => 'Filament\Tests\Models',
'--panel' => 'admin',
@@ -134,7 +134,7 @@ it('can generate a resource edit page with soft deletes', function () {
it('can generate a simple resource class', function () {
$this->artisan('make:filament-resource', [
'name' => 'Post',
'model' => 'Post',
'--simple' => true,
'--model-namespace' => 'Filament\Tests\Models',
'--panel' => 'admin',
@@ -148,7 +148,7 @@ it('can generate a simple resource class', function () {
it('can generate a simple resource manage page', function () {
$this->artisan('make:filament-resource', [
'name' => 'Post',
'model' => 'Post',
'--simple' => true,
'--model-namespace' => 'Filament\Tests\Models',
'--panel' => 'admin',
@@ -162,7 +162,7 @@ it('can generate a simple resource manage page', function () {
it('can generate a resource class in a nested directory', function () {
$this->artisan('make:filament-resource', [
'name' => 'Blog/Post',
'model' => 'Blog/Post',
'--model-namespace' => 'Filament\Tests\Models',
'--panel' => 'admin',
'--no-interaction' => true,
@@ -175,7 +175,7 @@ it('can generate a resource class in a nested directory', function () {
it('can generate a resource list page in a nested directory', function () {
$this->artisan('make:filament-resource', [
'name' => 'Blog/Post',
'model' => 'Blog/Post',
'--model-namespace' => 'Filament\Tests\Models',
'--panel' => 'admin',
'--no-interaction' => true,
@@ -188,7 +188,7 @@ it('can generate a resource list page in a nested directory', function () {
it('can generate a resource create page in a nested directory', function () {
$this->artisan('make:filament-resource', [
'name' => 'Blog/Post',
'model' => 'Blog/Post',
'--model-namespace' => 'Filament\Tests\Models',
'--panel' => 'admin',
'--no-interaction' => true,
@@ -201,7 +201,7 @@ it('can generate a resource create page in a nested directory', function () {
it('can generate a resource edit page in a nested directory', function () {
$this->artisan('make:filament-resource', [
'name' => 'Blog/Post',
'model' => 'Blog/Post',
'--model-namespace' => 'Filament\Tests\Models',
'--panel' => 'admin',
'--no-interaction' => true,
@@ -214,7 +214,7 @@ it('can generate a resource edit page in a nested directory', function () {
it('can generate a resource view page in a nested directory', function () {
$this->artisan('make:filament-resource', [
'name' => 'Blog/Post',
'model' => 'Blog/Post',
'--view' => true,
'--model-namespace' => 'Filament\Tests\Models',
'--panel' => 'admin',
@@ -228,7 +228,7 @@ it('can generate a resource view page in a nested directory', function () {
it('can generate a simple resource manage page in a nested directory', function () {
$this->artisan('make:filament-resource', [
'name' => 'Blog/Post',
'model' => 'Blog/Post',
'--simple' => true,
'--model-namespace' => 'Filament\Tests\Models',
'--panel' => 'admin',
@@ -124,7 +124,7 @@ it('can generate a page class in a resource', function () {
$this->withoutMockingConsoleOutput();
$this->artisan('make:filament-resource', [
'name' => 'User',
'model' => 'User',
'--panel' => 'admin',
'--no-interaction' => true,
]);
@@ -156,7 +156,7 @@ it('can generate a page view in a resource', function () {
$this->withoutMockingConsoleOutput();
$this->artisan('make:filament-resource', [
'name' => 'User',
'model' => 'User',
'--panel' => 'admin',
'--no-interaction' => true,
]);
@@ -188,7 +188,7 @@ it('can generate a create page class in a resource', function () {
$this->withoutMockingConsoleOutput();
$this->artisan('make:filament-resource', [
'name' => 'User',
'model' => 'User',
'--panel' => 'admin',
'--no-interaction' => true,
]);
@@ -222,7 +222,7 @@ it('can generate an edit page class in a resource', function () {
$this->withoutMockingConsoleOutput();
$this->artisan('make:filament-resource', [
'name' => 'User',
'model' => 'User',
'--panel' => 'admin',
'--no-interaction' => true,
]);
@@ -256,7 +256,7 @@ it('can generate a view page class in a resource', function () {
$this->withoutMockingConsoleOutput();
$this->artisan('make:filament-resource', [
'name' => 'User',
'model' => 'User',
'--panel' => 'admin',
'--no-interaction' => true,
]);
@@ -288,7 +288,7 @@ it('can generate a view page class in a resource', function () {
$runGenerateManageRelatedRecordsPageCommand = function (TestCase $testCase): PendingCommand {
$testCase->artisan('make:filament-resource', [
'name' => 'Team',
'model' => 'Team',
'--view' => true,
'--panel' => 'admin',
'--no-interaction' => true,
@@ -297,7 +297,7 @@ $runGenerateManageRelatedRecordsPageCommand = function (TestCase $testCase): Pen
->expectsQuestion('Does the model use soft deletes?', false);
$testCase->artisan('make:filament-resource', [
'name' => 'User',
'model' => 'User',
'--panel' => 'admin',
'--no-interaction' => true,
])
@@ -13,7 +13,7 @@ beforeEach(function () {
$this->withoutMockingConsoleOutput();
$this->artisan('make:filament-resource', [
'name' => 'Team',
'model' => 'Team',
'--model-namespace' => 'Filament\\Tests\\Models',
'--view' => true,
'--panel' => 'admin',
@@ -21,7 +21,7 @@ beforeEach(function () {
]);
$this->artisan('make:filament-resource', [
'name' => 'User',
'model' => 'User',
'--panel' => 'admin',
'--no-interaction' => true,
]);
@@ -19,7 +19,7 @@ beforeEach(function () {
it('can generate a resource class', function () {
$this->artisan('make:filament-resource', [
'name' => 'Post',
'model' => 'Post',
'--model-namespace' => 'Filament\Tests\Models',
'--panel' => 'admin',
'--no-interaction' => true,
@@ -32,7 +32,7 @@ it('can generate a resource class', function () {
it('can generate a resource form', function () {
$this->artisan('make:filament-resource', [
'name' => 'Post',
'model' => 'Post',
'--model-namespace' => 'Filament\Tests\Models',
'--panel' => 'admin',
'--no-interaction' => true,
@@ -45,7 +45,7 @@ it('can generate a resource form', function () {
it('can generate a resource infolist', function () {
$this->artisan('make:filament-resource', [
'name' => 'Post',
'model' => 'Post',
'--view' => true,
'--model-namespace' => 'Filament\Tests\Models',
'--panel' => 'admin',
@@ -59,7 +59,7 @@ it('can generate a resource infolist', function () {
it('can generate a resource table', function () {
$this->artisan('make:filament-resource', [
'name' => 'Post',
'model' => 'Post',
'--model-namespace' => 'Filament\Tests\Models',
'--panel' => 'admin',
'--no-interaction' => true,
@@ -72,7 +72,7 @@ it('can generate a resource table', function () {
it('can generate a resource list page', function () {
$this->artisan('make:filament-resource', [
'name' => 'Post',
'model' => 'Post',
'--model-namespace' => 'Filament\Tests\Models',
'--panel' => 'admin',
'--no-interaction' => true,
@@ -85,7 +85,7 @@ it('can generate a resource list page', function () {
it('can generate a resource create page', function () {
$this->artisan('make:filament-resource', [
'name' => 'Post',
'model' => 'Post',
'--model-namespace' => 'Filament\Tests\Models',
'--panel' => 'admin',
'--no-interaction' => true,
@@ -98,7 +98,7 @@ it('can generate a resource create page', function () {
it('can generate a resource edit page', function () {
$this->artisan('make:filament-resource', [
'name' => 'Post',
'model' => 'Post',
'--model-namespace' => 'Filament\Tests\Models',
'--panel' => 'admin',
'--no-interaction' => true,
@@ -111,7 +111,7 @@ it('can generate a resource edit page', function () {
it('can generate a resource view page', function () {
$this->artisan('make:filament-resource', [
'name' => 'Post',
'model' => 'Post',
'--view' => true,
'--model-namespace' => 'Filament\Tests\Models',
'--panel' => 'admin',
@@ -125,7 +125,7 @@ it('can generate a resource view page', function () {
it('can generate a resource class with embedded form', function () {
$this->artisan('make:filament-resource', [
'name' => 'Post',
'model' => 'Post',
'--embed-schemas' => true,
'--model-namespace' => 'Filament\Tests\Models',
'--panel' => 'admin',
@@ -139,7 +139,7 @@ it('can generate a resource class with embedded form', function () {
it('can generate a resource class with embedded infolist', function () {
$this->artisan('make:filament-resource', [
'name' => 'Post',
'model' => 'Post',
'--embed-schemas' => true,
'--view' => true,
'--model-namespace' => 'Filament\Tests\Models',
@@ -154,7 +154,7 @@ it('can generate a resource class with embedded infolist', function () {
it('can generate a resource class with embedded table', function () {
$this->artisan('make:filament-resource', [
'name' => 'Post',
'model' => 'Post',
'--embed-table' => true,
'--model-namespace' => 'Filament\Tests\Models',
'--panel' => 'admin',
@@ -168,7 +168,7 @@ it('can generate a resource class with embedded table', function () {
it('can generate the resource form content', function () {
$this->artisan('make:filament-resource', [
'name' => 'Post',
'model' => 'Post',
'--generate' => true,
'--model-namespace' => 'Filament\Tests\Models',
'--panel' => 'admin',
@@ -182,7 +182,7 @@ it('can generate the resource form content', function () {
it('can generate the resource table content', function () {
$this->artisan('make:filament-resource', [
'name' => 'Post',
'model' => 'Post',
'--generate' => true,
'--model-namespace' => 'Filament\Tests\Models',
'--panel' => 'admin',
@@ -196,7 +196,7 @@ it('can generate the resource table content', function () {
it('can generate the form and table content embedded in a resource class', function () {
$this->artisan('make:filament-resource', [
'name' => 'Post',
'model' => 'Post',
'--embed-schemas' => true,
'--embed-table' => true,
'--generate' => true,
@@ -212,7 +212,7 @@ it('can generate the form and table content embedded in a resource class', funct
it('can generate a resource class with soft deletes', function () {
$this->artisan('make:filament-resource', [
'name' => 'Post',
'model' => 'Post',
'--soft-deletes' => true,
'--model-namespace' => 'Filament\Tests\Models',
'--panel' => 'admin',
@@ -226,7 +226,7 @@ it('can generate a resource class with soft deletes', function () {
it('can generate a resource table with soft deletes', function () {
$this->artisan('make:filament-resource', [
'name' => 'Post',
'model' => 'Post',
'--soft-deletes' => true,
'--model-namespace' => 'Filament\Tests\Models',
'--panel' => 'admin',
@@ -240,7 +240,7 @@ it('can generate a resource table with soft deletes', function () {
it('can generate a resource edit page with soft deletes', function () {
$this->artisan('make:filament-resource', [
'name' => 'Post',
'model' => 'Post',
'--soft-deletes' => true,
'--model-namespace' => 'Filament\Tests\Models',
'--panel' => 'admin',
@@ -266,7 +266,7 @@ it('can generate a simple resource class', function () {
}
$this->artisan('make:filament-resource', [
'name' => 'Post',
'model' => 'Post',
'--simple' => true,
'--model-namespace' => 'Filament\Tests\Models',
'--panel' => 'admin',
@@ -284,7 +284,7 @@ it('can generate a simple resource class', function () {
it('can generate a simple resource manage page', function () {
$this->artisan('make:filament-resource', [
'name' => 'Post',
'model' => 'Post',
'--simple' => true,
'--model-namespace' => 'Filament\Tests\Models',
'--panel' => 'admin',
@@ -298,7 +298,7 @@ it('can generate a simple resource manage page', function () {
it('can generate a simple resource class without embedded schemas and table', function () {
$this->artisan('make:filament-resource', [
'name' => 'Post',
'model' => 'Post',
'--not-embedded' => true,
'--simple' => true,
'--view' => true,
@@ -314,7 +314,7 @@ it('can generate a simple resource class without embedded schemas and table', fu
it('can generate a resource class in a nested directory', function () {
$this->artisan('make:filament-resource', [
'name' => 'Blog/Post',
'model' => 'Blog/Post',
'--model-namespace' => 'Filament\Tests\Models',
'--panel' => 'admin',
'--no-interaction' => true,
@@ -327,7 +327,7 @@ it('can generate a resource class in a nested directory', function () {
it('can generate a resource form in a nested directory', function () {
$this->artisan('make:filament-resource', [
'name' => 'Blog/Post',
'model' => 'Blog/Post',
'--model-namespace' => 'Filament\Tests\Models',
'--panel' => 'admin',
'--no-interaction' => true,
@@ -340,7 +340,7 @@ it('can generate a resource form in a nested directory', function () {
it('can generate a resource infolist in a nested directory', function () {
$this->artisan('make:filament-resource', [
'name' => 'Blog/Post',
'model' => 'Blog/Post',
'--view' => true,
'--model-namespace' => 'Filament\Tests\Models',
'--panel' => 'admin',
@@ -354,7 +354,7 @@ it('can generate a resource infolist in a nested directory', function () {
it('can generate a resource table in a nested directory', function () {
$this->artisan('make:filament-resource', [
'name' => 'Blog/Post',
'model' => 'Blog/Post',
'--model-namespace' => 'Filament\Tests\Models',
'--panel' => 'admin',
'--no-interaction' => true,
@@ -367,7 +367,7 @@ it('can generate a resource table in a nested directory', function () {
it('can generate a resource list page in a nested directory', function () {
$this->artisan('make:filament-resource', [
'name' => 'Blog/Post',
'model' => 'Blog/Post',
'--model-namespace' => 'Filament\Tests\Models',
'--panel' => 'admin',
'--no-interaction' => true,
@@ -380,7 +380,7 @@ it('can generate a resource list page in a nested directory', function () {
it('can generate a resource create page in a nested directory', function () {
$this->artisan('make:filament-resource', [
'name' => 'Blog/Post',
'model' => 'Blog/Post',
'--model-namespace' => 'Filament\Tests\Models',
'--panel' => 'admin',
'--no-interaction' => true,
@@ -393,7 +393,7 @@ it('can generate a resource create page in a nested directory', function () {
it('can generate a resource edit page in a nested directory', function () {
$this->artisan('make:filament-resource', [
'name' => 'Blog/Post',
'model' => 'Blog/Post',
'--model-namespace' => 'Filament\Tests\Models',
'--panel' => 'admin',
'--no-interaction' => true,
@@ -406,7 +406,7 @@ it('can generate a resource edit page in a nested directory', function () {
it('can generate a resource view page in a nested directory', function () {
$this->artisan('make:filament-resource', [
'name' => 'Blog/Post',
'model' => 'Blog/Post',
'--view' => true,
'--model-namespace' => 'Filament\Tests\Models',
'--panel' => 'admin',
@@ -420,7 +420,7 @@ it('can generate a resource view page in a nested directory', function () {
it('can generate a simple resource manage page in a nested directory', function () {
$this->artisan('make:filament-resource', [
'name' => 'Blog/Post',
'model' => 'Blog/Post',
'--simple' => true,
'--model-namespace' => 'Filament\Tests\Models',
'--panel' => 'admin',
@@ -434,7 +434,7 @@ it('can generate a simple resource manage page in a nested directory', function
it('can generate a nested resource class', function () {
$this->artisan('make:filament-resource', [
'name' => 'User',
'model' => 'User',
'--panel' => 'admin',
'--no-interaction' => true,
]);
@@ -450,7 +450,7 @@ it('can generate a nested resource class', function () {
];
$this->artisan('make:filament-resource', [
'name' => 'Post',
'model' => 'Post',
'--nested' => 'Users',
'--model-namespace' => 'Filament\Tests\Models',
'--panel' => 'admin',
@@ -464,7 +464,7 @@ it('can generate a nested resource class', function () {
it('can generate a nested resource class with a plural parent resource name', function () {
$this->artisan('make:filament-resource', [
'name' => 'User',
'model' => 'User',
'--panel' => 'admin',
'--no-interaction' => true,
]);
@@ -480,7 +480,7 @@ it('can generate a nested resource class with a plural parent resource name', fu
];
$this->artisan('make:filament-resource', [
'name' => 'Posts',
'model' => 'Post',
'--nested' => 'Users',
'--model-namespace' => 'Filament\Tests\Models',
'--panel' => 'admin',
@@ -494,7 +494,7 @@ it('can generate a nested resource class with a plural parent resource name', fu
it('can generate a nested resource class with a parent resource name with `Resource` at the end', function () {
$this->artisan('make:filament-resource', [
'name' => 'User',
'model' => 'User',
'--panel' => 'admin',
'--no-interaction' => true,
]);
@@ -510,7 +510,7 @@ it('can generate a nested resource class with a parent resource name with `Resou
];
$this->artisan('make:filament-resource', [
'name' => 'Post',
'model' => 'Post',
'--nested' => 'UserResource',
'--model-namespace' => 'Filament\Tests\Models',
'--panel' => 'admin',
@@ -524,7 +524,7 @@ it('can generate a nested resource class with a parent resource name with `Resou
it('can generate a nested resource form', function () {
$this->artisan('make:filament-resource', [
'name' => 'User',
'model' => 'User',
'--panel' => 'admin',
'--no-interaction' => true,
]);
@@ -540,7 +540,7 @@ it('can generate a nested resource form', function () {
];
$this->artisan('make:filament-resource', [
'name' => 'Post',
'model' => 'Post',
'--nested' => 'Users',
'--model-namespace' => 'Filament\Tests\Models',
'--panel' => 'admin',
@@ -554,7 +554,7 @@ it('can generate a nested resource form', function () {
it('can generate a nested resource infolist', function () {
$this->artisan('make:filament-resource', [
'name' => 'User',
'model' => 'User',
'--panel' => 'admin',
'--no-interaction' => true,
]);
@@ -570,7 +570,7 @@ it('can generate a nested resource infolist', function () {
];
$this->artisan('make:filament-resource', [
'name' => 'Post',
'model' => 'Post',
'--nested' => 'Users',
'--view' => true,
'--model-namespace' => 'Filament\Tests\Models',
@@ -585,7 +585,7 @@ it('can generate a nested resource infolist', function () {
it('can generate a nested resource create page', function () {
$this->artisan('make:filament-resource', [
'name' => 'User',
'model' => 'User',
'--panel' => 'admin',
'--no-interaction' => true,
]);
@@ -601,7 +601,7 @@ it('can generate a nested resource create page', function () {
];
$this->artisan('make:filament-resource', [
'name' => 'Post',
'model' => 'Post',
'--nested' => 'Users',
'--model-namespace' => 'Filament\Tests\Models',
'--panel' => 'admin',
@@ -615,7 +615,7 @@ it('can generate a nested resource create page', function () {
it('can generate a nested resource edit page', function () {
$this->artisan('make:filament-resource', [
'name' => 'User',
'model' => 'User',
'--panel' => 'admin',
'--no-interaction' => true,
]);
@@ -631,7 +631,7 @@ it('can generate a nested resource edit page', function () {
];
$this->artisan('make:filament-resource', [
'name' => 'Post',
'model' => 'Post',
'--nested' => 'Users',
'--model-namespace' => 'Filament\Tests\Models',
'--panel' => 'admin',
@@ -645,7 +645,7 @@ it('can generate a nested resource edit page', function () {
it('can generate a nested resource view page', function () {
$this->artisan('make:filament-resource', [
'name' => 'User',
'model' => 'User',
'--panel' => 'admin',
'--no-interaction' => true,
]);
@@ -661,7 +661,7 @@ it('can generate a nested resource view page', function () {
];
$this->artisan('make:filament-resource', [
'name' => 'Post',
'model' => 'Post',
'--nested' => 'Users',
'--view' => true,
'--model-namespace' => 'Filament\Tests\Models',
@@ -676,7 +676,7 @@ it('can generate a nested resource view page', function () {
it('can generate a nested resource class in a nested directory', function () {
$this->artisan('make:filament-resource', [
'name' => 'User',
'model' => 'User',
'--panel' => 'admin',
'--no-interaction' => true,
]);
@@ -692,7 +692,7 @@ it('can generate a nested resource class in a nested directory', function () {
];
$this->artisan('make:filament-resource', [
'name' => 'Blog/Post',
'model' => 'Blog/Post',
'--nested' => 'Users',
'--model-namespace' => 'Filament\Tests\Models',
'--panel' => 'admin',