From 288f18613c5111c77bd6fcd37207183e6282201a Mon Sep 17 00:00:00 2001 From: brandonkelly Date: Tue, 21 May 2024 15:23:58 -0700 Subject: [PATCH] =?UTF-8?q?=E2=80=9CDelete=E2=80=9D=20action=20for=20entry?= =?UTF-8?q?=20types?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [ci skip] --- CHANGELOG-WIP.md | 3 +- src/controllers/EntryTypesController.php | 111 ++++++++++++++--------- 2 files changed, 69 insertions(+), 45 deletions(-) diff --git a/CHANGELOG-WIP.md b/CHANGELOG-WIP.md index 83f343473d4..e5c7ce03947 100644 --- a/CHANGELOG-WIP.md +++ b/CHANGELOG-WIP.md @@ -15,7 +15,8 @@ - The `db/restore` command now autodetects the backup format for PostgreSQL installs, if `--format` isn’t passed. ([#14931](https://github.com/craftcms/cms/pull/14931)) - The `install` command and web-based installer now validate the existing project config files at the outset, and abort installation if there are any issues. - The `resave/entries` command now has an `--all-sections` flag. -- The web-based installer now displays the error message when installation fails. +- The web-based installer now displays the error message when installation fails. +- Edit Entry Type pages now have a “Delete” action. ([#14983](https://github.com/craftcms/cms/discussions/14983)) ### Development - Added the `withCustomFields` element query param. ([#15003](https://github.com/craftcms/cms/pull/15003)) diff --git a/src/controllers/EntryTypesController.php b/src/controllers/EntryTypesController.php index 4b167938782..219a2b2c802 100644 --- a/src/controllers/EntryTypesController.php +++ b/src/controllers/EntryTypesController.php @@ -70,7 +70,7 @@ public function actionEdit(?int $entryTypeId = null, ?EntryType $entryType = nul $title = Craft::t('app', 'Create a new entry type'); } - return $this->asCpScreen() + $response = $this->asCpScreen() ->editUrl($entryType->getCpEditUrl()) ->title($title) ->addCrumb(Craft::t('app', 'Settings'), 'settings') @@ -87,46 +87,56 @@ public function actionEdit(?int $entryTypeId = null, ?EntryType $entryType = nul 'entryType' => $entryType, 'typeName' => Entry::displayName(), 'lowerTypeName' => Entry::lowerDisplayName(), - ]) - ->metaSidebarHtml($entryType->id ? Cp::metadataHtml([ - Craft::t('app', 'ID') => $entryType->id, - Craft::t('app', 'Used by') => function() use ($entryType) { - $usages = $entryType->findUsages(); - if (empty($usages)) { - return Html::tag('i', Craft::t('app', 'No usages')); - } - - $labels = []; - $items = array_map(function(Section|ElementContainerFieldInterface $usage) use (&$labels) { - if ($usage instanceof Section) { - $label = Craft::t('site', $usage->name); - $url = $usage->getCpEditUrl(); - $icon = 'newspaper'; - } else { - $label = Craft::t('site', $usage->name); - $url = UrlHelper::cpUrl("settings/fields/edit/$usage->id"); - $icon = $usage::icon(); + ]); + + if ($entryType->id) { + $response + ->addAltAction(Craft::t('app', 'Delete'), [ + 'action' => 'entry-types/delete', + 'destructive' => true, + ]) + ->metaSidebarHtml(Cp::metadataHtml([ + Craft::t('app', 'ID') => $entryType->id, + Craft::t('app', 'Used by') => function() use ($entryType) { + $usages = $entryType->findUsages(); + if (empty($usages)) { + return Html::tag('i', Craft::t('app', 'No usages')); } - $labels[] = $label; - $labelHtml = Html::beginTag('span', [ - 'class' => ['flex', 'flex-nowrap', 'gap-s'], - ]) . - Html::tag('div', Cp::iconSvg($icon), [ - 'class' => ['cp-icon', 'small'], - ]) . - Html::tag('span', Html::encode($label)) . - Html::endTag('span'); - return Html::a($labelHtml, $url); - }, $entryType->findUsages()); - - // sort by label - array_multisort($labels, SORT_ASC, $items); - - return Html::ul($items, [ - 'encode' => false, - ]); - }, - ]) : null); + + $labels = []; + $items = array_map(function(Section|ElementContainerFieldInterface $usage) use (&$labels) { + if ($usage instanceof Section) { + $label = Craft::t('site', $usage->name); + $url = $usage->getCpEditUrl(); + $icon = 'newspaper'; + } else { + $label = Craft::t('site', $usage->name); + $url = UrlHelper::cpUrl("settings/fields/edit/$usage->id"); + $icon = $usage::icon(); + } + $labels[] = $label; + $labelHtml = Html::beginTag('span', [ + 'class' => ['flex', 'flex-nowrap', 'gap-s'], + ]) . + Html::tag('div', Cp::iconSvg($icon), [ + 'class' => ['cp-icon', 'small'], + ]) . + Html::tag('span', Html::encode($label)) . + Html::endTag('span'); + return Html::a($labelHtml, $url); + }, $entryType->findUsages()); + + // sort by label + array_multisort($labels, SORT_ASC, $items); + + return Html::ul($items, [ + 'encode' => false, + ]); + }, + ])); + } + + return $response; } /** @@ -187,12 +197,25 @@ public function actionSave(): ?Response public function actionDelete(): Response { $this->requirePostRequest(); - $this->requireAcceptsJson(); - $entryTypeId = $this->request->getRequiredBodyParam('id'); + $entryTypeId = $this->request->getBodyParam('entryTypeId') ?? $this->request->getRequiredBodyParam('id'); + + $entriesService = Craft::$app->getEntries(); + $entryType = $entriesService->getEntryTypeById($entryTypeId); + + if (!$entryType) { + throw new BadRequestHttpException("Invalid entry type ID: $entryType"); + } + + if (!$entriesService->deleteEntryType($entryType)) { + return $this->asFailure(Craft::t('app', 'Couldn’t delete “{name}”.', [ + 'name' => $entryType->getUiLabel(), + ])); + } - $success = Craft::$app->getEntries()->deleteEntryTypeById($entryTypeId); - return $success ? $this->asSuccess() : $this->asFailure(); + return $this->asSuccess(Craft::t('app', '“{name}” deleted.', [ + 'name' => $entryType->getUiLabel(), + ])); } /**