Git Product home page Git Product logo

modeler's Introduction

ProcessMaker BPMN modeler

CircleCI

@processmaker/modeler is a Vue.js based BPMN modeler scaffolded using Vue CLI 3.

Project setup

Clone the repository and cd into the modeler directory:

git clone [email protected]:ProcessMaker/modeler.git
cd modeler

You can now run any of the below commands. Most commands make calls vue-cli-service. You can read more about those commands at https://cli.vuejs.org/guide/cli-service.html#cli-service.

# Compile the app and start a local development server
npm run serve

# Create a production build of the app to be distributed as an npm package
npm run build-bundle

# Report and fix ESLint errors
npm run lint

Docker Env

If you prefer to run Modeler using Docker

# Using Docker Compose
docker compose up

Testing

Unit tests are set up using jest and end-to-end tests are set up using Cypress. Unit and end-to-end tests can be run separately or together. Code coverage is collected for both types of tests and combined into a single coverage report for the entire project.

Tests can be run locally with the following commands:

# Run the Jest unit test suite
npm run test-unit

# Open Cypress to run the end-to-end (e2e) test suite
npm run open-cypress

# Run the Cypress end-to-end (e2e) test suite in headless mode
npm run test-ci

# Run the Jest unit test tests and then the Cypress tests in headless mode
npm test

Tests are run automatically on CircleCI when new branches are created and updated. The CI uses the npm test command to run both the unit and e2e test suites and to collect code coverage.

For more information on Cypress, visit https://cli.vuejs.org/config/#cypress.

For more information on Jest, visit https://jestjs.io.

Architecture

The entry point for the application is src/main.js; this is the "starting point" which is used when running npm run serve or npm run build.

Global event bus

window.ProcessMaker.EventBus points to an independent Vue instance which acts as the application's global event bus. The modeler currently emits two events on the event bus which can be listened to in application code to hook into, customize, and extend the modeler's behaviour: modeler-init, and modeler-start.

modeler-init

This event is fired before the modeler and BpmnModdle are set up and mounted. Listeners to this event are passed an object with three methods: registerInspectorExtension, registerBpmnExtension, and registerNode.

import bpmnExtension from '@processmaker/processmaker-bpmn-moddle/resources/processmaker.json';
import { intermediateMessageCatchEvent } from '@/components/nodes';

window.ProcessMaker.EventBus.$on('modeler-init', ({ registerBpmnExtension, registerNode, registerInspectorExtension }) => {

  /* Add a BPMN extension */
  registerBpmnExtension('pm', bpmnExtension);

  /* Register a component to be used in the modeler */
  registerNode(intermediateMessageCatchEvent);

  /* Add custom properties to inspector */
  registerInspectorExtension(intermediateMessageCatchEvent, {
    id: 'pm-condition',
    component: 'FormInput',
    config: {
      label: 'Condition',
      helper: 'Expression to be evaluated on webhook to activate event. Leave blank to accept always.',
      name: 'pm:condition',
    },
  });

});

modeler-start

This event is fired after the modeler has been set up and mounted. Listeners to this event are passed an object with a single method, loadXML.

window.ProcessMaker.EventBus.$on('modeler-start', ({ loadXML }) => {

  loadXML('<?xml version="1.0" encoding="UTF-8"?> ... </bpmn:definitions>');

});

For the modeler to function correctly, loadXML must be called when the application loads.

modeler-validate

This event is fired during validation, and can be used to add custom validation rules. See Adding validation rules during runtime.

modeler-change

This event is fired anytime a change is made to the modeler that causes the underlying XML to change. This event is fired immediately after new state is pushed to the undo/redo stack.

window.ProcessMaker.EventBus.$on('modeler-change', () => {
  console.log('The diagram has changed');
});

Undo/redo store

The undo/redo feature is implemented using Vuex, with the undo/redo Vuex store initialized in src/undoRedoStore.js. The undo/redo store keeps track of every change in the underlying BPMN XML, recording a copy of the XML string in a stack. Traversing the undo/redo stack simply uses the loadXML function to load the XML string from the current position in the stack.

Validation

Adding a new lint rule

By default, the modeler automatically validates your diagram as you create it. This validation can be toggled on and off using the switch in the status bar. Validation is handled using https://github.com/bpmn-io/bpmnlint.

