mirror of
https://github.com/filamentphp/filament.git
synced 2026-09-24 15:42:09 +08:00
fix: Nested infolist actions
This commit is contained in:
@@ -57,65 +57,6 @@
|
||||
@endphp
|
||||
@endif
|
||||
|
||||
@if ($this instanceof \Filament\Infolists\Contracts\HasInfolists && (! $this->hasInfolistsModalRendered))
|
||||
<form wire:submit.prevent="callMountedInfolistAction">
|
||||
@php
|
||||
$action = $this->getMountedInfolistAction();
|
||||
@endphp
|
||||
|
||||
<x-filament::modal
|
||||
:alignment="$action?->getModalAlignment()"
|
||||
:close-button="$action?->hasModalCloseButton()"
|
||||
:close-by-clicking-away="$action?->isModalClosedByClickingAway()"
|
||||
:description="$action?->getModalDescription()"
|
||||
display-classes="block"
|
||||
:footer-actions="$action?->getVisibleModalFooterActions()"
|
||||
:footer-actions-alignment="$action?->getModalFooterActionsAlignment()"
|
||||
:heading="$action?->getModalHeading()"
|
||||
:icon="$action?->getModalIcon()"
|
||||
:icon-color="$action?->getModalIconColor()"
|
||||
:id="$this->getId() . '-infolist-action'"
|
||||
:slide-over="$action?->isModalSlideOver()"
|
||||
:sticky-footer="$action?->isModalFooterSticky()"
|
||||
:sticky-header="$action?->isModalHeaderSticky()"
|
||||
:visible="filled($action)"
|
||||
:width="$action?->getModalWidth()"
|
||||
:wire:key="$action ? $this->getId() . '.infolist.actions.' . $action->getName() . '.modal' : null"
|
||||
x-on:closed-form-component-action-modal.window="if (($event.detail.id === '{{ $this->getId() }}') && $wire.mountedInfolistActions.length) open()"
|
||||
x-on:modal-closed.stop="
|
||||
const mountedInfolistActionShouldOpenModal = {{ \Illuminate\Support\Js::from($action && $this->mountedInfolistActionShouldOpenModal()) }}
|
||||
|
||||
if (! mountedInfolistActionShouldOpenModal) {
|
||||
return
|
||||
}
|
||||
|
||||
if ($wire.mountedFormComponentActions.length) {
|
||||
return
|
||||
}
|
||||
|
||||
$wire.unmountInfolistAction(false)
|
||||
"
|
||||
x-on:opened-form-component-action-modal.window="if ($event.detail.id === '{{ $this->getId() }}') close()"
|
||||
>
|
||||
@if ($action)
|
||||
{{ $action->getModalContent() }}
|
||||
|
||||
@if (count(($infolist = $action->getInfolist())?->getComponents() ?? []))
|
||||
{{ $infolist }}
|
||||
@elseif ($this->mountedInfolistActionHasForm())
|
||||
{{ $this->getMountedInfolistActionForm() }}
|
||||
@endif
|
||||
|
||||
{{ $action->getModalContentFooter() }}
|
||||
@endif
|
||||
</x-filament::modal>
|
||||
</form>
|
||||
|
||||
@php
|
||||
$this->hasInfolistsModalRendered = true;
|
||||
@endphp
|
||||
@endif
|
||||
|
||||
@if ($this instanceof \Filament\Tables\Contracts\HasTable && (! $this->hasTableModalRendered))
|
||||
<form wire:submit.prevent="callMountedTableAction">
|
||||
@php
|
||||
@@ -228,6 +169,65 @@
|
||||
@endphp
|
||||
@endif
|
||||
|
||||
@if ($this instanceof \Filament\Infolists\Contracts\HasInfolists && (! $this->hasInfolistsModalRendered))
|
||||
<form wire:submit.prevent="callMountedInfolistAction">
|
||||
@php
|
||||
$action = $this->getMountedInfolistAction();
|
||||
@endphp
|
||||
|
||||
<x-filament::modal
|
||||
:alignment="$action?->getModalAlignment()"
|
||||
:close-button="$action?->hasModalCloseButton()"
|
||||
:close-by-clicking-away="$action?->isModalClosedByClickingAway()"
|
||||
:description="$action?->getModalDescription()"
|
||||
display-classes="block"
|
||||
:footer-actions="$action?->getVisibleModalFooterActions()"
|
||||
:footer-actions-alignment="$action?->getModalFooterActionsAlignment()"
|
||||
:heading="$action?->getModalHeading()"
|
||||
:icon="$action?->getModalIcon()"
|
||||
:icon-color="$action?->getModalIconColor()"
|
||||
:id="$this->getId() . '-infolist-action'"
|
||||
:slide-over="$action?->isModalSlideOver()"
|
||||
:sticky-footer="$action?->isModalFooterSticky()"
|
||||
:sticky-header="$action?->isModalHeaderSticky()"
|
||||
:visible="filled($action)"
|
||||
:width="$action?->getModalWidth()"
|
||||
:wire:key="$action ? $this->getId() . '.infolist.actions.' . $action->getName() . '.modal' : null"
|
||||
x-on:closed-form-component-action-modal.window="if (($event.detail.id === '{{ $this->getId() }}') && $wire.mountedInfolistActions.length) open()"
|
||||
x-on:modal-closed.stop="
|
||||
const mountedInfolistActionShouldOpenModal = {{ \Illuminate\Support\Js::from($action && $this->mountedInfolistActionShouldOpenModal()) }}
|
||||
|
||||
if (! mountedInfolistActionShouldOpenModal) {
|
||||
return
|
||||
}
|
||||
|
||||
if ($wire.mountedFormComponentActions.length) {
|
||||
return
|
||||
}
|
||||
|
||||
$wire.unmountInfolistAction(false)
|
||||
"
|
||||
x-on:opened-form-component-action-modal.window="if ($event.detail.id === '{{ $this->getId() }}') close()"
|
||||
>
|
||||
@if ($action)
|
||||
{{ $action->getModalContent() }}
|
||||
|
||||
@if (count(($infolist = $action->getInfolist())?->getComponents() ?? []))
|
||||
{{ $infolist }}
|
||||
@elseif ($this->mountedInfolistActionHasForm())
|
||||
{{ $this->getMountedInfolistActionForm() }}
|
||||
@endif
|
||||
|
||||
{{ $action->getModalContentFooter() }}
|
||||
@endif
|
||||
</x-filament::modal>
|
||||
</form>
|
||||
|
||||
@php
|
||||
$this->hasInfolistsModalRendered = true;
|
||||
@endphp
|
||||
@endif
|
||||
|
||||
@if (! $this->hasFormsModalRendered)
|
||||
@php
|
||||
$action = $this->getMountedFormComponentAction();
|
||||
|
||||
@@ -84,4 +84,9 @@ class Action extends MountableAction implements Contracts\Groupable, Contracts\H
|
||||
|
||||
$this->record(null);
|
||||
}
|
||||
|
||||
public function getInfolistName(): string
|
||||
{
|
||||
return 'mountedActionInfolist';
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,7 +26,14 @@ trait HasInfolist
|
||||
|
||||
public function getInfolist(): ?Infolist
|
||||
{
|
||||
$infolist = Infolist::make($this->getLivewire());
|
||||
$infolistName = $this->getInfolistName();
|
||||
|
||||
if (blank($infolistName)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$infolist = Infolist::make($this->getLivewire())
|
||||
->name($infolistName);
|
||||
|
||||
if ($this instanceof HasRecord) {
|
||||
$infolist->record($this->getRecord());
|
||||
@@ -50,4 +57,9 @@ trait HasInfolist
|
||||
|
||||
return $modifiedInfolist;
|
||||
}
|
||||
|
||||
public function getInfolistName(): ?string
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ use Closure;
|
||||
use Filament\Actions\Action;
|
||||
use Filament\Forms;
|
||||
use Filament\Forms\Form;
|
||||
use Filament\Infolists\Infolist;
|
||||
use Filament\Support\Exceptions\Cancel;
|
||||
use Filament\Support\Exceptions\Halt;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
@@ -419,4 +420,9 @@ trait InteractsWithActions
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
public function mountedActionInfolist(): Infolist
|
||||
{
|
||||
return $this->getMountedAction()->getInfolist();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@ use Filament\Notifications\Notification;
|
||||
use Filament\Support\Exceptions\Cancel;
|
||||
use Filament\Support\Exceptions\Halt;
|
||||
|
||||
class MountableAction extends StaticAction implements HasLivewire
|
||||
abstract class MountableAction extends StaticAction implements HasLivewire
|
||||
{
|
||||
use Concerns\BelongsToLivewire;
|
||||
use Concerns\CanBeMounted;
|
||||
|
||||
@@ -80,4 +80,9 @@ class Action extends MountableAction
|
||||
default => parent::resolveDefaultClosureDependencyForEvaluationByType($parameterType),
|
||||
};
|
||||
}
|
||||
|
||||
public function getInfolistName(): string
|
||||
{
|
||||
return 'mountedFormComponentActionInfolist';
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ use Closure;
|
||||
use Exception;
|
||||
use Filament\Forms\Components\Component;
|
||||
use Filament\Forms\Form;
|
||||
use Filament\Infolists\Infolist;
|
||||
use Filament\Support\Concerns\ResolvesDynamicLivewireProperties;
|
||||
use Filament\Support\Contracts\TranslatableContentDriver;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
@@ -440,4 +441,9 @@ trait InteractsWithForms
|
||||
{
|
||||
return $this->isCachingForms;
|
||||
}
|
||||
|
||||
public function mountedFormComponentActionInfolist(): Infolist
|
||||
{
|
||||
return $this->getMountedFormComponentAction()->getInfolist();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
namespace Filament\Infolists\Components\Actions;
|
||||
|
||||
use Exception;
|
||||
use Filament\Actions\MountableAction;
|
||||
use Filament\Actions\StaticAction;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
@@ -2,7 +2,10 @@
|
||||
|
||||
namespace Filament\Infolists\Concerns;
|
||||
|
||||
use Exception;
|
||||
use Filament\Actions\Contracts\HasActions;
|
||||
use Filament\Forms;
|
||||
use Filament\Forms\Contracts\HasForms;
|
||||
use Filament\Forms\Form;
|
||||
use Filament\Infolists\Components\Actions\Action;
|
||||
use Filament\Infolists\Components\Component;
|
||||
@@ -10,6 +13,7 @@ use Filament\Infolists\Infolist;
|
||||
use Filament\Support\Exceptions\Cancel;
|
||||
use Filament\Support\Exceptions\Halt;
|
||||
|
||||
use Filament\Tables\Contracts\HasTable;
|
||||
use function Livewire\store;
|
||||
|
||||
trait InteractsWithInfolists
|
||||
@@ -49,6 +53,10 @@ trait InteractsWithInfolists
|
||||
|
||||
$infolist = $this->{$name}($this->makeInfolist());
|
||||
|
||||
if (! ($infolist instanceof Infolist)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $this->cacheInfolist($name, $infolist);
|
||||
}
|
||||
|
||||
@@ -186,11 +194,25 @@ trait InteractsWithInfolists
|
||||
|
||||
$this->resetErrorBag();
|
||||
|
||||
$this->dispatch('open-modal', id: "{$this->getId()}-infolist-action");
|
||||
$this->openInfolistActionModal();
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
protected function openInfolistActionModal(): void
|
||||
{
|
||||
if (
|
||||
($this instanceof HasActions && count($this->mountedActions)) ||
|
||||
($this instanceof HasForms && count($this->mountedFormComponentActions)) ||
|
||||
/** @phpstan-ignore-next-line */
|
||||
($this instanceof HasTable && (count($this->mountedTableActions) || filled($this->mountedTableBulkAction)))
|
||||
) {
|
||||
throw new Exception('Currently, infolist actions cannot open modals while they are nested within other action modals.');
|
||||
}
|
||||
|
||||
$this->dispatch('open-modal', id: "{$this->getId()}-infolist-action");
|
||||
}
|
||||
|
||||
public function mountedInfolistActionShouldOpenModal(): bool
|
||||
{
|
||||
$action = $this->getMountedInfolistAction();
|
||||
@@ -293,7 +315,7 @@ trait InteractsWithInfolists
|
||||
|
||||
$this->resetErrorBag();
|
||||
|
||||
$this->dispatch('open-modal', id: "{$this->getId()}-infolist-action");
|
||||
$this->openInfolistActionModal();
|
||||
}
|
||||
|
||||
protected function makeInfolist(): Infolist
|
||||
|
||||
@@ -7,6 +7,8 @@ use Filament\Actions\Concerns\InteractsWithActions;
|
||||
use Filament\Actions\Contracts\HasActions;
|
||||
use Filament\Forms\Concerns\InteractsWithForms;
|
||||
use Filament\Forms\Contracts\HasForms;
|
||||
use Filament\Infolists\Concerns\InteractsWithInfolists;
|
||||
use Filament\Infolists\Contracts\HasInfolists;
|
||||
use Filament\Support\Enums\Alignment;
|
||||
use Filament\Support\Exceptions\Halt;
|
||||
use Illuminate\Contracts\Support\Htmlable;
|
||||
@@ -14,10 +16,11 @@ use Illuminate\Contracts\View\View;
|
||||
use Illuminate\Validation\ValidationException;
|
||||
use Livewire\Component;
|
||||
|
||||
abstract class BasePage extends Component implements HasForms, HasActions
|
||||
abstract class BasePage extends Component implements HasActions, HasForms, HasInfolists
|
||||
{
|
||||
use InteractsWithActions;
|
||||
use InteractsWithForms;
|
||||
use InteractsWithInfolists;
|
||||
|
||||
protected static string $layout = 'filament-panels::components.layout.base';
|
||||
|
||||
|
||||
@@ -19,9 +19,8 @@ use Illuminate\Database\Eloquent\Relations\Relation;
|
||||
use Illuminate\Support\Str;
|
||||
use Livewire\Attributes\Url;
|
||||
|
||||
class ListRecords extends Page implements Forms\Contracts\HasForms, Tables\Contracts\HasTable
|
||||
class ListRecords extends Page implements Tables\Contracts\HasTable
|
||||
{
|
||||
use Forms\Concerns\InteractsWithForms;
|
||||
use Tables\Concerns\InteractsWithTable {
|
||||
makeTable as makeBaseTable;
|
||||
}
|
||||
|
||||
@@ -19,12 +19,11 @@ use Illuminate\Database\Eloquent\Model;
|
||||
/**
|
||||
* @property Form $form
|
||||
*/
|
||||
class ViewRecord extends Page implements HasInfolists
|
||||
class ViewRecord extends Page
|
||||
{
|
||||
use Concerns\HasRelationManagers;
|
||||
use Concerns\InteractsWithRecord;
|
||||
use InteractsWithFormActions;
|
||||
use InteractsWithInfolists;
|
||||
|
||||
/**
|
||||
* @var view-string
|
||||
|
||||
@@ -5,6 +5,7 @@ namespace Filament\Resources\RelationManagers;
|
||||
use Filament\Actions;
|
||||
use Filament\Forms;
|
||||
use Filament\Forms\Form;
|
||||
use Filament\Infolists;
|
||||
use Filament\Infolists\Infolist;
|
||||
use Filament\Resources\Pages\ViewRecord;
|
||||
use Filament\Support\Enums\IconPosition;
|
||||
@@ -22,10 +23,11 @@ use Livewire\Component;
|
||||
|
||||
use function Filament\authorize;
|
||||
|
||||
class RelationManager extends Component implements Actions\Contracts\HasActions, Forms\Contracts\HasForms, Tables\Contracts\HasTable
|
||||
class RelationManager extends Component implements Actions\Contracts\HasActions, Infolists\Contracts\HasInfolists, Forms\Contracts\HasForms, Tables\Contracts\HasTable
|
||||
{
|
||||
use Actions\Concerns\InteractsWithActions;
|
||||
use Forms\Concerns\InteractsWithForms;
|
||||
use Infolists\Concerns\InteractsWithInfolists;
|
||||
use Tables\Concerns\InteractsWithTable {
|
||||
makeTable as makeBaseTable;
|
||||
}
|
||||
|
||||
@@ -110,4 +110,9 @@ class Action extends MountableAction implements Groupable, HasRecord, HasTable
|
||||
->table($this->getTable())
|
||||
->record($this->getRecord());
|
||||
}
|
||||
|
||||
public function getInfolistName(): string
|
||||
{
|
||||
return 'mountedTableActionInfolist';
|
||||
}
|
||||
}
|
||||
|
||||
@@ -98,4 +98,9 @@ class BulkAction extends MountableAction implements Groupable, HasTable
|
||||
|
||||
return $arguments;
|
||||
}
|
||||
|
||||
public function getInfolistName(): string
|
||||
{
|
||||
return 'mountedTableBulkActionInfolist';
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
namespace Filament\Tables\Concerns;
|
||||
|
||||
use Filament\Forms\Form;
|
||||
use Filament\Infolists\Infolist;
|
||||
use Filament\Support\Exceptions\Cancel;
|
||||
use Filament\Support\Exceptions\Halt;
|
||||
use Filament\Tables\Actions\Action;
|
||||
@@ -322,4 +323,9 @@ trait HasActions
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
public function mountedTableActionInfolist(): Infolist
|
||||
{
|
||||
return $this->getMountedTableAction()->getInfolist();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ namespace Filament\Tables\Concerns;
|
||||
|
||||
use Closure;
|
||||
use Filament\Forms\Form;
|
||||
use Filament\Infolists\Infolist;
|
||||
use Filament\Support\Exceptions\Cancel;
|
||||
use Filament\Support\Exceptions\Halt;
|
||||
use Filament\Tables\Actions\BulkAction;
|
||||
@@ -404,4 +405,9 @@ trait HasBulkActions
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
public function mountedTableBulkActionInfolist(): Infolist
|
||||
{
|
||||
return $this->getMountedTableBulkAction()->getInfolist();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,16 +4,18 @@ namespace Filament\Widgets;
|
||||
|
||||
use Filament\Actions;
|
||||
use Filament\Forms;
|
||||
use Filament\Infolists;
|
||||
use Filament\Tables;
|
||||
use Filament\Tables\Table;
|
||||
use Illuminate\Contracts\Pagination\Paginator;
|
||||
use Illuminate\Contracts\Support\Htmlable;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
|
||||
class TableWidget extends Widget implements Actions\Contracts\HasActions, Forms\Contracts\HasForms, Tables\Contracts\HasTable
|
||||
class TableWidget extends Widget implements Actions\Contracts\HasActions, Infolists\Contracts\HasInfolists, Forms\Contracts\HasForms, Tables\Contracts\HasTable
|
||||
{
|
||||
use Actions\Concerns\InteractsWithActions;
|
||||
use Forms\Concerns\InteractsWithForms;
|
||||
use Infolists\Concerns\InteractsWithInfolists;
|
||||
use Tables\Concerns\InteractsWithTable {
|
||||
makeTable as makeBaseTable;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user