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 nor ActionDefinition 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 the isAvailable(String actionName, Item... items) method, and virtually also in the execute(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

TODO - changes and enhancements after the 5.1 release

 

  • No labels

11 Comments

  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.

    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.

    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.)

    How is the ActionExecutor API changed ?

    The change in BrowserPresenter seems rather trivial and expected. What other changes do we expect in code using ActionExecutor ?

    It is up to the action's developer to handle the possible problems and inform the user about the result,

    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 ?

    as well as to decide whether the action should be executed transactionally or not.

    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 (wink)

    1. 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.

      Construction of the action bar - at that moment, you don't know the actual Action, just the ActionDefinition (which contains the AvailabilityDefinition). 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 the AvailabilityDefinition.

      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 an allowsMultipleItems() method (and implement it to return false by default in the AbstractAction), 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.

      How is the ActionExecutor API changed ?

      It is not - as stated in the Considerations, the ActionExecutor.execute(...) method already accepts an array of Object arguments, so we can pass either an Item, or a List of items. Then it uses the ComponentProvider.newInstance(...) to get the instance of the Action, so it will use the proper constructor.

      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 ?

      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 an AbstractMultiItemAction, where we will define this behaviour as default, and refactor the DeleteItemAction 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. 

       

       

  2. Few more thing to consider:

    • 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
    • other actions might need to be aware of each other (e.g. select parent page and some sub page and try to delete both - when deleting child, parent (and child) might be already gone) so for such actions it should be possible to order items top down or bottom up (hierarchy wise) and execute them in such order
    • yet other actions might need to be serialized rather then parallelized

    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.

     

    1. 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.

      1. 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)

    2. other actions might need to be aware of each other

      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.

  3. 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.

  4. I've had a look at this concept page and I agree with Jan and others that we should at least know:

    1. How to deal with long-running actions: how do we signal progress? do we block the UI or do we execute them in the background?
    2. Are we executing batch-actions in a transaction?

    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.

    1. 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.

       

      1. 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.

        1. 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.