To add a new validation rule, create a new file in processmaker-plugin/rules named after your rule, for example, node-id.js. This file should export a function that returns an object with a check method. The check method will receive two arguments—node and reporter—and must return undefined if validation passes, or reporter.report to raise an error. For exmaple:

// processmaker-plugin/rules/node-id.js

/**
 * Rule that checks node IDs start with "node_"
 */
module.exports = function() {
  function check(node, reporter) {
    if (typeof node.id === 'string' && !node.id.startsWith('node_')) {
      reporter.report(node.id, 'Node ID must start with the string "node_"');
    }
  }

  return { check };
};

When you are done writing the rule, add it to processmaker-plugin/index.js:

module.exports = {
  configs: {
    all: {
      rules: {
        'processmaker/custom-validation': 'error',
        'processmaker/gateway-direction': 'error',
        'processmaker/node-id': 'error',
      },
    },
  },
};

For more examples, see the list of default rules at https://github.com/bpmn-io/bpmnlint/tree/master/rules.

Adding validation rules during runtime

To add custom validation when the linter runs, use the global event bus:

window.ProcessMaker.EventBus.$on('modeler-validate', (node, reporter) => {
  if (typeof node.id === 'string' && !node.id.startsWith('node_')) {
    reporter.report(node.id, 'Node ID must start with the string "node_"');
  }
});

Examples

Adding a new component

Creating a new modeler component requires creating a Vue component, a component config, and calling the registerNode method to register your component.

First, create your component config, and save it in a .js file:

// CustomComponentConfig.js

export default {
  // A unique ID that will be used to identify your component
  id: 'unique-custom-component-id',

  // A reference to the Vue component representing your component
  component: CustomComponent,

  // The bpmn type for your component, which will be used to save the component under in XML
  // It has the form prefix:name
  bpmnType: 'custom-namespace:CustomComponent',

  // A toggle to show/hide the component in the controls panel
  control: true,

  // The category to place the component under in the controls panel
  category: 'BPMN',

  // The icon representing the component in the controls panel
  icon: require('@/assets/toolpanel/scriptTask.svg'),

  // The label for the component in the controls panel
  label: 'Script Task',


  // The function used to create the BPMN definition object for the component in the XML
  // moddle is a reference to an instance of bpmn-moddle: https://github.com/bpmn-io/bpmn-moddle
  definition(moddle) {
    return moddle.create('bpmn:ScriptTask', {
      name: 'Script Task',
    });
  },

  // The function used to create the BPMN diagram object for the component in the XML
  // moddle is a reference to an instance of bpmn-moddle: https://github.com/bpmn-io/bpmn-moddle
  diagram(moddle) {
    return moddle.create('bpmndi:BPMNShape', {
      bounds: moddle.create('dc:Bounds', {
        height: taskHeight,
        width: 116,
      }),
    });
  },

  // The configuration for the inspector panel
  inspectorConfig: [
    {
      name: 'CustomComponent',
      items: [
        // Each item corresponds to a form element. 
        {
          // Component can be a custom Vue component or a reference to a form component from @processmaker/vue-form-elements
          component: 'FormText',
          config: {
            label: 'Custom Component Label',
            fontSize: '2em',
          },
        },
        // ...
      ],
    },
    // ...
  ],
};

Then, create a Vue component for your custom element:

// CustomComponent.vue

<template>
  <div />
</template>

<script>
import Task from '@/components/nodes/task/task';

export default {
  extends: Task,
  mounted() {
    // Do things with this.shape
  },
};
</script>

Finally, register your custom component:

registerNode(CustomComponentConfig);

modeler's People

Contributors

abdelilahlbardi avatar agustinbusso avatar alvaroflorespm avatar ana-mauricio avatar boliviacoca avatar caleeli avatar chipit24 avatar danloa avatar devmiguelangel avatar eiresendez avatar go-vehikl avatar gustavobascope avatar jcook21 avatar johnblackspear avatar josechirivella avatar lisa-fehr avatar marcoantonionina avatar mcraeteisha avatar milaendo avatar nolanpro avatar pmoskrojas avatar rodriquelca avatar ryancooley avatar sanjacornelius avatar tdondich avatar tincodes avatar tuantruong625 avatar uujfwmnp avatar vehikl-jacare avatar velkymx avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

