All New Frontend Plugin System for Cockpit starting with Camunda BPM 7.14

We are happy to announce, that Camunda BPM 7.14 (scheduled for Tuesday, October 13th, 2020) includes an all new frontend plugin system for Cockpit. It replaces the current AngularJS 1.8 based plugin system and enables you to extend Cockpit with domain-specific information written in the web-technologies of your choice.

What are Plugins

Webapp plugins are user extensions that provide custom functionality to Cockpit, Tasklist, and Admin, which Camunda does not provide out of the box. It allows you to embed domain-specific information into Camunda tooling without switching applications.

The new plugin system allows you to use the Javascript framework you are most familiar with, whether it be React, Angular, or just plain Javascript.
Cockpit is the first webapp to receive a new plugin system. Tasklist and Admin will behave the same as in 7.13.

Developing a Plugin

In this step-by-step example, we will guide you through creating a plugin, adding a frontend library (we are using React), and greeting the user on the dashboard. If you want to follow along, make sure you have a modern version of NodeJS and Camunda BPM 7.14.0 installed. We will be using the Tomcat distribution for this example. Some paths might be different if you are using another application server.

The Interface

Let’s have a look at the plugin API and how to integrate it into Cockpit. Check out this “Hello World” plugin:

// plugin.js
export default {
  id: "myDemoPlugin",
  pluginPoint: "cockpit.dashboard",
  priority: 10,
  render: (node, { api }) => {
    node.innerHTML = `Hello World!`;
  }
};

Let’s go through it line by line:

  • export default {}: Is a JavaScript Module which exports an Object. If you have multiple plugins in one file, you can also export an array of Objects.
  • id: "myDemoPlugin": The unique ID of our plugin.
  • pluginPoint: "cockpit.dashboard": The pluginPoint property describes where the plugin will be rendered. They correspond to the list of plugin-points shown in our documentation.
  • priority: 10: If there are multiple plugins at the same plugin point, the one with the highest priority will be at the top.
  • render: (node, { api }): The heart of our plugin, here is where we can extend cockpit. The render function receives two arguments: a DOM node in which we can render our content, and an Object with additional information. What will be passed as additional information depends on the plugin point. On the Dashboard, we only receive the api Object, which contains REST endpoints and the CSRF-Token to make REST requests.

To register it, save the file in your cockpit scripts folder. On Tomcat, this would be server/apache-tomcat-{version}/webapps/camunda/app/cockpit/scripts. Lastly, we register it in the config.js by adding it to the customScripts field:

// config.js
export default {
  customScripts: [
    'scripts/plugin.js'
  ]
}

Now you can open your browser and log in. If everything worked correctly, it should look something like the picture below. You might have to force-refresh the page to see the results.

If you don’t want to add a frontend library, you can stop here and continue developing your plugin using the DOM API.

Adding a Frontend Library

To use external libraries in your plugin, you have to provide them with your plugin code in a bundle. We will be using React as a library and Rollup as a bundler for this example. First, let’s create a project and install react.

npm init -y
npm install --save react react-dom

Now we can import and use React in our plugin code. For now, let’s create a simple component which receives the CSRF token as a prop:

// Greetings.js
import React from "react";

function Greetings({ camundaAPI }) {
  return This is rendered in React: {camundaAPI.CSRFToken};
}

export default Greetings;

And render it using React into the node in our plugin:

// plugin.js
import React from "react";
import ReactDOM from "react-dom";

import Greetings from "./Greetings";
let container;

export default {
  // ...,
  render: (node, { api }) => {
    container = node;
    ReactDOM.render(
      ,
      container
    );
  },
  unmount: () => {
    ReactDOM.unmountComponentAtNode(container);
  }
};

As you have noticed, we also added an unmount function and cached the container instance. While the plugin will work without it, it is good practice to unmount and clean up all your components to avoid memory leaks.

To deploy the react plugin, we will have to bundle it first. For this, we will install rollup and a few plugins so we can transpile the JSX we just wrote:

npm install --save-dev rollup \
    @babel/core \
    @babel/preset-react \
    @rollup/plugin-babel \
    @rollup/plugin-commonjs \
    @rollup/plugin-node-resolve \ 
    @rollup/plugin-replace

Now we can configure our bundle in the rollup.config.js. We will have to transpile JSX using babel, include all external modules, and replace NODE_ENV flags. The final configuration looks like this:

