From 1c644d89aa1ccec55f7e17b74de74c1e3e6dd15d Mon Sep 17 00:00:00 2001 From: Jack Sleight Date: Mon, 25 Jul 2022 15:17:41 +0100 Subject: [PATCH 01/64] Run actions from the edit entry view --- .../js/components/entries/PublishForm.vue | 12 ++++++ .../js/components/publish/HasListActions.js | 40 +++++++++++++++++++ resources/views/entries/edit.blade.php | 2 + src/Actions/Delete.php | 4 ++ .../CP/Collections/EntriesController.php | 2 + 5 files changed, 60 insertions(+) create mode 100644 resources/js/components/publish/HasListActions.js diff --git a/resources/js/components/entries/PublishForm.vue b/resources/js/components/entries/PublishForm.vue index 1b7f47ce74..dc8499fa4c 100644 --- a/resources/js/components/entries/PublishForm.vue +++ b/resources/js/components/entries/PublishForm.vue @@ -12,6 +12,14 @@ + +
@@ -258,12 +266,14 @@ import SaveButtonOptions from '../publish/SaveButtonOptions'; import RevisionHistory from '../revision-history/History'; import HasPreferences from '../data-list/HasPreferences'; import HasHiddenFields from '../data-list/HasHiddenFields'; +import HasListActions from '../publish/HasListActions'; export default { mixins: [ HasPreferences, HasHiddenFields, + HasListActions, ], components: { @@ -304,6 +314,8 @@ export default { listingUrl: String, collectionHasRoutes: Boolean, previewTargets: Array, + listActions: Array, + listActionUrl: String, }, data() { diff --git a/resources/js/components/publish/HasListActions.js b/resources/js/components/publish/HasListActions.js new file mode 100644 index 0000000000..8c634562c8 --- /dev/null +++ b/resources/js/components/publish/HasListActions.js @@ -0,0 +1,40 @@ +export default { + + methods: { + + actionStarted() { + this.saving = true; + }, + + actionCompleted(successful=null, response) { + this.saving = false; + + if (successful === false) return; + + this.$events.$emit('reset-action-modals'); + + if (response.callback) { + Statamic.$callbacks.call(response.callback[0], ...response.callback.slice(1)); + } + + if (response.message !== false) { + this.$toast.success(response.message || __("Action completed")); + } + + if (response.back) { + this.$toast.success(__("Redirecting…")); + setTimeout(() => { + window.location.href = this.listingUrl; + }, 1000); + } + + // this.afterActionSuccessfullyCompleted(); + }, + + // afterActionSuccessfullyCompleted() { + // this.request(); + // } + + } + +} diff --git a/resources/views/entries/edit.blade.php b/resources/views/entries/edit.blade.php index ad91602290..aa6e78fec2 100644 --- a/resources/views/entries/edit.blade.php +++ b/resources/views/entries/edit.blade.php @@ -34,6 +34,8 @@ create-another-url="{{ cp_route('collections.entries.create', [$collection, $locale]) }}" listing-url="{{ cp_route('collections.show', $collection) }}" :preview-targets="{{ json_encode($previewTargets) }}" + :list-actions="{{ json_encode($listActions) }}" + list-action-url="{{ cp_route('collections.entries.actions.run', $collection) }}" > @endsection diff --git a/src/Actions/Delete.php b/src/Actions/Delete.php index 81efdc129a..395388768e 100644 --- a/src/Actions/Delete.php +++ b/src/Actions/Delete.php @@ -52,5 +52,9 @@ public function confirmationText() public function run($items, $values) { $items->each->delete(); + + if ($this->context['edit'] ?? false) { + return ['back' => true]; + } } } diff --git a/src/Http/Controllers/CP/Collections/EntriesController.php b/src/Http/Controllers/CP/Collections/EntriesController.php index 3c67641d01..4810c704cf 100644 --- a/src/Http/Controllers/CP/Collections/EntriesController.php +++ b/src/Http/Controllers/CP/Collections/EntriesController.php @@ -7,6 +7,7 @@ use Statamic\Contracts\Entries\Entry as EntryContract; use Statamic\CP\Breadcrumbs; use Statamic\Exceptions\BlueprintNotFoundException; +use Statamic\Facades\Action; use Statamic\Facades\Asset; use Statamic\Facades\Entry; use Statamic\Facades\Site; @@ -106,6 +107,7 @@ public function edit(Request $request, $collection, $entry) 'createRevision' => $entry->createRevisionUrl(), 'editBlueprint' => cp_route('collections.blueprints.edit', [$collection, $blueprint]), ], + 'listActions' => Action::for($entry, ['collection' => $collection->handle(), 'edit' => true]), 'values' => array_merge($values, ['id' => $entry->id()]), 'meta' => $meta, 'collection' => $collection->handle(), From de72777d45e8cd937401ebd7545ea1c8e902594e Mon Sep 17 00:00:00 2001 From: Jack Sleight Date: Fri, 18 Nov 2022 16:53:57 +0000 Subject: [PATCH 02/64] WIP --- .../js/components/entries/PublishForm.vue | 8 ++- .../js/components/publish/HasListActions.js | 13 +---- resources/views/entries/edit.blade.php | 2 +- src/Actions/ActionRepository.php | 4 ++ src/Actions/Delete.php | 7 ++- src/Http/Controllers/CP/ActionController.php | 15 +++++- .../CP/Collections/EntriesController.php | 2 +- .../CP/Collections/EntryActionController.php | 51 +++++++++++++++++++ 8 files changed, 83 insertions(+), 19 deletions(-) diff --git a/resources/js/components/entries/PublishForm.vue b/resources/js/components/entries/PublishForm.vue index dc8499fa4c..46613b60ed 100644 --- a/resources/js/components/entries/PublishForm.vue +++ b/resources/js/components/entries/PublishForm.vue @@ -314,13 +314,14 @@ export default { listingUrl: String, collectionHasRoutes: Boolean, previewTargets: Array, - listActions: Array, + initialListActions: Array, listActionUrl: String, }, data() { return { actions: this.initialActions, + listActions: this.initialListActions, saving: false, localizing: false, fieldset: this.initialFieldset, @@ -445,6 +446,11 @@ export default { methods: { + afterListActionSuccessfullyCompleted(response) { + this.values = { ...this.values, ...response.data.values }; + this.listActions = response.data.listActions; + }, + clearErrors() { this.error = null; this.errors = {}; diff --git a/resources/js/components/publish/HasListActions.js b/resources/js/components/publish/HasListActions.js index 8c634562c8..94dbf74946 100644 --- a/resources/js/components/publish/HasListActions.js +++ b/resources/js/components/publish/HasListActions.js @@ -21,20 +21,9 @@ export default { this.$toast.success(response.message || __("Action completed")); } - if (response.back) { - this.$toast.success(__("Redirecting…")); - setTimeout(() => { - window.location.href = this.listingUrl; - }, 1000); - } - - // this.afterActionSuccessfullyCompleted(); + this.afterListActionSuccessfullyCompleted(response); }, - // afterActionSuccessfullyCompleted() { - // this.request(); - // } - } } diff --git a/resources/views/entries/edit.blade.php b/resources/views/entries/edit.blade.php index aa6e78fec2..0c4fde8e12 100644 --- a/resources/views/entries/edit.blade.php +++ b/resources/views/entries/edit.blade.php @@ -34,7 +34,7 @@ create-another-url="{{ cp_route('collections.entries.create', [$collection, $locale]) }}" listing-url="{{ cp_route('collections.show', $collection) }}" :preview-targets="{{ json_encode($previewTargets) }}" - :list-actions="{{ json_encode($listActions) }}" + :initial-list-actions="{{ json_encode($listActions) }}" list-action-url="{{ cp_route('collections.entries.actions.run', $collection) }}" > diff --git a/src/Actions/ActionRepository.php b/src/Actions/ActionRepository.php index d06d6decd7..6f4930aa60 100644 --- a/src/Actions/ActionRepository.php +++ b/src/Actions/ActionRepository.php @@ -22,6 +22,8 @@ public function all() public function for($item, $context = []) { + $context = $context + ['view' => 'listing']; + return $this->all() ->each->context($context) ->filter->visibleTo($item) @@ -31,6 +33,8 @@ public function for($item, $context = []) public function forBulk($items, $context = []) { + $context = $context + ['view' => 'listing']; + return $this->all() ->each->context($context) ->filter->visibleToBulk($items) diff --git a/src/Actions/Delete.php b/src/Actions/Delete.php index 395388768e..f926170cd7 100644 --- a/src/Actions/Delete.php +++ b/src/Actions/Delete.php @@ -52,9 +52,12 @@ public function confirmationText() public function run($items, $values) { $items->each->delete(); + } - if ($this->context['edit'] ?? false) { - return ['back' => true]; + public function redirect($items, $values) + { + if ($this->context['view'] === 'publishForm') { + return cp_route('collections.show', $items->first()->collection()->handle()); } } } diff --git a/src/Http/Controllers/CP/ActionController.php b/src/Http/Controllers/CP/ActionController.php index d5d5746776..e79b3c909d 100644 --- a/src/Http/Controllers/CP/ActionController.php +++ b/src/Http/Controllers/CP/ActionController.php @@ -42,10 +42,16 @@ public function run(Request $request) } if (is_string($response)) { - return ['message' => $response]; + $response = ['message' => $response]; } - return $response ?: []; + $response = $response ?: []; + + if ($context['view'] === 'publishForm') { + $response['data'] = $this->getItemData($items->first()); + } + + return $response; } public function bulkActions(Request $request) @@ -63,4 +69,9 @@ public function bulkActions(Request $request) } abstract protected function getSelectedItems($items, $context); + + protected function getItemData($item) + { + return []; + } } diff --git a/src/Http/Controllers/CP/Collections/EntriesController.php b/src/Http/Controllers/CP/Collections/EntriesController.php index 4810c704cf..be6d91def6 100644 --- a/src/Http/Controllers/CP/Collections/EntriesController.php +++ b/src/Http/Controllers/CP/Collections/EntriesController.php @@ -107,7 +107,7 @@ public function edit(Request $request, $collection, $entry) 'createRevision' => $entry->createRevisionUrl(), 'editBlueprint' => cp_route('collections.blueprints.edit', [$collection, $blueprint]), ], - 'listActions' => Action::for($entry, ['collection' => $collection->handle(), 'edit' => true]), + 'listActions' => Action::for($entry, ['collection' => $collection->handle(), 'view' => 'publishForm']), 'values' => array_merge($values, ['id' => $entry->id()]), 'meta' => $meta, 'collection' => $collection->handle(), diff --git a/src/Http/Controllers/CP/Collections/EntryActionController.php b/src/Http/Controllers/CP/Collections/EntryActionController.php index 888687ee6e..71adf90b1d 100644 --- a/src/Http/Controllers/CP/Collections/EntryActionController.php +++ b/src/Http/Controllers/CP/Collections/EntryActionController.php @@ -2,6 +2,7 @@ namespace Statamic\Http\Controllers\CP\Collections; +use Statamic\Facades\Action; use Statamic\Facades\Entry; use Statamic\Http\Controllers\CP\ActionController; @@ -13,4 +14,54 @@ protected function getSelectedItems($items, $context) return Entry::find($item); }); } + + protected function getItemData($entry) + { + $collection = $entry->collection(); + + $blueprint = $entry->blueprint(); + + [$values] = $this->extractFromFields($entry, $blueprint); + + return [ + 'values' => $values, + 'listActions' => Action::for($entry, ['collection' => $collection->handle(), 'view' => 'publishForm']), + ]; + } + + protected function extractFromFields($entry, $blueprint) + { + // The values should only be data merged with the origin data. + // We don't want injected collection values, which $entry->values() would have given us. + $target = $entry; + $values = $target->data(); + while ($target->hasOrigin()) { + $target = $target->origin(); + $values = $target->data()->merge($values); + } + $values = $values->all(); + + if ($entry->hasStructure()) { + $values['parent'] = array_filter([optional($entry->parent())->id()]); + } + + if ($entry->collection()->dated()) { + $datetime = substr($entry->date()->toDateTimeString(), 0, 16); + $datetime = ($entry->hasTime()) ? $datetime : substr($datetime, 0, 10); + $values['date'] = $datetime; + } + + $fields = $blueprint + ->fields() + ->addValues($values) + ->preProcess(); + + $values = $fields->values()->merge([ + 'title' => $entry->value('title'), + 'slug' => $entry->slug(), + 'published' => $entry->published(), + ]); + + return [$values->all(), $fields->meta()]; + } } From 8611bf8c92b7ee8c1fdf219433c389613b911196 Mon Sep 17 00:00:00 2001 From: Jack Sleight Date: Sat, 19 Nov 2022 14:22:18 +0000 Subject: [PATCH 03/64] WIP --- src/Actions/ActionRepository.php | 4 ---- src/Actions/Delete.php | 7 +++++-- src/Http/Controllers/CP/ActionController.php | 7 ++++--- src/Http/Controllers/CP/Collections/EntriesController.php | 2 +- .../Controllers/CP/Collections/EntryActionController.php | 4 ++-- 5 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/Actions/ActionRepository.php b/src/Actions/ActionRepository.php index 6f4930aa60..d06d6decd7 100644 --- a/src/Actions/ActionRepository.php +++ b/src/Actions/ActionRepository.php @@ -22,8 +22,6 @@ public function all() public function for($item, $context = []) { - $context = $context + ['view' => 'listing']; - return $this->all() ->each->context($context) ->filter->visibleTo($item) @@ -33,8 +31,6 @@ public function for($item, $context = []) public function forBulk($items, $context = []) { - $context = $context + ['view' => 'listing']; - return $this->all() ->each->context($context) ->filter->visibleToBulk($items) diff --git a/src/Actions/Delete.php b/src/Actions/Delete.php index f926170cd7..f7e1203650 100644 --- a/src/Actions/Delete.php +++ b/src/Actions/Delete.php @@ -56,8 +56,11 @@ public function run($items, $values) public function redirect($items, $values) { - if ($this->context['view'] === 'publishForm') { - return cp_route('collections.show', $items->first()->collection()->handle()); + if (! array_get($this->context, 'publish_form', false)) { + return; } + + // Also need to handle terms etc, todo + return cp_route('collections.show', $items->first()->collection()->handle()); } } diff --git a/src/Http/Controllers/CP/ActionController.php b/src/Http/Controllers/CP/ActionController.php index e79b3c909d..73c0a74407 100644 --- a/src/Http/Controllers/CP/ActionController.php +++ b/src/Http/Controllers/CP/ActionController.php @@ -47,8 +47,8 @@ public function run(Request $request) $response = $response ?: []; - if ($context['view'] === 'publishForm') { - $response['data'] = $this->getItemData($items->first()); + if (array_get($context, 'publish_form', false)) { + $response['data'] = $this->getItemData($items->first(), $context); } return $response; @@ -70,7 +70,8 @@ public function bulkActions(Request $request) abstract protected function getSelectedItems($items, $context); - protected function getItemData($item) + // Should be abstract, todo + protected function getItemData($item, $context) { return []; } diff --git a/src/Http/Controllers/CP/Collections/EntriesController.php b/src/Http/Controllers/CP/Collections/EntriesController.php index be6d91def6..4e1d6d3244 100644 --- a/src/Http/Controllers/CP/Collections/EntriesController.php +++ b/src/Http/Controllers/CP/Collections/EntriesController.php @@ -107,7 +107,7 @@ public function edit(Request $request, $collection, $entry) 'createRevision' => $entry->createRevisionUrl(), 'editBlueprint' => cp_route('collections.blueprints.edit', [$collection, $blueprint]), ], - 'listActions' => Action::for($entry, ['collection' => $collection->handle(), 'view' => 'publishForm']), + 'listActions' => Action::for($entry, ['collection' => $collection->handle(), 'publish_form' => true]), 'values' => array_merge($values, ['id' => $entry->id()]), 'meta' => $meta, 'collection' => $collection->handle(), diff --git a/src/Http/Controllers/CP/Collections/EntryActionController.php b/src/Http/Controllers/CP/Collections/EntryActionController.php index 71adf90b1d..46e914162d 100644 --- a/src/Http/Controllers/CP/Collections/EntryActionController.php +++ b/src/Http/Controllers/CP/Collections/EntryActionController.php @@ -15,7 +15,7 @@ protected function getSelectedItems($items, $context) }); } - protected function getItemData($entry) + protected function getItemData($entry, $context) { $collection = $entry->collection(); @@ -25,7 +25,7 @@ protected function getItemData($entry) return [ 'values' => $values, - 'listActions' => Action::for($entry, ['collection' => $collection->handle(), 'view' => 'publishForm']), + 'listActions' => Action::for($entry, $context), ]; } From e496f8e31c08554bf7a0ff4a68c639440b4da87e Mon Sep 17 00:00:00 2001 From: Jack Sleight Date: Thu, 1 Dec 2022 13:56:19 +0000 Subject: [PATCH 04/64] Implement redirect on entry duplication --- src/Actions/DuplicateEntry.php | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/src/Actions/DuplicateEntry.php b/src/Actions/DuplicateEntry.php index 66968287dd..b2e40bc76b 100644 --- a/src/Actions/DuplicateEntry.php +++ b/src/Actions/DuplicateEntry.php @@ -9,6 +9,8 @@ class DuplicateEntry extends Action { + protected $entries; + public static function title() { return __('Duplicate'); @@ -21,7 +23,7 @@ public function visibleTo($item) public function run($items, $values) { - $items->each(function (Entry $original) { + $this->entries = $items->map(function (Entry $original) { $originalParent = $this->getEntryParentFromStructure($original); [$title, $slug] = $this->generateTitleAndSlug($original); @@ -51,9 +53,20 @@ public function run($items, $values) ->appendTo($originalParent->id(), $entry) ->save(); } + + return $entry; }); } + public function redirect($items, $values) + { + if (! array_get($this->context, 'publish_form', false)) { + return; + } + + return $this->entries->first()->editUrl(); + } + protected function getEntryParentFromStructure(Entry $entry) { if (! $entry->structure()) { From 07293917f57dd10f849b1e1e0496718db961feb1 Mon Sep 17 00:00:00 2001 From: Jack Sleight Date: Fri, 12 May 2023 09:53:35 +0100 Subject: [PATCH 05/64] Run tests again --- src/Http/Controllers/CP/ActionController.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Http/Controllers/CP/ActionController.php b/src/Http/Controllers/CP/ActionController.php index 9177e51635..15f3cede62 100644 --- a/src/Http/Controllers/CP/ActionController.php +++ b/src/Http/Controllers/CP/ActionController.php @@ -72,7 +72,7 @@ public function bulkActions(Request $request) abstract protected function getSelectedItems($items, $context); - // Should be abstract, todo + // Should be abstract todo protected function getItemData($item, $context) { return []; From eb9332c3fd434441880245409146d6573f133dc8 Mon Sep 17 00:00:00 2001 From: Jason Varga Date: Tue, 5 Sep 2023 16:33:06 -0400 Subject: [PATCH 06/64] move actions after edit blueprint --- resources/js/components/entries/PublishForm.vue | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/resources/js/components/entries/PublishForm.vue b/resources/js/components/entries/PublishForm.vue index e5540c9341..e7f39b0606 100644 --- a/resources/js/components/entries/PublishForm.vue +++ b/resources/js/components/entries/PublishForm.vue @@ -11,7 +11,8 @@
- + + -
From c74662f0eeedca063a041bc58337a0fb0f85949a Mon Sep 17 00:00:00 2001 From: Jack Sleight Date: Fri, 15 Dec 2023 14:07:59 +0000 Subject: [PATCH 07/64] Update duplicate entry action --- src/Actions/DuplicateEntry.php | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/src/Actions/DuplicateEntry.php b/src/Actions/DuplicateEntry.php index 4cec6dce1d..aa1e0c1751 100644 --- a/src/Actions/DuplicateEntry.php +++ b/src/Actions/DuplicateEntry.php @@ -9,6 +9,8 @@ class DuplicateEntry extends Action { + protected $newItems; + public static function title() { return __('Duplicate'); @@ -49,7 +51,7 @@ public function warningText() public function run($items, $values) { - $items + $this->newItems = $items ->map(fn ($entry) => $entry->hasOrigin() ? $entry->root() : $entry) ->unique() ->each(fn ($original) => $this->duplicateEntry($original)); @@ -155,4 +157,13 @@ public function authorize($user, $item) { return $user->can('create', [Entry::class, $item->collection(), $item->site()]); } -} \ No newline at end of file + + public function redirect($items, $values) + { + if (! array_get($this->context, 'publish_form', false)) { + return; + } + + return $this->newItems->first()->editUrl(); + } +} From d007a027af3d33aee29c7f05e4baa432fd6f6f18 Mon Sep 17 00:00:00 2001 From: Jack Sleight Date: Fri, 15 Dec 2023 14:09:13 +0000 Subject: [PATCH 08/64] Update duplicate entry action --- src/Actions/DuplicateEntry.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/Actions/DuplicateEntry.php b/src/Actions/DuplicateEntry.php index aa1e0c1751..876af37ede 100644 --- a/src/Actions/DuplicateEntry.php +++ b/src/Actions/DuplicateEntry.php @@ -54,7 +54,7 @@ public function run($items, $values) $this->newItems = $items ->map(fn ($entry) => $entry->hasOrigin() ? $entry->root() : $entry) ->unique() - ->each(fn ($original) => $this->duplicateEntry($original)); + ->map(fn ($original) => $this->duplicateEntry($original)); } private function duplicateEntry(Entry $original, ?string $origin = null) @@ -100,6 +100,8 @@ private function duplicateEntry(Entry $original, ?string $origin = null) ->appendTo($originalParent->id(), $entry) ->save(); } + + return $entry; } protected function getEntryParentFromStructure(Entry $entry) From 1c7940fb11a21e024100056eac6e25101282d0be Mon Sep 17 00:00:00 2001 From: Jack Sleight Date: Fri, 15 Dec 2023 14:09:58 +0000 Subject: [PATCH 09/64] Rename mixin to HasActions --- resources/js/components/entries/PublishForm.vue | 4 ++-- .../components/publish/{HasListActions.js => HasActions.js} | 0 2 files changed, 2 insertions(+), 2 deletions(-) rename resources/js/components/publish/{HasListActions.js => HasActions.js} (100%) diff --git a/resources/js/components/entries/PublishForm.vue b/resources/js/components/entries/PublishForm.vue index 0c219f25f1..c63efa2764 100644 --- a/resources/js/components/entries/PublishForm.vue +++ b/resources/js/components/entries/PublishForm.vue @@ -301,14 +301,14 @@ import SaveButtonOptions from '../publish/SaveButtonOptions.vue'; import RevisionHistory from '../revision-history/History.vue'; import HasPreferences from '../data-list/HasPreferences'; import HasHiddenFields from '../publish/HasHiddenFields'; -import HasListActions from '../publish/HasListActions'; +import HasActions from '../publish/HasActions'; export default { mixins: [ HasPreferences, HasHiddenFields, - HasListActions, + HasActions, ], components: { diff --git a/resources/js/components/publish/HasListActions.js b/resources/js/components/publish/HasActions.js similarity index 100% rename from resources/js/components/publish/HasListActions.js rename to resources/js/components/publish/HasActions.js From 2a62a984898da36be00d2979cfbfe55dd607e5f0 Mon Sep 17 00:00:00 2001 From: Jack Sleight Date: Fri, 15 Dec 2023 14:13:02 +0000 Subject: [PATCH 10/64] Reanme listActions to itemActions --- resources/js/components/entries/PublishForm.vue | 10 +++++----- resources/js/components/publish/HasActions.js | 2 +- resources/views/entries/edit.blade.php | 2 +- .../Controllers/CP/Collections/EntriesController.php | 2 +- .../CP/Collections/EntryActionController.php | 2 +- 5 files changed, 9 insertions(+), 9 deletions(-) diff --git a/resources/js/components/entries/PublishForm.vue b/resources/js/components/entries/PublishForm.vue index c63efa2764..f52ebf2ef7 100644 --- a/resources/js/components/entries/PublishForm.vue +++ b/resources/js/components/entries/PublishForm.vue @@ -16,7 +16,7 @@ @@ -350,14 +350,14 @@ export default { collectionHasRoutes: Boolean, previewTargets: Array, autosaveInterval: Number, - initialListActions: Array, + initialItemActions: Array, listActionUrl: String, }, data() { return { actions: this.initialActions, - listActions: this.initialListActions, + itemActions: this.initialItemActions, saving: false, localizing: false, trackDirtyState: true, @@ -507,9 +507,9 @@ export default { methods: { - afterListActionSuccessfullyCompleted(response) { + afterItemActionSuccessfullyCompleted(response) { this.values = { ...this.values, ...response.data.values }; - this.listActions = response.data.listActions; + this.itemActions = response.data.itemActions; }, clearErrors() { diff --git a/resources/js/components/publish/HasActions.js b/resources/js/components/publish/HasActions.js index 94dbf74946..9f5660e8c7 100644 --- a/resources/js/components/publish/HasActions.js +++ b/resources/js/components/publish/HasActions.js @@ -21,7 +21,7 @@ export default { this.$toast.success(response.message || __("Action completed")); } - this.afterListActionSuccessfullyCompleted(response); + this.afterItemActionSuccessfullyCompleted(response); }, } diff --git a/resources/views/entries/edit.blade.php b/resources/views/entries/edit.blade.php index 93ac5e4443..25836268b2 100644 --- a/resources/views/entries/edit.blade.php +++ b/resources/views/entries/edit.blade.php @@ -36,7 +36,7 @@ initial-listing-url="{{ cp_route('collections.show', $collection) }}" :preview-targets="{{ json_encode($previewTargets) }}" :autosave-interval="{{ json_encode($autosaveInterval) }}" - :initial-list-actions="{{ json_encode($listActions) }}" + :initial-item-actions="{{ json_encode($itemActions) }}" list-action-url="{{ cp_route('collections.entries.actions.run', $collection) }}" > diff --git a/src/Http/Controllers/CP/Collections/EntriesController.php b/src/Http/Controllers/CP/Collections/EntriesController.php index 814bef64b1..9d22559609 100644 --- a/src/Http/Controllers/CP/Collections/EntriesController.php +++ b/src/Http/Controllers/CP/Collections/EntriesController.php @@ -118,7 +118,7 @@ public function edit(Request $request, $collection, $entry) 'createRevision' => $entry->createRevisionUrl(), 'editBlueprint' => cp_route('collections.blueprints.edit', [$collection, $blueprint]), ], - 'listActions' => Action::for($entry, ['collection' => $collection->handle(), 'publish_form' => true]), + 'itemActions' => Action::for($entry, ['collection' => $collection->handle(), 'publish_form' => true]), 'values' => array_merge($values, ['id' => $entry->id()]), 'meta' => $meta, 'collection' => $collection->handle(), diff --git a/src/Http/Controllers/CP/Collections/EntryActionController.php b/src/Http/Controllers/CP/Collections/EntryActionController.php index 46e914162d..7c01d5ea31 100644 --- a/src/Http/Controllers/CP/Collections/EntryActionController.php +++ b/src/Http/Controllers/CP/Collections/EntryActionController.php @@ -25,7 +25,7 @@ protected function getItemData($entry, $context) return [ 'values' => $values, - 'listActions' => Action::for($entry, $context), + 'itemActions' => Action::for($entry, $context), ]; } From 6a782e1addbefaedb7c8ac9e1a1dab4ca33f31ae Mon Sep 17 00:00:00 2001 From: Jack Sleight Date: Fri, 15 Dec 2023 14:15:31 +0000 Subject: [PATCH 11/64] Rename publish_form context key to view --- src/Actions/Delete.php | 2 +- src/Actions/DuplicateEntry.php | 2 +- src/Http/Controllers/CP/ActionController.php | 2 +- src/Http/Controllers/CP/Collections/EntriesController.php | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Actions/Delete.php b/src/Actions/Delete.php index 0ac7d63825..2df5ca16d2 100644 --- a/src/Actions/Delete.php +++ b/src/Actions/Delete.php @@ -59,7 +59,7 @@ public function run($items, $values) public function redirect($items, $values) { - if (! array_get($this->context, 'publish_form', false)) { + if ($this->context['view'] ?? null !== 'form') { return; } diff --git a/src/Actions/DuplicateEntry.php b/src/Actions/DuplicateEntry.php index 876af37ede..55a178cf55 100644 --- a/src/Actions/DuplicateEntry.php +++ b/src/Actions/DuplicateEntry.php @@ -162,7 +162,7 @@ public function authorize($user, $item) public function redirect($items, $values) { - if (! array_get($this->context, 'publish_form', false)) { + if ($this->context['view'] ?? null !== 'form') { return; } diff --git a/src/Http/Controllers/CP/ActionController.php b/src/Http/Controllers/CP/ActionController.php index 15f3cede62..51b4dc6f6c 100644 --- a/src/Http/Controllers/CP/ActionController.php +++ b/src/Http/Controllers/CP/ActionController.php @@ -49,7 +49,7 @@ public function run(Request $request) $response = $response ?: []; - if (array_get($context, 'publish_form', false)) { + if ($context['view'] ?? null === 'form') { $response['data'] = $this->getItemData($items->first(), $context); } diff --git a/src/Http/Controllers/CP/Collections/EntriesController.php b/src/Http/Controllers/CP/Collections/EntriesController.php index 9d22559609..286810c6f5 100644 --- a/src/Http/Controllers/CP/Collections/EntriesController.php +++ b/src/Http/Controllers/CP/Collections/EntriesController.php @@ -118,7 +118,7 @@ public function edit(Request $request, $collection, $entry) 'createRevision' => $entry->createRevisionUrl(), 'editBlueprint' => cp_route('collections.blueprints.edit', [$collection, $blueprint]), ], - 'itemActions' => Action::for($entry, ['collection' => $collection->handle(), 'publish_form' => true]), + 'itemActions' => Action::for($entry, ['collection' => $collection->handle(), 'view' => 'form']), 'values' => array_merge($values, ['id' => $entry->id()]), 'meta' => $meta, 'collection' => $collection->handle(), From 3b1b1e7cd19ebb0943dc4da30e3ddb7577d388d0 Mon Sep 17 00:00:00 2001 From: Jack Sleight Date: Fri, 15 Dec 2023 14:20:27 +0000 Subject: [PATCH 12/64] Rename publish_form context key to view --- src/Actions/Delete.php | 2 +- src/Actions/DuplicateEntry.php | 2 +- src/Http/Controllers/CP/ActionController.php | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Actions/Delete.php b/src/Actions/Delete.php index 2df5ca16d2..3b54db2aef 100644 --- a/src/Actions/Delete.php +++ b/src/Actions/Delete.php @@ -59,7 +59,7 @@ public function run($items, $values) public function redirect($items, $values) { - if ($this->context['view'] ?? null !== 'form') { + if (($this->context['view'] ?? null) !== 'form') { return; } diff --git a/src/Actions/DuplicateEntry.php b/src/Actions/DuplicateEntry.php index 55a178cf55..3dff184e52 100644 --- a/src/Actions/DuplicateEntry.php +++ b/src/Actions/DuplicateEntry.php @@ -162,7 +162,7 @@ public function authorize($user, $item) public function redirect($items, $values) { - if ($this->context['view'] ?? null !== 'form') { + if (($this->context['view'] ?? null) !== 'form') { return; } diff --git a/src/Http/Controllers/CP/ActionController.php b/src/Http/Controllers/CP/ActionController.php index 51b4dc6f6c..d1946dfc66 100644 --- a/src/Http/Controllers/CP/ActionController.php +++ b/src/Http/Controllers/CP/ActionController.php @@ -49,7 +49,7 @@ public function run(Request $request) $response = $response ?: []; - if ($context['view'] ?? null === 'form') { + if (($context['view'] ?? null) === 'form') { $response['data'] = $this->getItemData($items->first(), $context); } From 42f80b7c9f3159d2884dafb0cee83dcb617a3465 Mon Sep 17 00:00:00 2001 From: Jack Sleight Date: Fri, 15 Dec 2023 14:34:42 +0000 Subject: [PATCH 13/64] Add view key to all list contexts --- resources/js/components/entries/Listing.vue | 2 +- src/Actions/Action.php | 8 ++++++++ src/Actions/Delete.php | 2 +- src/Actions/DuplicateEntry.php | 4 +++- src/Http/Controllers/CP/ActionController.php | 4 ++-- src/Http/Resources/CP/Entries/ListedEntry.php | 3 ++- 6 files changed, 17 insertions(+), 6 deletions(-) diff --git a/resources/js/components/entries/Listing.vue b/resources/js/components/entries/Listing.vue index ae4a253496..de1d9bebcc 100644 --- a/resources/js/components/entries/Listing.vue +++ b/resources/js/components/entries/Listing.vue @@ -144,7 +144,7 @@ export default { computed: { actionContext() { - return {collection: this.collection}; + return {collection: this.collection, view: 'list'}; }, }, diff --git a/src/Actions/Action.php b/src/Actions/Action.php index 226d11ef06..5204753299 100644 --- a/src/Actions/Action.php +++ b/src/Actions/Action.php @@ -15,9 +15,13 @@ abstract class Action implements Arrayable protected static $binding = 'actions'; protected $items; + protected $confirm = true; + protected $dangerous = false; + protected $fields = []; + protected $context = []; public function __construct() @@ -62,6 +66,10 @@ public function authorizeBulk($user, $items) public function context($context) { + if (! isset($context['view'])) { + $context['view'] = 'list'; + } + $this->context = $context; return $this; diff --git a/src/Actions/Delete.php b/src/Actions/Delete.php index 3b54db2aef..46aae35fc5 100644 --- a/src/Actions/Delete.php +++ b/src/Actions/Delete.php @@ -59,7 +59,7 @@ public function run($items, $values) public function redirect($items, $values) { - if (($this->context['view'] ?? null) !== 'form') { + if ($this->context['view'] !== 'form') { return; } diff --git a/src/Actions/DuplicateEntry.php b/src/Actions/DuplicateEntry.php index 3dff184e52..1d9cb66a38 100644 --- a/src/Actions/DuplicateEntry.php +++ b/src/Actions/DuplicateEntry.php @@ -51,6 +51,8 @@ public function warningText() public function run($items, $values) { + dd($this->context); + $this->newItems = $items ->map(fn ($entry) => $entry->hasOrigin() ? $entry->root() : $entry) ->unique() @@ -162,7 +164,7 @@ public function authorize($user, $item) public function redirect($items, $values) { - if (($this->context['view'] ?? null) !== 'form') { + if ($this->context['view'] !== 'form') { return; } diff --git a/src/Http/Controllers/CP/ActionController.php b/src/Http/Controllers/CP/ActionController.php index d1946dfc66..1fdf3b37f0 100644 --- a/src/Http/Controllers/CP/ActionController.php +++ b/src/Http/Controllers/CP/ActionController.php @@ -17,7 +17,7 @@ public function run(Request $request) 'context' => 'sometimes', ]); - $context = $data['context'] ?? []; + $context = $data['context'] ?? ['view' => 'list']; $items = $this->getSelectedItems(collect($data['selections']), $context); @@ -49,7 +49,7 @@ public function run(Request $request) $response = $response ?: []; - if (($context['view'] ?? null) === 'form') { + if ($context['view'] === 'form') { $response['data'] = $this->getItemData($items->first(), $context); } diff --git a/src/Http/Resources/CP/Entries/ListedEntry.php b/src/Http/Resources/CP/Entries/ListedEntry.php index 557a6d2c66..45c57379d2 100644 --- a/src/Http/Resources/CP/Entries/ListedEntry.php +++ b/src/Http/Resources/CP/Entries/ListedEntry.php @@ -9,6 +9,7 @@ class ListedEntry extends JsonResource { protected $blueprint; + protected $columns; public function blueprint($blueprint) @@ -46,7 +47,7 @@ public function toArray($request) 'collection' => array_merge($entry->collection()->toArray(), ['dated' => $entry->collection()->dated()]), 'viewable' => User::current()->can('view', $entry), 'editable' => User::current()->can('edit', $entry), - 'actions' => Action::for($entry, ['collection' => $collection->handle()]), + 'actions' => Action::for($entry, ['collection' => $collection->handle(), 'view' => 'list']), ]; } From 099e34e37bdc7ab639fa1ac101818f42b743ee97 Mon Sep 17 00:00:00 2001 From: Jack Sleight Date: Fri, 15 Dec 2023 14:36:48 +0000 Subject: [PATCH 14/64] Rename listActionUrl --- resources/js/components/entries/PublishForm.vue | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/resources/js/components/entries/PublishForm.vue b/resources/js/components/entries/PublishForm.vue index f52ebf2ef7..5bf85f22e1 100644 --- a/resources/js/components/entries/PublishForm.vue +++ b/resources/js/components/entries/PublishForm.vue @@ -15,7 +15,7 @@ Date: Fri, 15 Dec 2023 14:38:18 +0000 Subject: [PATCH 15/64] Add blank callback method --- resources/js/components/publish/HasActions.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/resources/js/components/publish/HasActions.js b/resources/js/components/publish/HasActions.js index 9f5660e8c7..b7770f2531 100644 --- a/resources/js/components/publish/HasActions.js +++ b/resources/js/components/publish/HasActions.js @@ -24,6 +24,8 @@ export default { this.afterItemActionSuccessfullyCompleted(response); }, + afterItemActionSuccessfullyCompleted() {} + } } From 3094e395e085cca5b0d6a45b6bcabf5dcb642e50 Mon Sep 17 00:00:00 2001 From: Jack Sleight Date: Fri, 15 Dec 2023 14:39:02 +0000 Subject: [PATCH 16/64] Move method --- resources/js/components/entries/PublishForm.vue | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/resources/js/components/entries/PublishForm.vue b/resources/js/components/entries/PublishForm.vue index 5bf85f22e1..487ea041b0 100644 --- a/resources/js/components/entries/PublishForm.vue +++ b/resources/js/components/entries/PublishForm.vue @@ -507,11 +507,6 @@ export default { methods: { - afterItemActionSuccessfullyCompleted(response) { - this.values = { ...this.values, ...response.data.values }; - this.itemActions = response.data.itemActions; - }, - clearErrors() { this.error = null; this.errors = {}; @@ -795,7 +790,13 @@ export default { }, this.autosaveInterval); this.$store.commit(`publish/${this.publishContainer}/setAutosaveInterval`, interval); - } + }, + + afterItemActionSuccessfullyCompleted(response) { + this.values = { ...this.values, ...response.data.values }; + this.itemActions = response.data.itemActions; + }, + }, mounted() { From 74f640cd151fb6a5f312e7e27d9994e6d6ef5b90 Mon Sep 17 00:00:00 2001 From: Jack Sleight Date: Fri, 15 Dec 2023 15:00:59 +0000 Subject: [PATCH 17/64] Terms support (and some other tweaks) --- .../js/components/entries/PublishForm.vue | 6 ++-- resources/js/components/terms/Listing.vue | 2 +- resources/js/components/terms/PublishForm.vue | 22 +++++++++++- resources/views/entries/edit.blade.php | 2 +- resources/views/terms/edit.blade.php | 2 ++ src/Actions/Delete.php | 12 +++++-- src/Actions/DuplicateEntry.php | 2 -- src/Actions/DuplicateTerm.php | 15 +++++++- .../CP/Collections/EntryActionController.php | 7 ++-- .../CP/Taxonomies/TermActionController.php | 35 +++++++++++++++++++ .../CP/Taxonomies/TermsController.php | 2 ++ .../Resources/CP/Taxonomies/ListedTerm.php | 3 +- 12 files changed, 95 insertions(+), 15 deletions(-) diff --git a/resources/js/components/entries/PublishForm.vue b/resources/js/components/entries/PublishForm.vue index 487ea041b0..071d2d4fbd 100644 --- a/resources/js/components/entries/PublishForm.vue +++ b/resources/js/components/entries/PublishForm.vue @@ -793,8 +793,10 @@ export default { }, afterItemActionSuccessfullyCompleted(response) { - this.values = { ...this.values, ...response.data.values }; - this.itemActions = response.data.itemActions; + if (response.data) { + this.values = this.resetValuesFromResponse(response.data.data.values); + this.itemActions = response.data.itemActions; + } }, }, diff --git a/resources/js/components/terms/Listing.vue b/resources/js/components/terms/Listing.vue index 6073c437b6..6730ca7364 100644 --- a/resources/js/components/terms/Listing.vue +++ b/resources/js/components/terms/Listing.vue @@ -132,7 +132,7 @@ export default { computed: { actionContext() { - return {taxonomy: this.taxonomy}; + return {taxonomy: this.taxonomy, view: 'list'}; }, }, diff --git a/resources/js/components/terms/PublishForm.vue b/resources/js/components/terms/PublishForm.vue index b3caebbbcf..aeea2c4406 100644 --- a/resources/js/components/terms/PublishForm.vue +++ b/resources/js/components/terms/PublishForm.vue @@ -15,6 +15,13 @@ +
@@ -243,12 +250,14 @@ import SaveButtonOptions from '../publish/SaveButtonOptions.vue'; import RevisionHistory from '../revision-history/History.vue'; import HasPreferences from '../data-list/HasPreferences'; import HasHiddenFields from '../publish/HasHiddenFields'; +import HasActions from '../publish/HasActions'; export default { mixins: [ HasPreferences, HasHiddenFields, + HasActions, ], components: { @@ -287,11 +296,14 @@ export default { createAnotherUrl: String, listingUrl: String, previewTargets: Array, + initialItemActions: Array, + itemActionUrl: String, }, data() { return { actions: this.initialActions, + itemActions: this.initialItemActions, saving: false, localizing: false, fieldset: this.initialFieldset, @@ -619,7 +631,15 @@ export default { this.localizedFields.push(handle); this.$refs.container.dirty(); - } + }, + + afterItemActionSuccessfullyCompleted(response) { + if (response.data) { + this.values = { ...this.values, ...response.data.values }; + this.itemActions = response.data.itemActions; + } + }, + }, mounted() { diff --git a/resources/views/entries/edit.blade.php b/resources/views/entries/edit.blade.php index 25836268b2..ee8cae9e06 100644 --- a/resources/views/entries/edit.blade.php +++ b/resources/views/entries/edit.blade.php @@ -37,7 +37,7 @@ :preview-targets="{{ json_encode($previewTargets) }}" :autosave-interval="{{ json_encode($autosaveInterval) }}" :initial-item-actions="{{ json_encode($itemActions) }}" - list-action-url="{{ cp_route('collections.entries.actions.run', $collection) }}" + item-action-url="{{ cp_route('collections.entries.actions.run', $collection) }}" > @endsection diff --git a/resources/views/terms/edit.blade.php b/resources/views/terms/edit.blade.php index 98e9c80e52..61bc941480 100644 --- a/resources/views/terms/edit.blade.php +++ b/resources/views/terms/edit.blade.php @@ -34,6 +34,8 @@ create-another-url="{{ cp_route('taxonomies.terms.create', [$taxonomy, $locale]) }}" listing-url="{{ cp_route('taxonomies.show', $taxonomy) }}" :preview-targets="{{ json_encode($previewTargets) }}" + :initial-item-actions="{{ json_encode($itemActions) }}" + item-action-url="{{ cp_route('taxonomies.terms.actions.run', $taxonomy) }}" > @endsection diff --git a/src/Actions/Delete.php b/src/Actions/Delete.php index 46aae35fc5..1b14d0314b 100644 --- a/src/Actions/Delete.php +++ b/src/Actions/Delete.php @@ -63,7 +63,15 @@ public function redirect($items, $values) return; } - // Also need to handle terms etc, todo - return cp_route('collections.show', $items->first()->collection()->handle()); + $item = $items->first(); + + switch (true) { + case $item instanceof Contracts\Entries\Entry: + return cp_route('collections.show', $item->collection()->handle()); + break; + case $item instanceof Contracts\Taxonomies\Term: + return cp_route('taxonomies.show', $item->taxonomy()->handle()); + break; + } } } diff --git a/src/Actions/DuplicateEntry.php b/src/Actions/DuplicateEntry.php index 1d9cb66a38..e7e9cb9af3 100644 --- a/src/Actions/DuplicateEntry.php +++ b/src/Actions/DuplicateEntry.php @@ -51,8 +51,6 @@ public function warningText() public function run($items, $values) { - dd($this->context); - $this->newItems = $items ->map(fn ($entry) => $entry->hasOrigin() ? $entry->root() : $entry) ->unique() diff --git a/src/Actions/DuplicateTerm.php b/src/Actions/DuplicateTerm.php index 899f683cb6..1fbd1a883f 100644 --- a/src/Actions/DuplicateTerm.php +++ b/src/Actions/DuplicateTerm.php @@ -8,6 +8,8 @@ class DuplicateTerm extends Action { + protected $newItems; + public static function title() { return __('Duplicate'); @@ -20,7 +22,7 @@ public function visibleTo($item) public function run($items, $values) { - $items->each(function (Term $original) { + $this->newItems = $items->map(function (Term $original) { [$title, $slug] = $this->generateTitleAndSlug($original); $data = $original->data() @@ -37,6 +39,8 @@ public function run($items, $values) ->data($data); $term->save(); + + return $term; }); } @@ -72,4 +76,13 @@ public function authorize($user, $item) { return $user->can('create', [Term::class, $item->taxonomy()]); } + + public function redirect($items, $values) + { + if ($this->context['view'] !== 'form') { + return; + } + + return $this->newItems->first()->editUrl(); + } } diff --git a/src/Http/Controllers/CP/Collections/EntryActionController.php b/src/Http/Controllers/CP/Collections/EntryActionController.php index 7c01d5ea31..2f21e450c6 100644 --- a/src/Http/Controllers/CP/Collections/EntryActionController.php +++ b/src/Http/Controllers/CP/Collections/EntryActionController.php @@ -17,15 +17,14 @@ protected function getSelectedItems($items, $context) protected function getItemData($entry, $context) { - $collection = $entry->collection(); - $blueprint = $entry->blueprint(); - [$values] = $this->extractFromFields($entry, $blueprint); + [$values, $meta] = $this->extractFromFields($entry, $blueprint); return [ - 'values' => $values, 'itemActions' => Action::for($entry, $context), + 'values' => array_merge($values, ['id' => $entry->id()]), + 'meta' => $meta, ]; } diff --git a/src/Http/Controllers/CP/Taxonomies/TermActionController.php b/src/Http/Controllers/CP/Taxonomies/TermActionController.php index 91d2304ebd..d6d0f04a9e 100644 --- a/src/Http/Controllers/CP/Taxonomies/TermActionController.php +++ b/src/Http/Controllers/CP/Taxonomies/TermActionController.php @@ -2,6 +2,7 @@ namespace Statamic\Http\Controllers\CP\Taxonomies; +use Statamic\Facades\Action; use Statamic\Facades\Term; use Statamic\Http\Controllers\CP\ActionController; @@ -13,4 +14,38 @@ protected function getSelectedItems($items, $context) return Term::find($item); })->filter(); } + + protected function getItemData($term, $context) + { + $blueprint = $term->blueprint(); + + [$values, $meta] = $this->extractFromFields($term, $blueprint); + + return [ + 'itemActions' => Action::for($term, $context), + 'values' => array_merge($values, ['id' => $term->id()]), + 'meta' => $meta, + ]; + } + + protected function extractFromFields($term, $blueprint) + { + // The values should only be data merged with the origin data. + // We don't want injected taxonomy values, which $term->values() would have given us. + $values = $term->inDefaultLocale()->data()->merge( + $term->data() + ); + + $fields = $blueprint + ->fields() + ->addValues($values->all()) + ->preProcess(); + + $values = $fields->values()->merge([ + 'title' => $term->value('title'), + 'slug' => $term->slug(), + ]); + + return [$values->all(), $fields->meta()]; + } } diff --git a/src/Http/Controllers/CP/Taxonomies/TermsController.php b/src/Http/Controllers/CP/Taxonomies/TermsController.php index 9881c1832a..4f6ff98eed 100644 --- a/src/Http/Controllers/CP/Taxonomies/TermsController.php +++ b/src/Http/Controllers/CP/Taxonomies/TermsController.php @@ -5,6 +5,7 @@ use Illuminate\Http\Request; use Statamic\Contracts\Taxonomies\Term as TermContract; use Statamic\CP\Breadcrumbs; +use Statamic\Facades\Action; use Statamic\Facades\Asset; use Statamic\Facades\Site; use Statamic\Facades\Term; @@ -106,6 +107,7 @@ public function edit(Request $request, $taxonomy, $term) 'createRevision' => $term->createRevisionUrl(), 'editBlueprint' => cp_route('taxonomies.blueprints.edit', [$taxonomy, $blueprint]), ], + 'itemActions' => Action::for($term, ['taxonomy' => $taxonomy->handle(), 'view' => 'form']), 'values' => array_merge($values, ['id' => $term->id()]), 'meta' => $meta, 'taxonomy' => $taxonomy->handle(), diff --git a/src/Http/Resources/CP/Taxonomies/ListedTerm.php b/src/Http/Resources/CP/Taxonomies/ListedTerm.php index 997e56a547..ae7ad76973 100644 --- a/src/Http/Resources/CP/Taxonomies/ListedTerm.php +++ b/src/Http/Resources/CP/Taxonomies/ListedTerm.php @@ -9,6 +9,7 @@ class ListedTerm extends JsonResource { protected $blueprint; + protected $columns; public function blueprint($blueprint) @@ -45,7 +46,7 @@ public function toArray($request) 'taxonomy' => $term->taxonomy()->toArray(), 'viewable' => User::current()->can('view', $term), 'editable' => User::current()->can('edit', $term), - 'actions' => Action::for($term, ['taxonomy' => $taxonomy->handle()]), + 'actions' => Action::for($term, ['taxonomy' => $taxonomy->handle(), 'view' => 'list']), ]; } From bd93be4636c1a22df5a31abd02016bee267eae2f Mon Sep 17 00:00:00 2001 From: Jack Sleight Date: Fri, 15 Dec 2023 15:33:19 +0000 Subject: [PATCH 18/64] Support users --- .../js/components/entries/PublishForm.vue | 12 +++++----- resources/js/components/publish/HasActions.js | 19 ++++++++++++++- resources/js/components/terms/PublishForm.vue | 12 +++++----- resources/js/components/users/Listing.vue | 7 +++++- resources/js/components/users/PublishForm.vue | 23 ++++++++++++++++-- resources/views/users/edit.blade.php | 2 ++ .../CP/Collections/EntriesController.php | 2 +- .../CP/Taxonomies/TermsController.php | 2 +- .../CP/Users/UserActionController.php | 24 +++++++++++++++++++ .../Controllers/CP/Users/UsersController.php | 2 ++ src/Http/Resources/CP/Users/ListedUser.php | 3 ++- 11 files changed, 89 insertions(+), 19 deletions(-) diff --git a/resources/js/components/entries/PublishForm.vue b/resources/js/components/entries/PublishForm.vue index 071d2d4fbd..b319c52473 100644 --- a/resources/js/components/entries/PublishForm.vue +++ b/resources/js/components/entries/PublishForm.vue @@ -14,7 +14,7 @@ @@ -150,7 +151,11 @@ export default { return { group: this.group, } - } + }, + + actionContext() { + return {view: 'list'}; + }, } diff --git a/resources/js/components/users/PublishForm.vue b/resources/js/components/users/PublishForm.vue index 5f8e1f629d..80ef34be88 100644 --- a/resources/js/components/users/PublishForm.vue +++ b/resources/js/components/users/PublishForm.vue @@ -8,6 +8,13 @@

+ import ChangePassword from './ChangePassword.vue'; import HasHiddenFields from '../publish/HasHiddenFields'; +import HasActions from '../publish/HasActions'; export default { mixins: [ HasHiddenFields, + HasActions, ], components: { @@ -95,7 +104,11 @@ export default { hasErrors() { return this.error || Object.keys(this.errors).length; - } + }, + + initialReferenceId() { + return this.initialReference.split('::')[1]; + }, }, @@ -127,7 +140,13 @@ export default { this.$toast.error(__('Something went wrong')); } }); - } + }, + + afterItemActionSuccessfullyCompleted(response) { + if (response.data) { + this.values = this.resetValuesFromResponse(response.data.values); + } + }, }, diff --git a/resources/views/users/edit.blade.php b/resources/views/users/edit.blade.php index 856a61c8f0..8a73f208b1 100644 --- a/resources/views/users/edit.blade.php +++ b/resources/views/users/edit.blade.php @@ -15,6 +15,8 @@ :can-edit-password="{{ Statamic\Support\Str::bool($canEditPassword) }}" :can-edit-blueprint="{{ Statamic\Support\Str::bool($user->can('configure fields')) }}" :requires-current-password="{{ Statamic\Support\Str::bool($requiresCurrentPassword) }}" + :initial-item-actions="{{ json_encode($itemActions) }}" + item-action-url="{{ cp_route('users.actions.run') }}" > @endsection diff --git a/src/Http/Controllers/CP/Collections/EntriesController.php b/src/Http/Controllers/CP/Collections/EntriesController.php index 286810c6f5..92e8ef2442 100644 --- a/src/Http/Controllers/CP/Collections/EntriesController.php +++ b/src/Http/Controllers/CP/Collections/EntriesController.php @@ -118,7 +118,6 @@ public function edit(Request $request, $collection, $entry) 'createRevision' => $entry->createRevisionUrl(), 'editBlueprint' => cp_route('collections.blueprints.edit', [$collection, $blueprint]), ], - 'itemActions' => Action::for($entry, ['collection' => $collection->handle(), 'view' => 'form']), 'values' => array_merge($values, ['id' => $entry->id()]), 'meta' => $meta, 'collection' => $collection->handle(), @@ -157,6 +156,7 @@ public function edit(Request $request, $collection, $entry) 'canManagePublishState' => User::current()->can('publish', $entry), 'previewTargets' => $collection->previewTargets()->all(), 'autosaveInterval' => $collection->autosaveInterval(), + 'itemActions' => Action::for($entry, ['collection' => $collection->handle(), 'view' => 'form']), ]; if ($request->wantsJson()) { diff --git a/src/Http/Controllers/CP/Taxonomies/TermsController.php b/src/Http/Controllers/CP/Taxonomies/TermsController.php index 4f6ff98eed..d2733b8238 100644 --- a/src/Http/Controllers/CP/Taxonomies/TermsController.php +++ b/src/Http/Controllers/CP/Taxonomies/TermsController.php @@ -107,7 +107,6 @@ public function edit(Request $request, $taxonomy, $term) 'createRevision' => $term->createRevisionUrl(), 'editBlueprint' => cp_route('taxonomies.blueprints.edit', [$taxonomy, $blueprint]), ], - 'itemActions' => Action::for($term, ['taxonomy' => $taxonomy->handle(), 'view' => 'form']), 'values' => array_merge($values, ['id' => $term->id()]), 'meta' => $meta, 'taxonomy' => $taxonomy->handle(), @@ -141,6 +140,7 @@ public function edit(Request $request, $taxonomy, $term) 'revisionsEnabled' => $term->revisionsEnabled(), 'breadcrumbs' => $this->breadcrumbs($taxonomy), 'previewTargets' => $taxonomy->previewTargets()->all(), + 'itemActions' => Action::for($term, ['taxonomy' => $taxonomy->handle(), 'view' => 'form']), ]; if ($request->wantsJson()) { diff --git a/src/Http/Controllers/CP/Users/UserActionController.php b/src/Http/Controllers/CP/Users/UserActionController.php index ca2b83c499..c899341beb 100644 --- a/src/Http/Controllers/CP/Users/UserActionController.php +++ b/src/Http/Controllers/CP/Users/UserActionController.php @@ -2,6 +2,7 @@ namespace Statamic\Http\Controllers\CP\Users; +use Statamic\Facades\Action; use Statamic\Facades\User; use Statamic\Http\Controllers\CP\ActionController; @@ -13,4 +14,27 @@ protected function getSelectedItems($items, $context) return User::find($item); }); } + + protected function getItemData($user, $context) + { + $blueprint = $user->blueprint(); + + [$values, $meta] = $this->extractFromFields($user, $blueprint); + + return [ + 'itemActions' => Action::for($user, $context), + 'values' => array_merge($values, ['id' => $user->id()]), + 'meta' => $meta, + ]; + } + + protected function extractFromFields($user, $blueprint) + { + $fields = $blueprint + ->fields() + ->addValues($user->data()->all()) + ->preProcess(); + + return [$fields->values()->all(), $fields->meta()->all()]; + } } diff --git a/src/Http/Controllers/CP/Users/UsersController.php b/src/Http/Controllers/CP/Users/UsersController.php index 0691688f8f..38d0e0a3e5 100644 --- a/src/Http/Controllers/CP/Users/UsersController.php +++ b/src/Http/Controllers/CP/Users/UsersController.php @@ -6,6 +6,7 @@ use Statamic\Auth\Passwords\PasswordReset; use Statamic\Contracts\Auth\User as UserContract; use Statamic\Exceptions\NotFoundHttpException; +use Statamic\Facades\Action; use Statamic\Facades\Scope; use Statamic\Facades\Search; use Statamic\Facades\User; @@ -240,6 +241,7 @@ public function edit(Request $request, $user) ], 'canEditPassword' => User::fromUser($request->user())->can('editPassword', $user), 'requiresCurrentPassword' => $request->user()->id === $user->id(), + 'itemActions' => Action::for($user, ['view' => 'form']), ]; if ($request->wantsJson()) { diff --git a/src/Http/Resources/CP/Users/ListedUser.php b/src/Http/Resources/CP/Users/ListedUser.php index fc97452a97..b56d9783ff 100644 --- a/src/Http/Resources/CP/Users/ListedUser.php +++ b/src/Http/Resources/CP/Users/ListedUser.php @@ -9,6 +9,7 @@ class ListedUser extends JsonResource { protected $blueprint; + protected $columns; public function blueprint($blueprint) @@ -41,7 +42,7 @@ public function toArray($request) 'initials' => $this->initials(), 'editable' => User::current()->can('edit', $this->resource), 'deleteable' => User::current()->can('delete', $this->resource), - 'actions' => Action::for($this->resource), + 'actions' => Action::for($this->resource, ['view' => 'list']), ]; } From a641a4498d1dbe3166fee6d76a76a44590d1cd43 Mon Sep 17 00:00:00 2001 From: Jack Sleight Date: Mon, 18 Dec 2023 15:49:47 +0000 Subject: [PATCH 19/64] Rename callback method --- resources/js/components/entries/PublishForm.vue | 2 +- resources/js/components/publish/HasActions.js | 4 ++-- resources/js/components/terms/PublishForm.vue | 2 +- resources/js/components/users/PublishForm.vue | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/resources/js/components/entries/PublishForm.vue b/resources/js/components/entries/PublishForm.vue index b319c52473..fb1defd3cc 100644 --- a/resources/js/components/entries/PublishForm.vue +++ b/resources/js/components/entries/PublishForm.vue @@ -793,7 +793,7 @@ export default { this.$store.commit(`publish/${this.publishContainer}/setAutosaveInterval`, interval); }, - afterItemActionSuccessfullyCompleted(response) { + afterActionSuccessfullyCompleted(response) { if (response.data) { this.values = this.resetValuesFromResponse(response.data.values); } diff --git a/resources/js/components/publish/HasActions.js b/resources/js/components/publish/HasActions.js index dd80d5ded0..a9f15cb7d4 100644 --- a/resources/js/components/publish/HasActions.js +++ b/resources/js/components/publish/HasActions.js @@ -36,10 +36,10 @@ export default { this.itemActions = response.data.itemActions; } - this.afterItemActionSuccessfullyCompleted(response); + this.afterActionSuccessfullyCompleted(response); }, - afterItemActionSuccessfullyCompleted(response) { + afterActionSuccessfullyCompleted(response) { // } diff --git a/resources/js/components/terms/PublishForm.vue b/resources/js/components/terms/PublishForm.vue index 28210ddadf..cbb5033efb 100644 --- a/resources/js/components/terms/PublishForm.vue +++ b/resources/js/components/terms/PublishForm.vue @@ -634,7 +634,7 @@ export default { this.$refs.container.dirty(); }, - afterItemActionSuccessfullyCompleted(response) { + afterActionSuccessfullyCompleted(response) { if (response.data) { this.values = this.resetValuesFromResponse(response.data.values); } diff --git a/resources/js/components/users/PublishForm.vue b/resources/js/components/users/PublishForm.vue index 80ef34be88..a8adc715c9 100644 --- a/resources/js/components/users/PublishForm.vue +++ b/resources/js/components/users/PublishForm.vue @@ -142,7 +142,7 @@ export default { }); }, - afterItemActionSuccessfullyCompleted(response) { + afterActionSuccessfullyCompleted(response) { if (response.data) { this.values = this.resetValuesFromResponse(response.data.values); } From 8233b74d04ba9c0721e3a3c75bf35e0878ee22d2 Mon Sep 17 00:00:00 2001 From: Jack Sleight Date: Mon, 18 Dec 2023 17:14:49 +0000 Subject: [PATCH 20/64] Refactor a bunch of thingd --- resources/css/elements/dropdowns.css | 5 +++++ .../js/components/entries/PublishForm.vue | 22 ++++++++++++++----- resources/js/components/terms/PublishForm.vue | 11 +++++++--- resources/js/components/users/PublishForm.vue | 22 +++++++++++++++---- .../CP/Collections/EntryActionController.php | 7 +++--- .../CP/Taxonomies/TermActionController.php | 7 +++--- .../CP/Taxonomies/TermsController.php | 9 +++++++- .../CP/Users/UserActionController.php | 11 ++++++---- .../Controllers/CP/Users/UsersController.php | 18 +++++++++++++++ src/Taxonomies/Term.php | 7 ++++++ 10 files changed, 95 insertions(+), 24 deletions(-) diff --git a/resources/css/elements/dropdowns.css b/resources/css/elements/dropdowns.css index b7bd59899d..98749dfa00 100644 --- a/resources/css/elements/dropdowns.css +++ b/resources/css/elements/dropdowns.css @@ -40,6 +40,11 @@ .divider { @apply h-px bg-gray-400 overflow-hidden; margin: 6px -8px; + /* Hide dividers that come first or immediately after another (due to v-if) */ + & + &, + &:first-child { + display: none; + } } .align-left & { diff --git a/resources/js/components/entries/PublishForm.vue b/resources/js/components/entries/PublishForm.vue index fb1defd3cc..025fa9167f 100644 --- a/resources/js/components/entries/PublishForm.vue +++ b/resources/js/components/entries/PublishForm.vue @@ -13,10 +13,11 @@ +
  • @@ -493,7 +494,11 @@ export default { }, initialReferenceId() { - return this.initialReference.split('::')[2]; + return this.initialReference.split('::').pop(); + }, + + itemActionsFiltered() { + return this.itemActions.filter(action => !['publish', 'unpublish'].includes(action.handle)); }, }, @@ -502,7 +507,13 @@ export default { saving(saving) { this.$progress.loading(`${this.publishContainer}-entry-publish-form`, saving); - } + }, + + title(title) { + if (this.isBase) { + document.title = title + ' ‹ ' + this.breadcrumbs[1].text + ' ‹ ' + this.breadcrumbs[0].text + ' ‹ Statamic'; + } + }, }, @@ -556,9 +567,6 @@ export default { } this.title = response.data.data.title; this.isWorkingCopy = true; - if (this.isBase) { - document.title = this.title + ' ‹ ' + this.breadcrumbs[1].text + ' ‹ ' + this.breadcrumbs[0].text + ' ‹ Statamic'; - } if (!this.revisionsEnabled) this.permalink = response.data.data.permalink; if (!this.isCreating && !this.isAutosave) this.$toast.success(__('Saved')); this.$refs.container.saved(); @@ -795,6 +803,8 @@ export default { afterActionSuccessfullyCompleted(response) { if (response.data) { + this.title = response.data.title; + if (!this.revisionsEnabled) this.permalink = response.data.permalink; this.values = this.resetValuesFromResponse(response.data.values); } }, diff --git a/resources/js/components/terms/PublishForm.vue b/resources/js/components/terms/PublishForm.vue index cbb5033efb..6e365fc577 100644 --- a/resources/js/components/terms/PublishForm.vue +++ b/resources/js/components/terms/PublishForm.vue @@ -13,8 +13,9 @@
  • - - + + +
  • { // If revisions are enabled, just emit event. if (this.revisionsEnabled) { + this.values = this.resetValuesFromResponse(response.data.data.values); this.$nextTick(() => this.$emit('saved', response)); return; } @@ -506,6 +508,7 @@ export default { // the hooks are resolved because if this form is being shown in a stack, we only // want to close it once everything's done. else { + this.values = this.resetValuesFromResponse(response.data.data.values); this.$nextTick(() => this.$emit('saved', response)); } @@ -636,6 +639,8 @@ export default { afterActionSuccessfullyCompleted(response) { if (response.data) { + this.title = response.data.title; + this.permalink = response.data.permalink; this.values = this.resetValuesFromResponse(response.data.values); } }, diff --git a/resources/js/components/users/PublishForm.vue b/resources/js/components/users/PublishForm.vue index a8adc715c9..bd7707d5ee 100644 --- a/resources/js/components/users/PublishForm.vue +++ b/resources/js/components/users/PublishForm.vue @@ -6,12 +6,13 @@

    - - + + +
  • @@ -90,6 +91,7 @@ export default { }, data() { + console.log(this.initialTitle); return { fieldset: _.clone(this.initialFieldset), values: _.clone(this.initialValues), @@ -107,7 +109,11 @@ export default { }, initialReferenceId() { - return this.initialReference.split('::')[1]; + return this.initialReference.split('::').pop(); + }, + + itemActionsFiltered() { + return this.itemActions.filter(action => !['assign_groups'].includes(action.handle)); }, }, @@ -124,6 +130,7 @@ export default { this.$axios[this.method](this.actions.save, this.visibleValues).then(response => { this.title = response.data.title; + this.values = this.resetValuesFromResponse(response.data.data.values); if (!response.data.saved) { return this.$toast.error(`Couldn't save user`) } @@ -144,12 +151,19 @@ export default { afterActionSuccessfullyCompleted(response) { if (response.data) { + this.title = response.data.title; this.values = this.resetValuesFromResponse(response.data.values); } }, }, + watch: { + title() { + console.log(this.title); + }, + }, + mounted() { this.$keys.bindGlobal(['mod+s'], e => { e.preventDefault(); diff --git a/src/Http/Controllers/CP/Collections/EntryActionController.php b/src/Http/Controllers/CP/Collections/EntryActionController.php index 2f21e450c6..e2344a8ca5 100644 --- a/src/Http/Controllers/CP/Collections/EntryActionController.php +++ b/src/Http/Controllers/CP/Collections/EntryActionController.php @@ -19,12 +19,13 @@ protected function getItemData($entry, $context) { $blueprint = $entry->blueprint(); - [$values, $meta] = $this->extractFromFields($entry, $blueprint); + [$values] = $this->extractFromFields($entry, $blueprint); return [ - 'itemActions' => Action::for($entry, $context), + 'title' => $entry->value('title'), + 'permalink' => $entry->absoluteUrl(), 'values' => array_merge($values, ['id' => $entry->id()]), - 'meta' => $meta, + 'itemActions' => Action::for($entry, $context), ]; } diff --git a/src/Http/Controllers/CP/Taxonomies/TermActionController.php b/src/Http/Controllers/CP/Taxonomies/TermActionController.php index d6d0f04a9e..ebe62bfe59 100644 --- a/src/Http/Controllers/CP/Taxonomies/TermActionController.php +++ b/src/Http/Controllers/CP/Taxonomies/TermActionController.php @@ -19,12 +19,13 @@ protected function getItemData($term, $context) { $blueprint = $term->blueprint(); - [$values, $meta] = $this->extractFromFields($term, $blueprint); + [$values] = $this->extractFromFields($term, $blueprint); return [ - 'itemActions' => Action::for($term, $context), + 'title' => $term->value('title'), + 'permalink' => $term->absoluteUrl(), 'values' => array_merge($values, ['id' => $term->id()]), - 'meta' => $meta, + 'itemActions' => Action::for($term, $context), ]; } diff --git a/src/Http/Controllers/CP/Taxonomies/TermsController.php b/src/Http/Controllers/CP/Taxonomies/TermsController.php index d2733b8238..9464cecf37 100644 --- a/src/Http/Controllers/CP/Taxonomies/TermsController.php +++ b/src/Http/Controllers/CP/Taxonomies/TermsController.php @@ -200,8 +200,15 @@ public function update(Request $request, $taxonomy, $term, $site) $saved = $term->updateLastModified(User::current())->save(); } + [$values] = $this->extractFromFields($term, $term->blueprint()); + return (new TermResource($term)) - ->additional(['saved' => $saved]); + ->additional([ + 'saved' => $saved, + 'data' => [ + 'values' => $values, + ], + ]); } public function create(Request $request, $taxonomy, $site) diff --git a/src/Http/Controllers/CP/Users/UserActionController.php b/src/Http/Controllers/CP/Users/UserActionController.php index c899341beb..bdd47d4e1c 100644 --- a/src/Http/Controllers/CP/Users/UserActionController.php +++ b/src/Http/Controllers/CP/Users/UserActionController.php @@ -19,12 +19,12 @@ protected function getItemData($user, $context) { $blueprint = $user->blueprint(); - [$values, $meta] = $this->extractFromFields($user, $blueprint); + [$values] = $this->extractFromFields($user, $blueprint); return [ - 'itemActions' => Action::for($user, $context), + 'title' => $user->title(), 'values' => array_merge($values, ['id' => $user->id()]), - 'meta' => $meta, + 'itemActions' => Action::for($user, $context), ]; } @@ -32,7 +32,10 @@ protected function extractFromFields($user, $blueprint) { $fields = $blueprint ->fields() - ->addValues($user->data()->all()) + ->addValues(array_merge( + $user->data()->all(), + ['email' => $user->email()], + )) ->preProcess(); return [$fields->values()->all(), $fields->meta()->all()]; diff --git a/src/Http/Controllers/CP/Users/UsersController.php b/src/Http/Controllers/CP/Users/UsersController.php index 38d0e0a3e5..bb041ae654 100644 --- a/src/Http/Controllers/CP/Users/UsersController.php +++ b/src/Http/Controllers/CP/Users/UsersController.php @@ -287,9 +287,14 @@ public function update(Request $request, $user) $save = $user->save(); + [$values] = $this->extractFromFields($user, $user->blueprint()); + return [ 'title' => $user->title(), 'saved' => is_bool($save) ? $save : true, + 'data' => [ + 'values' => $values, + ], ]; } @@ -307,4 +312,17 @@ public function destroy($user) return response('', 204); } + + protected function extractFromFields($user, $blueprint) + { + $fields = $blueprint + ->fields() + ->addValues(array_merge( + $user->data()->all(), + ['email' => $user->email()], + )) + ->preProcess(); + + return [$fields->values()->all(), $fields->meta()->all()]; + } } diff --git a/src/Taxonomies/Term.php b/src/Taxonomies/Term.php index 84ca6bea55..9301059b25 100644 --- a/src/Taxonomies/Term.php +++ b/src/Taxonomies/Term.php @@ -24,12 +24,19 @@ class Term implements TermContract use ExistsAsFile, FluentlyGetsAndSets, SyncsOriginalState; protected $taxonomy; + protected $slug; + protected $blueprint; + protected $collection; + protected $data; + protected $afterSaveCallbacks = []; + protected $withEvents = true; + protected $syncOriginalProperties = ['slug']; public function __construct() From f7f74a7e4f4146fe2364c0fcf91be961e9bb3cfe Mon Sep 17 00:00:00 2001 From: Jack Sleight Date: Mon, 18 Dec 2023 17:53:00 +0000 Subject: [PATCH 21/64] Assets support --- .../js/components/assets/Editor/Editor.vue | 25 ++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/resources/js/components/assets/Editor/Editor.vue b/resources/js/components/assets/Editor/Editor.vue index ce6f193d28..d25e97fee2 100644 --- a/resources/js/components/assets/Editor/Editor.vue +++ b/resources/js/components/assets/Editor/Editor.vue @@ -64,6 +64,16 @@ + + + +
  • @@ -271,7 +281,20 @@ export default { isToolbarVisible() { return ! this.readOnly && this.showToolbar; - } + }, + + menuActions() + { + return this.actions.filter(action => ![ + 'rename_asset', + 'move_asset', + 'replace_asset', + 'reupload_asset', + 'download_asset', + 'delete', + ].includes(action.handle)); + }, + }, mounted() { From 25ea12ef6788463ae162e93c8410c2fa4e3f0a82 Mon Sep 17 00:00:00 2001 From: Jack Sleight Date: Mon, 18 Dec 2023 17:53:16 +0000 Subject: [PATCH 22/64] Rename filtered actions list --- resources/js/components/entries/PublishForm.vue | 4 ++-- resources/js/components/users/PublishForm.vue | 5 ++--- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/resources/js/components/entries/PublishForm.vue b/resources/js/components/entries/PublishForm.vue index 025fa9167f..5c2cfde3d0 100644 --- a/resources/js/components/entries/PublishForm.vue +++ b/resources/js/components/entries/PublishForm.vue @@ -17,7 +17,7 @@ @@ -497,7 +497,7 @@ export default { return this.initialReference.split('::').pop(); }, - itemActionsFiltered() { + itemActionsMenu() { return this.itemActions.filter(action => !['publish', 'unpublish'].includes(action.handle)); }, diff --git a/resources/js/components/users/PublishForm.vue b/resources/js/components/users/PublishForm.vue index bd7707d5ee..296a09d62a 100644 --- a/resources/js/components/users/PublishForm.vue +++ b/resources/js/components/users/PublishForm.vue @@ -12,7 +12,7 @@ @@ -91,7 +91,6 @@ export default { }, data() { - console.log(this.initialTitle); return { fieldset: _.clone(this.initialFieldset), values: _.clone(this.initialValues), @@ -112,7 +111,7 @@ export default { return this.initialReference.split('::').pop(); }, - itemActionsFiltered() { + itemActionsMenu() { return this.itemActions.filter(action => !['assign_groups'].includes(action.handle)); }, From d73aa2a833de0aa6dfe95e8252173ce64cc991c1 Mon Sep 17 00:00:00 2001 From: Jack Sleight Date: Tue, 19 Dec 2023 10:11:00 +0000 Subject: [PATCH 23/64] Ensure view context is always set --- resources/js/components/assets/Browser/Browser.vue | 2 +- resources/js/components/forms/SubmissionListing.vue | 2 +- src/Actions/Action.php | 4 ---- src/Http/Resources/CP/Assets/Asset.php | 1 + src/Http/Resources/CP/Assets/Folder.php | 1 + src/Http/Resources/CP/Assets/FolderAsset.php | 1 + src/Http/Resources/CP/Submissions/ListedSubmission.php | 2 +- 7 files changed, 6 insertions(+), 7 deletions(-) diff --git a/resources/js/components/assets/Browser/Browser.vue b/resources/js/components/assets/Browser/Browser.vue index ea5930ac63..126fd29087 100644 --- a/resources/js/components/assets/Browser/Browser.vue +++ b/resources/js/components/assets/Browser/Browser.vue @@ -373,7 +373,7 @@ export default { }, actionContext() { - return {container: this.selectedContainer}; + return {container: this.selectedContainer, view: 'list'}; }, showContainerTabs() { diff --git a/resources/js/components/forms/SubmissionListing.vue b/resources/js/components/forms/SubmissionListing.vue index 10e9cac068..b3064169fa 100644 --- a/resources/js/components/forms/SubmissionListing.vue +++ b/resources/js/components/forms/SubmissionListing.vue @@ -92,7 +92,7 @@ export default { computed: { actionContext() { - return {form: this.form}; + return {form: this.form, view: 'list'}; }, }, diff --git a/src/Actions/Action.php b/src/Actions/Action.php index 5204753299..aea86dfbcb 100644 --- a/src/Actions/Action.php +++ b/src/Actions/Action.php @@ -66,10 +66,6 @@ public function authorizeBulk($user, $items) public function context($context) { - if (! isset($context['view'])) { - $context['view'] = 'list'; - } - $this->context = $context; return $this; diff --git a/src/Http/Resources/CP/Assets/Asset.php b/src/Http/Resources/CP/Assets/Asset.php index 49c56cf8fa..4e0ff2c437 100644 --- a/src/Http/Resources/CP/Assets/Asset.php +++ b/src/Http/Resources/CP/Assets/Asset.php @@ -53,6 +53,7 @@ public function toArray($request) 'actions' => Action::for($this->resource, [ 'container' => $this->container()->handle(), 'folder' => $this->folder(), + 'view' => 'form', ]), 'blueprint' => $this->blueprint()->toPublishArray(), diff --git a/src/Http/Resources/CP/Assets/Folder.php b/src/Http/Resources/CP/Assets/Folder.php index 330f8d1d02..1472a48a9a 100644 --- a/src/Http/Resources/CP/Assets/Folder.php +++ b/src/Http/Resources/CP/Assets/Folder.php @@ -24,6 +24,7 @@ public function toArray($request) 'actions' => Action::for($this->resource, [ 'container' => $this->container()->handle(), 'folder' => $this->path(), + 'view' => 'list', ]), $this->mergeWhen($this->withChildFolders, function () { diff --git a/src/Http/Resources/CP/Assets/FolderAsset.php b/src/Http/Resources/CP/Assets/FolderAsset.php index 384d3f1c53..8fec2e9371 100644 --- a/src/Http/Resources/CP/Assets/FolderAsset.php +++ b/src/Http/Resources/CP/Assets/FolderAsset.php @@ -30,6 +30,7 @@ public function toArray($request) 'actions' => Action::for($this->resource, [ 'container' => $this->container()->handle(), 'folder' => $this->folder(), + 'view' => 'list', ]), ]; } diff --git a/src/Http/Resources/CP/Submissions/ListedSubmission.php b/src/Http/Resources/CP/Submissions/ListedSubmission.php index 27d2525332..2d7fe12c7b 100644 --- a/src/Http/Resources/CP/Submissions/ListedSubmission.php +++ b/src/Http/Resources/CP/Submissions/ListedSubmission.php @@ -36,7 +36,7 @@ public function toArray($request) ])), 'url' => cp_route('forms.submissions.show', [$form->handle(), $this->resource->id()]), 'deleteable' => User::current()->can('delete', $this->resource), - 'actions' => Action::for($this->resource), + 'actions' => Action::for($this->resource, ['view' => 'list']), ]; } From a02baffb10788e293046edbb26b2ba12ee7aa64e Mon Sep 17 00:00:00 2001 From: Jack Sleight Date: Tue, 19 Dec 2023 10:24:50 +0000 Subject: [PATCH 24/64] User delete redirect --- src/Actions/Delete.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/Actions/Delete.php b/src/Actions/Delete.php index 1b14d0314b..fab22c4f00 100644 --- a/src/Actions/Delete.php +++ b/src/Actions/Delete.php @@ -72,6 +72,9 @@ public function redirect($items, $values) case $item instanceof Contracts\Taxonomies\Term: return cp_route('taxonomies.show', $item->taxonomy()->handle()); break; + case $item instanceof Contracts\Auth\User: + return cp_route('users.index'); + break; } } } From d4351d81699e7952a6ad87649ea806a3592a2726 Mon Sep 17 00:00:00 2001 From: Jack Sleight Date: Tue, 19 Dec 2023 10:30:25 +0000 Subject: [PATCH 25/64] Fix error creating new entries and terms --- resources/js/components/entries/PublishForm.vue | 3 ++- resources/js/components/terms/PublishForm.vue | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/resources/js/components/entries/PublishForm.vue b/resources/js/components/entries/PublishForm.vue index 5c2cfde3d0..72d914a012 100644 --- a/resources/js/components/entries/PublishForm.vue +++ b/resources/js/components/entries/PublishForm.vue @@ -11,10 +11,11 @@
  • - +
  • - +
  • Date: Tue, 19 Dec 2023 10:52:29 +0000 Subject: [PATCH 26/64] Reanme initialReferenceId to just id --- resources/js/components/entries/PublishForm.vue | 4 ++-- resources/js/components/terms/PublishForm.vue | 4 ++-- resources/js/components/users/PublishForm.vue | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/resources/js/components/entries/PublishForm.vue b/resources/js/components/entries/PublishForm.vue index 72d914a012..073c3ed2ec 100644 --- a/resources/js/components/entries/PublishForm.vue +++ b/resources/js/components/entries/PublishForm.vue @@ -16,7 +16,7 @@
  • Date: Tue, 19 Dec 2023 10:52:55 +0000 Subject: [PATCH 27/64] Remove duplicate callback call --- resources/js/components/publish/HasActions.js | 4 ---- 1 file changed, 4 deletions(-) diff --git a/resources/js/components/publish/HasActions.js b/resources/js/components/publish/HasActions.js index a9f15cb7d4..329eb28dff 100644 --- a/resources/js/components/publish/HasActions.js +++ b/resources/js/components/publish/HasActions.js @@ -24,10 +24,6 @@ export default { this.$events.$emit('reset-action-modals'); - if (response.callback) { - Statamic.$callbacks.call(response.callback[0], ...response.callback.slice(1)); - } - if (response.message !== false) { this.$toast.success(response.message || __("Action completed")); } From 42ccbdb2dfbb1a859a8f76320dd23d2e1cb93ef8 Mon Sep 17 00:00:00 2001 From: Jack Sleight Date: Tue, 19 Dec 2023 10:56:07 +0000 Subject: [PATCH 28/64] Refactor user extractFromFields --- .../CP/Users/UserActionController.php | 11 +++++--- .../Controllers/CP/Users/UsersController.php | 26 +++++++------------ 2 files changed, 17 insertions(+), 20 deletions(-) diff --git a/src/Http/Controllers/CP/Users/UserActionController.php b/src/Http/Controllers/CP/Users/UserActionController.php index bdd47d4e1c..7ded5c8211 100644 --- a/src/Http/Controllers/CP/Users/UserActionController.php +++ b/src/Http/Controllers/CP/Users/UserActionController.php @@ -30,12 +30,15 @@ protected function getItemData($user, $context) protected function extractFromFields($user, $blueprint) { + $values = $user->data() + ->merge($user->computedData()) + ->merge(['email' => $user->email()]); + $fields = $blueprint + ->removeField('password') + ->removeField('password_confirmation') ->fields() - ->addValues(array_merge( - $user->data()->all(), - ['email' => $user->email()], - )) + ->addValues($values->all()) ->preProcess(); return [$fields->values()->all(), $fields->meta()->all()]; diff --git a/src/Http/Controllers/CP/Users/UsersController.php b/src/Http/Controllers/CP/Users/UsersController.php index bb041ae654..c50f37e088 100644 --- a/src/Http/Controllers/CP/Users/UsersController.php +++ b/src/Http/Controllers/CP/Users/UsersController.php @@ -217,21 +217,12 @@ public function edit(Request $request, $user) $blueprint->ensureField('super', ['type' => 'toggle']); } - $values = $user->data() - ->merge($user->computedData()) - ->merge(['email' => $user->email()]); - - $fields = $blueprint - ->removeField('password') - ->removeField('password_confirmation') - ->fields() - ->addValues($values->all()) - ->preProcess(); + [$values, $meta] = $this->extractFromFields($user, $blueprint); $viewData = [ 'title' => $user->email(), - 'values' => $fields->values()->all(), - 'meta' => $fields->meta(), + 'values' => $values, + 'meta' => $meta, 'blueprint' => $user->blueprint()->toPublishArray(), 'reference' => $user->reference(), 'actions' => [ @@ -315,12 +306,15 @@ public function destroy($user) protected function extractFromFields($user, $blueprint) { + $values = $user->data() + ->merge($user->computedData()) + ->merge(['email' => $user->email()]); + $fields = $blueprint + ->removeField('password') + ->removeField('password_confirmation') ->fields() - ->addValues(array_merge( - $user->data()->all(), - ['email' => $user->email()], - )) + ->addValues($values->all()) ->preProcess(); return [$fields->values()->all(), $fields->meta()->all()]; From bc76eafbedee5b47d9b7d7c906ed44651dea9840 Mon Sep 17 00:00:00 2001 From: Jack Sleight Date: Tue, 19 Dec 2023 10:56:15 +0000 Subject: [PATCH 29/64] Fix whitespace --- src/Actions/Action.php | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/Actions/Action.php b/src/Actions/Action.php index aea86dfbcb..b95308b545 100644 --- a/src/Actions/Action.php +++ b/src/Actions/Action.php @@ -13,15 +13,10 @@ abstract class Action implements Arrayable use HasFields, HasHandle, HasTitle, RegistersItself; protected static $binding = 'actions'; - protected $items; - protected $confirm = true; - protected $dangerous = false; - protected $fields = []; - protected $context = []; public function __construct() From 42287d1d6114d2791807cb729df2424618e20450 Mon Sep 17 00:00:00 2001 From: Jack Sleight Date: Tue, 19 Dec 2023 10:59:10 +0000 Subject: [PATCH 30/64] Fix test --- tests/Feature/Entries/DeleteEntryTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/Feature/Entries/DeleteEntryTest.php b/tests/Feature/Entries/DeleteEntryTest.php index 1f7cb22040..6b2a4d30ad 100644 --- a/tests/Feature/Entries/DeleteEntryTest.php +++ b/tests/Feature/Entries/DeleteEntryTest.php @@ -139,7 +139,7 @@ public function deleteEntries($ids) { return $this->postJson('/cp/collections/test/entries/actions', [ 'action' => 'delete', - 'context' => ['collection' => 'test'], + 'context' => ['collection' => 'test', 'view' => 'list'], 'selections' => $ids, 'values' => [], ]); From 8bd45b95c833ede0e59f081978878183e8b399aa Mon Sep 17 00:00:00 2001 From: Jack Sleight Date: Tue, 19 Dec 2023 10:59:40 +0000 Subject: [PATCH 31/64] Ensure actions always have view context param --- src/Actions/Action.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/Actions/Action.php b/src/Actions/Action.php index b95308b545..b82e972c1c 100644 --- a/src/Actions/Action.php +++ b/src/Actions/Action.php @@ -61,6 +61,10 @@ public function authorizeBulk($user, $items) public function context($context) { + if (! isset($context['view'])) { + $context['view'] = 'list'; + } + $this->context = $context; return $this; From eb0fc4e36275379501deae60d9a1011edb246379 Mon Sep 17 00:00:00 2001 From: Jack Sleight Date: Tue, 19 Dec 2023 11:04:15 +0000 Subject: [PATCH 32/64] Rename menuActions to actionsMenu --- resources/js/components/assets/Editor/Editor.vue | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/resources/js/components/assets/Editor/Editor.vue b/resources/js/components/assets/Editor/Editor.vue index d25e97fee2..40cf420851 100644 --- a/resources/js/components/assets/Editor/Editor.vue +++ b/resources/js/components/assets/Editor/Editor.vue @@ -65,11 +65,11 @@ - + @@ -283,7 +283,7 @@ export default { return ! this.readOnly && this.showToolbar; }, - menuActions() + actionsMenu() { return this.actions.filter(action => ![ 'rename_asset', From 9f8091b84a7c31017ac61258ff7d7e711dcf59cb Mon Sep 17 00:00:00 2001 From: Jack Sleight Date: Tue, 19 Dec 2023 11:07:17 +0000 Subject: [PATCH 33/64] Fix whitespace --- src/Actions/Action.php | 1 + src/Taxonomies/Term.php | 7 ------- 2 files changed, 1 insertion(+), 7 deletions(-) diff --git a/src/Actions/Action.php b/src/Actions/Action.php index b82e972c1c..79bc17c5b7 100644 --- a/src/Actions/Action.php +++ b/src/Actions/Action.php @@ -13,6 +13,7 @@ abstract class Action implements Arrayable use HasFields, HasHandle, HasTitle, RegistersItself; protected static $binding = 'actions'; + protected $items; protected $confirm = true; protected $dangerous = false; diff --git a/src/Taxonomies/Term.php b/src/Taxonomies/Term.php index 9301059b25..84ca6bea55 100644 --- a/src/Taxonomies/Term.php +++ b/src/Taxonomies/Term.php @@ -24,19 +24,12 @@ class Term implements TermContract use ExistsAsFile, FluentlyGetsAndSets, SyncsOriginalState; protected $taxonomy; - protected $slug; - protected $blueprint; - protected $collection; - protected $data; - protected $afterSaveCallbacks = []; - protected $withEvents = true; - protected $syncOriginalProperties = ['slug']; public function __construct() From 1c89ed05bfaf4b24127b89306f44ccacfb8df61b Mon Sep 17 00:00:00 2001 From: Jack Sleight Date: Tue, 19 Dec 2023 11:58:08 +0000 Subject: [PATCH 34/64] Also hide dividers if they're last --- resources/css/elements/dropdowns.css | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/resources/css/elements/dropdowns.css b/resources/css/elements/dropdowns.css index 98749dfa00..1458373605 100644 --- a/resources/css/elements/dropdowns.css +++ b/resources/css/elements/dropdowns.css @@ -42,7 +42,8 @@ margin: 6px -8px; /* Hide dividers that come first or immediately after another (due to v-if) */ & + &, - &:first-child { + &:first-child, + &:last-child { display: none; } } From de03616b09456f23a107ae6aa366cf5e1f3f8136 Mon Sep 17 00:00:00 2001 From: Jack Sleight Date: Tue, 19 Dec 2023 11:58:42 +0000 Subject: [PATCH 35/64] Also hide dividers if they're last --- resources/css/elements/dropdowns.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/css/elements/dropdowns.css b/resources/css/elements/dropdowns.css index 1458373605..fabda5b237 100644 --- a/resources/css/elements/dropdowns.css +++ b/resources/css/elements/dropdowns.css @@ -40,7 +40,7 @@ .divider { @apply h-px bg-gray-400 overflow-hidden; margin: 6px -8px; - /* Hide dividers that come first or immediately after another (due to v-if) */ + /* Hide dividers that come first, last or immediately after another (due to v-if) */ & + &, &:first-child, &:last-child { From e380cd19114c037fec8541f48fc396172c64db9d Mon Sep 17 00:00:00 2001 From: Jack Sleight Date: Fri, 12 Jan 2024 15:48:07 +0000 Subject: [PATCH 36/64] That shouldn't be there --- resources/js/components/users/PublishForm.vue | 6 ------ 1 file changed, 6 deletions(-) diff --git a/resources/js/components/users/PublishForm.vue b/resources/js/components/users/PublishForm.vue index aec344efff..0d04cb4731 100644 --- a/resources/js/components/users/PublishForm.vue +++ b/resources/js/components/users/PublishForm.vue @@ -157,12 +157,6 @@ export default { }, - watch: { - title() { - console.log(this.title); - }, - }, - mounted() { this.$keys.bindGlobal(['mod+s'], e => { e.preventDefault(); From 7b88dd3fafd9aae3a380a705fbcfaf1ca236ca2c Mon Sep 17 00:00:00 2001 From: Jack Sleight Date: Tue, 14 May 2024 10:29:26 +0200 Subject: [PATCH 37/64] Update title watcher --- resources/js/components/entries/PublishForm.vue | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/resources/js/components/entries/PublishForm.vue b/resources/js/components/entries/PublishForm.vue index 2f84b1a6b8..6d4b77a0bd 100644 --- a/resources/js/components/entries/PublishForm.vue +++ b/resources/js/components/entries/PublishForm.vue @@ -519,7 +519,8 @@ export default { title(title) { if (this.isBase) { - document.title = title + ' ‹ ' + this.breadcrumbs[1].text + ' ‹ ' + this.breadcrumbs[0].text + ' ‹ Statamic'; + const arrow = this.direction === 'ltr' ? '‹' : '›'; + document.title = `${title} ${arrow} ${this.breadcrumbs[1].text} ${arrow} ${this.breadcrumbs[0].text} ${arrow} ${__('Statamic')}`; } }, @@ -575,10 +576,6 @@ export default { } this.title = response.data.data.title; this.isWorkingCopy = true; - if (this.isBase) { - const arrow = this.direction === 'ltr' ? '‹' : '›'; - document.title = `${this.title} ${arrow} ${this.breadcrumbs[1].text} ${arrow} ${this.breadcrumbs[0].text} ${arrow} ${__('Statamic')}`; - } if (!this.revisionsEnabled) this.permalink = response.data.data.permalink; if (!this.isCreating && !this.isAutosave) this.$toast.success(__('Saved')); this.$refs.container.saved(); From 931456f50ae3807d15efb675512167f167da435b Mon Sep 17 00:00:00 2001 From: Jack Sleight Date: Thu, 16 May 2024 09:13:01 +0200 Subject: [PATCH 38/64] Remove copy asset URL action from menu --- resources/js/components/assets/Editor/Editor.vue | 1 + 1 file changed, 1 insertion(+) diff --git a/resources/js/components/assets/Editor/Editor.vue b/resources/js/components/assets/Editor/Editor.vue index 61a869ec57..7dc1b748df 100644 --- a/resources/js/components/assets/Editor/Editor.vue +++ b/resources/js/components/assets/Editor/Editor.vue @@ -292,6 +292,7 @@ export default { 'reupload_asset', 'download_asset', 'delete', + 'copy_asset_url', ].includes(action.handle)); }, From c5fa2afb5eac7958bcff6203fc832c86839e5fc5 Mon Sep 17 00:00:00 2001 From: Jason Varga Date: Thu, 16 May 2024 16:40:24 -0400 Subject: [PATCH 39/64] use trait --- .../CP/Collections/EntryActionController.php | 38 +------------------ 1 file changed, 2 insertions(+), 36 deletions(-) diff --git a/src/Http/Controllers/CP/Collections/EntryActionController.php b/src/Http/Controllers/CP/Collections/EntryActionController.php index e2344a8ca5..ab44622109 100644 --- a/src/Http/Controllers/CP/Collections/EntryActionController.php +++ b/src/Http/Controllers/CP/Collections/EntryActionController.php @@ -8,6 +8,8 @@ class EntryActionController extends ActionController { + use ExtractsFromEntryFields; + protected function getSelectedItems($items, $context) { return $items->map(function ($item) { @@ -28,40 +30,4 @@ protected function getItemData($entry, $context) 'itemActions' => Action::for($entry, $context), ]; } - - protected function extractFromFields($entry, $blueprint) - { - // The values should only be data merged with the origin data. - // We don't want injected collection values, which $entry->values() would have given us. - $target = $entry; - $values = $target->data(); - while ($target->hasOrigin()) { - $target = $target->origin(); - $values = $target->data()->merge($values); - } - $values = $values->all(); - - if ($entry->hasStructure()) { - $values['parent'] = array_filter([optional($entry->parent())->id()]); - } - - if ($entry->collection()->dated()) { - $datetime = substr($entry->date()->toDateTimeString(), 0, 16); - $datetime = ($entry->hasTime()) ? $datetime : substr($datetime, 0, 10); - $values['date'] = $datetime; - } - - $fields = $blueprint - ->fields() - ->addValues($values) - ->preProcess(); - - $values = $fields->values()->merge([ - 'title' => $entry->value('title'), - 'slug' => $entry->slug(), - 'published' => $entry->published(), - ]); - - return [$values->all(), $fields->meta()]; - } } From 3fc43bd024c271ac19bb637eb8764c3392d1a20a Mon Sep 17 00:00:00 2001 From: Jason Varga Date: Thu, 16 May 2024 16:50:54 -0400 Subject: [PATCH 40/64] unreachable --- src/Actions/Delete.php | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/Actions/Delete.php b/src/Actions/Delete.php index fab22c4f00..daa9191e8e 100644 --- a/src/Actions/Delete.php +++ b/src/Actions/Delete.php @@ -68,13 +68,10 @@ public function redirect($items, $values) switch (true) { case $item instanceof Contracts\Entries\Entry: return cp_route('collections.show', $item->collection()->handle()); - break; case $item instanceof Contracts\Taxonomies\Term: return cp_route('taxonomies.show', $item->taxonomy()->handle()); - break; case $item instanceof Contracts\Auth\User: return cp_route('users.index'); - break; } } } From 84d5b2e428b640ffe794007d6d3262719a286919 Mon Sep 17 00:00:00 2001 From: Jason Varga Date: Thu, 16 May 2024 16:50:58 -0400 Subject: [PATCH 41/64] visibility --- src/Actions/DuplicateEntry.php | 2 +- src/Actions/DuplicateTerm.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Actions/DuplicateEntry.php b/src/Actions/DuplicateEntry.php index 07412ed0cb..aee01f9504 100644 --- a/src/Actions/DuplicateEntry.php +++ b/src/Actions/DuplicateEntry.php @@ -10,7 +10,7 @@ class DuplicateEntry extends Action { - protected $newItems; + private $newItems; public static function title() { diff --git a/src/Actions/DuplicateTerm.php b/src/Actions/DuplicateTerm.php index 1fbd1a883f..ef02aa5ebe 100644 --- a/src/Actions/DuplicateTerm.php +++ b/src/Actions/DuplicateTerm.php @@ -8,7 +8,7 @@ class DuplicateTerm extends Action { - protected $newItems; + private $newItems; public static function title() { From 617cb14ad74c04776212f98858df11aa313b2e0c Mon Sep 17 00:00:00 2001 From: Jason Varga Date: Thu, 16 May 2024 17:26:05 -0400 Subject: [PATCH 42/64] Providing view of list is unnecessary since its the default in the Action::context() method. --- resources/js/components/assets/Browser/Browser.vue | 2 +- resources/js/components/entries/Listing.vue | 2 +- resources/js/components/terms/Listing.vue | 2 +- resources/js/components/users/Listing.vue | 7 +------ src/Http/Resources/CP/Assets/Folder.php | 1 - src/Http/Resources/CP/Assets/FolderAsset.php | 1 - src/Http/Resources/CP/Entries/ListedEntry.php | 2 +- src/Http/Resources/CP/Submissions/ListedSubmission.php | 2 +- src/Http/Resources/CP/Taxonomies/ListedTerm.php | 2 +- src/Http/Resources/CP/Users/ListedUser.php | 2 +- tests/Feature/Entries/DeleteEntryTest.php | 2 +- 11 files changed, 9 insertions(+), 16 deletions(-) diff --git a/resources/js/components/assets/Browser/Browser.vue b/resources/js/components/assets/Browser/Browser.vue index 69c4fa74a8..6e5ee08a5c 100644 --- a/resources/js/components/assets/Browser/Browser.vue +++ b/resources/js/components/assets/Browser/Browser.vue @@ -373,7 +373,7 @@ export default { }, actionContext() { - return {container: this.selectedContainer, view: 'list'}; + return {container: this.selectedContainer}; }, showContainerTabs() { diff --git a/resources/js/components/entries/Listing.vue b/resources/js/components/entries/Listing.vue index 1e388a1966..9063c4594c 100644 --- a/resources/js/components/entries/Listing.vue +++ b/resources/js/components/entries/Listing.vue @@ -145,7 +145,7 @@ export default { computed: { actionContext() { - return {collection: this.collection, view: 'list'}; + return {collection: this.collection}; }, }, diff --git a/resources/js/components/terms/Listing.vue b/resources/js/components/terms/Listing.vue index 409eec32ef..2e740f2d50 100644 --- a/resources/js/components/terms/Listing.vue +++ b/resources/js/components/terms/Listing.vue @@ -133,7 +133,7 @@ export default { computed: { actionContext() { - return {taxonomy: this.taxonomy, view: 'list'}; + return {taxonomy: this.taxonomy}; }, }, diff --git a/resources/js/components/users/Listing.vue b/resources/js/components/users/Listing.vue index 6dc585d088..b28c762c20 100644 --- a/resources/js/components/users/Listing.vue +++ b/resources/js/components/users/Listing.vue @@ -62,7 +62,6 @@ @@ -152,11 +151,7 @@ export default { return { group: this.group, } - }, - - actionContext() { - return {view: 'list'}; - }, + } } diff --git a/src/Http/Resources/CP/Assets/Folder.php b/src/Http/Resources/CP/Assets/Folder.php index 1472a48a9a..330f8d1d02 100644 --- a/src/Http/Resources/CP/Assets/Folder.php +++ b/src/Http/Resources/CP/Assets/Folder.php @@ -24,7 +24,6 @@ public function toArray($request) 'actions' => Action::for($this->resource, [ 'container' => $this->container()->handle(), 'folder' => $this->path(), - 'view' => 'list', ]), $this->mergeWhen($this->withChildFolders, function () { diff --git a/src/Http/Resources/CP/Assets/FolderAsset.php b/src/Http/Resources/CP/Assets/FolderAsset.php index 8fec2e9371..384d3f1c53 100644 --- a/src/Http/Resources/CP/Assets/FolderAsset.php +++ b/src/Http/Resources/CP/Assets/FolderAsset.php @@ -30,7 +30,6 @@ public function toArray($request) 'actions' => Action::for($this->resource, [ 'container' => $this->container()->handle(), 'folder' => $this->folder(), - 'view' => 'list', ]), ]; } diff --git a/src/Http/Resources/CP/Entries/ListedEntry.php b/src/Http/Resources/CP/Entries/ListedEntry.php index 02ac91c679..63492e71b9 100644 --- a/src/Http/Resources/CP/Entries/ListedEntry.php +++ b/src/Http/Resources/CP/Entries/ListedEntry.php @@ -47,7 +47,7 @@ public function toArray($request) 'collection' => array_merge($entry->collection()->toArray(), ['dated' => $entry->collection()->dated()]), 'viewable' => User::current()->can('view', $entry), 'editable' => User::current()->can('edit', $entry), - 'actions' => Action::for($entry, ['collection' => $collection->handle(), 'view' => 'list']), + 'actions' => Action::for($entry, ['collection' => $collection->handle()]), ]; } diff --git a/src/Http/Resources/CP/Submissions/ListedSubmission.php b/src/Http/Resources/CP/Submissions/ListedSubmission.php index 2d7fe12c7b..27d2525332 100644 --- a/src/Http/Resources/CP/Submissions/ListedSubmission.php +++ b/src/Http/Resources/CP/Submissions/ListedSubmission.php @@ -36,7 +36,7 @@ public function toArray($request) ])), 'url' => cp_route('forms.submissions.show', [$form->handle(), $this->resource->id()]), 'deleteable' => User::current()->can('delete', $this->resource), - 'actions' => Action::for($this->resource, ['view' => 'list']), + 'actions' => Action::for($this->resource), ]; } diff --git a/src/Http/Resources/CP/Taxonomies/ListedTerm.php b/src/Http/Resources/CP/Taxonomies/ListedTerm.php index a6bfb6a0f8..12b55ab94b 100644 --- a/src/Http/Resources/CP/Taxonomies/ListedTerm.php +++ b/src/Http/Resources/CP/Taxonomies/ListedTerm.php @@ -46,7 +46,7 @@ public function toArray($request) 'taxonomy' => $term->taxonomy()->toArray(), 'viewable' => User::current()->can('view', $term), 'editable' => User::current()->can('edit', $term), - 'actions' => Action::for($term, ['taxonomy' => $taxonomy->handle(), 'view' => 'list']), + 'actions' => Action::for($term, ['taxonomy' => $taxonomy->handle()]), ]; } diff --git a/src/Http/Resources/CP/Users/ListedUser.php b/src/Http/Resources/CP/Users/ListedUser.php index 5f69f0b427..3342adea38 100644 --- a/src/Http/Resources/CP/Users/ListedUser.php +++ b/src/Http/Resources/CP/Users/ListedUser.php @@ -42,7 +42,7 @@ public function toArray($request) 'initials' => $this->initials(), 'editable' => User::current()->can('edit', $this->resource), 'deleteable' => User::current()->can('delete', $this->resource), - 'actions' => Action::for($this->resource, ['view' => 'list']), + 'actions' => Action::for($this->resource), ]; } diff --git a/tests/Feature/Entries/DeleteEntryTest.php b/tests/Feature/Entries/DeleteEntryTest.php index 6b2a4d30ad..1f7cb22040 100644 --- a/tests/Feature/Entries/DeleteEntryTest.php +++ b/tests/Feature/Entries/DeleteEntryTest.php @@ -139,7 +139,7 @@ public function deleteEntries($ids) { return $this->postJson('/cp/collections/test/entries/actions', [ 'action' => 'delete', - 'context' => ['collection' => 'test', 'view' => 'list'], + 'context' => ['collection' => 'test'], 'selections' => $ids, 'values' => [], ]); From 67396e1360c5308a0029ca8b6ee76bbbbde5afff Mon Sep 17 00:00:00 2001 From: Jason Varga Date: Thu, 16 May 2024 17:28:03 -0400 Subject: [PATCH 43/64] nitpick --- src/Http/Resources/CP/Entries/ListedEntry.php | 1 - src/Http/Resources/CP/Taxonomies/ListedTerm.php | 1 - src/Http/Resources/CP/Users/ListedUser.php | 1 - 3 files changed, 3 deletions(-) diff --git a/src/Http/Resources/CP/Entries/ListedEntry.php b/src/Http/Resources/CP/Entries/ListedEntry.php index 63492e71b9..c6ccb2135d 100644 --- a/src/Http/Resources/CP/Entries/ListedEntry.php +++ b/src/Http/Resources/CP/Entries/ListedEntry.php @@ -9,7 +9,6 @@ class ListedEntry extends JsonResource { protected $blueprint; - protected $columns; public function blueprint($blueprint) diff --git a/src/Http/Resources/CP/Taxonomies/ListedTerm.php b/src/Http/Resources/CP/Taxonomies/ListedTerm.php index 12b55ab94b..8ded62d479 100644 --- a/src/Http/Resources/CP/Taxonomies/ListedTerm.php +++ b/src/Http/Resources/CP/Taxonomies/ListedTerm.php @@ -9,7 +9,6 @@ class ListedTerm extends JsonResource { protected $blueprint; - protected $columns; public function blueprint($blueprint) diff --git a/src/Http/Resources/CP/Users/ListedUser.php b/src/Http/Resources/CP/Users/ListedUser.php index 3342adea38..775aab0fc6 100644 --- a/src/Http/Resources/CP/Users/ListedUser.php +++ b/src/Http/Resources/CP/Users/ListedUser.php @@ -9,7 +9,6 @@ class ListedUser extends JsonResource { protected $blueprint; - protected $columns; public function blueprint($blueprint) From 9f2d5be6968f4d533a74bbcbcb1fec30b2106623 Mon Sep 17 00:00:00 2001 From: Jason Varga Date: Thu, 16 May 2024 19:51:43 -0400 Subject: [PATCH 44/64] abstract --- src/Http/Controllers/CP/ActionController.php | 6 +----- .../Controllers/CP/Collections/EntryActionController.php | 2 +- src/Http/Controllers/CP/Taxonomies/TermActionController.php | 2 +- src/Http/Controllers/CP/Users/UserActionController.php | 2 +- 4 files changed, 4 insertions(+), 8 deletions(-) diff --git a/src/Http/Controllers/CP/ActionController.php b/src/Http/Controllers/CP/ActionController.php index 1fdf3b37f0..3e3c95749c 100644 --- a/src/Http/Controllers/CP/ActionController.php +++ b/src/Http/Controllers/CP/ActionController.php @@ -72,9 +72,5 @@ public function bulkActions(Request $request) abstract protected function getSelectedItems($items, $context); - // Should be abstract todo - protected function getItemData($item, $context) - { - return []; - } + abstract protected function getItemData($item, $context): array; } diff --git a/src/Http/Controllers/CP/Collections/EntryActionController.php b/src/Http/Controllers/CP/Collections/EntryActionController.php index ab44622109..41ab494143 100644 --- a/src/Http/Controllers/CP/Collections/EntryActionController.php +++ b/src/Http/Controllers/CP/Collections/EntryActionController.php @@ -17,7 +17,7 @@ protected function getSelectedItems($items, $context) }); } - protected function getItemData($entry, $context) + protected function getItemData($entry, $context): array { $blueprint = $entry->blueprint(); diff --git a/src/Http/Controllers/CP/Taxonomies/TermActionController.php b/src/Http/Controllers/CP/Taxonomies/TermActionController.php index ebe62bfe59..f35ecede3f 100644 --- a/src/Http/Controllers/CP/Taxonomies/TermActionController.php +++ b/src/Http/Controllers/CP/Taxonomies/TermActionController.php @@ -15,7 +15,7 @@ protected function getSelectedItems($items, $context) })->filter(); } - protected function getItemData($term, $context) + protected function getItemData($term, $context): array { $blueprint = $term->blueprint(); diff --git a/src/Http/Controllers/CP/Users/UserActionController.php b/src/Http/Controllers/CP/Users/UserActionController.php index 7ded5c8211..254b0fe1ec 100644 --- a/src/Http/Controllers/CP/Users/UserActionController.php +++ b/src/Http/Controllers/CP/Users/UserActionController.php @@ -15,7 +15,7 @@ protected function getSelectedItems($items, $context) }); } - protected function getItemData($user, $context) + protected function getItemData($user, $context): array { $blueprint = $user->blueprint(); From fea9cebfdac2ad7b3654e87677810205f397b305 Mon Sep 17 00:00:00 2001 From: Jason Varga Date: Thu, 16 May 2024 19:52:37 -0400 Subject: [PATCH 45/64] Revert and use arr::get instead --- src/Http/Controllers/CP/ActionController.php | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/Http/Controllers/CP/ActionController.php b/src/Http/Controllers/CP/ActionController.php index 3e3c95749c..35bb7e31f5 100644 --- a/src/Http/Controllers/CP/ActionController.php +++ b/src/Http/Controllers/CP/ActionController.php @@ -5,6 +5,7 @@ use Illuminate\Http\Request; use Statamic\Facades\Action; use Statamic\Facades\User; +use Statamic\Support\Arr; use Symfony\Component\HttpFoundation\Response; abstract class ActionController extends CpController @@ -17,7 +18,7 @@ public function run(Request $request) 'context' => 'sometimes', ]); - $context = $data['context'] ?? ['view' => 'list']; + $context = $data['context'] ?? []; $items = $this->getSelectedItems(collect($data['selections']), $context); @@ -49,7 +50,7 @@ public function run(Request $request) $response = $response ?: []; - if ($context['view'] === 'form') { + if (Arr::get($context, 'view') === 'form') { $response['data'] = $this->getItemData($items->first(), $context); } From 1a877af3167193c15c78caf9b03f264a0ed0be9c Mon Sep 17 00:00:00 2001 From: Jason Varga Date: Thu, 16 May 2024 20:14:09 -0400 Subject: [PATCH 46/64] Exclude entry actions in the actions rather than in vue. --- resources/js/components/entries/PublishForm.vue | 6 +----- src/Actions/Publish.php | 2 +- src/Actions/Unpublish.php | 2 +- 3 files changed, 3 insertions(+), 7 deletions(-) diff --git a/resources/js/components/entries/PublishForm.vue b/resources/js/components/entries/PublishForm.vue index 5f895f4132..353d0d4ff7 100644 --- a/resources/js/components/entries/PublishForm.vue +++ b/resources/js/components/entries/PublishForm.vue @@ -18,7 +18,7 @@ v-if="!isCreating" :item="id" :url="itemActionUrl" - :actions="itemActionsMenu" + :actions="itemActions" @started="actionStarted" @completed="actionCompleted" /> @@ -501,10 +501,6 @@ export default { return this.initialReference.split('::').pop(); }, - itemActionsMenu() { - return this.itemActions.filter(action => !['publish', 'unpublish'].includes(action.handle)); - }, - direction() { return this.$config.get('direction', 'ltr'); }, diff --git a/src/Actions/Publish.php b/src/Actions/Publish.php index b0bb9c0709..d573174cbc 100644 --- a/src/Actions/Publish.php +++ b/src/Actions/Publish.php @@ -14,7 +14,7 @@ public static function title() public function visibleTo($item) { - return $item instanceof Entry && ! $item->published(); + return $this->context['view'] === 'list' && $item instanceof Entry && ! $item->published(); } public function visibleToBulk($items) diff --git a/src/Actions/Unpublish.php b/src/Actions/Unpublish.php index f2d6ab367d..2d27e0f8dc 100644 --- a/src/Actions/Unpublish.php +++ b/src/Actions/Unpublish.php @@ -9,7 +9,7 @@ class Unpublish extends Action { public function visibleTo($item) { - return $item instanceof Entry && $item->published(); + return $this->context['view'] === 'list' && $item instanceof Entry && $item->published(); } public function visibleToBulk($items) From 36e62345a76e0b814da06af3111448abba04ef48 Mon Sep 17 00:00:00 2001 From: Jason Varga Date: Thu, 16 May 2024 20:20:24 -0400 Subject: [PATCH 47/64] Send back data in a consistent way to saving --- .../CP/Collections/EntryActionController.php | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/Http/Controllers/CP/Collections/EntryActionController.php b/src/Http/Controllers/CP/Collections/EntryActionController.php index 41ab494143..f6a7f909f8 100644 --- a/src/Http/Controllers/CP/Collections/EntryActionController.php +++ b/src/Http/Controllers/CP/Collections/EntryActionController.php @@ -5,6 +5,7 @@ use Statamic\Facades\Action; use Statamic\Facades\Entry; use Statamic\Http\Controllers\CP\ActionController; +use Statamic\Http\Resources\CP\Entries\Entry as EntryResource; class EntryActionController extends ActionController { @@ -19,15 +20,15 @@ protected function getSelectedItems($items, $context) protected function getItemData($entry, $context): array { + $entry = $entry->fresh(); + $blueprint = $entry->blueprint(); [$values] = $this->extractFromFields($entry, $blueprint); - return [ - 'title' => $entry->value('title'), - 'permalink' => $entry->absoluteUrl(), - 'values' => array_merge($values, ['id' => $entry->id()]), + return array_merge((new EntryResource($entry))->resolve()['data'], [ + 'values' => $values, 'itemActions' => Action::for($entry, $context), - ]; + ]); } } From 5b564336d7c105ba7e74e627b0625d36a7b79a49 Mon Sep 17 00:00:00 2001 From: Jason Varga Date: Thu, 16 May 2024 20:21:38 -0400 Subject: [PATCH 48/64] The actions werent being updated ... This could happen if the state of the entry causes different actions to be available. For example when its published, the unpublished action is visible but not the publish action, and visa versa. --- resources/js/components/entries/PublishForm.vue | 1 + 1 file changed, 1 insertion(+) diff --git a/resources/js/components/entries/PublishForm.vue b/resources/js/components/entries/PublishForm.vue index 353d0d4ff7..6f7126c951 100644 --- a/resources/js/components/entries/PublishForm.vue +++ b/resources/js/components/entries/PublishForm.vue @@ -819,6 +819,7 @@ export default { this.title = response.data.title; if (!this.revisionsEnabled) this.permalink = response.data.permalink; this.values = this.resetValuesFromResponse(response.data.values); + this.itemActions = response.data.itemActions; } }, From 735322b39dfcf00882f9e69f2568982de941c9c9 Mon Sep 17 00:00:00 2001 From: Jason Varga Date: Thu, 16 May 2024 20:22:17 -0400 Subject: [PATCH 49/64] Even though we aren't showing the publish actions, update it anyway to be consistent with saving. Maybe third party actions will. --- resources/js/components/entries/PublishForm.vue | 3 +++ 1 file changed, 3 insertions(+) diff --git a/resources/js/components/entries/PublishForm.vue b/resources/js/components/entries/PublishForm.vue index 6f7126c951..c0a6baed00 100644 --- a/resources/js/components/entries/PublishForm.vue +++ b/resources/js/components/entries/PublishForm.vue @@ -819,6 +819,9 @@ export default { this.title = response.data.title; if (!this.revisionsEnabled) this.permalink = response.data.permalink; this.values = this.resetValuesFromResponse(response.data.values); + this.initialPublished = response.data.published; + this.activeLocalization.published = response.data.published; + this.activeLocalization.status = response.data.status; this.itemActions = response.data.itemActions; } }, From 3cb96ccea6655e8066dec0659bd4fb238f04a322 Mon Sep 17 00:00:00 2001 From: Jason Varga Date: Fri, 17 May 2024 10:33:03 -0400 Subject: [PATCH 50/64] use id from values --- resources/js/components/entries/PublishForm.vue | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/resources/js/components/entries/PublishForm.vue b/resources/js/components/entries/PublishForm.vue index c0a6baed00..3ceabddde6 100644 --- a/resources/js/components/entries/PublishForm.vue +++ b/resources/js/components/entries/PublishForm.vue @@ -16,7 +16,7 @@
  • Date: Fri, 17 May 2024 10:35:11 -0400 Subject: [PATCH 51/64] extract trait --- .../CP/Taxonomies/ExtractsFromTermFields.php | 27 +++++++++++++++++++ .../CP/Taxonomies/TermActionController.php | 23 ++-------------- .../CP/Taxonomies/TermsController.php | 24 ++--------------- 3 files changed, 31 insertions(+), 43 deletions(-) create mode 100644 src/Http/Controllers/CP/Taxonomies/ExtractsFromTermFields.php diff --git a/src/Http/Controllers/CP/Taxonomies/ExtractsFromTermFields.php b/src/Http/Controllers/CP/Taxonomies/ExtractsFromTermFields.php new file mode 100644 index 0000000000..71c84d63e9 --- /dev/null +++ b/src/Http/Controllers/CP/Taxonomies/ExtractsFromTermFields.php @@ -0,0 +1,27 @@ +values() would have given us. + $values = $term->inDefaultLocale()->data()->merge( + $term->data() + ); + + $fields = $blueprint + ->fields() + ->addValues($values->all()) + ->preProcess(); + + $values = $fields->values()->merge([ + 'title' => $term->value('title'), + 'slug' => $term->slug(), + ]); + + return [$values->all(), $fields->meta()]; + } +} diff --git a/src/Http/Controllers/CP/Taxonomies/TermActionController.php b/src/Http/Controllers/CP/Taxonomies/TermActionController.php index f35ecede3f..1482f06f95 100644 --- a/src/Http/Controllers/CP/Taxonomies/TermActionController.php +++ b/src/Http/Controllers/CP/Taxonomies/TermActionController.php @@ -8,6 +8,8 @@ class TermActionController extends ActionController { + use ExtractsFromTermFields; + protected function getSelectedItems($items, $context) { return $items->map(function ($item) { @@ -28,25 +30,4 @@ protected function getItemData($term, $context): array 'itemActions' => Action::for($term, $context), ]; } - - protected function extractFromFields($term, $blueprint) - { - // The values should only be data merged with the origin data. - // We don't want injected taxonomy values, which $term->values() would have given us. - $values = $term->inDefaultLocale()->data()->merge( - $term->data() - ); - - $fields = $blueprint - ->fields() - ->addValues($values->all()) - ->preProcess(); - - $values = $fields->values()->merge([ - 'title' => $term->value('title'), - 'slug' => $term->slug(), - ]); - - return [$values->all(), $fields->meta()]; - } } diff --git a/src/Http/Controllers/CP/Taxonomies/TermsController.php b/src/Http/Controllers/CP/Taxonomies/TermsController.php index 862b4e7f5b..77446b793d 100644 --- a/src/Http/Controllers/CP/Taxonomies/TermsController.php +++ b/src/Http/Controllers/CP/Taxonomies/TermsController.php @@ -20,7 +20,8 @@ class TermsController extends CpController { - use QueriesFilters; + use ExtractsFromTermFields, + QueriesFilters; public function index(FilteredRequest $request, $taxonomy) { @@ -322,27 +323,6 @@ public function store(Request $request, $taxonomy, $site) ->additional(['saved' => $saved]); } - protected function extractFromFields($term, $blueprint) - { - // The values should only be data merged with the origin data. - // We don't want injected taxonomy values, which $term->values() would have given us. - $values = $term->inDefaultLocale()->data()->merge( - $term->data() - ); - - $fields = $blueprint - ->fields() - ->addValues($values->all()) - ->preProcess(); - - $values = $fields->values()->merge([ - 'title' => $term->value('title'), - 'slug' => $term->slug(), - ]); - - return [$values->all(), $fields->meta()]; - } - protected function extractAssetsFromValues($values) { return collect($values) From 19f2816938734aad036574b08d72afb0c7900128 Mon Sep 17 00:00:00 2001 From: Jason Varga Date: Fri, 17 May 2024 10:50:17 -0400 Subject: [PATCH 52/64] use term resourse for consistency --- .../CP/Taxonomies/TermActionController.php | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/Http/Controllers/CP/Taxonomies/TermActionController.php b/src/Http/Controllers/CP/Taxonomies/TermActionController.php index 1482f06f95..3b04b2eb80 100644 --- a/src/Http/Controllers/CP/Taxonomies/TermActionController.php +++ b/src/Http/Controllers/CP/Taxonomies/TermActionController.php @@ -5,6 +5,7 @@ use Statamic\Facades\Action; use Statamic\Facades\Term; use Statamic\Http\Controllers\CP\ActionController; +use Statamic\Http\Resources\CP\Taxonomies\Term as TermResource; class TermActionController extends ActionController { @@ -19,15 +20,15 @@ protected function getSelectedItems($items, $context) protected function getItemData($term, $context): array { + $term = $term->fresh(); + $blueprint = $term->blueprint(); [$values] = $this->extractFromFields($term, $blueprint); - return [ - 'title' => $term->value('title'), - 'permalink' => $term->absoluteUrl(), - 'values' => array_merge($values, ['id' => $term->id()]), + return array_merge((new TermResource($term))->resolve()['data'], [ + 'values' => $values, 'itemActions' => Action::for($term, $context), - ]; + ]); } } From 2330504ecff881eb5dcb73371be2d432635395d9 Mon Sep 17 00:00:00 2001 From: Jason Varga Date: Fri, 17 May 2024 10:52:27 -0400 Subject: [PATCH 53/64] extract trait --- .../CP/Users/ExtractsFromUserFields.php | 22 +++++++++++++++++++ .../CP/Users/UserActionController.php | 18 ++------------- .../Controllers/CP/Users/UsersController.php | 19 ++-------------- 3 files changed, 26 insertions(+), 33 deletions(-) create mode 100644 src/Http/Controllers/CP/Users/ExtractsFromUserFields.php diff --git a/src/Http/Controllers/CP/Users/ExtractsFromUserFields.php b/src/Http/Controllers/CP/Users/ExtractsFromUserFields.php new file mode 100644 index 0000000000..31ff82e054 --- /dev/null +++ b/src/Http/Controllers/CP/Users/ExtractsFromUserFields.php @@ -0,0 +1,22 @@ +data() + ->merge($user->computedData()) + ->merge(['email' => $user->email()]); + + $fields = $blueprint + ->removeField('password') + ->removeField('password_confirmation') + ->fields() + ->addValues($values->all()) + ->preProcess(); + + return [$fields->values()->all(), $fields->meta()->all()]; + } +} diff --git a/src/Http/Controllers/CP/Users/UserActionController.php b/src/Http/Controllers/CP/Users/UserActionController.php index 254b0fe1ec..4e715d0e08 100644 --- a/src/Http/Controllers/CP/Users/UserActionController.php +++ b/src/Http/Controllers/CP/Users/UserActionController.php @@ -8,6 +8,8 @@ class UserActionController extends ActionController { + use ExtractsFromUserFields; + protected function getSelectedItems($items, $context) { return $items->map(function ($item) { @@ -27,20 +29,4 @@ protected function getItemData($user, $context): array 'itemActions' => Action::for($user, $context), ]; } - - protected function extractFromFields($user, $blueprint) - { - $values = $user->data() - ->merge($user->computedData()) - ->merge(['email' => $user->email()]); - - $fields = $blueprint - ->removeField('password') - ->removeField('password_confirmation') - ->fields() - ->addValues($values->all()) - ->preProcess(); - - return [$fields->values()->all(), $fields->meta()->all()]; - } } diff --git a/src/Http/Controllers/CP/Users/UsersController.php b/src/Http/Controllers/CP/Users/UsersController.php index 553b3212e2..f9145ecc88 100644 --- a/src/Http/Controllers/CP/Users/UsersController.php +++ b/src/Http/Controllers/CP/Users/UsersController.php @@ -23,7 +23,8 @@ class UsersController extends CpController { - use QueriesFilters; + use ExtractsFromUserFields, + QueriesFilters; /** * @var UserContract @@ -322,20 +323,4 @@ public function destroy($user) return response('', 204); } - - protected function extractFromFields($user, $blueprint) - { - $values = $user->data() - ->merge($user->computedData()) - ->merge(['email' => $user->email()]); - - $fields = $blueprint - ->removeField('password') - ->removeField('password_confirmation') - ->fields() - ->addValues($values->all()) - ->preProcess(); - - return [$fields->values()->all(), $fields->meta()->all()]; - } } From 16d582deaf796b563ce59ff1a00c9f782910fb41 Mon Sep 17 00:00:00 2001 From: Jason Varga Date: Fri, 17 May 2024 11:34:02 -0400 Subject: [PATCH 54/64] send ids consistent with the other forms --- resources/js/components/users/PublishForm.vue | 6 +----- src/Http/Controllers/CP/Users/UsersController.php | 4 ++-- 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/resources/js/components/users/PublishForm.vue b/resources/js/components/users/PublishForm.vue index 5f86327541..9ac5abf4a0 100644 --- a/resources/js/components/users/PublishForm.vue +++ b/resources/js/components/users/PublishForm.vue @@ -10,7 +10,7 @@
  • !['assign_groups'].includes(action.handle)); }, diff --git a/src/Http/Controllers/CP/Users/UsersController.php b/src/Http/Controllers/CP/Users/UsersController.php index f9145ecc88..2f4542e327 100644 --- a/src/Http/Controllers/CP/Users/UsersController.php +++ b/src/Http/Controllers/CP/Users/UsersController.php @@ -241,7 +241,7 @@ public function edit(Request $request, $user) $viewData = [ 'title' => $user->email(), - 'values' => $values, + 'values' => array_merge($values, ['id' => $user->id()]), 'meta' => $meta, 'blueprint' => $user->blueprint()->toPublishArray(), 'reference' => $user->reference(), @@ -268,7 +268,7 @@ public function update(Request $request, $user) $this->authorize('edit', $user); - $fields = $user->blueprint()->fields()->except(['password'])->addValues($request->all()); + $fields = $user->blueprint()->fields()->except(['password'])->addValues($request->except('id')); $fields ->validator() From ce015618b44e79a7cf5201ab8b5f5604ecefa5d6 Mon Sep 17 00:00:00 2001 From: Jason Varga Date: Fri, 17 May 2024 11:40:36 -0400 Subject: [PATCH 55/64] exclude user actions in php --- resources/js/components/users/PublishForm.vue | 8 ++------ src/Actions/AssignGroups.php | 2 +- src/Actions/AssignRoles.php | 2 +- 3 files changed, 4 insertions(+), 8 deletions(-) diff --git a/resources/js/components/users/PublishForm.vue b/resources/js/components/users/PublishForm.vue index 9ac5abf4a0..cbd23c7c4f 100644 --- a/resources/js/components/users/PublishForm.vue +++ b/resources/js/components/users/PublishForm.vue @@ -12,7 +12,7 @@ @@ -105,11 +105,7 @@ export default { hasErrors() { return this.error || Object.keys(this.errors).length; - }, - - itemActionsMenu() { - return this.itemActions.filter(action => !['assign_groups'].includes(action.handle)); - }, + } }, diff --git a/src/Actions/AssignGroups.php b/src/Actions/AssignGroups.php index db4fee7dd9..3cfb9116b3 100644 --- a/src/Actions/AssignGroups.php +++ b/src/Actions/AssignGroups.php @@ -14,7 +14,7 @@ public static function title() public function visibleTo($item) { - return $item instanceof UserContract && UserGroup::all()->isNotEmpty(); + return $this->context['view'] === 'list' && $item instanceof UserContract && UserGroup::all()->isNotEmpty(); } public function authorize($authed, $user) diff --git a/src/Actions/AssignRoles.php b/src/Actions/AssignRoles.php index 1c97ccb5ab..b4a4fdc7fc 100644 --- a/src/Actions/AssignRoles.php +++ b/src/Actions/AssignRoles.php @@ -14,7 +14,7 @@ public static function title() public function visibleTo($item) { - return $item instanceof UserContract && Role::all()->isNotEmpty(); + return $this->context['view'] === 'list' && $item instanceof UserContract && Role::all()->isNotEmpty(); } public function authorize($authed, $user) From cc59cea2493904d847cc9617071b7f0191add409 Mon Sep 17 00:00:00 2001 From: Jason Varga Date: Fri, 17 May 2024 11:43:38 -0400 Subject: [PATCH 56/64] grab id from values --- resources/js/components/terms/PublishForm.vue | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/resources/js/components/terms/PublishForm.vue b/resources/js/components/terms/PublishForm.vue index 12e6b18609..5b418c68d7 100644 --- a/resources/js/components/terms/PublishForm.vue +++ b/resources/js/components/terms/PublishForm.vue @@ -18,7 +18,7 @@
  • Date: Fri, 17 May 2024 11:48:19 -0400 Subject: [PATCH 57/64] missed from 617cb14a --- resources/js/components/forms/SubmissionListing.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/js/components/forms/SubmissionListing.vue b/resources/js/components/forms/SubmissionListing.vue index 3eb3c946c0..f23be286bb 100644 --- a/resources/js/components/forms/SubmissionListing.vue +++ b/resources/js/components/forms/SubmissionListing.vue @@ -126,7 +126,7 @@ export default { computed: { actionContext() { - return {form: this.form, view: 'list'}; + return {form: this.form}; }, }, From 625050ea1630acc2377c97051e6eb34273fc6100 Mon Sep 17 00:00:00 2001 From: Jason Varga Date: Fri, 17 May 2024 11:49:03 -0400 Subject: [PATCH 58/64] nitpick --- resources/js/components/terms/PublishForm.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/js/components/terms/PublishForm.vue b/resources/js/components/terms/PublishForm.vue index 5b418c68d7..993e147ad1 100644 --- a/resources/js/components/terms/PublishForm.vue +++ b/resources/js/components/terms/PublishForm.vue @@ -398,7 +398,7 @@ export default { afterSaveOption() { return this.getPreference('after_save'); - } + }, }, From b74ce3c454a66c241328986a8b0d0e9d79dac400 Mon Sep 17 00:00:00 2001 From: Jason Varga Date: Fri, 17 May 2024 11:56:20 -0400 Subject: [PATCH 59/64] context --- resources/js/components/assets/Editor/Editor.vue | 3 +++ 1 file changed, 3 insertions(+) diff --git a/resources/js/components/assets/Editor/Editor.vue b/resources/js/components/assets/Editor/Editor.vue index 7dc1b748df..1c5251bb17 100644 --- a/resources/js/components/assets/Editor/Editor.vue +++ b/resources/js/components/assets/Editor/Editor.vue @@ -285,6 +285,9 @@ export default { actionsMenu() { + // We filter out the actions that are already in the toolbar. + // We don't want them to appear in the dropdown as well. + // If we filtered them out in PHP they wouldn't appear as buttons. return this.actions.filter(action => ![ 'rename_asset', 'move_asset', From 82e68f4e71c78863b4ce7cd85aedbb45a37db65a Mon Sep 17 00:00:00 2001 From: Jason Varga Date: Fri, 17 May 2024 12:02:05 -0400 Subject: [PATCH 60/64] This must have accidentally been re-added in a merge. It was removed in #9689 --- src/Http/Controllers/CP/Users/UsersController.php | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/src/Http/Controllers/CP/Users/UsersController.php b/src/Http/Controllers/CP/Users/UsersController.php index 2f4542e327..61e2424417 100644 --- a/src/Http/Controllers/CP/Users/UsersController.php +++ b/src/Http/Controllers/CP/Users/UsersController.php @@ -308,19 +308,4 @@ public function update(Request $request, $user) ], ]; } - - public function destroy($user) - { - throw_unless($user = User::find($user), new NotFoundHttpException); - - if (! $user = User::find($user)) { - return $this->pageNotFound(); - } - - $this->authorize('delete', $user); - - $user->delete(); - - return response('', 204); - } } From 5eed6b43b92d31d4caa90e6bc6432be2dfb45009 Mon Sep 17 00:00:00 2001 From: Jason Varga Date: Fri, 17 May 2024 13:01:00 -0400 Subject: [PATCH 61/64] Actions will show a dirty state warning ... When the form is dirty, a warning will be shown. The message will be generic, unless overridden on the action, like the Duplicate action is doing. Actions can opt out of the dirty state navigate-away dialog, like the Delete action is doing. In those cases, the warning won't be shown either. --- resources/js/components/data-list/Action.vue | 20 +++++++++++++++++-- resources/js/components/data-list/Actions.js | 5 ++++- .../js/components/data-list/InlineActions.vue | 4 +++- .../js/components/entries/PublishForm.vue | 1 + src/Actions/Action.php | 13 ++++++++++++ src/Actions/Delete.php | 5 +++++ src/Actions/DuplicateEntry.php | 6 ++++++ src/Http/Controllers/CP/ActionController.php | 5 ++++- 8 files changed, 54 insertions(+), 5 deletions(-) diff --git a/resources/js/components/data-list/Action.vue b/resources/js/components/data-list/Action.vue index 28cf706d4c..9c95243888 100644 --- a/resources/js/components/data-list/Action.vue +++ b/resources/js/components/data-list/Action.vue @@ -11,9 +11,11 @@ @confirm="confirm" @cancel="reset" > -
    +
    -
    +
    + +
    { data = JSON.parse(data); - if (data.redirect) window.location = data.redirect; + if (data.redirect) { + if (data.bypassesDirtyWarning) this.$dirty.disableWarning(); + window.location = data.redirect; + } if (data.callback) Statamic.$callbacks.call(data.callback[0], ...data.callback.slice(1)); this.$emit('completed', true, data); }); diff --git a/resources/js/components/data-list/InlineActions.vue b/resources/js/components/data-list/InlineActions.vue index f6f208e178..17bce57d57 100644 --- a/resources/js/components/data-list/InlineActions.vue +++ b/resources/js/components/data-list/InlineActions.vue @@ -7,6 +7,7 @@ :action="action" :selections="1" :errors="errors" + :is-dirty="isDirty" @selected="run" >
    @@ -30,7 +31,8 @@ export default { props: { actions: Array, - item: { required: true } + item: { required: true }, + isDirty: { type: Boolean, default: false }, }, computed: { diff --git a/resources/js/components/entries/PublishForm.vue b/resources/js/components/entries/PublishForm.vue index 3ceabddde6..b090ccc7cb 100644 --- a/resources/js/components/entries/PublishForm.vue +++ b/resources/js/components/entries/PublishForm.vue @@ -19,6 +19,7 @@ :item="values.id" :url="itemActionUrl" :actions="itemActions" + :is-dirty="isDirty" @started="actionStarted" @completed="actionCompleted" /> diff --git a/src/Actions/Action.php b/src/Actions/Action.php index 79bc17c5b7..7a91d390c9 100644 --- a/src/Actions/Action.php +++ b/src/Actions/Action.php @@ -108,6 +108,17 @@ public function warningText() return null; } + public function dirtyWarningText() + { + /** @translation */ + return "Any unsaved changes will not be reflected in this action's behavior."; + } + + public function bypassesDirtyWarning(): bool + { + return false; + } + public function toArray() { return [ @@ -117,6 +128,8 @@ public function toArray() 'buttonText' => $this->buttonText(), 'confirmationText' => $this->confirmationText(), 'warningText' => $this->warningText(), + 'dirtyWarningText' => $this->dirtyWarningText(), + 'bypassesDirtyWarning' => $this->bypassesDirtyWarning(), 'dangerous' => $this->dangerous, 'fields' => $this->fields()->toPublishArray(), 'values' => $this->fields()->preProcess()->values(), diff --git a/src/Actions/Delete.php b/src/Actions/Delete.php index daa9191e8e..30dbd99877 100644 --- a/src/Actions/Delete.php +++ b/src/Actions/Delete.php @@ -52,6 +52,11 @@ public function confirmationText() return 'Are you sure you want to delete this?|Are you sure you want to delete these :count items?'; } + public function bypassesDirtyWarning(): bool + { + return true; + } + public function run($items, $values) { $items->each->delete(); diff --git a/src/Actions/DuplicateEntry.php b/src/Actions/DuplicateEntry.php index aee01f9504..96e90e2426 100644 --- a/src/Actions/DuplicateEntry.php +++ b/src/Actions/DuplicateEntry.php @@ -50,6 +50,12 @@ public function warningText() } } + public function dirtyWarningText() + { + /** @translation */ + return 'Any unsaved changes will not be duplicated into the new entry.'; + } + public function run($items, $values) { $this->newItems = $items diff --git a/src/Http/Controllers/CP/ActionController.php b/src/Http/Controllers/CP/ActionController.php index 35bb7e31f5..59c4388e9b 100644 --- a/src/Http/Controllers/CP/ActionController.php +++ b/src/Http/Controllers/CP/ActionController.php @@ -39,7 +39,10 @@ public function run(Request $request) $response = $action->run($items, $values); if ($redirect = $action->redirect($items, $values)) { - return ['redirect' => $redirect]; + return [ + 'redirect' => $redirect, + 'bypassesDirtyWarning' => $action->bypassesDirtyWarning(), + ]; } elseif ($download = $action->download($items, $values)) { return $download instanceof Response ? $download : response()->download($download); } From 5e8bf686d0cddc7261e8adf8e083ca6be0b9da60 Mon Sep 17 00:00:00 2001 From: Jason Varga Date: Fri, 17 May 2024 13:16:23 -0400 Subject: [PATCH 62/64] Ability to disable the dirty warning text when it doesn't matter, like sending password reset. --- resources/js/components/data-list/Action.vue | 2 +- src/Actions/SendPasswordReset.php | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/resources/js/components/data-list/Action.vue b/resources/js/components/data-list/Action.vue index 9c95243888..af870a14d8 100644 --- a/resources/js/components/data-list/Action.vue +++ b/resources/js/components/data-list/Action.vue @@ -95,7 +95,7 @@ export default { }, showDirtyWarning() { - return this.isDirty && ! this.action.bypassesDirtyWarning; + return this.isDirty && this.action.dirtyWarningText && ! this.action.bypassesDirtyWarning; }, runButtonText() { diff --git a/src/Actions/SendPasswordReset.php b/src/Actions/SendPasswordReset.php index 8a5a1c3700..22e8e6a516 100644 --- a/src/Actions/SendPasswordReset.php +++ b/src/Actions/SendPasswordReset.php @@ -27,6 +27,11 @@ public function confirmationText() return 'Send password reset email to this user?|Send password reset email to these :count users?'; } + public function dirtyWarningText() + { + return null; + } + public function buttonText() { /** @translation */ From eda9a0f0899342f19ea0171f1a54e5b8f1f46833 Mon Sep 17 00:00:00 2001 From: Jason Varga Date: Fri, 17 May 2024 13:17:10 -0400 Subject: [PATCH 63/64] Make impersonate confirmable with appropriate messaging which makes more sense on the user form. --- resources/lang/en/messages.php | 1 + src/Actions/Impersonate.php | 19 +++++++++++++++++-- 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/resources/lang/en/messages.php b/resources/lang/en/messages.php index 5c2abdf154..abcc65e45d 100644 --- a/resources/lang/en/messages.php +++ b/resources/lang/en/messages.php @@ -139,6 +139,7 @@ 'globals_configure_handle_instructions' => 'Used to reference this global set on the frontend. It\'s non-trivial to change later.', 'globals_configure_intro' => 'A global set is a group of variables available across all front-end pages.', 'globals_configure_title_instructions' => 'We recommend a noun representing the set\'s contents. eg. "Brand" or "Company"', + 'impersonate_action_confirmation' => 'You will be logged in as this user. You can return to your account using the avatar menu.', 'licensing_config_cached_warning' => 'Any changes you make to your .env or config files will not be detected until you clear the cache. If you are seeing unexpected licensing results here, it may be because of this. You can use the php artisan config:cache command to regenerate the cache.', 'licensing_error_invalid_domain' => 'Invalid domain', 'licensing_error_invalid_edition' => 'License is for :edition edition', diff --git a/src/Actions/Impersonate.php b/src/Actions/Impersonate.php index ce3db84560..6136f1e695 100644 --- a/src/Actions/Impersonate.php +++ b/src/Actions/Impersonate.php @@ -10,8 +10,6 @@ class Impersonate extends Action { - protected $confirm = false; - public static function title() { return __('Start Impersonating'); @@ -67,4 +65,21 @@ public function redirect($users, $values) return $users->first()->can('access cp') ? cp_route('index') : '/'; } + + public function confirmationText() + { + /** @translation */ + return 'statamic::messages.impersonate_action_confirmation'; + } + + public function buttonText() + { + /** @translation */ + return 'Confirm'; + } + + public function bypassesDirtyWarning(): bool + { + return true; + } } From 430564685e185dc53b77bbd591ceec53a87797ed Mon Sep 17 00:00:00 2001 From: Jason Varga Date: Fri, 17 May 2024 13:17:20 -0400 Subject: [PATCH 64/64] Make it work on terms and users --- resources/js/components/terms/PublishForm.vue | 1 + resources/js/components/users/PublishForm.vue | 7 ++++++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/resources/js/components/terms/PublishForm.vue b/resources/js/components/terms/PublishForm.vue index 993e147ad1..f44e830286 100644 --- a/resources/js/components/terms/PublishForm.vue +++ b/resources/js/components/terms/PublishForm.vue @@ -21,6 +21,7 @@ :item="values.id" :url="itemActionUrl" :actions="itemActions" + :is-dirty="isDirty" @started="actionStarted" @completed="actionCompleted" /> diff --git a/resources/js/components/users/PublishForm.vue b/resources/js/components/users/PublishForm.vue index cbd23c7c4f..38e65e851e 100644 --- a/resources/js/components/users/PublishForm.vue +++ b/resources/js/components/users/PublishForm.vue @@ -13,6 +13,7 @@ :item="values.id" :url="itemActionUrl" :actions="itemActions" + :is-dirty="isDirty" @started="actionStarted" @completed="actionCompleted" /> @@ -105,7 +106,11 @@ export default { hasErrors() { return this.error || Object.keys(this.errors).length; - } + }, + + isDirty() { + return this.$dirty.has(this.publishContainer); + }, },