Custom rule for contextpad element creation

I have this following rule added in my customrulesprovider (it works as intended so you can ignore what’s inside if you want, or else for context see this topic):

  this.tasksLevelMap=new Map([['StartEvent_1',0]]);
  let self=this;
  this.addRule("connection.create", 2000, function (context) {

    if (context.source.id===context.target.id || (self.tasksLevelMap.has(context.source.id) && self.tasksLevelMap.has(context.target.id))){
      return false;
    }
    if (!(self.tasksLevelMap.has(context.source.id))){
      return false;
    }else if (self.tasksLevelMap.has(context.target.id)){
      if(self.tasksLevelMap.get(context.target.id)<=self.tasksLevelMap.get(context.source.id)){
        return false;
      }
    }else{
      self.tasksLevelMap.set(context.target.id,self.tasksLevelMap.get(context.source.id)+1);
    }
    console.log(self.tasksLevelMap);
});

My problem is that this event is fired only when the connection is created from the palette, is there an event/rule I can add that fires when a task/element is created from the contextpadimage (only from the contextpad would be ideal) and get the newly created element’s id and the source element id.

What are you trying to achieve?

1 Like

When appending a shape no rules regarding connections are checked. If there is a context pad entry for appending a shape it has already been checked whether that shape can be connected.

1 Like

Thank you for the reply.
@barmac
I explained what I want to achieve in this reply
I pretty much achieved what I’m looking for but only when adding connections from the palette, all I need is an event that triggers with the creation of a task through the contextpad (I don’t intend to cancel it just need the ids both sides of the new connection).

@philippfromme
If there is a context pad entry for appending a shape it has already been checked 1 whether that shape can be connected.
So there is no way to add an event that triggers when a task is created through the contextpad? (I don’t want to cancel the creation by the way, I just need the Id of the element whose contextpad was used to add the new task and the id of the new task that has been created that’s all), so I would just update my Map variable “tasksLevelMap”.

I read the linked post and cannot really imagine how appending a shape could break the condition that you described there. Anyway, if you want to disallow some context pad actions, rules are not the way to go. Check out this example: https://github.com/bpmn-io/bpmn-js-example-custom-controls

1 Like

You can also look at this CodeSandbox.

You can by definition not create a loop through appending an element. So what are you trying to do here?

Thank you for the links provided, but I’d rather not disable the append from contextpad unless I would have no other choice.
I’ll try to show an example where this causes problem for my map variable.
I have created this following diagram with the palette only and as you can see my map variable is set fine (yellow task is what I call level 1 task and blue one level 2 task)
image
Then I added a new task using the palette: as you can see the map didn’t get update and the new task id wasn’t added to the map.
image
If I try to connect the newly created task (via contextpad) to another task my map gets updated and it will be added but it will be set to a wrong level (in this case 2 instead of 1):
image
This could have been avoided or fixed, if I was able to update my map variable when the green task was added via the contextpad and set to the right level.

Okay, so the issue is that you’re not able to hook into the appending of the new task through the context pad so you can’t update your map?

1 Like

And why "Process_1" => 1?

That’s something that gets added automatically when adding a connection and while moving the mouse it fires the “connection.create” above and adds it to my map,also I’m loading this xml file at the start:

<bpmn:definitions xmlns:bpmn="http://www.omg.org/spec/BPMN/20100524/MODEL" 
                  xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" 
                  xmlns:dc="http://www.omg.org/spec/DD/20100524/DC" 
                  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
                  id="Definitions_1" 
                  targetNamespace="http://bpmn.io/schema/bpmn">
    <bpmn:process id="Process_1" isExecutable="false">
        <bpmn:startEvent id="StartEvent_1" name="Start"/>
        <bpmn:endEvent id="EndEvent_1" name="End"/>
    </bpmn:process>
    <bpmndi:BPMNDiagram id="BPMNDiagram_1">
        <bpmndi:BPMNPlane id="BPMNPlane_1" bpmnElement="Process_1">
            <bpmndi:BPMNShape id="_BPMNShape_StartEvent_2" bpmnElement="StartEvent_1">
                <dc:Bounds x="100" y="372" width="36" height="36" />
            </bpmndi:BPMNShape>
            <bpmndi:BPMNShape id="EndEvent_1_di" bpmnElement="EndEvent_1">
                <dc:Bounds x="1550" y="372" width="36" height="36" />
            </bpmndi:BPMNShape>
        </bpmndi:BPMNPlane>
    </bpmndi:BPMNDiagram>
</bpmn:definitions>

I wasn’t sure bpmn:process was necessary or not so I just left it, but since in the map variable it didn’t cause any problems I can just ignore it.

Please tell me if I understand you correctly.

Your goal is to disallow multiple sequence flows (connections) to connect to a single target. In other words, a task should have at most one incoming connection. The map variable that you mentioned several times is just a mean to this goal.

Is that correct?

2 Likes

If you really need to assign levels to each element there are different ways of doing it. For example with a model extension and some behavior: https://codesandbox.io/s/assign-level-behavior-nmlub

1 Like

I wanted to avoid going in details inside the rule itself as I fear I may not explain it very well.
I want to create a diagram that goes in one way only, that is starting from the startevent to the endevent.
So at the very beginning if you try to add any connection it wont allow it if the source is not the startevent. then when you are developing the diagram the rule set above will only allow you to add that connection if the source of the connection is added in the map variable(so it must be connected already to the startevent even indirectly/through a set of tasks) if it’s not it won’t go through and will be canceled,

if (!(self.tasksLevelMap.has(context.source.id))){
      return false;
}

There are other conditions too such as the connection can’t go from a higher level element to a lower/equal level one for example or self connected tasks.
But the overall Idea is the diagram flows in one way (from startevent to end event through tasks that also go in the same way “only forward”).

Thank you, I’ll check it out and try to work with it and see.
My current idea is to keep the same customrule but instead of working with the map variable and values i’ll use instead the properties set by the model extension your provided(by adding elementregistry extension to my customruelsprovider), that way, when creating a connection by palette it takes account the level of the elements created by contextpad.

Sorry for making this topic this long :sweat_smile: but I have a little request if you may, concerning the model extension you provided(or the sandbox), I would like to put the model extension in a separate file, something similar to this customrulesprovider. and import it in my main component, do you have a codesandbox example on how to do it? Sorry, I’m fairly new to JS.

This is as easy as import moddleExtension from './moddleExtension.js' as long as you have a bundler which is the case for the CodeSandbox.

1 Like

Yes, I managed to do it I first made a typescript file and $inject caused some problem, worked with a js file.
Thank you @barmac @philippfromme .