Enable concurrent editing: Replace the postPreview action with atomic equivalents
>>> [!note] Migrated issue
<!-- Drupal.org comment -->
<!-- Migrated from issue #3492065. -->
Reported by: [larowlan](https://www.drupal.org/user/395439)
Related to !709 !1511 !1510 !1440
>>>
<h3 id="overview">Overview</h3>
<p>In <span class="drupalorg-gitlab-issue-link project-issue-status-info project-issue-status-7"><a href="https://www.drupal.org/project/experience_builder/issues/3467954" title="Status: Closed (fixed)">#3467954: META: Evolve XB UI's data model to allow non-SDC components' inputs, DynamicPropSource support, etc.</a></span> we introduce a <code>PreviewEnvelope</code> controller result.<br>
Returning this allows combining a preview render array with a JSON data object and still invoking the preview renderer to combine the render array and the rest of the page elements into a HTML property in a JSON response.</p>
<p>It also adds a slice to hold the current preview HTML and introduces a <code>patchComponent</code> action that fires when a component's props are updated. This calls a backend controller that update <strong>only the component being edited</strong> in the auto-save store. This means component edits work concurrently.</p>
<p>However, we still call postPreview for many other changes to the layout slice and these <strong>overwrite any other changes being made by a concurrent editor</strong></p>
<h3 id="proposed-resolution">Proposed resolution</h3>
<p>After <span class="drupalorg-gitlab-issue-link project-issue-status-info project-issue-status-7"><a href="https://www.drupal.org/project/experience_builder/issues/3467954" title="Status: Closed (fixed)">#3467954: META: Evolve XB UI's data model to allow non-SDC components' inputs, DynamicPropSource support, etc.</a></span> and <span class="drupalorg-gitlab-issue-link project-issue-status-info project-issue-status-7"><a href="https://www.drupal.org/project/experience_builder/issues/3492061" title="Status: Closed (fixed)">#3492061: Include the preview HTML in the layout controller payload</a></span> are in, we no longer need to call postPreview to get the initial preview HTML. So from this point we can move to atomic operations against the auto-save rather than a 'write the full layout and model every time' approach.</p>
<p>This allows us to:</p>
<p>Remove the postPreview api from the front-end<br>
Introduce a patchModelAndLayout api method<br>
Add a listener middleware to the store that listens for the following actions:</p>
<ul>
<li>deleteNode</li>
<li>duplicateNode</li>
<li>moveNode</li>
<li>shiftNode</li>
<li>sortNode</li>
<li>insertNodes</li>
</ul>
<p>For each of these:</p>
<ul>
<li>dispatch the patchModelAndLayout api with the action's payload</li>
<li>Rewrite the preview controller in Drupal to respond to this payload and mirror that operation in the auto-save entry for the given entity.</li>
<li>Add a onQueryStarted method for patchModelAndLayout that unwraps the preview html and calls dispatch to set the new HTML</li>
</ul>
<p>e.g. if a user duplicates a node in the UI the workflow should be</p>
<ol>
<li>duplicateNode reducer called</li>
<li>listener middleware reacts to duplicateNode action and fires patchModelAndLayout</li>
<li>Drupal controller receives PATCH request for duplicateNode and applies the same logic to its representation of the model/layout as the front end, writing <strong>just those changes</strong> to the autosave store</li>
<li>Drupal controller response with HTML</li>
<li>onQueryStarted method of patchModelAndLayout action stores the new HTML</li>
</ol>
<h3 id="ui-changes">User interface changes</h3>
> Related issue: [Issue #3492059](https://www.drupal.org/node/3492059)
issue