modeler's Issues

Tasks should be able to connect to exclusive gateways

Connecting via flow needs to be allowed from task to exclusive gateway. And exclusive gateway also needs to allow connecting to tasks.

However, the exclusive gateway can only have two outbound flows and only one inbound flow. We should enforce these rules.

@enriquecolosa , do you agree with these rules? What should the behavior be if you attempt to do something against these rules?

Default Rendering

By default the modeler should render a single start event in the top left side of the canvas.

Sequence flow properties duplicated when uploading diagram

When uploading a diagram with sequence flows, the incoming and outgoing properties on the connected flow elements are duplicated. E.g.:

After first upload:

<bpmn:startEvent id="node_1" name="Start Event">
  <bpmn:outgoing>node_3</bpmn:outgoing>
</bpmn:startEvent>
<bpmn:task id="node_2" name="New Task">
  <bpmn:incoming>node_3</bpmn:incoming>
</bpmn:task>
<bpmn:sequenceFlow id="node_3" sourceRef="node_1" targetRef="node_2" />

After downloading and re-uploading:

<bpmn:startEvent id="node_1" name="Start Event">
  <bpmn:outgoing>node_3</bpmn:outgoing>
  <bpmn:outgoing>node_3</bpmn:outgoing>
</bpmn:startEvent>
<bpmn:task id="node_2" name="New Task">
  <bpmn:incoming>node_3</bpmn:incoming>
  <bpmn:incoming>node_3</bpmn:incoming>
</bpmn:task>
<bpmn:sequenceFlow id="node_3" name="" sourceRef="node_1" targetRef="node_2" />

bpmn:outgoing and bpmn:incoming are duplicated even though the diagram was not modified between re-uploading.

Undo / Redo

We'd like to be able to undo changes in the modeler and redo them.

Pools overlapping

To reproduce:

  • Drag two pools onto the grid.
  • Add an element to one of the pools.
  • Drag the element, and it causes the other pool to resize when it shouldn't.

pool_bug

Downloadable XML File

Currently in the application the generated xml appears in an alert.

This issue will add the ability to download the xml as a file.

Implement Exclusive, Inclusive and Parallel Gateways Elements

As a process modeler I want to have the ability to add Gateways to my process so I can use them to control the flow logic across the process execution.

Gateway Element Supported

  • Exclusive Gateways (Rhombus element with a X inside)
  • Inclusive Gateways (Rhombus element with a O inside)
  • Parallel Gateways (Rhombus element with a + inside)

Crown
Crown for gateway element are the same than other BPMN elements already implemented.

ToolBar
screen shot 2018-10-19 at 8 42 47 am

Element Inspector
Please refer to xx, xx and xx to see process inspector details for each type of gateways.

Flow Element Crown

When you click on a flow element on the canvas two icons should appear to the right of the element. These icons are a flow segment and a trash can.

Clicking on the flow element will allow for drawing a line from the current element to another.

Clicking on the trash can will remove that element.

screenshot 2018-10-08 14 58 22

Support Complex Node Types with parsing and saving functionality

We have complex node types that we need to be able to add dynamically, for example with ProcessMaker BPM 4.

The intent is that, a node type could be something like Script Task, or a connector. So there are some general properties:

  • Category of node type (Example: Social, BPMN, CRM...)
  • Name of node type (Example: Send Tweet, Create Lead, Send Email)
  • Custom inspector configuration
  • Ability for inspector changes to dynamically change underlying bpmn representation in custom ways
    • For example, there might be an inspector control to modify the entire json object of the pm:config attribute.
    • Or, there might be individual controls that modify attributes directly in the json object of the pm:config
    • Idea on this is there should instead be an intermediate 2-way binding data model for that node, and a custom Inspector modification handler that dynamically updates that node's bpmn object appropriately.
  • Parsing of that node type
    • So when a bpmn file is loaded, parsers should be registered so that custom node types have a parser to help identify itself and that it's the node type for the underlying bpmn object.
    • So, connectors, for example, are represented in the bpmn file as service tasks, being uniquely identified by the 'implementation' attribute. So, a specific node type might have a parser that looks for that implementation attribute for a specific value. If it matches, then perhaps that parser returns a built node that is ready to be attached to the modeler. If there is no match, then returns null and the next parser runs.
  • The ability to modify EXISTING node types. For example, certain packages might want to modify/replace the inspector configuration for Task types. So, there should be interfaces to allow fetching a node type and it's configuration, and then an interface to modify it's configuration/parsing ability.

