Conversation
There was a problem hiding this comment.
This is looking good, thanks!
However we are moving away from sending all the actions down the wire initially. It really bloats the responses.
We have a mechanism to lazily load the actions when you hover over the dropdown. You should rework this PR to allow for that.
See RowActions.vue which is used in the Listing component.
https://github.com/statamic/cms/blob/6.x/resources/js/components/ui/Listing/RowActions.vue
In fact you might actually be able to use the RowActions component itself.
…e component is mounted. Update the Show page to display the skeleton loader. Remove unnecessary action references in TreeBuilder.
|
Hello @jasonvarga thanks for your response, Feel free to let me know what you think. |
|
@jasonvarga I also fixed the issue where the modal remained open after clicking an action, and based on what I saw in RowActions.vue, I’ve now set the „default“ value for :variants in Show.vue instead of undefined. |
…irmable actions in collection tree view
|
I've made a few more adjustments to ensure it runs smoothly. Please give it a try and let me know what you think. |
|
@jasonvarga Is there anything I can do to help here, or are you guys just too busy with other, more important PR right now? Cheers |
|
dunno what happend, but the PHPStan / Analyze (pull_request) test is failing. |
|
Don't worry about it - #15083 should fix it. |
jasonvarga
left a comment
There was a problem hiding this comment.
This review was generated by an AI (Claude), performing an automated code review pass.
Three issues found that should be addressed before merge:
- Tree actions run with no success/failure feedback and no tree refresh.
DeleteMultisiteEntryslips past the delete-handle filter and remains a second, non-tree-aware delete path in multi-site collections.- The second
DropdownSeparatorcan render orphaned when neither built-in menu item is present.
See inline comments for details and suggested fixes.
| <ItemActions | ||
| v-if="branch.entry" | ||
| :url="entriesActionUrl" | ||
| :context="{ view: 'tree' }" | ||
| :item="branch.entry" | ||
| v-slot="{ actions, loadActions, shouldShowSkeleton }" | ||
| > |
There was a problem hiding this comment.
Warning — Actions run silently: no success/failure feedback, no tree refresh
ItemActions emits started/completed events, and the sibling RowActions.vue (used by the standard list view) listens for these to show a toast and refresh:
function actionSuccess(response) {
if (response.message !== false) Statamic.$toast.success(response.message || __('Action completed'));
refresh();
}
function actionFailed(response) {
Statamic.$toast.error(response.message || __('Action failed'));
}runServerAction/handleActionSuccess (resources/js/components/actions/Actions.js) never show a toast themselves — that's entirely the calling component's job via completed. This usage binds neither @started nor @completed. Running any real action from the tree dropdown gives no confirmation toast, no error message, and if the action mutates the entry, the tree won't reflect it until a manual reload. Worth wiring @started/@completed the way RowActions.vue does, before merge.
| @click="deleteTreeBranch(branch, removeBranch)" | ||
| /> | ||
|
|
||
| <DropdownSeparator v-if="shouldShowSkeleton || branchTreeActions(actions).length" /> |
There was a problem hiding this comment.
Warning — Orphaned separator when neither built-in dropdown option is present
When both built-in groups are absent (depth >= structureMaxDepth AND !branch.can_delete), this separator still renders above the actions list with nothing above it — an orphaned separator at the top of the menu.
Fix:
<DropdownSeparator v-if="(depth < structureMaxDepth || branch.can_delete) && (shouldShowSkeleton || branchTreeActions(actions).length)" />| }, | ||
|
|
||
| branchTreeActions(actions) { | ||
| return (actions || []).filter((action) => action.handle !== 'delete'); |
There was a problem hiding this comment.
Warning — DeleteMultisiteEntry still leaks into multi-site tree dropdowns as a second, non-tree-aware delete path
DeleteMultisiteEntry extends Delete (src/Actions/DeleteMultisiteEntry.php) and doesn't override handle(), so via HasHandle::handle() (Str::snake($shortClassName)) its handle is delete_multisite_entry, not delete — this filter doesn't catch it. Its visibleTo() only checks multi-site + non-root, with no awareness of context.view, so it stays visible in the tree.
Result: multi-site collection trees get two delete paths — the built-in "Delete" item (tree-aware, calls deleteTreeBranch(), deferred until "Save Changes") and DeleteMultisiteEntry via the actions list (runs immediately as a server action through ConfirmableAction, isn't tree-aware, and won't remove the node from the UI — leaves a ghost entry until refresh).
Fix: filter on !action.dangerous instead of enumerating handles, to also catch this and any future delete-like action:
branchTreeActions(actions) {
return (actions || []).filter((action) => !action.dangerous);
},|
Hello, and thank you, @jasonvarga, for the detailed response. I’ve looked into the issue and fixed the errors you (Claude) pointed out. I’ve also updated my CustomActionTreeView.php in the first post. If you don’t specify a return value in the |
Hello everyone,
First of all, thank you for Statamic 6. After someone on Discord pointed me to Issue 575 and I saw the other pull requests 4070 & 4439, I decided to give it a try and follow the contribution guidelines.
Procedure:
npm ci && npm run buildin the statamic/cms projectddev artisan vendor:publish --tag=statamic-cp --force && ddev yarn build && ddev artisan optimize:clearddev artisan statamic:make:actionIf I've forgotten anything or something is missing, please let me know. Even if it isn't accepted, as stated in the Contribution Guidelines, it might still be helpful to others who need it.
This is what my custom action looks like
How it looks like in the TreeView:

How it looks like in the ListView:
