Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Redirect after #1416

Merged
merged 11 commits into from
Dec 26, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/Laravel/src/Buttons/DeleteButton.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ final class DeleteButton
public static function for(
CrudResource $resource,
?string $componentName = null,
string $redirectAfterDelete = '',
?string $redirectAfterDelete = null,
bool $isAsync = true,
string $modalName = 'resource-delete-modal',
): ActionButtonContract {
Expand Down
2 changes: 1 addition & 1 deletion src/Laravel/src/Buttons/MassDeleteButton.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ final class MassDeleteButton
public static function for(
CrudResource $resource,
string $componentName = null,
string $redirectAfterDelete = '',
?string $redirectAfterDelete = null,
bool $isAsync = true,
string $modalName = 'resource-mass-delete-modal',
): ActionButtonContract {
Expand Down
20 changes: 14 additions & 6 deletions src/Laravel/src/Fields/Relationships/HasMany.php
Original file line number Diff line number Diff line change
Expand Up @@ -105,15 +105,24 @@ public function redirectAfter(Closure $callback): static
return $this;
}

public function getRedirectAfter(Model|int|null|string $parentId): string
public function getRedirectAfter(Model|int|null|string $parentId): ?string
{
if (! \is_null($this->redirectAfter)) {
return (string) value($this->redirectAfter, $parentId, $this);
}

if ($this->isAsync()) {
return null;
}

return $this->getDefaultRedirect($parentId);
}

public function getDefaultRedirect(Model|int|null|string $parentId): ?string
{
return moonshineRequest()
->getResource()
?->getFormPageUrl($parentId) ?? '';
?->getFormPageUrl($parentId);
}

/**
Expand Down Expand Up @@ -450,10 +459,9 @@ protected function getItemButtons(): array
{
$resource = $this->getResource()->stopGettingItemFromUrl();

$redirectAfter = $this->isAsync()
? '' : $this->getRedirectAfter(
$this->getRelatedModel()?->getKey()
);
$redirectAfter = $this->getRedirectAfter(
$this->getRelatedModel()?->getKey()
);

$editButton = $this->editButton ?? HasManyButton::for($this, update: true);

Expand Down
19 changes: 14 additions & 5 deletions src/Laravel/src/Fields/Relationships/HasOne.php
Original file line number Diff line number Diff line change
Expand Up @@ -162,15 +162,24 @@ public function redirectAfter(Closure $callback): static
return $this;
}

public function getRedirectAfter(Model|int|null|string $parentId): string
public function getRedirectAfter(Model|int|null|string $parentId): ?string
{
if (! \is_null($this->redirectAfter)) {
return (string) value($this->redirectAfter, $parentId, $this);
}

if ($this->isAsync() && ! \is_null($this->toValue())) {
return null;
}

return $this->getDefaultRedirect($parentId);
}

public function getDefaultRedirect(Model|int|null|string $parentId): ?string
{
return moonshineRequest()
->getResource()
?->getFormPageUrl($parentId) ?? '';
->getResource()
?->getFormPageUrl($parentId);
}

/**
Expand Down Expand Up @@ -257,7 +266,7 @@ protected function getComponent(): FormBuilder
)
->toArray()
)
->redirect($isAsync ? null : $redirectAfter)
->redirect($redirectAfter)
->fillCast(
$item?->toArray() ?? array_filter([
$relation->getForeignKeyName() => $this->getRelatedModel()?->getKey(),
Expand All @@ -272,7 +281,7 @@ protected function getComponent(): FormBuilder
? []
: [
$resource->getDeleteButton(
redirectAfterDelete: $redirectAfter,
redirectAfterDelete: $this->getDefaultRedirect($parentItem->getKey()),
isAsync: false,
modalName: "has-one-{$this->getRelationName()}",
)->class('btn-lg'),
Expand Down
6 changes: 6 additions & 0 deletions src/Laravel/src/Fields/Relationships/ModelRelationField.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
use Illuminate\Support\Stringable;
use MoonShine\Contracts\Core\HasResourceContract;
use MoonShine\Contracts\Core\TypeCasts\DataWrapperContract;
use MoonShine\Contracts\UI\HasFieldsContract;
use MoonShine\Core\Traits\HasResource;
use MoonShine\Laravel\Resources\ModelResource;
use MoonShine\UI\Exceptions\FieldException;
Expand Down Expand Up @@ -86,6 +87,11 @@ public function __construct(
} else {
$this->setResource($resource);
}

// required to create field entities and load assets
if ($this instanceof HasFieldsContract && ! $this->isMorph()) {
$this->getResource()?->getFormFields();
}
}

/**
Expand Down
26 changes: 19 additions & 7 deletions src/Laravel/src/Http/Controllers/CrudController.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
use MoonShine\Laravel\Http\Requests\Resources\StoreFormRequest;
use MoonShine\Laravel\Http\Requests\Resources\UpdateFormRequest;
use MoonShine\Laravel\MoonShineRequest;
use MoonShine\Laravel\Resources\CrudResource;
use MoonShine\Support\Enums\ToastType;
use Symfony\Component\HttpFoundation\Response;
use Throwable;
Expand Down Expand Up @@ -90,7 +91,6 @@ public function destroy(DeleteFormRequest $request): Response

$redirectRoute = $request->input('_redirect', $resource->getRedirectAfterDelete());


try {
$resource->delete($resource->getItemOrFail());
} catch (Throwable $e) {
Expand Down Expand Up @@ -150,7 +150,19 @@ protected function updateOrCreate(
$resource = $request->getResource();
$item = $resource->getItemOrInstance();

$redirectRoute = static fn ($resource): mixed => $request->input('_redirect', $resource->getRedirectAfterSave());
$redirectRoute = static function (CrudResource $resource) use ($request): ?string {
if ($request->boolean('_without-redirect')) {
return null;
}

$redirect = $request->input('_redirect', $resource->getRedirectAfterSave());

if (\is_null($redirect) && ! $resource->isCreateInModal() && $resource->isRecentlyCreated()) {
return $resource->getFormPageUrl($resource->getCastedData());
}

return $redirect;
};

try {
$item = $resource->save($item);
Expand All @@ -161,13 +173,9 @@ protected function updateOrCreate(
$resource->setItem($item);

if ($request->ajax() || $request->wantsJson()) {
$forceRedirect = $request->boolean('_force_redirect')
? $redirectRoute($resource)
: null;

return $this->json(
message: __('moonshine::ui.saved'),
redirect: $request->input('_redirect', $forceRedirect),
redirect: $redirectRoute($resource),
status: $resource->isRecentlyCreated() ? Response::HTTP_CREATED : Response::HTTP_OK
);
}
Expand All @@ -177,6 +185,10 @@ protected function updateOrCreate(
ToastType::SUCCESS
);

if (\is_null($redirectRoute($resource))) {
return back();
}

return redirect(
$redirectRoute($resource)
);
Expand Down
7 changes: 6 additions & 1 deletion src/Laravel/src/Http/Controllers/HasManyController.php
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ public function formComponent(RelationModelFieldRequest $request): string
};

$formName = "{$resource->getUriKey()}-unique-" . ($item->getKey() ?? "create");
$redirectRoute = $field->getRedirectAfter($parent);

return (string) FormBuilder::make($action($item))
/** @phpstan-ignore-next-line */
Expand Down Expand Up @@ -121,7 +122,11 @@ public function formComponent(RelationModelFieldRequest $request): string
&& $element->getColumn() === $relation->getForeignKeyName()
))
->buttons($field->getFormButtons())
->redirect($isAsync ? null : $field->getRedirectAfter($parent));
->redirect($redirectRoute)
->when(
! $update && \is_null($redirectRoute),
static fn (FormBuilderContract $form): FormBuilderContract => $form->withoutRedirect(),
);
}