Add support for modifying inspector configurations for elements

As a developer integrating modeler into other systems (such as ProcessMaker BPM), I need to be able to extend/replace the inspector configuration for elements so I can add better integration into the target platform.

Use Case: In ProcessMaker BPM, there are concepts of screens which are customized input screens designed by vue-form-builder. For user tasks in BPM, we need to be able to assign a specified screen to a user task. This is stored in the XML as the screenRef attribute, but in the inspector for the task, I should be able to specify it using a custom visual inspector configuration component.

Render Pools and Lanes

When importing a BPMN or dragging a pool (and subsequently a lane), the canvas should render the pool and lanes. Pools will render a crown with a trash icon for removing the pool and its lanes.

What are lanes?

https://www.signavio.com/post/bpmn-pools-and-lanes/

lanes

Acceptance Criteria

Drag a pool to the canvas
Create lanes above and below (via the crown)
Drag elements between lanes (and pools)
Update the XML with the correct data for the pools

Publish initial master branch as version 0.1.0 for npm

BPM project requires the modeler to be available as a npm package to install and load for it's internal modeler. In order to accomplish this, an initial release should be made to npm so it can be referenced in bpm's package.json

Multiselect Flow Elements

Add the ability to drag a box with the mouse to multiselect flow elements on the canvas. Then, once select you should be able to drag all selected elements as one.

image

Auth UUID in Binary

In the Auth session the UUID is being stored as binary and not at uuid text.

Add ability to connect elements via a sequential flow

Utilizing the crown and clicking, the ability to connect elements via sequential flow needs to be added. Ideally, this is done by clicking the flow icon in a crown on the source object, and then clicking on the target item.

Please refer to the camunda modeler for example of this.

For now, support start event to task, and task to task, and exclusive gateway to task, and task, and those elements to end/stop event.

These should be represented by Sequential Flow.

Enforce valid order of nodes

XSD validation requires that the textAnnotations nodes should be stored after all the rest of the flow elements, if not it cause an validation error:
image

Add ability to connect elements via an association flow

Utilizing the crown and clicking, the ability to connect elements via association flow (dotted line) needs to be added. Ideally, this is done by clicking the flow icon in a crown on the source object, and then clicking on the target item.

Please refer to the camunda modeler for example of this.

Association Flow Restrictions

  • Any element in the modeler can be connected to any element but text annotations or lanes

Uploading an BPMN file leaves previous elements in data store

If I am working inside a bpmn file and I upload another bpmn file, it appears that the previous elements are still in the canvas and data model.

When importing a bpmn file, at this time, it's okay to clear all data, even if not saved/downloaded. We'll take care of that at a later time.

Exclusive Gateways

Exclusive gateways are represented with this shape:

image

An exclusive gateway evaluates the state of the business process and, based on the condition, breaks the flow into one of the two or more mutually exclusive paths.

The inspector for the gateway itself should only contain a name and id field.

The sequence flow lines coming off of the gateway are special as they have an additional parameter not present in a normal sequence flow. These flows contain an EXPRESSION. An expression a small bit of code using the FEEL syntax that will evaluate the data received, and make a decision to route to the subsequent elements based on the evaluation.

The sidebar for these expression sequence flow line should add a required text box labeled Expression.

screen shot 2018-11-02 at 12 09 28 pm

Expression Requiring Quotes

When I put an expression in a gateway evaluation. I must quote the expression for it to work.

This works: "color==blue"

This does not: color==blue

Remove processmaker-bpmn-moddle from this repository

Since the processmaker-bpmn-moddle is to support processmaker bpm extensions specifically, this stand-alone modeler codebase should no longer import it. Instead, the bpm4 codebase should import and then call registerBpmnExtension on the Modeler instead.

Connector: Email

We'd like to have a connector that can send out email via the laravel mailer component. Inspector should allow for; subject, screen (from screen type email), and who to send to.

Text Annotation Element

When I click on the text icon in the flow menu, I want to be able to drag a text annotation onto the canvas. I need to be able to then click on the flow element and edit the text in the inspector pane.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.