Issue #3613299: A modeler save no longer empties a variables node, and its Add and Remove act in place

Follow-up to the plugin type merged from this issue. Two blockers found while driving the editor on a real model.

A modeler save emptied the node

Saving the diagram in BPMN.io left the node with no providers and a null scope. The diagram was never at fault: the saved BPMN carried both values correctly.

modeler_api's Component::validate() replays the plugin through a runtime form on every save, seeding it with the node's own stored configuration, then overwrites the component's configuration with the plugin's resulting one. A table element cannot take its stored JSON string back as rows, so that replay reaches submitConfigurationForm() carrying no providers at all, and the submit read it as "the editor cleared the list".

The submit now rewrites the list only for a submit that carries a marker the rendered editor emits (a hidden element, which the template builder skips, so it stays out of the diagram). A replay leaves the stored value untouched. The scope is guarded the same way, so a replay carrying no value cannot null it. mergeSelection() also accepts the stored shape (a JSON list) as well as the editor's table rows.

Add submitted the whole editor

OrchestraCmForm wires settings triggers by walking only the direct children of the settings subform, so the Add button, nested one level inside a container, was never wired and behaved as a plain submit: it saved the model and returned the user to the workflow list.

The wiring is now recursive, so a flagged element at any depth gets the structure AJAX. That is what a plugin already had to assume, and it is what makes per-row controls possible. Both of this node's controls also carry their own submit handler and an empty validation scope, so they rebuild in place even where a host does not wire them.

Remove is a button, not a checkbox

Removing a provider no longer means ticking a box and saving the whole workflow: each row has a Remove button that drops it on the spot, through the same rebuild as Add.

A newly added provider jumped to the front

Adding a provider put it second in the list rather than last, and a manual reorder afterwards persisted correctly. The browser does not always send a drag value for a row the editor has just added, and the merge read that absence as weight zero: a stable sort then tied the new row with the first one and placed it second. A row that comes back without a weight is now understood as newly added and joins the end, after every row that does carry one.

Tests

Five new: a row submitted without a weight lands last, a replayed submit leaves the selection and scope untouched (the regression above), the editor can still clear the list deliberately, the Add button is a direct child carrying its own fallback and a node-scoped name, and a trigger nested in a table row is wired by the canvas form. The suite for the variables node, the canvas form and the modeler is green: 64 tests, 389 assertions.

Edited by Frank Mably

Merge request reports

Loading