Rule for when deleting a element is permitted?

I want to prevent some elements from being deleted.
Is there a rule for this?
If the answer is no (which is as far as I can tell), where would you like this to be implemented? Modeling.removeElements?

We do not global rules for whether deletion is allowed or not yet.

Our general approach towards rules is: Rules need to be checked before any of the modeling#... methods are being called.

So in order to implement them, you’d need to surround all the places that currently invoke modeling#removeElements with a respective rule check.

Deleting raises some interesting questions because

  • it is performed in a nested manner
  • it can be done on multiple elements

Thanks!

it is performed in a nested manner

The use case I have is to prevent some root-level xor-gateways from being deleted. So nested elements is not covered in my use case.
As this delete rule does not (yet) have any built-in use in bpmn.io the rule would always pass by default. If and when someone have a use case with protecting nested elements from being deleted; let them describe their use case. Currently I simply do not have any opinion on how to handle nested elements. Out of scope.

it can be done on multiple elements

I can think of three solutions

  1. Cancel the entire operation as the collection contains ‘protected’ elements
  2. Pause and wait for feedback from user
  3. Delete elements that were not ‘protected’

Option #2 would be a very nice feature, but I belive this would require the rules to be implemented “async” to allow us to wait for user feedback.
So currently that leaves us with options #1 and #3, and I belive #3 is the most reasonable of those two.

Added an issue for that:

Trying to figure out what the name of the rule should be.

rules.allowed('element.remove', { ... });

The above code does not work, even though I have added a custom rule with that name.
It does not work since there is no command handler registered named ‘element.remove’.

There is however a command called ‘elements.delete’, so adding a rule with that name gives the expected result.

Although the name ‘elements.delete’ suggest that it’s executed once for multiple elements (not once per element as in my current implementation, see below)…

I am not ready yet to do a pull request (need to fix the context-pad in bpmn-js as well), but you can checkout my work so far at

https://github.com/adbre/diagram-js/commit/8308193df4073c293c73ea8cd3d96987de3696f1

I think it is best to use the high level elements.delete command for rule checking, i.e.

rules.allowed('elements.delete', { elements: [ list, of, shapes ] });

This gives users access to all the available context information.

One approach to do this is to employ the return semantics that are built into our eventBus (and thus into rules, too).

Given a selection of elements shall be removed:

  • Returning true (default) from a rule implementation denotes the selection can be removed.
  • Returning a list of elements [ shapeA, shapeB, ...] denotes only these elements that may be deleted.
  • Returning false disallows the deletion all together.

And in terms of rule implementation:

function CustomRules(eventBus) {
  RuleProvider.call(this, eventBus);

  this.addRule('elements.delete', function(context) {
    // allow all
    return true;

    // allow only some
    return context.elements.filter(function(e) {
      return e.businessObject.$instanceOf('foo:Bar');
    });

    // disallow all together
    return false;
  });
}

Agree.

But do you mean elements.remove or elements.delete ? Your statement and example code differs.
(Only elements.delete actually works currently)

The internal id elements.delete it should be. I updated my post accordingly.

Not being able to remove a element type can be bypassed by replacing it with another element type (see gif below).
So it would be reasonable that it should be possible to write custom shape.replace rules (there’s no element.replace) as well.

Thoughts?

I see two options regarding replace:

(1) add rules to generally allow / disallow replace
(2) add rules to return allowed replace operations

Currently we are implementing replace outside the rules infrastructure. So (1) would be an easy pick.

Any thoughts?

That works for us for this use case.
At least for now. In the long run we’d like to disable some operations, but that’s another use case.
And it can wait until you’re done refactoring.