Diagram-js: where to put external business logic (golang/wasm) with own element storage? Advice needed

Could you guys please give me an advice?

I have following situation:

  • I’m creating custom diagram based on diagram-js (not on bpmn-js)
  • I have main (let’s name it core/business logic) module written in Golang, compiled to wasm, which exposing functions to JS (seems to be working).

Currently trying to glue those things together and looking for good place where to put core/business logic part. I’m going to use this module as provider of rules too.

Currently I’m seeing such issue - the core/busines logic module has it’s own “element registry”, with little bit different structure (there is no connections as separate element but reference property on “source shape”) and data exchanging between JS and Golang is little bit hindered (actually it is possible but generally it works with simple types like strings or ints, and it is also possible to serialize objects to JSON and de-serialized them on other side, but this is quite cumbersome, and not works with complex objects that have some references for example to DOM). So generally I’m forced to keep data about elements in 2 places, what may cause issues, but seems that don’t have another option.

I was planning to treat diagram-js registry as a primary source of information about elements and Golang part as a side-effect storage.

Not sure if this is best place but was going to listen for ‘commandStack.execute/revert’ event (or override execute/revert methods for CommandInterceptor class) to track changes (like ‘elements.create’, etc.) in diagram-js and reflect them on Golang storage. I choose this place since I’m able to handle undo/redo functionality too. However this solution also generates one more issue - Golang logic may return an error that for example element cannot be created. In such situation I’d like to rollback/terminate currently executig (already started on diagram-js side) command. Is it feasible?

For a while I was thinking about writing own CustomElementRegistry which will be using Golang storage to keep all data in one place, and registering it as a module in diagram-js. However due to cumberstone data exchange (for example problem with storing and retracting gfx object belonging to each element), I’m closer to making my decision with ‘commandStack.execute/revert’.

Could you please advice if this ‘commandStack’ this is a good place for this purpose or maybe there is some another trap that I’m not aware yet?

BTW: what is the difference between commands ‘elements.create’ and ‘shape.create’ in events ‘commandStack.execute’? On which should I listen for?

Sorry about long and expanded question, but I really appreciate the advice.

Regards,
Michal

Hi,

(actually it is possible but generally it works with simple types like strings or ints, and it is also possible to serialize objects to JSON and de-serialized them on other side, but this is quite cumbersome, and not works with complex objects that have some references for example to DOM).

The question I’d ask myself is whether I really need to keep references to DOM in my business logic. In case of bpmn-js, we keep the business logic on the businessObject reference so that it’s not mixed with diagram-js shapes and connections. Then, when we need to reflect the diagram state in the business logic state, we have a dedicated module which just writes them to the business objects.

Not sure if this is best place but was going to listen for ‘commandStack.execute/revert’ event (or override execute/revert methods for CommandInterceptor class) to track changes (like ‘elements.create’, etc.) in diagram-js and reflect them on Golang storage.

If you want to be notified of elements being changed, I’d suggest listening to elements.changed event. This is fired after the command stack handles its logic so that you don’t interfere with the ongoing actions.

However this solution also generates one more issue - Golang logic may return an error that for example element cannot be created. In such situation I’d like to rollback/terminate currently executig (already started on diagram-js side) command. Is it feasible?

As soon as a command is dispatched, it cannot be stopped. It’s the Rules module which can stop actions, e.g. in Create. So you could implement a rules provider which could then call your Golang part to check whether certain actions should be allowed.

elements.create is a convenient wrapper for creating multiple elements at once. Check out how it is used in Create and CopyPaste. Behind the scenes, modeling.createElements uses modeling.createShape.

Best

Maciej

4 Likes

Thanks Maciej for great explanation.
Regards,
Michal