[PP-1] Do not allow a user Publish request while there are pending changes to the current layout
>>> [!note] Migrated issue <!-- Drupal.org comment --> <!-- Migrated from issue #3520592. --> Reported by: [tedbow](https://www.drupal.org/user/240860) Related to !931 >>> <h3 id="overview">Overview</h3> <p>found this from <span class="drupalorg-gitlab-issue-link project-issue-status-info project-issue-status-7"><a href="https://www.drupal.org/project/experience_builder/issues/3520067" title="Status: Closed (fixed)">#3520067: [Needs design] Confusing messages when publishing immediately after making changes: auto-save race condition</a></span><br> @lauriii wrote</p> <blockquote><p> I ran into this by making a change and then quickly trying to publish it after making that change. I think the error I got was "This item is unexpected." and it was really confusing because I had no idea what is "this" in the context of the message and why it was unexpected. </p></blockquote> <p>I was able to reproduce this too but not consistently </p> <p><strong>Steps to reproduce:</strong></p> <ol> <li>Add a heading component to the canvas.</li> <li>Change the styling from <strong>Primary</strong> to <strong>Secondary</strong> and wait until the 'Review 1 change' button appears.</li> <li> Click inside the text field to edit it (while keeping your cursor near the 'Review 1 change' button), then quickly enter some text, click the review button, and immediately publish. </li> <li> You will encounter a <strong>409 (Conflict)</strong> error with the message: <br><br> <em>"An item in the publish request did not match the expected format or value. Please refresh your page and try again."</em> <p><img src="https://www.drupal.org/files/issues/2025-06-26/Screenshot%202025-06-26%20at%205.34.36%E2%80%AFPM.png" alt=""> </p></li> </ol> <p><strong>Details seen in the network response:</strong></p> <pre> { "detail": "An item in the publish request did not match the expected format or value. Please refresh your page and try again.", "source": { "pointer": "xb_page:1:en" }, "code": 2, "meta": { "entity_type": "xb_page", "entity_id": "1", "label": "Test page", "api_auto_save_key": "xb_page:1:en" } } </pre><p>What is probably happening with "then quickly enter some text, click the review button, and immediately publish." from above:</p> <ol> <li>Entering the test will trigger a POST request to <code>\Drupal\experience_builder\Controller\ApiLayoutController::post</code></li> <li>This triggers a request will result in the AutoSave entry for the entity to be updated</li> <li>There is request to <code>\Drupal\experience_builder\Controller\ApiAutoSaveController::post()</code> which receives a 409</li> <li><strong>After</strong> that there is request to <code>\Drupal\experience_builder\Controller\ApiAutoSaveController::get()</code></li> </ol> <p>I am not sure what triggers the last request to <code>ApiAutoSaveController::get()</code>. My guess would be that it is <strong>NOT</strong> clicking "review x changes" or that would happen <strong>before</strong> the request to <code>ApiAutoSaveController::post()</code> which is triggered by clicking "Publish all changes"</p> <p>The 409 error happens because the request to <code>ApiAutoSaveController::post()</code> could not possibly have the latest auto-save hashes because there has not been a new request to <code>ApiAutoSaveController::get()</code></p> <h3 id="proposed-resolution">Proposed resolution</h3> <h4>Original suggestion</h4> <p>When returning the updated layout preview also return the item's auto-save</p> <p>Merge this on the client side with the existing list of auto-saves</p> <h4>Updated suggestion</h4> <p>I, tedbow, made the original suggestion. I realize now without front-end changes this likely would solve the problem. If there nothing stops the user from clicking "Publish all changes" before the request to <code>\Drupal\experience_builder\Controller\ApiLayoutController::post</code> returns it won't matter if we update the auto-save entry on the client side when the <code>ApiLayoutController::post</code> request returns because the POST request to <code>ApiAutoSaveController::post()</code> would have already been sent with the old aut-save hash.</p> <p>The safest method I think would be </p> <ol> <li>When the user clicks "Review X Changes</li> <p> disallow any new UI changes. </p><li>Disable the "publish all changes" button</li> <li>If there are any existing requests to update the layout then wait for them to return</li> <li>Make a request to <code>ApiAutoSaveController::get()</code> to update the publish list</li> <li>only then after the client data has been updated then enable the "publish all changes" button which would the request to <code>ApiLayoutController::post</code></li> </ol> <h3 id="ui-changes">User interface changes</h3> > Related issue: [Issue #3522368](https://www.drupal.org/node/3522368) > Related issue: [Issue #3526907](https://www.drupal.org/node/3526907) > Related issue: [Issue #3521002](https://www.drupal.org/node/3521002)
issue