mirror of
https://github.com/filamentphp/filament.git
synced 2026-10-29 18:19:53 +08:00
Generate Table Livewire components
This commit is contained in:
+1
-1
@@ -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;
|
||||
@@ -20,7 +20,7 @@ class FormsServiceProvider extends PackageServiceProvider
|
||||
->name('filament-forms')
|
||||
->hasCommands([
|
||||
Commands\MakeFieldCommand::class,
|
||||
Commands\MakeFormCommand::class,
|
||||
Commands\MakeLivewireFormCommand::class,
|
||||
])
|
||||
->hasTranslations()
|
||||
->hasViews();
|
||||
|
||||
+3
-151
@@ -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(['\\', '/'], '');
|
||||
|
||||
@@ -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,
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
*/
|
||||
|
||||
+76
-50
@@ -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();
|
||||
|
||||
@@ -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',
|
||||
|
||||
Reference in New Issue
Block a user