Show the Classic modeler's validation errors after an AJAX action, next to the control that was pressed
Closes https://www.drupal.org/project/orchestra/issues/3631389
In the Classic modeler, a refused AJAX action (e.g. Add node with an empty machine name) outlined the field in red but showed no message.
Cause: the nodes-and-flows structure, the AJAX wrapper, took its id from Html::getUniqueId(), which adds a new random suffix on every AJAX request. The response first replaced the old wrapper with the rebuilt one, then prepended the status messages to the old id, which no longer existed, so jQuery dropped them. Every AJAX action of the form lost its messages this way.
Fix:
- The wrapper takes a stable id (
Html::getId()), so core's messages find it again for every AJAX action. - When an action fails validation,
rebuildStructureAjax()answers withbuildRefusedActionResponse():- the messages go just above the block holding the pressed control (the "Add a node" block, a node row, a flow row, or a section in one), found through the existing
data-orchestra-cm-detailkeys, instead of the top of a possibly long structure; - the first field in error takes the focus, so the browser scrolls to it.
- the messages go just above the block holding the pressed control (the "Add a node" block, a node row, a flow row, or a section in one), found through the existing
Test: OrchestraCmFormTest::testRefusedActionSaysWhyNextToItsControl (the id stays the same on an AJAX request; the message is placed before the "Add a node" block; the machine name field is marked for focus). Mutants checked locally, each failing it: getUniqueId() back, no refused-action response, no focus mark.
AI-Generated: Yes (Claude Code was used to write the change, its test and this description. I reviewed them.)