In this recipe we will show how to customize a page with a form (we took an example of articles from the main demo repository), where we will place the relationship fields in separate tabs,
and this recipe will also give you an understanding of the enormous possibilities of page customization.
namespace App\MoonShine\Pages\Article;
use App\Models\Comment;
use App\MoonShine\Resources\CommentResource;
use App\MoonShine\Resources\MoonShineUserResource;
use MoonShine\Laravel\Fields\Relationships\BelongsTo;
use MoonShine\Laravel\Fields\Relationships\BelongsToMany;
use MoonShine\Laravel\Fields\Relationships\HasMany;
use MoonShine\Laravel\Fields\Relationships\HasOne;
use MoonShine\Laravel\Fields\Slug;
use MoonShine\Laravel\Pages\Crud\FormPage;
use MoonShine\Laravel\TypeCasts\ModelCaster;
use MoonShine\TinyMce\Fields\TinyMce;
use MoonShine\UI\Components\ActionButton;
use MoonShine\UI\Components\Collapse;
use MoonShine\UI\Components\Heading;
use MoonShine\UI\Components\Layout\Box;
use MoonShine\UI\Components\Layout\Column;
use MoonShine\UI\Components\Layout\Flex;
use MoonShine\UI\Components\Layout\Grid;
use MoonShine\UI\Components\Layout\LineBreak;
use MoonShine\UI\Components\Table\TableBuilder;
use MoonShine\UI\Components\Tabs;
use MoonShine\UI\Components\Tabs\Tab;
use MoonShine\UI\Fields\Color;
use MoonShine\UI\Fields\ID;
use MoonShine\UI\Fields\Image;
use MoonShine\UI\Fields\Json;
use MoonShine\UI\Fields\Number;
use MoonShine\UI\Fields\Preview;
use MoonShine\UI\Fields\RangeSlider;
use MoonShine\UI\Fields\StackFields;
use MoonShine\UI\Fields\Switcher;
use MoonShine\UI\Fields\Text;
use MoonShine\UI\Fields\Url;
final class ArticleFormPage extends FormPage
{
protected function fields(): iterable
{
return [
ID::make(),
Grid::make([
Column::make([
Box::make('Main information', [
ActionButton::make(
'Link to article',
$this->getResource()->getItem()?->getKey() ? route('articles.show', $this->getResource()->getItem()) : '/',
)
->icon('paper-clip')
->blank(),
LineBreak::make(),
BelongsTo::make('Author', resource: MoonShineUserResource::class)
->asyncSearch()
->canSee(fn () => auth()->user()->moonshine_user_role_id === 1)
->required(),
Collapse::make('Title/Slug', [
Heading::make('Title/Slug'),
Flex::make([
Text::make('Title')
->withoutWrapper()
->required()
,
Slug::make('Slug')
->from('title')
->unique()
->separator('-')
->withoutWrapper()
->required()
,
])
->name('flex-titles')
->justifyAlign('start')
->itemsAlign('start'),
]),
StackFields::make('Files')->fields([
Image::make('Thumbnail')
->removable()
->disk('public')
->dir('articles'),
]),
Preview::make('No input field', 'no_input', static fn () => fake()->realText()),
RangeSlider::make('Age')
->min(0)
->max(60)
->step(1)
->fromTo('age_from', 'age_to'),
Number::make('Rating')
->hint('From 0 to 5')
->min(0)
->max(5)
->link('https://cutcode.dev', 'CutCode', blank: true)
->stars(),
Url::make('Link')
->hint('Url')
->link('https://cutcode.dev', 'CutCode', blank: true)
->suffix('url')
,
Color::make('Color'),
Json::make('Data')->fields([
Text::make('Title'),
Text::make('Value'),
])->creatable()->removable(),
Switcher::make('Active'),
]),
])->columnSpan(6),
Column::make([
Box::make('Seo and categories', [
Tabs::make([
Tab::make('Seo', [
Text::make('Seo title')
->withoutWrapper(),
Text::make('Seo description')
->withoutWrapper(),
TinyMce::make('Description')
->addPlugins(['code', 'codesample'])
->toolbar(' | code codesample')
->required()
,
]),
Tab::make('Categories', [
BelongsToMany::make('Categories')->tree('category_id'),
]),
]),
]),
])->columnSpan(6),
]),
$this->getCommentsField(),
$this->getCommentField(),
];
}
private function getCommentsField(): HasMany
{
return HasMany::make('Comments', resource: CommentResource::class)
->fillData($this->getResource()->getItem())
->async()
->creatable();
}
private function getCommentField(): HasOne
{
return HasOne::make('Comment', resource: CommentResource::class)
->fillData($this->getResource()->getItem())
->async();
}
protected function mainLayer(): array
{
return [
Tabs::make([
Tab::make('Basics', parent::mainLayer()),
Tab::make('Comments', [
$this->getResource()->getItem() ? $this->getCommentsField() : 'To add comments, save the article',
]),
Tab::make('Comment', [
$this->getResource()->getItem() ? $this->getCommentField() : 'To add comments, save the article',
]),
Tab::make('Table', [
TableBuilder::make()
->fields([
ID::make(),
Text::make('Text')
])
->cast(new ModelCaster(Comment::class))
->items($this->getResource()->getItem()?->comments ?? [])
]),
]),
];
}
protected function bottomLayer(): array
{
return [];
}
}
namespace App\MoonShine\Pages\Article;
use App\Models\Comment;
use App\MoonShine\Resources\CommentResource;
use App\MoonShine\Resources\MoonShineUserResource;
use MoonShine\Laravel\Fields\Relationships\BelongsTo;
use MoonShine\Laravel\Fields\Relationships\BelongsToMany;
use MoonShine\Laravel\Fields\Relationships\HasMany;
use MoonShine\Laravel\Fields\Relationships\HasOne;
use MoonShine\Laravel\Fields\Slug;
use MoonShine\Laravel\Pages\Crud\FormPage;
use MoonShine\Laravel\TypeCasts\ModelCaster;
use MoonShine\TinyMce\Fields\TinyMce;
use MoonShine\UI\Components\ActionButton;
use MoonShine\UI\Components\Collapse;
use MoonShine\UI\Components\Heading;
use MoonShine\UI\Components\Layout\Box;
use MoonShine\UI\Components\Layout\Column;
use MoonShine\UI\Components\Layout\Flex;
use MoonShine\UI\Components\Layout\Grid;
use MoonShine\UI\Components\Layout\LineBreak;
use MoonShine\UI\Components\Table\TableBuilder;
use MoonShine\UI\Components\Tabs;
use MoonShine\UI\Components\Tabs\Tab;
use MoonShine\UI\Fields\Color;
use MoonShine\UI\Fields\ID;
use MoonShine\UI\Fields\Image;
use MoonShine\UI\Fields\Json;
use MoonShine\UI\Fields\Number;
use MoonShine\UI\Fields\Preview;
use MoonShine\UI\Fields\RangeSlider;
use MoonShine\UI\Fields\StackFields;
use MoonShine\UI\Fields\Switcher;
use MoonShine\UI\Fields\Text;
use MoonShine\UI\Fields\Url;
final class ArticleFormPage extends FormPage
{
protected function fields(): iterable
{
return [
ID::make(),
Grid::make([
Column::make([
Box::make('Main information', [
ActionButton::make(
'Link to article',
$this->getResource()->getItem()?->getKey() ? route('articles.show', $this->getResource()->getItem()) : '/',
)
->icon('paper-clip')
->blank(),
LineBreak::make(),
BelongsTo::make('Author', resource: MoonShineUserResource::class)
->asyncSearch()
->canSee(fn () => auth()->user()->moonshine_user_role_id === 1)
->required(),
Collapse::make('Title/Slug', [
Heading::make('Title/Slug'),
Flex::make([
Text::make('Title')
->withoutWrapper()
->required()
,
Slug::make('Slug')
->from('title')
->unique()
->separator('-')
->withoutWrapper()
->required()
,
])
->name('flex-titles')
->justifyAlign('start')
->itemsAlign('start'),
]),
StackFields::make('Files')->fields([
Image::make('Thumbnail')
->removable()
->disk('public')
->dir('articles'),
]),
Preview::make('No input field', 'no_input', static fn () => fake()->realText()),
RangeSlider::make('Age')
->min(0)
->max(60)
->step(1)
->fromTo('age_from', 'age_to'),
Number::make('Rating')
->hint('From 0 to 5')
->min(0)
->max(5)
->link('https://cutcode.dev', 'CutCode', blank: true)
->stars(),
Url::make('Link')
->hint('Url')
->link('https://cutcode.dev', 'CutCode', blank: true)
->suffix('url')
,
Color::make('Color'),
Json::make('Data')->fields([
Text::make('Title'),
Text::make('Value'),
])->creatable()->removable(),
Switcher::make('Active'),
]),
])->columnSpan(6),
Column::make([
Box::make('Seo and categories', [
Tabs::make([
Tab::make('Seo', [
Text::make('Seo title')
->withoutWrapper(),
Text::make('Seo description')
->withoutWrapper(),
TinyMce::make('Description')
->addPlugins(['code', 'codesample'])
->toolbar(' | code codesample')
->required()
,
]),
Tab::make('Categories', [
BelongsToMany::make('Categories')->tree('category_id'),
]),
]),
]),
])->columnSpan(6),
]),
$this->getCommentsField(),
$this->getCommentField(),
];
}
private function getCommentsField(): HasMany
{
return HasMany::make('Comments', resource: CommentResource::class)
->fillData($this->getResource()->getItem())
->async()
->creatable();
}
private function getCommentField(): HasOne
{
return HasOne::make('Comment', resource: CommentResource::class)
->fillData($this->getResource()->getItem())
->async();
}
protected function mainLayer(): array
{
return [
Tabs::make([
Tab::make('Basics', parent::mainLayer()),
Tab::make('Comments', [
$this->getResource()->getItem() ? $this->getCommentsField() : 'To add comments, save the article',
]),
Tab::make('Comment', [
$this->getResource()->getItem() ? $this->getCommentField() : 'To add comments, save the article',
]),
Tab::make('Table', [
TableBuilder::make()
->fields([
ID::make(),
Text::make('Text')
])
->cast(new ModelCaster(Comment::class))
->items($this->getResource()->getItem()?->comments ?? [])
]),
]),
];
}
protected function bottomLayer(): array
{
return [];
}
}
namespace App\MoonShine\Pages\Article;
use App\Models\Comment;
use App\MoonShine\Resources\CommentResource;
use App\MoonShine\Resources\MoonShineUserResource;
use MoonShine\Laravel\Fields\Relationships\BelongsTo;
use MoonShine\Laravel\Fields\Relationships\BelongsToMany;
use MoonShine\Laravel\Fields\Relationships\HasMany;
use MoonShine\Laravel\Fields\Relationships\HasOne;
use MoonShine\Laravel\Fields\Slug;
use MoonShine\Laravel\Pages\Crud\FormPage;
use MoonShine\Laravel\TypeCasts\ModelCaster;
use MoonShine\TinyMce\Fields\TinyMce;
use MoonShine\UI\Components\ActionButton;
use MoonShine\UI\Components\Collapse;
use MoonShine\UI\Components\Heading;
use MoonShine\UI\Components\Layout\Box;
use MoonShine\UI\Components\Layout\Column;
use MoonShine\UI\Components\Layout\Flex;
use MoonShine\UI\Components\Layout\Grid;
use MoonShine\UI\Components\Layout\LineBreak;
use MoonShine\UI\Components\Table\TableBuilder;
use MoonShine\UI\Components\Tabs;
use MoonShine\UI\Components\Tabs\Tab;
use MoonShine\UI\Fields\Color;
use MoonShine\UI\Fields\ID;
use MoonShine\UI\Fields\Image;
use MoonShine\UI\Fields\Json;
use MoonShine\UI\Fields\Number;
use MoonShine\UI\Fields\Preview;
use MoonShine\UI\Fields\RangeSlider;
use MoonShine\UI\Fields\StackFields;
use MoonShine\UI\Fields\Switcher;
use MoonShine\UI\Fields\Text;
use MoonShine\UI\Fields\Url;
final class ArticleFormPage extends FormPage
{
protected function fields(): iterable
{
return [
ID::make(),
Grid::make([
Column::make([
Box::make('Main information', [
ActionButton::make(
'Link to article',
$this->getResource()->getItem()?->getKey() ? route('articles.show', $this->getResource()->getItem()) : '/',
)
->icon('paper-clip')
->blank(),
LineBreak::make(),
BelongsTo::make('Author', resource: MoonShineUserResource::class)
->asyncSearch()
->canSee(fn () => auth()->user()->moonshine_user_role_id === 1)
->required(),
Collapse::make('Title/Slug', [
Heading::make('Title/Slug'),
Flex::make([
Text::make('Title')
->withoutWrapper()
->required()
,
Slug::make('Slug')
->from('title')
->unique()
->separator('-')
->withoutWrapper()
->required()
,
])
->name('flex-titles')
->justifyAlign('start')
->itemsAlign('start'),
]),
StackFields::make('Files')->fields([
Image::make('Thumbnail')
->removable()
->disk('public')
->dir('articles'),
]),
Preview::make('No input field', 'no_input', static fn () => fake()->realText()),
RangeSlider::make('Age')
->min(0)
->max(60)
->step(1)
->fromTo('age_from', 'age_to'),
Number::make('Rating')
->hint('From 0 to 5')
->min(0)
->max(5)
->link('https://cutcode.dev', 'CutCode', blank: true)
->stars(),
Url::make('Link')
->hint('Url')
->link('https://cutcode.dev', 'CutCode', blank: true)
->suffix('url')
,
Color::make('Color'),
Json::make('Data')->fields([
Text::make('Title'),
Text::make('Value'),
])->creatable()->removable(),
Switcher::make('Active'),
]),
])->columnSpan(6),
Column::make([
Box::make('Seo and categories', [
Tabs::make([
Tab::make('Seo', [
Text::make('Seo title')
->withoutWrapper(),
Text::make('Seo description')
->withoutWrapper(),
TinyMce::make('Description')
->addPlugins(['code', 'codesample'])
->toolbar(' | code codesample')
->required()
,
]),
Tab::make('Categories', [
BelongsToMany::make('Categories')->tree('category_id'),
]),
]),
]),
])->columnSpan(6),
]),
$this->getCommentsField(),
$this->getCommentField(),
];
}
private function getCommentsField(): HasMany
{
return HasMany::make('Comments', resource: CommentResource::class)
->fillData($this->getResource()->getItem())
->async()
->creatable();
}
private function getCommentField(): HasOne
{
return HasOne::make('Comment', resource: CommentResource::class)
->fillData($this->getResource()->getItem())
->async();
}
protected function mainLayer(): array
{
return [
Tabs::make([
Tab::make('Basics', parent::mainLayer()),
Tab::make('Comments', [
$this->getResource()->getItem() ? $this->getCommentsField() : 'To add comments, save the article',
]),
Tab::make('Comment', [
$this->getResource()->getItem() ? $this->getCommentField() : 'To add comments, save the article',
]),
Tab::make('Table', [
TableBuilder::make()
->fields([
ID::make(),
Text::make('Text')
])
->cast(new ModelCaster(Comment::class))
->items($this->getResource()->getItem()?->comments ?? [])
]),
]),
];
}
protected function bottomLayer(): array
{
return [];
}
}
namespace App\MoonShine\Pages\Article;
use App\Models\Comment;
use App\MoonShine\Resources\CommentResource;
use App\MoonShine\Resources\MoonShineUserResource;
use MoonShine\Laravel\Fields\Relationships\BelongsTo;
use MoonShine\Laravel\Fields\Relationships\BelongsToMany;
use MoonShine\Laravel\Fields\Relationships\HasMany;
use MoonShine\Laravel\Fields\Relationships\HasOne;
use MoonShine\Laravel\Fields\Slug;
use MoonShine\Laravel\Pages\Crud\FormPage;
use MoonShine\Laravel\TypeCasts\ModelCaster;
use MoonShine\TinyMce\Fields\TinyMce;
use MoonShine\UI\Components\ActionButton;
use MoonShine\UI\Components\Collapse;
use MoonShine\UI\Components\Heading;
use MoonShine\UI\Components\Layout\Box;
use MoonShine\UI\Components\Layout\Column;
use MoonShine\UI\Components\Layout\Flex;
use MoonShine\UI\Components\Layout\Grid;
use MoonShine\UI\Components\Layout\LineBreak;
use MoonShine\UI\Components\Table\TableBuilder;
use MoonShine\UI\Components\Tabs;
use MoonShine\UI\Components\Tabs\Tab;
use MoonShine\UI\Fields\Color;
use MoonShine\UI\Fields\ID;
use MoonShine\UI\Fields\Image;
use MoonShine\UI\Fields\Json;
use MoonShine\UI\Fields\Number;
use MoonShine\UI\Fields\Preview;
use MoonShine\UI\Fields\RangeSlider;
use MoonShine\UI\Fields\StackFields;
use MoonShine\UI\Fields\Switcher;
use MoonShine\UI\Fields\Text;
use MoonShine\UI\Fields\Url;
final class ArticleFormPage extends FormPage
{
protected function fields(): iterable
{
return [
ID::make(),
Grid::make([
Column::make([
Box::make('Main information', [
ActionButton::make(
'Link to article',
$this->getResource()->getItem()?->getKey() ? route('articles.show', $this->getResource()->getItem()) : '/',
)
->icon('paper-clip')
->blank(),
LineBreak::make(),
BelongsTo::make('Author', resource: MoonShineUserResource::class)
->asyncSearch()
->canSee(fn () => auth()->user()->moonshine_user_role_id === 1)
->required(),
Collapse::make('Title/Slug', [
Heading::make('Title/Slug'),
Flex::make([
Text::make('Title')
->withoutWrapper()
->required()
,
Slug::make('Slug')
->from('title')
->unique()
->separator('-')
->withoutWrapper()
->required()
,
])
->name('flex-titles')
->justifyAlign('start')
->itemsAlign('start'),
]),
StackFields::make('Files')->fields([
Image::make('Thumbnail')
->removable()
->disk('public')
->dir('articles'),
]),
Preview::make('No input field', 'no_input', static fn () => fake()->realText()),
RangeSlider::make('Age')
->min(0)
->max(60)
->step(1)
->fromTo('age_from', 'age_to'),
Number::make('Rating')
->hint('From 0 to 5')
->min(0)
->max(5)
->link('https://cutcode.dev', 'CutCode', blank: true)
->stars(),
Url::make('Link')
->hint('Url')
->link('https://cutcode.dev', 'CutCode', blank: true)
->suffix('url')
,
Color::make('Color'),
Json::make('Data')->fields([
Text::make('Title'),
Text::make('Value'),
])->creatable()->removable(),
Switcher::make('Active'),
]),
])->columnSpan(6),
Column::make([
Box::make('Seo and categories', [
Tabs::make([
Tab::make('Seo', [
Text::make('Seo title')
->withoutWrapper(),
Text::make('Seo description')
->withoutWrapper(),
TinyMce::make('Description')
->addPlugins(['code', 'codesample'])
->toolbar(' | code codesample')
->required()
,
]),
Tab::make('Categories', [
BelongsToMany::make('Categories')->tree('category_id'),
]),
]),
]),
])->columnSpan(6),
]),
$this->getCommentsField(),
$this->getCommentField(),
];
}
private function getCommentsField(): HasMany
{
return HasMany::make('Comments', resource: CommentResource::class)
->fillData($this->getResource()->getItem())
->async()
->creatable();
}
private function getCommentField(): HasOne
{
return HasOne::make('Comment', resource: CommentResource::class)
->fillData($this->getResource()->getItem())
->async();
}
protected function mainLayer(): array
{
return [
Tabs::make([
Tab::make('Basics', parent::mainLayer()),
Tab::make('Comments', [
$this->getResource()->getItem() ? $this->getCommentsField() : 'To add comments, save the article',
]),
Tab::make('Comment', [
$this->getResource()->getItem() ? $this->getCommentField() : 'To add comments, save the article',
]),
Tab::make('Table', [
TableBuilder::make()
->fields([
ID::make(),
Text::make('Text')
])
->cast(new ModelCaster(Comment::class))
->items($this->getResource()->getItem()?->comments ?? [])
]),
]),
];
}
protected function bottomLayer(): array
{
return [];
}
}
namespace App\MoonShine\Pages\Article;
use App\Models\Comment;
use App\MoonShine\Resources\CommentResource;
use App\MoonShine\Resources\MoonShineUserResource;
use MoonShine\Laravel\Fields\Relationships\BelongsTo;
use MoonShine\Laravel\Fields\Relationships\BelongsToMany;
use MoonShine\Laravel\Fields\Relationships\HasMany;
use MoonShine\Laravel\Fields\Relationships\HasOne;
use MoonShine\Laravel\Fields\Slug;
use MoonShine\Laravel\Pages\Crud\FormPage;
use MoonShine\Laravel\TypeCasts\ModelCaster;
use MoonShine\TinyMce\Fields\TinyMce;
use MoonShine\UI\Components\ActionButton;
use MoonShine\UI\Components\Collapse;
use MoonShine\UI\Components\Heading;
use MoonShine\UI\Components\Layout\Box;
use MoonShine\UI\Components\Layout\Column;
use MoonShine\UI\Components\Layout\Flex;
use MoonShine\UI\Components\Layout\Grid;
use MoonShine\UI\Components\Layout\LineBreak;
use MoonShine\UI\Components\Table\TableBuilder;
use MoonShine\UI\Components\Tabs;
use MoonShine\UI\Components\Tabs\Tab;
use MoonShine\UI\Fields\Color;
use MoonShine\UI\Fields\ID;
use MoonShine\UI\Fields\Image;
use MoonShine\UI\Fields\Json;
use MoonShine\UI\Fields\Number;
use MoonShine\UI\Fields\Preview;
use MoonShine\UI\Fields\RangeSlider;
use MoonShine\UI\Fields\StackFields;
use MoonShine\UI\Fields\Switcher;
use MoonShine\UI\Fields\Text;
use MoonShine\UI\Fields\Url;
final class ArticleFormPage extends FormPage
{
protected function fields(): iterable
{
return [
ID::make(),
Grid::make([
Column::make([
Box::make('Main information', [
ActionButton::make(
'Link to article',
$this->getResource()->getItem()?->getKey() ? route('articles.show', $this->getResource()->getItem()) : '/',
)
->icon('paper-clip')
->blank(),
LineBreak::make(),
BelongsTo::make('Author', resource: MoonShineUserResource::class)
->asyncSearch()
->canSee(fn () => auth()->user()->moonshine_user_role_id === 1)
->required(),
Collapse::make('Title/Slug', [
Heading::make('Title/Slug'),
Flex::make([
Text::make('Title')
->withoutWrapper()
->required()
,
Slug::make('Slug')
->from('title')
->unique()
->separator('-')
->withoutWrapper()
->required()
,
])
->name('flex-titles')
->justifyAlign('start')
->itemsAlign('start'),
]),
StackFields::make('Files')->fields([
Image::make('Thumbnail')
->removable()
->disk('public')
->dir('articles'),
]),
Preview::make('No input field', 'no_input', static fn () => fake()->realText()),
RangeSlider::make('Age')
->min(0)
->max(60)
->step(1)
->fromTo('age_from', 'age_to'),
Number::make('Rating')
->hint('From 0 to 5')
->min(0)
->max(5)
->link('https://cutcode.dev', 'CutCode', blank: true)
->stars(),
Url::make('Link')
->hint('Url')
->link('https://cutcode.dev', 'CutCode', blank: true)
->suffix('url')
,
Color::make('Color'),
Json::make('Data')->fields([
Text::make('Title'),
Text::make('Value'),
])->creatable()->removable(),
Switcher::make('Active'),
]),
])->columnSpan(6),
Column::make([
Box::make('Seo and categories', [
Tabs::make([
Tab::make('Seo', [
Text::make('Seo title')
->withoutWrapper(),
Text::make('Seo description')
->withoutWrapper(),
TinyMce::make('Description')
->addPlugins(['code', 'codesample'])
->toolbar(' | code codesample')
->required()
,
]),
Tab::make('Categories', [
BelongsToMany::make('Categories')->tree('category_id'),
]),
]),
]),
])->columnSpan(6),
]),
$this->getCommentsField(),
$this->getCommentField(),
];
}
private function getCommentsField(): HasMany
{
return HasMany::make('Comments', resource: CommentResource::class)
->fillData($this->getResource()->getItem())
->async()
->creatable();
}
private function getCommentField(): HasOne
{
return HasOne::make('Comment', resource: CommentResource::class)
->fillData($this->getResource()->getItem())
->async();
}
protected function mainLayer(): array
{
return [
Tabs::make([
Tab::make('Basics', parent::mainLayer()),
Tab::make('Comments', [
$this->getResource()->getItem() ? $this->getCommentsField() : 'To add comments, save the article',
]),
Tab::make('Comment', [
$this->getResource()->getItem() ? $this->getCommentField() : 'To add comments, save the article',
]),
Tab::make('Table', [
TableBuilder::make()
->fields([
ID::make(),
Text::make('Text')
])
->cast(new ModelCaster(Comment::class))
->items($this->getResource()->getItem()?->comments ?? [])
]),
]),
];
}
protected function bottomLayer(): array
{
return [];
}
}
final class ArticleFormPage extends FormPage
{
protected function fields(): iterable
{
return [
ID::make(),
$this->getCommentsField(),
$this->getCommentField(),
];
}
private function getCommentsField(): HasMany
{
return HasMany::make('Comments', resource: CommentResource::class)
->fillData($this->getResource()->getItem())
->async()
->creatable();
}
private function getCommentField(): HasOne
{
return HasOne::make('Comment', resource: CommentResource::class)
->fillData($this->getResource()->getItem())
->async();
}
protected function mainLayer(): array
{
return [
Tabs::make([
Tab::make('Basics', parent::mainLayer()),
Tab::make('Comments', [
$this->getResource()->getItem() ? $this->getCommentsField() : 'To add comments, save the article',
]),
Tab::make('Comment', [
$this->getResource()->getItem() ? $this->getCommentField() : 'To add comments, save the article',
]),
Tab::make('Table', [
TableBuilder::make()
->fields([
ID::make(),
Text::make('Text')
])
->cast(new ModelCaster(Comment::class))
->items($this->getResource()->getItem()?->comments ?? [])
]),
]),
];
}
protected function bottomLayer(): array
{
return [];
}
}
final class ArticleFormPage extends FormPage
{
protected function fields(): iterable
{
return [
ID::make(),
// ...
$this->getCommentsField(),
$this->getCommentField(),
];
}
private function getCommentsField(): HasMany
{
return HasMany::make('Comments', resource: CommentResource::class)
->fillData($this->getResource()->getItem())
->async()
->creatable();
}
private function getCommentField(): HasOne
{
return HasOne::make('Comment', resource: CommentResource::class)
->fillData($this->getResource()->getItem())
->async();
}
protected function mainLayer(): array
{
return [
Tabs::make([
Tab::make('Basics', parent::mainLayer()),
Tab::make('Comments', [
$this->getResource()->getItem() ? $this->getCommentsField() : 'To add comments, save the article',
]),
Tab::make('Comment', [
$this->getResource()->getItem() ? $this->getCommentField() : 'To add comments, save the article',
]),
Tab::make('Table', [
TableBuilder::make()
->fields([
ID::make(),
Text::make('Text')
])
->cast(new ModelCaster(Comment::class))
->items($this->getResource()->getItem()?->comments ?? [])
]),
]),
];
}
protected function bottomLayer(): array
{
return [];
}
}
final class ArticleFormPage extends FormPage
{
protected function fields(): iterable
{
return [
ID::make(),
// ...
$this->getCommentsField(),
$this->getCommentField(),
];
}
private function getCommentsField(): HasMany
{
return HasMany::make('Comments', resource: CommentResource::class)
->fillData($this->getResource()->getItem())
->async()
->creatable();
}
private function getCommentField(): HasOne
{
return HasOne::make('Comment', resource: CommentResource::class)
->fillData($this->getResource()->getItem())
->async();
}
protected function mainLayer(): array
{
return [
Tabs::make([
Tab::make('Basics', parent::mainLayer()),
Tab::make('Comments', [
$this->getResource()->getItem() ? $this->getCommentsField() : 'To add comments, save the article',
]),
Tab::make('Comment', [
$this->getResource()->getItem() ? $this->getCommentField() : 'To add comments, save the article',
]),
Tab::make('Table', [
TableBuilder::make()
->fields([
ID::make(),
Text::make('Text')
])
->cast(new ModelCaster(Comment::class))
->items($this->getResource()->getItem()?->comments ?? [])
]),
]),
];
}
protected function bottomLayer(): array
{
return [];
}
}
final class ArticleFormPage extends FormPage
{
protected function fields(): iterable
{
return [
ID::make(),
// ...
$this->getCommentsField(),
$this->getCommentField(),
];
}
private function getCommentsField(): HasMany
{
return HasMany::make('Comments', resource: CommentResource::class)
->fillData($this->getResource()->getItem())
->async()
->creatable();
}
private function getCommentField(): HasOne
{
return HasOne::make('Comment', resource: CommentResource::class)
->fillData($this->getResource()->getItem())
->async();
}
protected function mainLayer(): array
{
return [
Tabs::make([
Tab::make('Basics', parent::mainLayer()),
Tab::make('Comments', [
$this->getResource()->getItem() ? $this->getCommentsField() : 'To add comments, save the article',
]),
Tab::make('Comment', [
$this->getResource()->getItem() ? $this->getCommentField() : 'To add comments, save the article',
]),
Tab::make('Table', [
TableBuilder::make()
->fields([
ID::make(),
Text::make('Text')
])
->cast(new ModelCaster(Comment::class))
->items($this->getResource()->getItem()?->comments ?? [])
]),
]),
];
}
protected function bottomLayer(): array
{
return [];
}
}
final class ArticleFormPage extends FormPage
{
protected function fields(): iterable
{
return [
ID::make(),
// ...
$this->getCommentsField(),
$this->getCommentField(),
];
}
private function getCommentsField(): HasMany
{
return HasMany::make('Comments', resource: CommentResource::class)
->fillData($this->getResource()->getItem())
->async()
->creatable();
}
private function getCommentField(): HasOne
{
return HasOne::make('Comment', resource: CommentResource::class)
->fillData($this->getResource()->getItem())
->async();
}
protected function mainLayer(): array
{
return [
Tabs::make([
Tab::make('Basics', parent::mainLayer()),
Tab::make('Comments', [
$this->getResource()->getItem() ? $this->getCommentsField() : 'To add comments, save the article',
]),
Tab::make('Comment', [
$this->getResource()->getItem() ? $this->getCommentField() : 'To add comments, save the article',
]),
Tab::make('Table', [
TableBuilder::make()
->fields([
ID::make(),
Text::make('Text')
])
->cast(new ModelCaster(Comment::class))
->items($this->getResource()->getItem()?->comments ?? [])
]),
]),
];
}
protected function bottomLayer(): array
{
return [];
}
}