Can't place custom component

I’m working on creating a custom element for emails. The element should have the following fields:
To, CC, BCC, Subject and Body

When saved, the XML should be converted to a service task that contains the above fields.

I’ve tried to follow the custom-elements example, I’ve updated the palette, created a custom renderer, and added json for the new element, but I’m not able to place the element on the canvas.

Any help would be appreciated

JSON

{
  "name": "Acme",
  "uri": "http://some-company/schema/bpmn/qa",
  "prefix": "acme",
  "xml": {
    "tagAlias": "lowerCase"
  },
  "types": [
    {
      "name": "Email",
      "extends": [
        "bpmn:ServiceTask"
      ],
      "properties": [
        {
          "name": "To",
          "isAttr": true,
          "type": "String"
        },
        {
          "name": "CC",
          "isAttr": true,
          "type": "String"
        },
        {
          "name": "BCC",
          "isAttr": true,
          "type": "String"
        },
        {
          "name": "Subject",
          "isAttr": true,
          "type": "String"
        },
        {
          "name": "Body",
          "isAttr": true,
          "type": "String"
        }
      ]
    }
  ],
  "emumerations": [],
  "associations": []
}

Palette

import emailSVG from '../../assets/email.svg'

export default class CustomPalette {
  constructor(bpmnFactory, create, elementFactory, palette, translate) {
    this.bpmnFactory = bpmnFactory
    this.create = create
    this.elementFactory = elementFactory
    this.translate = translate

    palette.registerProvider(this)
  }

  getPaletteEntries() {
    const {
      bpmnFactory,
      create,
      elementFactory,
      translate
    } = this

    function createEmail() {
      return function(event) {
        const businessObject = bpmnFactory.create('acme:Email')
        
        const shape = elementFactory.createShape({
          type: 'acme:Email',
          businessObject: businessObject
        })

        create.start(event, shape)
      }
    }

    return {
      'create.acme-email': {
        group: 'activity',
        title: translate('Create acme Email'),
        imageUrl: emailSVG,
        action: {
          dragstart: createEmail(),
          click: createEmail()
        }
      },
    }
  }
}

CustomPalette.$inject = [
  'bpmnFactory',
  'create',
  'elementFactory',
  'palette',
  'translate'
]

Renderer

import inherits from 'inherits'
import BaseRenderer from 'diagram-js/lib/draw/BaseRenderer'

import {
  append as svgAppend,
  create as svgCreate
} from 'tiny-svg'

import {
  is
} from 'bpmn-js/lib/util/ModelUtil'


import emailSVG from '../../assets/email.svg'

export default function AcmeEmailRenderer(eventBus) {
  BaseRenderer.call(this, eventBus, 1500)

  this.canRender = function(element) {
    return is(element, 'acme:Email')
  }


  this.drawShape = function(parent, shape) {
    var emailIcon = svgCreate('image', {
      x: 0,
      y: 0,
      width: shape.width,
      height: shape.height,
      href: emailSVG
    })

    svgAppend(parent, emailIcon)

    return emailIcon
  }

  this.getShapePath = function(shape) {
    return this.bpmnRenderer.getShapePath(shape);
  }
}

inherits(AcmeEmailRenderer, BaseRenderer)

AcmeEmailRenderer.$inject = [ 'eventBus' ]

How about if you create an actual bpmn:ServiceTask with desired properties right away?

    function createEmail() {
      return function(event) {
        const businessObject = bpmnFactory.create('bpmn:ServiceTask', {
          To: '...',
          CC: '...'
        });
        
        const shape = elementFactory.createShape({
          type: 'bpmn:ServiceTask',
          businessObject: businessObject
        })

        create.start(event, shape)
      }
    }

Then, in the renderer you could look for the properties:

  this.canRender = function(element) {
    var businessObject = getBusinessObject(element);

    return businessObject.get('acme:To') || businessObject.get('acme:CC') || ...
  }
1 Like

that makes a lot of sense thanks!

1 Like