// rollup.config.js
import babel from "@rollup/plugin-babel";
import resolve from "@rollup/plugin-node-resolve";
import commonjs from "@rollup/plugin-commonjs";
import replace from "@rollup/plugin-replace";

export default {
  input: "src/plugin.js",
  output: {
    file: "dist/plugin.js"
  },
  plugins: [
    resolve(),
    babel({"presets": ["@babel/preset-react"]}),
    commonjs({
      include: "node_modules/**"
    }),
    replace({
      "process.env.NODE_ENV": JSON.stringify("production")
    })
  ]
};

Running rollup -c with this configuration will take plugin.js located in the src/ folder and transforms it into a deployable plugin.js in the dist/ folder.
When you deploy it, it should look like this:

Writing your Plugin

Let’s extend the functionality and greet the user by name. To achieve that, we will use react hooks for state management and the fetch API to get the currently logged in user.

// Greetings.js
import React, { useState, useEffect } from "react";

function Greetings({ camundaAPI }) {
  const [user, setUser] = useState();

  useEffect(() => {
    fetch(camundaAPI.adminApi + "/auth/user/default", {
      headers: {
        "Accept": "application/json",
        "X-XSRF-TOKEN": camundaAPI.CSRFToken,
      },
    }).then(async (res) => {
      setUser(await res.json());
    });
  }, [setUser, CSRFToken]);

  if (!user) {
    return Loading...;
  }
  return 

Welcome {user.userId}, have a nice day!

; } export default Greetings;

As you can see, we use the base tag to get the admin api and the CSRF token we passed as a prop in the request headers.
State management is done with Reacts useState hook. You can extend this example with your own React components. For example, you could display all open Tasks that are assigned to the user or build a calendar integration with an external service.
If you want to add custom CSS, you can extend the user-styles.css in the Cockpit webapp folder.

Here are some ideas for you to continue with the development:

  • minify the bundle using uglify
  • add custom CSS in the user-styles
  • try out the other plugin points

You can read about the plugin system in more detail in our docs or check out the finished example on Github. If you get stuck or want to share the cool plugins you have build, head over to our community forum and tell us about it.

If you are interested in using other libraries, check out our other examples.

  • Cawemo Enterprise (On-Premises) 1.5 Released

    We’re happy to announce the 1.5 release of Cawemo Enterprise On-Premises. Cawemo is the BPMN process specification platform of the Camunda stack, enabling all stakeholders to model and collaborate on process diagrams and related files. The main improvements in this release are: New UiPath template editor Cawemo provides a form-based editor for element templates that are tailored specifically to be used with Camunda’s RPA Bridge and UiPath. Template versioning You are able to manage and publish versions of the same template, allowing you to adjust templates to changes in your UiPath scripts or other task implementations. Integration with Camunda’s new identity and access management solution Camunda Account takes over the user management for Cawemo and will enable LDAP support in...

    Read more
  • Camunda Modeler 4.5 Released

    We are happy to announce the release of Camunda Modeler 4.5. This release introduces the ability to handle versioned templates, improves the navigation of DMN Decision Tables and delivers various smaller improvements when modeling BPMN. Download the latest release and start modeling right away. Templates Versioning Templates allow you to configure a diagram element with predefined properties —  very helpful when you work with predefined properties or reuse configuration in multiple elements. During development, you may need to change a template. This can now be achieved thanks to templates versioning. By specifying an optional `version` field in the template configuration, the Camunda Modeler can detect and handle newer versions by offering an update option. Templates created and published on Cawemo,...

    Read more
  • Test Your Processes With JUnit 5

    If you’re a fan of JUnit5 for testing on the JVM, we have good news — there’s a brand-new library available: camunda-bpm-junit5, published as a community extension for Camunda BPM. The project is now available on Maven central, so you can start testing your processes with the latest technology. Getting started To add the extension to your project, just add the Maven dependency to your pom file: <dependency> <groupId>org.camunda.bpm.extension</groupId> <artifactId>camunda-bpm-junit5</artifactId> <version>1.0.0</version> <scope>test</scope> </dependency> Add the dependencies to JUnit 5 if you don’t already have them (they are included in the spring-boot-starter-test artifact): <dependency> <groupId>org.junit.jupiter</groupId> <artifactId>junit-jupiter</artifactId> <version>5.6.2</version> <scope>test</scope> </dependency> To start testing you can extend your test class with the ProcessEngineExtension: This injects the ProcessEngine configured in the camunda.cfg.xml file into...

    Read more