Goal
The goal is to allow actions to act over more than one item, e.g. deleting multiple items at once etc.
The restriction is to make it possible with minimal intervention to the current API.
Jira issue: MGNLUI-1515 - Getting issue details... STATUS
Considerations
- most of the actions will remain single-item restricted;
- multi-item actions are to be used (mostly) in the workbench;
- neither
Action
norActionDefinition
interfaces specify anything about the items passed to the action - it's all done in the action's constructor; - the
ActionExecutor
interface already expects multiple items in theisAvailable(String actionName, Item... items)
method, and virtually also in theexecute(String actionName, Object... args)
method;
Proposal
Next: 5.1
The action availability described in the Concept - Action availability and access control will be extended with an availability.multiple
property, set by default to false
.
The AbstractActionExecutor.isAvailable()
method will be changed to take the availability.multiple
property into account in the availability evaluation (ATM it just returns false if the items.length
is bigger than 1). Note (for the documentation): if more advanced availability evaluation is required (e.g. action should be available only if all the items are on the same level, or have the same parent), the Availability Rules should be used.
The BrowserPresenter.executeAction()
method will be changed to pass the whole item list to the actionExecutor
in such case, instead of just the first selected item. (There is already a TODO note with the above issue ID.)
The action is responsible to handle the items in a correct order, or solve the obvious dependencies (e.g. when deleting multiple nodes, where one node is a sub-node of the other one, delete them in a correct order to avoid exception, or handle such exception).
The action is responsible for informing the user about the result, i.e. whether it has successfully processed all the items, or failed on some of them. It is also responsible for the potential "transactional" processing, i.e. reverting all the items to the initial state, if the processing of one or more items fails. The recommended behaviour for most actions is "non-transactional" plus notifying the user about how many and which items couldn't be processed. The base support for this recommended behaviour will be implemented in new AbstractMultiItemAction
class.
If the action supports multiple items, it must provide a constructor with a List<Item>
parameter, but still MUST provide also the constructor with the Item
parameter. The ActionExecutor
will use the proper constructor (via the ComponentProvider
) depending on the number of items selected.
As an example (and a best-practices model), the DeleteItemAction
will be made multi-item supporting.
Future
- MGNLUI-1942 - Getting issue details... STATUS
TODO - changes and enhancements after the 5.1 release
11 Comments
Magnolia International
What's an example use-case where this would need to be configured ? Either the action implementation knows how to treat multiple items or it doesn't. Adding a configurable property for this seems redundant.
How is the
ActionExecutor
API changed ?The change in
BrowserPresenter
seems rather trivial and expected. What other changes do we expect in code usingActionExecutor
?How ? That is actually one of the difficulties with this topic; it's easy enough to act on one node and inform about the result. If 3 out of 4 actions were carried properly, what do you do ? Ignore the 4th (or warn the user), rollback the others ? Let the user decide between those options ? Either way: how ?
How ? Any example of how we (could) do this ?
ps: you're talking about code. Stuff doesn't happen because they're "up to the developer". What we need to know in a concept page is which object is reponsible for which action or decision, not whether or not Jim was in a good enough mood to finish is assignment
Jozef Chocholacek
Construction of the action bar - at that moment, you don't know the actual
Action
, just theActionDefinition
(which contains theAvailabilityDefinition
). So to enable/disable the action button in the action bar / context menu in case that more than one item is selected, you need to define this in theAvailabilityDefinition
.Also there could be a situation, when you want to limit a generally multi-item enabled action to just one item - e.g. the above mentioned
DeleteItemAction
in the Configuration App, to force the admin to delete nodes/properties carefully (one-by-one).Of course, there is also the other approach - to extend the
Action
interface with anallowsMultipleItems()
method (and implement it to returnfalse
by default in theAbstractAction
), but that would require to instantiate every action for every actionbar re-draw (i.e. whenever the selection is changed). Or implement some caching mechanism. By now, the action is instantiate only when it is requested.It is not - as stated in the Considerations, the
ActionExecutor.execute(...)
method already accepts an array ofObject
arguments, so we can pass either anItem
, or aList
of items. Then it uses theComponentProvider.newInstance(...)
to get the instance of theAction
, so it will use the proper constructor.That's something that can be different for each action. Most actions, IMO, can/will use the "warn the user" approach - e.g. the
DeleteItemAction
can definitely act this way. Thus I'll define this default behaviour in the Concept. (Perhaps we can even create anAbstractMultiItemAction
, where we will define this behaviour as default, and refactor theDeleteItemAction
to extend this class.)But again, for some actions, the desired behaviour might differ, so we must allow to redefine this behaviour. And it is up to the action's
execute()
method (thus the action's developer) - and IMHO beyond the scope of this concept - to define and implement the desired failure response.Jan Haderka
Few more thing to consider:
while the concept doesn't have to solve all those issues, it should outline how it will allow custom actions to satisfy their execution requirements in respect to other actions in the bulk.
Jozef Chocholacek
Regarding the time-demanding (asynchronous?) actions, it'd be probably better to handle them in a separate concept.
Anyway, it is definitely worth to mention these notes both in the Concept, and later in the documentation.
Magnolia International
The workflow is already such an action, somehow. Essentially, what those actions are (would be) doing, is send a command to a queue for deferred execution. And as Marvin points out below, we might want some sort of locking mechanism there, which isn't an easy topic. (esp if we also also synchronous operations - what should they do when there is a queued command for the same node)
Magnolia International
Entirely up to the action implementation - the action gets
execute()
'd once, so it should indeed deal with that sort of stuff itself, not just blindly loop through its given arguments and delete.Marvin Kerkhoff
Jan Haderka: some of the actions might take time to execute (e.g. publishing dam resources to akamai) so it would be beneficial to execute such actions in parallel and asynchronously
Yes some actions are very slow. In my case a Deadlink-Crawler (Deadlink App) it could be some minutes. It would be nice if there is a possibility to get a status (running, completet or failed) from an Action-Bus. Also if the action is running it should be unpossible to do other actions on this node except other nodes in the workspace.
Andreas Weder
I've had a look at this concept page and I agree with Jan and others that we should at least know:
We do not have to deal with all of this right from the start, but we should have a forward looking idea on how we plan to treat it.
On point 1, from my part, concepts for showing the status of long-running and/or background actions in the UI exist, though I would want to re-visit them. Some older designs:
On point 2, for me, such batch actions need not be executed inside a single transaction, as long as we're capable of properly reporting what has and what has not yet been done in case a batch actions fails mid-way or is aborted. E.g. here for a publication:
One last remark on this, to give a little bit of an additional, future perspective. The idea of batch actions is also to eventually extend it to other, non-trivial actions such as "rename", "change template" or even "edit", where a bulk action results in a bulk change as we know them from e.g. JIRA. Boris mentions this as a feature every now and then, that he thinks would make batch actions actually useful. I think they already are useful for simpler operations, but I agree with him that a bulk change feature would be a nice future target to aim at.
Marvin Kerkhoff
Point 1: Thx, that looks nice. But is the Actionbar realy the right position for this tasks running? Because sometimes you start a task and switch to a different app or subapp, there should be a way to see this status on a higher lever.
Also to discuss: Some actions could be system-wide some of the actions only personalized.
Andreas Weder
That is indeed a point we would need to discuss. The idea was that either such a long-running action would stick to the app it was launched from and only notify the user, once the batch action had come to a conclusion. It would do that either through Pulse (a natural, but albeit a bit heavy way for merely notifying a user of action completion) or through an indicator in the header. The other idea we pondered was to simply show that spinner in every app you switch to - a bit unconventional, no doubt, but we felt it could actually work fine.
But as I mentioned, this are quite early visuals. At that time, we didn't find a convincing and especially visual compelling location to show both a spinner as well as all the details of a long-running action including an option to abort it. We've gained more experience with the new visual and interface language since then and have also developed additional visual elements such as popups, thus I would really want to re-consider all options before going ahead and simply implementing this one.
Marvin Kerkhoff
Hi Andreas, is there any wiki page you can provide for this, to discuss and mockup this functionality? I think it will be necessary for common actions. Yesterday for example: I stuck on deleting a node with 60.000 subnodes.