diff --git a/packages/builder/DEVLOG.md b/packages/builder/DEVLOG.md index 7605488aa..ee1df9c98 100644 --- a/packages/builder/DEVLOG.md +++ b/packages/builder/DEVLOG.md @@ -4,41 +4,28 @@ We work on these tasks in order from top to bottom: ## Tasks -### General (WIP) - -From publishable item we learn that TitleWithSlug should implement it's own section, it currently seems to add a comma, why? -Another issue is that the List page is missing the eloquent builder use statement, why? -After fixing that, the list page has other issues too. -Tabs are not generated from the Publish block, should overwrite Tabs block - -We need to document the new section API and section classes. - -And we need to fix the issue with the FullItem, maybe we need a new way to handle relations like author, user, etc. -Failed to create entity: SQLSTATE[HY000]: General error: 1824 Failed to open the referenced table 'authors' (Connection: mysql, SQL: alter table `preview_preview_full_items` add constraint `preview_preview_full_items_author_id_foreign` foreign key (`author_id`) references `authors` (`id`) on delete cascade) - ### Entity - [WIP] We currently work on generating Presets in Preview Context and optimize the generated resources - - [WIP] PreviewSimItem is working like a charm including actions, filters, bulk actions and taxonomies - - [ ] Delete does not delete the record - - [ ] Status field is not working as expected, completely weird behavior + - [x] PreviewSimItem is working like a charm including actions, filters, bulk actions, tabs and taxonomies + - [WIP] PreviewPubItem + - [ ] Saving is not working, trait or code in pages or resource missing? Must be for TitleWithSlug block + - [ ] List page is missing the eloquent builder use statement, why? + - [ ] After fixing that, the list page has other issues too. - [ ] Uniqueness is not implemented or not used? - [ ] Taxonomies needs to be tested, TaxonomyInPages has issues - - [ ] Page / AbstractPage generators need section-based API implementation? - [ ] Relations needs - [ ] to be implemented first, because relations is a bit different to taxonomies - [ ] to be generated in the Resource - [ ] to be generated in the Config - - [WIP] PreviewPubItem - - [ ] We need to bring this on the Simple Item level first - - [ ] Tabs needs to be implemented and should replace the simple tabs - - [ ] Taxonomies needs to be tested, TaxonomyInPages has issues - - [ ] TitleWithSlug should implement it's own section - - [ ] Relations - - [ ] Actions need to work as expected + - [ ] RelationManager? + - [ ] Page / AbstractPage generators need section-based API implementation? - [ ] We need to work on the publish feature with custom actions, see https://youtu.be/bjv_RiBUtNs?si=cellheQYyxhiHxRg&t=167 - [ ] Then we need to implement the relation feature - - [WIP] PreviewFullItem + - [ ] Add author when fixed + - [ ] PreviewFullItem + - [ ] We need a new way to handle relations like author, user, etc. from the block to fix: + Failed to create entity: SQLSTATE[HY000]: General error: 1824 Failed to open the referenced table 'authors' (Connection: mysql, SQL: alter table `preview_preview_full_items` add constraint `preview_preview_full_items_author_id_foreign` foreign key (`author_id`) references `authors` (`id`) on delete cascade) - [ ] We need to bring this on the Publish Item level first - [ ] We need to work on all existing blocks and generate theme here - [ ] Maybe add the three widgets here, needs wiget-generator and template? @@ -52,10 +39,7 @@ Failed to create entity: SQLSTATE[HY000]: General error: 1824 Failed to open the - [ ] Then we need to implement the soft delete feature - [ ] Then it need Category specific implementation with nested set - [ ] Iterate over all blocks, presets and contexts to find out if they are working as expected -- [ ] Moox Core Features need to be refactored to be able to generate them without issues, eliminate methods and move to traits - - [ ] Publish feature seems to miss the save method - - [ ] Relations, like Taxonomies, but "on the left" - - [ ] Relations like Taxonomies, and what about Relationsmanagers? +- [ ] Moox Core Features need to be documented - [ ] Naming convention InModel InResource InPages and Single for single-use traits - [ ] TabsInResource - contains TODO - [ ] TabsInListPage - just getTabs needs to be defined @@ -64,11 +48,11 @@ Failed to create entity: SQLSTATE[HY000]: General error: 1824 Failed to open the - [ ] Add --migration option to create command - [ ] Would Builder now be able to generate itself based on the current migrations? - [ ] How would we generate a complete different type of resource, like a Media Manager? The only thing we need is a different table, switching to a grid. - -- All Blocks need to be updated +- [ ] All Blocks need to be updated - [ ] Toggleable option like in Text - [ ] Filterable option like in Text, and filterable needs to be implemented in ResourceGenerator (only generate filters if filterable is true) - [ ] The new section API +- [ ] Document the new section API ### Merge and Release diff --git a/packages/builder/src/Blocks/Author.php b/packages/builder/src/Blocks/Author.php index 51116d88c..781cf3fc0 100644 --- a/packages/builder/src/Blocks/Author.php +++ b/packages/builder/src/Blocks/Author.php @@ -6,12 +6,30 @@ class Author extends AbstractBlock { + protected bool $searchable; + + protected bool $toggleable; + + protected bool $sortable; + + protected string $userModel; + public function __construct( string $name = 'author', string $label = 'Author', string $description = 'Author management', + bool $nullable = false, + bool $searchable = true, + bool $toggleable = true, + bool $sortable = true, + string $userModel = 'App\Models\User', ) { - parent::__construct($name, $label, $description); + parent::__construct($name, $label, $description, $nullable); + + $this->searchable = $searchable; + $this->toggleable = $toggleable; + $this->sortable = $sortable; + $this->userModel = $userModel; $this->useStatements = [ 'resource' => [ @@ -31,18 +49,16 @@ public function __construct( $this->formFields['resource'] = [ "Select::make('author_id') - ->relationship('author', 'name') - ->searchable() - ->preload() - ->required()", + ->relationship('author', 'name')" + .($this->nullable ? '' : '->required()'), ]; $this->tableColumns['resource'] = [ "TextColumn::make('author.name') - ->label(__('core::core.author')) - ->sortable() - ->searchable() - ->toggleable()", + ->label(__('core::core.author'))" + .($this->sortable ? '' : '->sortable()') + .($this->searchable ? '' : '->searchable()') + .($this->toggleable ? '' : '->toggleable()'), ]; $this->migrations['fields'] = [ diff --git a/packages/builder/src/Blocks/ColorPicker.php b/packages/builder/src/Blocks/ColorPicker.php index ceb4aeb0f..a7dc70bcc 100644 --- a/packages/builder/src/Blocks/ColorPicker.php +++ b/packages/builder/src/Blocks/ColorPicker.php @@ -18,24 +18,20 @@ public function __construct( 'resource' => [ 'forms' => ['use Filament\Forms\Components\ColorPicker;'], 'columns' => ['use Filament\Tables\Columns\ColorColumn;'], - 'filters' => ['use Filament\Tables\Filters\TextFilter;'], ], ]; - $this->formFields['resource'] = [ - "ColorPicker::make('{$this->name}') - ->label('{$this->label}')" - .($this->nullable ? '' : '->required()'), - ]; + $this->addSection('form') + ->withFields([ + "ColorPicker::make('{$this->name}') + ->label('{$this->label}')" + .($this->nullable ? '' : '->required()'), + ]); $this->tableColumns['resource'] = [ "ColorColumn::make('{$this->name}')", ]; - $this->filters['resource'] = [ - "TextFilter::make('{$this->name}')", - ]; - $this->migrations['fields'] = [ "\$table->string('{$this->name}', 7)" .($this->nullable ? '->nullable()' : ''), diff --git a/packages/builder/src/Blocks/MarkdownEditor.php b/packages/builder/src/Blocks/MarkdownEditor.php index 141143799..cc32c8365 100644 --- a/packages/builder/src/Blocks/MarkdownEditor.php +++ b/packages/builder/src/Blocks/MarkdownEditor.php @@ -20,15 +20,15 @@ public function __construct( 'resource' => [ 'forms' => ['use Filament\Forms\Components\MarkdownEditor;'], 'columns' => ['use Filament\Tables\Columns\TextColumn;'], - 'filters' => ['use Filament\Tables\Filters\TextFilter;'], ], ]; - $this->formFields['resource'] = [ - "MarkdownEditor::make('{$this->name}') - ->label('{$this->label}')" - .($this->nullable ? '' : '->required()'), - ]; + $this->addSection('form') + ->withFields([ + "MarkdownEditor::make('{$this->name}') + ->label('{$this->label}')" + .($this->nullable ? '' : '->required()'), + ]); $this->tableColumns['resource'] = [ "TextColumn::make('{$this->name}') @@ -36,10 +36,6 @@ public function __construct( .($this->searchable ? '->searchable()' : ''), ]; - $this->filters['resource'] = [ - "TextFilter::make('{$this->name}')", - ]; - $this->migrations['fields'] = [ "\$table->text('{$this->name}')" .($this->nullable ? '->nullable()' : ''), diff --git a/packages/builder/src/Blocks/Publish.php b/packages/builder/src/Blocks/Publish.php index c30aece22..dd2d3ea75 100644 --- a/packages/builder/src/Blocks/Publish.php +++ b/packages/builder/src/Blocks/Publish.php @@ -33,9 +33,10 @@ public function __construct( ], 'pages' => [ 'list' => [ - 'use Moox\Core\Traits\SinglePublishInListPage;', // This is missing in the generated list page, why? 'use Illuminate\Database\Eloquent\Builder;', + // while this is generated + 'use Moox\Core\Traits\SinglePublishInListPage;', ], ], ]; @@ -71,20 +72,11 @@ public function __construct( }', ]; - $this->formFields['resource'] = [ - ]; - - $this->formSections['resource'] = [ - ]; - $this->metaFields['resource'] = [ 'static::getFormActions()', 'static::getPublishAtFormField()', ]; - $this->metaSections['resource'] = [ - ]; - $this->tableColumns['resource'] = [ "TextColumn::make('publish_at') ->label(__('core::core.publish_at')) @@ -148,7 +140,7 @@ public function __construct( ]; $this->config['tabs'] = [ - "'all' => [ + 'all' => [ 'label' => 'trans//core::core.all', 'icon' => 'gmdi-filter-list', 'query' => [ @@ -158,60 +150,41 @@ public function __construct( 'value' => null, ], ], - ],", - "'published' => [ + ], + 'published' => [ 'label' => 'trans//core::core.published', 'icon' => 'gmdi-check-circle', 'query' => [ [ 'field' => 'publish_at', 'operator' => '<=', - 'value' => function () { - return now(); - }, - ], - [ - 'field' => 'deleted_at', - 'operator' => '=', - 'value' => null, + 'value' => 'now()', ], ], - ],", - "'scheduled' => [ + ], + 'scheduled' => [ 'label' => 'trans//core::core.scheduled', 'icon' => 'gmdi-schedule', 'query' => [ [ 'field' => 'publish_at', 'operator' => '>', - 'value' => function () { - return now(); - }, - ], - [ - 'field' => 'deleted_at', - 'operator' => '=', - 'value' => null, + 'value' => 'now()', ], ], - ],", - "'draft' => [ + ], + 'draft' => [ 'label' => 'trans//core::core.draft', - 'icon' => 'gmdi-text-snippet', + 'icon' => 'gmdi-drafts', 'query' => [ [ - 'field' => 'publish_at', - 'operator' => '=', - 'value' => null, - ], - [ - 'field' => 'deleted_at', + 'field' => 'published_at', 'operator' => '=', 'value' => null, ], ], - ],", - "'deleted' => [ + ], + 'deleted' => [ 'label' => 'trans//core::core.deleted', 'icon' => 'gmdi-delete', 'query' => [ @@ -221,7 +194,12 @@ public function __construct( 'value' => null, ], ], - ],", + ], ]; } + + public function getTabs(): array + { + return $this->config['tabs']; + } } diff --git a/packages/builder/src/Blocks/RichEditor.php b/packages/builder/src/Blocks/RichEditor.php index 61f0ea5f8..9ae126d50 100644 --- a/packages/builder/src/Blocks/RichEditor.php +++ b/packages/builder/src/Blocks/RichEditor.php @@ -19,15 +19,15 @@ public function __construct( 'resource' => [ 'forms' => ['use Filament\Forms\Components\RichEditor;'], 'columns' => ['use Filament\Tables\Columns\TextColumn;'], - 'filters' => ['use Filament\Tables\Filters\TextFilter;'], ], ]; - $this->formFields['resource'] = [ - "RichEditor::make('{$this->name}') - ->label('{$this->label}')" - .($this->nullable ? '' : '->required()'), - ]; + $this->addSection('form') + ->withFields([ + "RichEditor::make('{$this->name}') + ->label('{$this->label}')" + .($this->nullable ? '' : '->required()'), + ]); $this->tableColumns['resource'] = [ "TextColumn::make('{$this->name}') @@ -36,10 +36,6 @@ public function __construct( .($this->searchable ? '->searchable()' : ''), ]; - $this->filters['resource'] = [ - "TextFilter::make('{$this->name}')", - ]; - $this->migrations['fields'] = [ "\$table->text('{$this->name}')" .($this->nullable ? '->nullable()' : ''), diff --git a/packages/builder/src/Blocks/SimpleStatus.php b/packages/builder/src/Blocks/SimpleStatus.php index bb4c64536..c29769041 100644 --- a/packages/builder/src/Blocks/SimpleStatus.php +++ b/packages/builder/src/Blocks/SimpleStatus.php @@ -16,7 +16,7 @@ public function __construct( string $name = 'status', string $label = 'Status', string $description = 'Adds a simple status field based on an enum to a resource', - array $enum = ['New', 'Open', 'Pending', 'Closed', 'Rejected', 'Cancelled'], + array $enum = ['New', 'Open', 'Pending', 'Closed'], bool $nullable = false, bool $sortable = true, bool $searchable = true, @@ -37,7 +37,7 @@ public function __construct( ], ]; - $options = '["'.implode('", "', $enum).'"]'; + $options = '['.implode(', ', array_map(fn ($value) => "'$value' => '$value'", $enum)).']'; $this->addSection('status') ->asMeta() @@ -46,7 +46,8 @@ public function __construct( 'Select::make(\''.$this->name.'\') ->label(\''.$this->label.'\') ->placeholder(__(\'core::core.status\')) - ->options('.$options.')', + ->options('.$options.') + '.($this->nullable ? '' : '->required()'), ]); $this->tableColumns['resource'] = [ @@ -70,5 +71,62 @@ public function __construct( ->options({$options}) ])", ]; + + $this->config['tabs'] = [ + 'all' => [ + 'label' => 'trans//core::core.all', + 'icon' => 'gmdi-filter-list', + 'query' => [], + ], + 'probably' => [ + 'label' => 'Probably', + 'icon' => 'gmdi-filter-list', + 'query' => [ + [ + 'field' => 'status', + 'operator' => '=', + 'value' => 'Probably', + ], + ], + ], + 'never' => [ + 'label' => 'Never', + 'icon' => 'gmdi-filter-list', + 'query' => [ + [ + 'field' => 'status', + 'operator' => '=', + 'value' => 'Never', + ], + ], + ], + 'done' => [ + 'label' => 'Done', + 'icon' => 'gmdi-filter-list', + 'query' => [ + [ + 'field' => 'status', + 'operator' => '=', + 'value' => 'Done', + ], + ], + ], + 'maybe' => [ + 'label' => 'Maybe', + 'icon' => 'gmdi-filter-list', + 'query' => [ + [ + 'field' => 'status', + 'operator' => '=', + 'value' => 'Maybe', + ], + ], + ], + ]; + } + + public function getTabs(): array + { + return $this->config['tabs']; } } diff --git a/packages/builder/src/Blocks/TitleWithSlug.php b/packages/builder/src/Blocks/TitleWithSlug.php index 07dfef935..85d9aecf7 100644 --- a/packages/builder/src/Blocks/TitleWithSlug.php +++ b/packages/builder/src/Blocks/TitleWithSlug.php @@ -30,12 +30,16 @@ public function __construct( ], ]; - $this->formFields['resource'] = [ - "TitleWithSlugInput::make( - fieldTitle: '{$this->titleFieldName}', - fieldSlug: '{$this->slugFieldName}', - ),", - ]; + $this->addSection('form') + ->withFields([ + "TitleWithSlugInput::make( + fieldTitle: '{$this->titleFieldName}', + fieldSlug: '{$this->slugFieldName}', + )", + "TextInput::make('{$this->slugFieldName}') + ->label('Slug') + ->placeholder('Slug')", + ]); $this->tableColumns['resource'] = [ "TextColumn::make('{$this->titleFieldName}') diff --git a/packages/builder/src/Generators/Entity/ConfigGenerator.php b/packages/builder/src/Generators/Entity/ConfigGenerator.php index d46841624..5c435233f 100644 --- a/packages/builder/src/Generators/Entity/ConfigGenerator.php +++ b/packages/builder/src/Generators/Entity/ConfigGenerator.php @@ -36,9 +36,13 @@ public function generate(): void protected function collectFeatures(): void { + $this->tabs = []; + $this->taxonomies = []; + $this->relations = []; + foreach ($this->getBlocks() as $block) { if (method_exists($block, 'getTabs')) { - $this->tabs = array_merge($this->tabs, $block->getTabs()); + $this->tabs = $block->getTabs(); } if (method_exists($block, 'getTaxonomies')) { diff --git a/packages/builder/src/Presets/PublishableItemPreset.php b/packages/builder/src/Presets/PublishableItemPreset.php index 0836b2f1b..998ff2ac3 100644 --- a/packages/builder/src/Presets/PublishableItemPreset.php +++ b/packages/builder/src/Presets/PublishableItemPreset.php @@ -21,8 +21,8 @@ protected function initializePreset(): void description: 'The title of the item', nullable: false ), - new Publish, new Tabs, + new Publish, new MarkdownEditor( name: 'content', label: 'Content', diff --git a/packages/builder/src/Presets/SimpleItemPreset.php b/packages/builder/src/Presets/SimpleItemPreset.php index 6d87a816c..e83305343 100644 --- a/packages/builder/src/Presets/SimpleItemPreset.php +++ b/packages/builder/src/Presets/SimpleItemPreset.php @@ -22,7 +22,17 @@ protected function initializePreset(): void name: 'title', label: 'Title', description: 'The title of the item', - length: 255, + nullable: false, + unique: true, + searchable: true, + sortable: true, + toggleable: true, + filterable: true, + ), + new Text( + name: 'slug', + label: 'Slug', + description: 'The slug of the item', nullable: false, unique: true, searchable: true, @@ -58,7 +68,9 @@ protected function initializePreset(): void createForm: '\Moox\Tag\Forms\TaxonomyCreateForm::class', ), new AddressSection, - new SimpleStatus, + new SimpleStatus( + enum: ['Probably', 'Never', 'Done', 'Maybe'], + ), ]; } } diff --git a/packages/core/src/Traits/SingleSimpleInResource.php b/packages/core/src/Traits/SingleSimpleInResource.php index 8d8fb1acf..7a412f2da 100644 --- a/packages/core/src/Traits/SingleSimpleInResource.php +++ b/packages/core/src/Traits/SingleSimpleInResource.php @@ -56,10 +56,13 @@ public static function getDeleteAction(): Action ->color('danger') ->outlined() ->extraAttributes(attributes: ['class' => 'w-full']) - ->action(fn ($record) => $record->delete()) + ->action(function ($livewire) { + $livewire->record->delete(); + $livewire->redirect(static::getUrl('index')); + }) ->keyBindings(['delete']) - ->url(fn ($record) => static::getUrl('index')) - ->visible(fn ($livewire) => $livewire instanceof EditRecord); + ->visible(fn ($livewire) => $livewire instanceof EditRecord) + ->requiresConfirmation(); } public static function getEditAction(): Action