/**
Expand Down
6 changes: 5 additions & 1 deletion src/Laravel/src/Http/Controllers/MoonShineController.php
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ protected function view(string $path, array $data = []): PageContract
/**
* @throws Throwable
*/
protected function reportAndResponse(bool $isAjax, Throwable $e, string $redirectRoute): Response
protected function reportAndResponse(bool $isAjax, Throwable $e, ?string $redirectRoute): Response
{
report_if(moonshine()->isProduction(), $e);

Expand All @@ -75,6 +75,10 @@ protected function reportAndResponse(bool $isAjax, Throwable $e, string $redirec

$this->toast(__($message), $type);

if (\is_null($redirectRoute)) {
return back()->withInput();
}

return redirect($redirectRoute)->withInput();
}

Expand Down
6 changes: 0 additions & 6 deletions src/Laravel/src/Pages/Crud/FormPage.php
Original file line number Diff line number Diff line change
Expand Up @@ -233,12 +233,6 @@ protected function getFormComponent(
Hidden::make('_method')->setValue('PUT')
)
)
->when(
! $resource->isItemExists() && ! $resource->isCreateInModal(),
static fn (Fields $fields): Fields => $fields->push(
Hidden::make('_force_redirect')->setValue(true)
)
)
->toArray(),
])
->when(
Expand Down
24 changes: 14 additions & 10 deletions src/Laravel/src/Traits/Resource/ResourceCrudRouter.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
*/
trait ResourceCrudRouter
{
protected ?PageType $redirectAfterSave = PageType::FORM;
protected ?PageType $redirectAfterSave = null;

/**
* @param DataWrapperContract<T>|int|string|null $key
Expand Down Expand Up @@ -112,20 +112,24 @@ public function getAsyncMethodUrl(
);
}

public function getRedirectAfterSave(): string
public function getRedirectAfterSave(): ?string
{
if (\is_null($this->redirectAfterSave) && ! $this->isAsync()) {
$this->redirectAfterSave = PageType::FORM;
}

if (\is_null($this->redirectAfterSave)) {
return null;
}

$params = \is_null($this->getItem()) || $this->redirectAfterSave === PageType::INDEX
? []
: ['resourceItem' => $this->getCastedData()?->getKey()];

if (! \is_null($this->redirectAfterSave)) {
return $this
->getPages()
->findByType($this->redirectAfterSave)
?->getRoute($params);
}

return $this->getFormPageUrl(params: $params);
return $this
->getPages()
->findByType($this->redirectAfterSave)
?->getRoute($params);
}

public function getRedirectAfterDelete(): string
Expand Down
8 changes: 4 additions & 4 deletions src/Laravel/src/Traits/Resource/ResourceWithButtons.php
Original file line number Diff line number Diff line change
Expand Up @@ -170,15 +170,15 @@ public function getDetailButton(

public function getDeleteButton(
?string $componentName = null,
string $redirectAfterDelete = '',
?string $redirectAfterDelete = null,
bool $isAsync = true,
string $modalName = 'resource-delete-modal',
): ActionButtonContract {
return $this->modifyDeleteButton(
DeleteButton::for(
$this,
componentName: $componentName,
redirectAfterDelete: $isAsync ? '' : $redirectAfterDelete,
redirectAfterDelete: $isAsync ? null : $redirectAfterDelete,
isAsync: $isAsync,
modalName: $modalName
)
Expand All @@ -192,15 +192,15 @@ public function getFiltersButton(): ActionButtonContract

public function getMassDeleteButton(
?string $componentName = null,
string $redirectAfterDelete = '',
?string $redirectAfterDelete = null,
bool $isAsync = true,
string $modalName = 'resource-mass-delete-modal',
): ActionButtonContract {
return $this->modifyMassDeleteButton(
MassDeleteButton::for(
$this,
componentName: $componentName,
redirectAfterDelete: $isAsync ? '' : $redirectAfterDelete,
redirectAfterDelete: $isAsync ? null : $redirectAfterDelete,
isAsync: $isAsync,
modalName: $modalName
)
Expand Down
9 changes: 8 additions & 1 deletion src/UI/src/Components/FormBuilder.php
Original file line number Diff line number Diff line change
Expand Up @@ -58,8 +58,8 @@ final class FormBuilder extends MoonShineComponent implements
protected iterable $buttons = [];

protected array $excludeFields = [
'_force_redirect',
'_redirect',
'_without-redirect',
'_method',
'_component_name',
'_async_field',
Expand Down Expand Up @@ -240,6 +240,13 @@ public function redirect(?string $uri = null): self
return $this;
}

public function withoutRedirect(): self
{
$this->additionalFields[] = Hidden::make('_without-redirect')->setValue(true);

return $this;
}

public function getMethod(): FormMethod
{
return $this->method;
Expand Down
9 changes: 5 additions & 4 deletions tests/Feature/Controllers/CrudControllerTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@
$this->itemResource->getRoute('crud.update', $item->getKey()),
['name' => 'New test name']
)
->assertRedirect();
->assertRedirect($this->itemResource->getFormPageUrl($item->getKey()));

$item->refresh();

Expand All @@ -104,7 +104,7 @@
asAdmin()->delete(
$this->itemResource->getRoute('crud.destroy', $item->getKey())
)
->assertRedirect();
->assertRedirect($this->itemResource->getIndexPageUrl());
});

it('when component crud delete', function () {
Expand Down Expand Up @@ -136,7 +136,7 @@
asAdmin()->delete(
$this->itemResource->getRoute('crud.destroy', $item->getKey())
)
->assertRedirect();
->assertRedirect($this->itemResource->getIndexPageUrl());
});

it('crud mass delete', function () {
Expand All @@ -147,7 +147,8 @@
asAdmin()->delete(
$this->itemResource->getRoute('crud.massDelete', query: ['ids' => $ids])
)
->assertRedirect();
->assertRedirect($this->itemResource->getIndexPageUrl())
;

$items = Item::query()->get()->toArray();

Expand Down