Writing a custom properties panel

As part of the successful Drupal integration, where bpmn.io already has around 8.000 reported installations, we’re planning to write our own properties panel which will utilize Drupal’s form API, something that probably only makes sense for a solution that embedded into Drupal.

I’m wondering if there is any guide on how to write such a properties panel, especially with regard to hooking into the element select and unselect events, where we need to create the property panel for the current element. I was looking into the code at bpmn-io/properties-panel but feel a bit lost. If anyone could give me a good starting point with some boiler plate code, that would be amazing.

There is no an end-to-end guide as such. Have a look at:

Feel free to post about problems you run into during the implementation. :slight_smile:

Thank you @jarekdanielak the example repo has already been a great source for this for the last couple of days, especially the interaction example which goes into the eventbus, an important starting point and it got me pretty far already. I’ll be able to share something working within a few days I would hope.

I got it implemented, and I’m pretty happy with it. It works, when the user selects an element. What is only working in parts, when the selected element has no template yet, I want to open the template chooser. That works, when the element already exists and gets selected, but if the element is created-and-selected, then the template chooser appears and disappears again.

Here is my code, maybe you have a hint what I’m doing wrong?

  Drupal.bpmn_io.elementSelected = function (element) {
    if (element.type === 'bpmn:Process') {
      // Ignore the click on the main canvas but close the previous config form.
      Drupal.bpmn_io.closeOffCanvas();
      return;
    }
    let pluginId = Drupal.bpmn_io.findPluginId(element);
    if (pluginId === undefined) {
      Drupal.bpmn_io.eventBus.once('elementTemplateChooser.chosen', (e) => {
        Drupal.bpmn_io.eventBus.fire('popupMenu.close');
        Drupal.bpmn_io.elementTemplates.applyTemplate(element, e.template);
        pluginId = Drupal.bpmn_io.findPluginId(element);
        if (pluginId !== undefined) {
          Drupal.bpmn_io.loadConfigForm(element, pluginId);
        }
      });
      Drupal.bpmn_io.eventBus.fire('elementTemplates.select', { element: element });
      return true;
    }
    Drupal.bpmn_io.loadConfigForm(element, pluginId);
  };

  Drupal.bpmn_io.eventHandler = function () {
    if (drupalSettings.modeler_api.useFormApi) {
      Drupal.bpmn_io.eventBus.on('selection.changed', 250 , function (e) {
        if (e.newSelection[0] === undefined) {
          Drupal.bpmn_io.closeOffCanvas();
        }
        else if (e.newSelection[1] === undefined) {
          Drupal.bpmn_io.elementSelected(e.newSelection[0]);
        }
      });
    }
    else {
      Drupal.bpmn_io.eventBus.on('element.click', function (e) {
        setTimeout(function () {
          Drupal.bpmn_io.updateCanvas(e.element);
        }, 5);
      });
    }
  };
2 Likes

To be more precise: it works correctly for start events, sub-groups, etc. but not for tasks. There, the template chooser quickly appears and then the task label inline edit field comes on which also seems to hide the template chooser again.

Direct editing activates for new tasks. If you want to prevent that, then you want to customize the LabelEditingProvider.

Thanks @nikku for that suggestion. I want to avoid writing my own implementation for this, and therefore patch the LabelEditingProvider to not subscribe to create.end and autoPlace.end. But that’s certainly not the correct way of doing this. Do you have any other suggestions? I’d love to use eventBus.off() but I don’t have the callback available that I want to turn off at this point.

@jurgenhaas The simplest way to do it (today) is to override the behavior, provide your own labelEditingProvider. Of course there is more that we could do:

  • The provider plugs in with low priority into create.end and autoPlace.end. It could investigate the preventDefault flag in the event and only apply the editing behavior it is not set
  • The provider could make overriding of initialization simpler, i.e. move certain parts into separate methods (so you can sub-class)

Probably more options.

Would be great if the behaviour were adjustable from outside with either of those options. For now, I take my described approach and adjust it when better ways become available.

Thank you @nikku