diff --git a/actions.md b/actions.md index 9ccf594..4b1bead 100644 --- a/actions.md +++ b/actions.md @@ -87,30 +87,14 @@ $action->authorize(static function (Request $request): bool { ### Visibility -You may show or hide actions based on the current resource view. For example, some actions might be visible on the index page, while others should be hidden. You can easily customize the action visibility logic using the `visibleOn` and `hiddenOn` methods: +You may show or hide actions based on the current resource view. For example, some actions might be visible on the `index` page, while others should be hidden. You can easily customize the action visibility logic using the `visibleOn` and `hiddenOn` methods: ```php -$action->visibleOn(static function (Request $request): bool { - return $request->user()->can('batchPublish', Post::class); -}); - -$action->hiddenOn(static function (Request $request): bool { - return $request->user()->cannot('batchPublish', Post::class); -}); -``` - -Also, you can use the built-in methods as well: - -```php -$action->visibleOnIndex(); -$action->visibleOnShow(); +$field->visibleOn(['index', 'show']); -$action->hiddenOnIndex(); -$action->hiddenOnShow(); +$field->hiddenOn(['update', 'create']); ``` -> Note, actions are using the `ResolvesVisibility` trait, but methods like `visibleOnUpdate()` have no effect. - ### Destructive Actions You may mark an action as destructive. That means, the `Run` button that performs the action becomes red, indicating it is a dangerous action to run. @@ -126,3 +110,11 @@ You may mark an action as confirmable. That means, when pressing the `Run` butto ```php $action->confirmable(); ``` + +### Standalone Actions + +You may mark an action as standalone. That means, the action does not need any selected models. Also, the `$models` collection in the `handle` method will be empty. + +```php +$action->standalone(); +``` diff --git a/bazar.md b/bazar.md new file mode 100644 index 0000000..cfd454b --- /dev/null +++ b/bazar.md @@ -0,0 +1,5 @@ +--- +title: "Bazar" +github: "https://github.com/conedevelopment/root-docs/blob/master/bazar.md" +order: 11 +--- diff --git a/contribution.md b/contribution.md index b71c114..d6c3afa 100644 --- a/contribution.md +++ b/contribution.md @@ -1,5 +1,5 @@ --- title: "Contributing to Root" github: "https://github.com/conedevelopment/root-docs/blob/master/contribution.md" -order: 11 +order: 12 --- diff --git a/core-concepts.md b/core-concepts.md index bc07d13..b46e7ec 100644 --- a/core-concepts.md +++ b/core-concepts.md @@ -16,6 +16,4 @@ However, it comes with a price: Root is scoped to small, medium-sized projects: ## Comparing to other packages, solutions -Root is heavily inspired by [Symfony EasyAdmin](https://symfony.com/bundles/EasyAdminBundle/current/index.html) and [Laravel Nova](https://nova.laravel.com/). - -Root is targeting smaller applications and offers simpler and faster integration into your running or fresh application. But for very large applications you may consider using Nova. Nova has a big community and first-party support since it's maintained by the Laravel team. Also, it has some features (Queueable Actions, Vapor and Scout support for example) that we don't and probably won't support in the future. +Root is targeting smaller applications and offers simpler and faster integration into your running or fresh application. diff --git a/fields.md b/fields.md index 47339b2..f5db49f 100644 --- a/fields.md +++ b/fields.md @@ -24,15 +24,12 @@ use Illuminate\Http\Request; /** * Define the fields for the resource. - * - * @param \Illuminate\Http\Request $request - * @return array */ public function fields(Request $request): array { - return array_merge(parent::fields($request), [ + return [ Text::make(__('Title'), 'title'), - ]); + ]; } ``` @@ -41,17 +38,14 @@ Alternatively, you can use `withFields` method on an object that resolves action ```php use App\Root\Fields\Text; use Illuminate\Http\Request; -use Cone\Root\Support\Collections\Fields; -$resource->withFields(static function (Request $request, Fields $fields): Fields { - return $fields->merge([ +$resource->withFields(static function (Request $request): array { + return [ Text::make(__('Title'), 'title'), - ]); + ]; }); ``` -> You can also pass an `array` instead of a `Closure`. In that case the array will be merged into the collection. - ### Configuration ### Value Resolution @@ -66,7 +60,7 @@ use Illuminate\Databsase\Eloquent\Model; use Illuminate\Http\Request; Text::make('Title') - ->default(static function (Request $request, Model $model, mixed $value): string { + ->value(static function (Request $request, Model $model, mixed $value): string { return is_null($value) ? 'foo' : $value; }); ``` @@ -81,10 +75,11 @@ You may define custom value formatters for the field values. In that case you ca use Cone\Root\Fields\Number; use Illuminate\Databsase\Eloquent\Model; use Illuminate\Http\Request; +use Illuminate\Support\Number; Number::make('Price') ->format(static function (Request $request, Model $model, mixed $value): string { - return sprintf('%d USD', $value); + return Number::currency($value); }); ``` @@ -103,11 +98,6 @@ class CustomField extends Field { /** * Hydrate the model. - * - * @param \Illuminate\Http\Request $request - * @param \Illuminate\Database\Eloquent\Model $model - * @param mixed $value - * @return void */ public function hydrate(Request $request, Model $model, mixed $value): void { @@ -157,50 +147,12 @@ $field->authorize(static function (Request $request, ?Model $model = null, ?Mode ### Visibility -You may show or hide fields based on the current resource view. For example, some fields might be visible on the index page, while others should be hidden. You can easily customize the field visibility logic using the `visible` method: +You may show or hide fields based on the current resource view. For example, some fields might be visible on the `index` page, while others should be hidden. You can easily customize the action visibility logic using the `visibleOn` and `hiddenOn` methods: ```php -use Illuminate\Http\Request; - -$field->visibleOn(static function (Request $request): bool { - return $request->user()->isAdmin(); -}); +$field->visibleOn(['index', 'show']); -$field->hiddenOn(static function (Request $request): bool { - return ! $request->user()->isAdmin(); -}); -``` - -Also, you can use the built-in methods as well. They are enough in most of the cases: - -```php -$field->visibleOnIndex(); -$field->visibleOnCreate(); -$field->visibleOnShow(); -$field->visibleOnUpdate(); -$field->visibleOnDisplay(); -$field->visibleOnForm(); - -$field->hiddenOnIndex(); -$field->hiddenOnCreate(); -$field->hiddenOnShow(); -$field->hiddenOnUpdate(); -$field->hiddenOnDisplay(); -$field->hiddenOnForm(); -``` - -You can also pass a `Closure` to any of the listed methods, to fully customize the visibility logic: - -```php -use Illuminate\Http\Request; - -$this->visible(static function (Request $request): bool { - return $request->user()->can('attachTag', Post::class); -}); - -$this->hidden(static function (Request $request): bool { - return $request->user()->cannot('attachTag', Post::class); -}); +$field->hiddenOn(['update', 'create']); ``` ### Validation @@ -208,8 +160,8 @@ $this->hidden(static function (Request $request): bool { You may define validation rules for your field instances. To do so, you can call the `rules`, `createRules` and `updateRules` on the field instance: ```php -use Illuminate\Http\Request; use Illuminate\Database\Eloquent\Model; +use Illuminate\Http\Request; use Illuminate\Validation\Rule; $field->rules(['string', 'required']) @@ -251,8 +203,6 @@ $field->searchable(false); ### ID -### Json - ### Media ### Number diff --git a/filters.md b/filters.md index 6fb52c5..7dde765 100644 --- a/filters.md +++ b/filters.md @@ -24,9 +24,6 @@ use Illuminate\Http\Request; /** * Define the filters for the resource. - * - * @param \Illuminate\Http\Request $request - * @return array */ public function filters(Request $request): array { @@ -43,15 +40,13 @@ use App\Root\Filters\Category; use Cone\Root\Support\Collections\Filters; use Illuminate\Http\Request; -$resource->withFilters(static function (Request $request, Filters $filters): Filters { - return $filters->merge([ +$resource->withFilters(static function (Request $request): array { + return [ Category::make(), - ]); + ]; }); ``` -> You can also pass an `array` instead of a `Closure`. In that case the array will be merged into the collection. - ## Configuration ### Options @@ -69,11 +64,6 @@ class Category extends Filter { /** * Apply the filter on the query. - * - * @param \Illuminate\Http\Request $request - * @param \Illuminate\Database\Eloquent\Builder $query - * @param mixed $value - * @return \Illuminate\Database\Eloquent\Builder */ public function apply(Request $request, Builder $query, mixed $value): Builder { @@ -82,9 +72,6 @@ class Category extends Filter /** * Get the filter options. - * - * @param \Illuminate\Http\Request $request - * @return array */ public function options(Request $request): array { @@ -102,30 +89,6 @@ Also, you may configure a select filter with multiple selectable choices. To do Category::make()->multiple(); ``` -### Custom Components - -By default, filters use the `Select` form component, however you can use any component you want. You may also register your own custom component as well: - -```js -document.addEventListener('root:booting', ({ detail }) => { - detail.app.component('CustomFilter', require('./Components/CustomFilter').defaul); -}); -``` - -```php -use Cone\Root\Filters\Filter; - -class CustomFilter extends Filter -{ - /** - * The Vue component. - * - * @var string|null - */ - protected ?string $component = 'CustomFilter'; -} -``` - ### Functional Filters Also, in some cases you may interact with the Query Builder in a filter, but you don't want to render any component for it on the front-end. In that case, you may use functional components. For functional components the `$component` property is set to `null`: diff --git a/widgets.md b/widgets.md index bdec2a8..0a4a4a1 100644 --- a/widgets.md +++ b/widgets.md @@ -24,9 +24,6 @@ use Illuminate\Http\Request; /** * Define the widgets for the resource. - * - * @param \Illuminate\Http\Request $request - * @return array */ public function widgets(Request $request): array { @@ -69,23 +66,9 @@ $widget->authorize(static function (Request $request): bool { You may show or hide widgets based on the current resource view. For example, some widgets might be visible on the index page, while others should be hidden. You can easily customize the action visibility logic using the `visibleOn` and `hiddenOn` methods: ```php -$widget->visibleOn(static function (Request $request): bool { - return $request->user()->can('viewPostCount'); -}); - -$widget->hiddenOn(static function (Request $request): bool { - return $request->user()->cannot('viewPostCount'); -}); -``` +$field->visibleOn(['index']); -Also, you can use the built-in methods as well: - -```php -$widget->visibleOnIndex(); -$widget->visibleOnShow(); - -$widget->hiddenOnIndex(); -$widget->hiddenOnShow(); +$field->hiddenOn(['index']); ``` ### Blade Templates @@ -99,8 +82,6 @@ class PostCount extends Widget { /** * The Blade template. - * - * @var string */ protected string $template = 'widgets.post-count; } @@ -112,71 +93,19 @@ You can customize the data passed to the blade template by using the `data` meth ```php use App\Models\Post; -use Illuminate\Http\Request; use Cone\Root\Widgets\Widget; +use Illuminate\Http\Request; class PostCount extends Widget { /** * Get the data. - * - * @param \Illuminate\Http\Request $request - * @return array */ public function data(Request $request): array { - return [ + return array_merge(parent::data($request), [ 'count' => Post::query()->count(), - ]; + ]); } } ``` - -Alternatively, you can use `with` method on a widget. It can be useful when you just want to hook into the object for some reason. - -```php -use App\Models\Post; -use Illuminate\Http\Request; - -$widget->with(static function (Request $request): array { - return [ - 'published_count' => Post::query()->published()->count(), - ]; -}); -``` - -> You can also pass an `array` instead of a `Closure`. - -### Custom Components - -By default, widget use the `Widget` component, however you can use any component you want. You may also register your own custom component as well: - -```js -document.addEventListener('root:booting', ({ detail }) => { - detail.app.component('CustomWidget', require('./Components/CustomWidget').defaul); -}); -``` - -```php -use Cone\Root\Widgets\Widget; - -class PostCount extends Widget -{ - /** - * The Vue component. - * - * @var string|null - */ - protected string $component = 'CustomWidget'; -} -``` - -### Async Widgets - -In some scenarios, you may want your widget to be asynchronously loaded. For example, when the rendered template generates a huge chunk of data, you may want to load the component in another HTTP request. To do so, call the `ąsyc` method on the widget instance: - -```php -PostCount::make()->async(); -``` - -> Please note, all the routes for the asnyc widgets will be registered automatically.