diff --git a/resources/views/dashboard.blade.php b/resources/views/dashboard.blade.php index 71413623..dfd6f0fa 100644 --- a/resources/views/dashboard.blade.php +++ b/resources/views/dashboard.blade.php @@ -7,7 +7,7 @@ @section('content')
@foreach($widgets as $widget) - {!! $widget !!} + @include($widget['template'], $widget) @endforeach
@endsection diff --git a/resources/views/resources/index.blade.php b/resources/views/resources/index.blade.php index 9a42d0d2..001ea0c0 100644 --- a/resources/views/resources/index.blade.php +++ b/resources/views/resources/index.blade.php @@ -18,7 +18,7 @@ @if(! empty($widgets))
@foreach($widgets as $widget) - {!! $widget !!} + @include($widget['template'], $widget) @endforeach
@endif diff --git a/src/Actions/Action.php b/src/Actions/Action.php index 55386ee7..fef18a6b 100644 --- a/src/Actions/Action.php +++ b/src/Actions/Action.php @@ -91,14 +91,6 @@ public function getModalKey(): string return sprintf('action-%s', $this->getKey()); } - /** - * Get the Blade template. - */ - public function getTemplate(): string - { - return $this->template; - } - /** * Set the Eloquent query. */ @@ -213,7 +205,7 @@ public function toArray(): array 'key' => $this->getKey(), 'modalKey' => $this->getModalKey(), 'name' => $this->getName(), - 'template' => $this->getTemplate(), + 'template' => $this->template, 'url' => $this->getUri(), ]; } diff --git a/src/Fields/Editor.php b/src/Fields/Editor.php index 0119d8f1..f6156515 100644 --- a/src/Fields/Editor.php +++ b/src/Fields/Editor.php @@ -14,10 +14,10 @@ class Editor extends Field { + use ResolvesFields; use RegistersRoutes { RegistersRoutes::registerRoutes as __registerRoutes; } - use ResolvesFields; /** * The Blade template. @@ -43,6 +43,7 @@ public function __construct(string $label, string $modelAttribute = null) $this->config = Config::get('root.editor', []); $this->height('350px'); + $this->hiddenOn(['index']); } /** diff --git a/src/Fields/Field.php b/src/Fields/Field.php index dce6f015..9dbfc7c9 100644 --- a/src/Fields/Field.php +++ b/src/Fields/Field.php @@ -128,14 +128,6 @@ public function __construct(string $label, string $modelAttribute = null) $this->setAttribute('class', 'form-control'); } - /** - * Get the template. - */ - public function getTemplate(): string - { - return $this->template; - } - /** * Get the model attribute. */ @@ -538,7 +530,7 @@ public function toArray(): array 'label' => $this->label, 'prefix' => $this->prefix, 'suffix' => $this->suffix, - 'template' => $this->getTemplate(), + 'template' => $this->template, 'searchable' => $this->isSearchable(), 'sortable' => $this->isSortable(), ]; diff --git a/src/Fields/ID.php b/src/Fields/ID.php index fee71343..4bd1d5e8 100644 --- a/src/Fields/ID.php +++ b/src/Fields/ID.php @@ -10,5 +10,7 @@ class ID extends Field public function __construct(string $label = 'ID', string $modelAttribute = 'id') { parent::__construct($label, $modelAttribute); + + $this->hiddenOn(['crate', 'update']); } } diff --git a/src/Fields/Meta.php b/src/Fields/Meta.php index 2d0e7703..22537794 100644 --- a/src/Fields/Meta.php +++ b/src/Fields/Meta.php @@ -55,14 +55,14 @@ public function as(string $field, Closure $callback = null): static { $this->field = new $field($this->label, $this->getModelAttribute()); - if (! is_null($callback)) { - call_user_func_array($callback, [$this->field]); - } - $this->field->value(function (Request $request, Model $model): mixed { return $this->resolveValue($request, $model); }); + if (! is_null($callback)) { + call_user_func_array($callback, [$this->field]); + } + return $this; } @@ -249,6 +249,14 @@ public function toArray(): array return $this->field->toArray(); } + /** + * {@inheritdoc} + */ + public function toDisplay(Request $request, Model $model): array + { + return $this->field->toDisplay($request, $model); + } + /** * {@inheritdoc} */ diff --git a/src/Fields/Relation.php b/src/Fields/Relation.php index 92749e83..b72e7825 100644 --- a/src/Fields/Relation.php +++ b/src/Fields/Relation.php @@ -201,6 +201,30 @@ public function getValue(Model $model): mixed return $model->getAttribute($name); } + /** + * {@inheritdoc} + */ + public function resolveFormat(Request $request, Model $model): mixed + { + if (is_null($this->formatResolver)) { + $this->formatResolver = function (Request $request, Model $model): mixed { + $default = $this->getValue($model); + + if ($default instanceof Model) { + return $this->resolveDisplay($default); + } elseif ($default instanceof Collection) { + return $default->map(function (Model $related): mixed { + return $this->resolveDisplay($related); + })->join(', '); + } + + return $default; + }; + } + + return parent::resolveFormat($request, $model); + } + /** * Set the query resolver. */ diff --git a/src/Http/Controllers/DashboardController.php b/src/Http/Controllers/DashboardController.php index 57d07e1b..258cf5c8 100644 --- a/src/Http/Controllers/DashboardController.php +++ b/src/Http/Controllers/DashboardController.php @@ -15,7 +15,7 @@ class DashboardController extends Controller public function __invoke(Request $request, Root $root): Response { return ResponseFactory::view('root::dashboard', [ - 'widgets' => $root->widgets->all(), + 'widgets' => $root->widgets->toArray(), ]); } } diff --git a/src/Resources/Resource.php b/src/Resources/Resource.php index d6eccbde..1c362c06 100644 --- a/src/Resources/Resource.php +++ b/src/Resources/Resource.php @@ -274,7 +274,10 @@ public function paginate(Request $request): LengthAwarePaginator 'id' => $model->getKey(), 'url' => $this->modelUrl($model), 'model' => $model, - 'fields' => $this->resolveFields($request)->mapToDisplay($request, $model), + 'fields' => $this->resolveFields($request) + ->authorized($request, $model) + ->visible('index') + ->mapToDisplay($request, $model), ]; }); } @@ -315,11 +318,18 @@ public function toIndex(Request $request): array { return array_merge($this->toArray(), [ 'title' => $this->getName(), - 'actions' => $this->resolveActions($request)->mapToForms($request), + 'actions' => $this->resolveActions($request) + ->authorized($request) + ->visible('index') + ->mapToForms($request), 'data' => $this->paginate($request), - 'widgets' => $this->resolveWidgets($request)->all(), + 'widgets' => $this->resolveWidgets($request) + ->authorized($request) + ->visible('index') + ->toArray(), 'perPageOptions' => $this->getPerPageOptions(), 'filters' => $this->resolveFilters($request) + ->authorized($request) ->renderable() ->map(function (RenderableFilter $filter) use ($request): array { return $filter->toField()->toInput($request, $this->getModelInstance()); @@ -339,7 +349,10 @@ public function toCreate(Request $request): array 'model' => $model = $this->getModelInstance(), 'action' => $this->getUri(), 'method' => 'POST', - 'fields' => $this->resolveFields($request)->mapToInputs($request, $model), + 'fields' => $this->resolveFields($request) + ->authorized($request, $model) + ->visible('update') + ->mapToInputs($request, $model), ]); } @@ -349,11 +362,14 @@ public function toCreate(Request $request): array public function toEdit(Request $request, Model $model): array { return array_merge($this->toArray(), [ - 'title' => '', + 'title' => __('Edit :model', ['model' => sprintf('%s #%s', $this->getModelName(), $model->getKey())]), 'model' => $model, 'action' => $this->modelUrl($model), 'method' => 'PATCH', - 'fields' => $this->resolveFields($request)->mapToInputs($request, $model), + 'fields' => $this->resolveFields($request) + ->authorized($request, $model) + ->visible('update') + ->mapToInputs($request, $model), ]); } } diff --git a/src/Widgets/Widget.php b/src/Widgets/Widget.php index 4aedd984..6f14bfe6 100644 --- a/src/Widgets/Widget.php +++ b/src/Widgets/Widget.php @@ -2,15 +2,20 @@ namespace Cone\Root\Widgets; -use Cone\Root\Support\Element; use Cone\Root\Traits\Authorizable; +use Cone\Root\Traits\HasAttributes; use Cone\Root\Traits\Makeable; +use Cone\Root\Traits\ResolvesVisibility; +use Illuminate\Contracts\Support\Arrayable; use Illuminate\Support\Str; +use JsonSerializable; -abstract class Widget extends Element +abstract class Widget implements Arrayable, JsonSerializable { use Authorizable; + use HasAttributes; use Makeable; + use ResolvesVisibility; /** * The Blade template. @@ -33,14 +38,24 @@ public function getName(): string return __(Str::of(static::class)->classBasename()->headline()->value()); } + /** + * Convert the element to a JSON serializable format. + */ + public function jsonSerialize(): mixed + { + return $this->toArray(); + } + /** * Convert the widget to an array. */ public function toArray(): array { return [ + 'attrs' => $this->newAttributeBag(), 'key' => $this->getKey(), 'name' => $this->getName(), + 'template' => $this->template, ]; } } diff --git a/src/Widgets/Widgets.php b/src/Widgets/Widgets.php index bff732c2..e559d0b9 100644 --- a/src/Widgets/Widgets.php +++ b/src/Widgets/Widgets.php @@ -2,56 +2,38 @@ namespace Cone\Root\Widgets; +use Illuminate\Database\Eloquent\Model; +use Illuminate\Http\Request; use Illuminate\Support\Arr; use Illuminate\Support\Collection; -use Illuminate\Support\Traits\ForwardsCalls; -class Widgets +class Widgets extends Collection { - use ForwardsCalls; - - /** - * The widgets collection. - */ - protected Collection $widgets; - - /** - * Create a new widgets instance. - */ - public function __construct(array $widgets = []) - { - $this->widgets = new Collection($widgets); - } - /** * Register the given widgets. */ public function register(array|Widget $widgets): static { foreach (Arr::wrap($widgets) as $widget) { - $this->widgets->push($widget); + $this->push($widget); } return $this; } /** - * Make a new widget instance. + * Filter the fields that are available for the current request and model. */ - public function widget(string $widget, ...$params): Widget + public function authorized(Request $request, Model $model = null): static { - $instance = new $widget(...$params); - - $this->register($instance); - - return $instance; + return $this->filter->authorized($request, $model)->values(); } /** - * Handle the dynamic method call. + * Filter the fields that are visible in the given context. */ - public function __call($method, $parameters): mixed + public function visible(string|array $context): static { - return $this->forwardCallTo($this->widgets, $method, $parameters); + return $this->filter->visible($context)->values(); } }