Home

Awesome

camunda-modeler-autosave-plugin

Build Status Compatible with Camunda Modeler version 5 Plugin Type

This offers an auto-save mechanism to save your diagram changes after a defined amount of time.

This includes an example plugin on how to extend the Camunda Modeler user interface as React component.

How to use

  1. Download and copy this repository into the plugins directory of the Camunda Modeler
  2. Start the Camunda Modeler
  3. Enable and configure autosave mechanism via overlay

Refer to the plugins documentation to get detailed information on how to create and integrate Camunda Modeler plugins.

Development Setup

Firstly, clone this repository to your machine

$ git clone https://github.com/pinussilvestrus/camunda-modeler-autosave-plugin.git
$ cd camunda-modeler-autosave-plugin

Install all dependencies

$ npm install

To work properly inside the Camunda Modeler, this plugin needs to be bundled.

$ npm run all

Compatibility Notice

This plugin is currently compatible with the following Camunda Modeler versions.

Camunda ModelerAutosave Plugin
3.4 - 4.120.2
5.x0.3 or newer

About

The AutoSavePlugin component implements the basic functionality to render the autosave mechanism into the Camunda Modeler application.

First of all, it offers a render method to return the React component to be included in the application. It handles the appearance configuration overlay via its state and fills an action button into the application's status bar component.

render() {
  const {
    configOpen,
    enabled,
    interval
  } = this.state;

  const initValues = {
    enabled,
    interval
  };

  // we can use fills to hook React components into certain places of the UI
  return <Fragment>
    <Fill slot="status-bar__app" group="1_autosave">
      <button
        ref={ this._buttonRef }
        className={ classNames('btn', { 'btn--active': configOpen }) }
        onClick={ () => this.setState({ configOpen: true }) }>
        <Icon />
      </button>
    </Fill>
    { this.state.configOpen && (
      <ConfigOverlay
        anchor={ this._buttonRef.current }
        onClose={ this.handleConfigClosed }
        initValues={ initValues }
      />
    )}
  </Fragment>;
}

When creating our UI extensions, we can even rely on built-in styles, like sections, primary and secondary buttons. This is important to let our new components fit into the application look & feel.

<Overlay anchor={ anchor } onClose={ onClose } offset={ OFFSET }>
  <Section>
    <Section.Header>Auto save configuration</Section.Header>
    <Section.Body>
      /* ... */

      <Section.Actions>
        <button
          type="submit"
          className="btn btn-primary"
          form="autoSaveConfigForm">
            Save
        </button>
      </Section.Actions>
    </Section.Body>
  </Section>
</Overlay>

When the plugin component got first time rendered (cf. componentDidMount), it retrieves plugin specific information from the application configuration to properly configure the autosave mechanism.

// retrieve plugin related information from the application configuration
config.getForPlugin('autoSave', 'config')
  .then(config => this.setState(config));

Furthermore, it hooks into certain application events to properly setup and restart the auto save timer.

 // subscribe to the event when the active tab changed in the application
subscribe('app.activeTabChanged', ({ activeTab }) => {
  this.clearTimer();

  if (this.state.enabled && activeTab.file && activeTab.file.path) {
    this.setupTimer();
  }
});

// subscribe to the event when a tab was saved in the application
subscribe('tab.saved', () => {
  if (!this.timer && this.state.enabled) {
    this.setupTimer();
  }
});

As a main purpose the extension should save diagram changed after a defined amount of time. To do this, it uses the given triggerAction functionality to send a save request to the application. When something got wrong, plugins are even allowed to display notification on the UI.

save() {
  const {
    displayNotification,
    triggerAction
  } = this.props;

  // trigger a tab save operation
  triggerAction('save')
    .then(tab => {
      if (!tab) {
        return displayNotification({ title: 'Failed to save' });
      }
    });
}

To properly work inside the Camunda Modeler application, every plugin needs to have a general entry point, in this example named the index.js. This gives general information about where to find the React component, general styling, and, if needed, application menu extensions. To get detailed information about how to integrate a plugin into the Camunda Modeler, please refer to the existing plugins documentation.

module.exports = {
  script: './dist/client.js',
  style: './client/style.css',
  name: 'autosave-plugin'
};

To work inside a browser application, the React extension needs to be bundled. Refer to the webpack.config.js on how to achieve this.

Resources

License

MIT