fix(uve): lock layout canvas during save to prevent container data loss (#36197) - #37168
Open
gortiz-dotcms wants to merge 4 commits into
Open
fix(uve): lock layout canvas during save to prevent container data loss (#36197)#37168gortiz-dotcms wants to merge 4 commits into
gortiz-dotcms wants to merge 4 commits into
Conversation
…ss (#36197) The GridStack canvas in the UVE Layout tab was never disabled while a save was in flight, allowing edits during the debounce window, the in-flight POST, and the post-save pageReload() re-hydration to be silently dropped when the server response overwrote local state. Changes: - Add `disabled` @input to TemplateBuilderComponent. When true, ngOnChanges calls grid.disable() + subgrid.disable() synchronously (before any render cycle) and dispatches keydown Escape to cancel any in-progress drag or close any open PrimeNG dropdown. - Add a visible overlay (semi-transparent white + backdrop-blur + PrimeNG ProgressSpinner) rendered after the grid content so it sits on top in DOM order, giving users clear saving feedback. - Add $isSaving computed signal in EditEmaLayoutComponent that reads uveStatus === LOADING and binds it to [disabled] on the template builder. - Move setUveStatus(LOADING) from the tap() before debounceTime into switchMap, so the canvas only locks when the POST is actually sent — not on every keystroke during the 5-second debounce window. - Guard nextTemplateUpdate() to discard templateChange events that arrive while uveStatus === LOADING, covering the edge case where an in-progress action (held drag, open dropdown) completes after the freeze activates. The lock spans the full lifecycle: POST fired → pageReload() re-fetch → updateOldRows() re-hydration → uveStatus reset to LOADED → canvas unlocked. Refs: #36197 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
6 tasks
Contributor
|
Claude finished @gortiz-dotcms's task in 3m 3s —— View job SDK Compatibility Analysis
Result: No SDK breaking changes detected. The diff touches only two admin-editor UI libraries:
None of it touches an SDK-relevant wire surface:
This is purely local Angular editor UI state (GridStack lock/overlay while a layout save is in flight) with no effect on No comment or label added, per instructions for non-breaking changes. |
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Cover the disabled input, overlay rendering, grid API interactions, nextTemplateUpdate LOADING guard, and debounce-before-lock behaviour. Refs: #36197 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
MockDotRouterJestService is a singleton across the test suite; without clearing forbidRouteDeactivation before the guard assertion, accumulated calls from prior tests cause a false failure. Refs: #36197 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Fixes #36197 — UVE Layout tab data loss caused by the GridStack canvas never being locked while a layout save is in flight.
Root cause
Every layout change emits
templateChange→updateTemplate$→ 5-second debounce →POST /api/v1/page/{id}/layout. The canvas remained fully interactive during the entire debounce window, the in-flight POST, and thepageReload()+updateOldRows()re-hydration cycle. Any edit made in that window was silently discarded when the server response overwrote local state. Because the backend performs a destructive diff (deletes any container absent from the incoming payload), mid-flight edits could permanently remove content.Changes
TemplateBuilderComponent(template-builder.component.ts/.html)@Input() disabled = false— new input that locks the canvas.applyGridDisabled(disabled)— called synchronously fromngOnChanges(before any render cycle):grid.disable()/grid.enable()on the main grid and every subgrid — blocks drag, resize, and external drop at the GridStack event level.keydown Escapeondocument— GridStack'sDDDraggableregisters a document-levelkeydownhandler and callscancel()on Escape, removing the drag clone from the body so the overlay is visible. PrimeNG dropdowns also close on Escape, covering the open-dropdown edge case.@if (disabled)block rendered after the grid content (correct DOM stacking order), withbg-white/50 backdrop-blur-[2px]and a centeredp-progress-spinner, so the user clearly sees the canvas is saving.EditEmaLayoutComponent(edit-ema-layout.component.ts/.html)$isSavingcomputed signal —computed(() => uveStore.uveStatus() === UVE_STATUS.LOADING), bound as[disabled]="$isSaving()"on the template builder.setUveStatus(LOADING)moved from thetap()beforedebounceTime(locked on every keystroke) intoswitchMap(locks only when the POST is actually sent, i.e. when the "Saving…" toast appears). Users can edit freely during the 5-second debounce window.nextTemplateUpdateguard — returns early whenuveStatus === LOADING. Covers edge cases where an in-progress action (held drag, open dropdown selection) completes after the freeze activates, preventing the latetemplateChangefrom resetting the debounce or corrupting the in-flight payload.Lock lifecycle
Test plan
uveStatusset toERROR, user can retrypnpm nx test portlets-edit-ema-portlet --testPathPattern=edit-ema-layoutpnpm nx test template-builder --testPathPattern=template-builder.componentGrabacion.de.pantalla.2026-08-24.a.la.s.5.41.44.p.m.mov
🤖 Generated with Claude Code