diff --git a/src/Umbraco.Web.UI.Client/src/packages/block/block-grid/property-editors/block-grid-editor/property-editor-ui-block-grid.element.ts b/src/Umbraco.Web.UI.Client/src/packages/block/block-grid/property-editors/block-grid-editor/property-editor-ui-block-grid.element.ts index a36e0f5658..8ab27986e1 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/block/block-grid/property-editors/block-grid-editor/property-editor-ui-block-grid.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/block/block-grid/property-editors/block-grid-editor/property-editor-ui-block-grid.element.ts @@ -17,7 +17,7 @@ import type { UmbPropertyEditorUiElement, UmbPropertyEditorConfigCollection, } from '@umbraco-cms/backoffice/property-editor'; -import { observeMultiple } from '@umbraco-cms/backoffice/observable-api'; +import { jsonStringComparison, observeMultiple } from '@umbraco-cms/backoffice/observable-api'; import { UMB_PROPERTY_CONTEXT, UMB_PROPERTY_DATASET_CONTEXT } from '@umbraco-cms/backoffice/property'; import { UmbFormControlMixin, UmbValidationContext } from '@umbraco-cms/backoffice/validation'; import type { UmbBlockTypeGroup } from '@umbraco-cms/backoffice/block-type'; @@ -181,15 +181,22 @@ export class UmbPropertyEditorUIBlockGridElement ]).pipe(debounceTime(20)), ([layouts, contents, settings, exposes]) => { if (layouts.length === 0) { + if (this.value === undefined) { + return; + } super.value = undefined; } else { - super.value = { + const newValue = { ...super.value, layout: { [UMB_BLOCK_GRID_PROPERTY_EDITOR_SCHEMA_ALIAS]: layouts }, contentData: contents, settingsData: settings, expose: exposes, }; + if (jsonStringComparison(this.value, newValue)) { + return; + } + super.value = newValue; } // If we don't have a value set from the outside or an internal value, we don't want to set the value. diff --git a/src/Umbraco.Web.UI.Client/src/packages/block/block-list/property-editors/block-list-editor/property-editor-ui-block-list.element.ts b/src/Umbraco.Web.UI.Client/src/packages/block/block-list/property-editors/block-list-editor/property-editor-ui-block-list.element.ts index ddc7fe5967..f5169b5062 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/block/block-list/property-editors/block-list-editor/property-editor-ui-block-list.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/block/block-list/property-editors/block-list-editor/property-editor-ui-block-list.element.ts @@ -25,7 +25,7 @@ import { UmbFormControlMixin, UmbValidationContext, } from '@umbraco-cms/backoffice/validation'; -import { observeMultiple } from '@umbraco-cms/backoffice/observable-api'; +import { jsonStringComparison, observeMultiple } from '@umbraco-cms/backoffice/observable-api'; import { debounceTime } from '@umbraco-cms/backoffice/external/rxjs'; import { UMB_CONTENT_WORKSPACE_CONTEXT } from '@umbraco-cms/backoffice/content'; @@ -339,15 +339,22 @@ export class UmbPropertyEditorUIBlockListElement ]).pipe(debounceTime(20)), ([layouts, contents, settings, exposes]) => { if (layouts.length === 0) { + if (this.value === undefined) { + return; + } super.value = undefined; } else { - super.value = { + const newValue = { ...super.value, layout: { [UMB_BLOCK_LIST_PROPERTY_EDITOR_SCHEMA_ALIAS]: layouts }, contentData: contents, settingsData: settings, expose: exposes, }; + if (jsonStringComparison(this.value, newValue)) { + return; + } + super.value = newValue; } // If we don't have a value set from the outside or an internal value, we don't want to set the value. diff --git a/src/Umbraco.Web.UI.Client/src/packages/rte/components/rte-base.element.ts b/src/Umbraco.Web.UI.Client/src/packages/rte/components/rte-base.element.ts index ef841b82fc..e22c9220bd 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/rte/components/rte-base.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/rte/components/rte-base.element.ts @@ -1,6 +1,6 @@ import type { UmbPropertyEditorRteValueType } from '../types.js'; import { UMB_BLOCK_RTE_PROPERTY_EDITOR_SCHEMA_ALIAS } from '../constants.js'; -import { observeMultiple } from '@umbraco-cms/backoffice/observable-api'; +import { jsonStringComparison, observeMultiple } from '@umbraco-cms/backoffice/observable-api'; import { property, state } from '@umbraco-cms/backoffice/external/lit'; import { UmbBlockRteEntriesContext, UmbBlockRteManagerContext } from '@umbraco-cms/backoffice/block-rte'; import { UmbChangeEvent } from '@umbraco-cms/backoffice/event'; @@ -243,9 +243,12 @@ export abstract class UmbPropertyEditorUiRteElementBase ([layouts, contents, settings, exposes]) => { if (layouts.length === 0) { if (super.value?.markup === undefined) { + if (this.value === undefined) { + return; + } super.value = undefined; } else { - super.value = { + const newValue = { ...super.value, blocks: { layout: {}, @@ -254,9 +257,13 @@ export abstract class UmbPropertyEditorUiRteElementBase expose: [], }, }; + if (jsonStringComparison(this.value, newValue)) { + return; + } + super.value = newValue; } } else { - super.value = { + const newValue = { markup: this._markup, blocks: { layout: { [UMB_BLOCK_RTE_PROPERTY_EDITOR_SCHEMA_ALIAS]: layouts }, @@ -265,6 +272,10 @@ export abstract class UmbPropertyEditorUiRteElementBase expose: exposes, }, }; + if (jsonStringComparison(this.value, newValue)) { + return; + } + super.value = newValue; } // If we don't have a value set from the outside or an internal value, we don't want to set the value. diff --git a/tests/Umbraco.Tests.AcceptanceTest/tests/DefaultConfig/Content/BlockGrid/ContentWithBlockGrid.spec.ts b/tests/Umbraco.Tests.AcceptanceTest/tests/DefaultConfig/Content/BlockGrid/ContentWithBlockGrid.spec.ts index b16ede4a08..b9d8d9ac96 100644 --- a/tests/Umbraco.Tests.AcceptanceTest/tests/DefaultConfig/Content/BlockGrid/ContentWithBlockGrid.spec.ts +++ b/tests/Umbraco.Tests.AcceptanceTest/tests/DefaultConfig/Content/BlockGrid/ContentWithBlockGrid.spec.ts @@ -417,3 +417,22 @@ test('can add a variant block element with invariant RTE Tiptap in the content', await umbracoApi.documentType.ensureNameNotExists(customElementTypeName); await umbracoApi.language.ensureNameNotExists('Danish'); }); + +// Tests regression issue: https://github.com/umbraco/Umbraco-CMS/issues/20680 +test('can move away from a content node with a block grid after making no changes without seeing discard unsaved changes', {tag: '@smoke'}, async ({umbracoApi, umbracoUi}) => { + // Arrange + const customDataTypeId = await umbracoApi.dataType.createBlockGridWithPermissions(customDataTypeName, elementTypeId, true, true); + const documentTypeId = await umbracoApi.documentType.createDocumentTypeWithPropertyEditor(documentTypeName, customDataTypeName, customDataTypeId); + await umbracoApi.document.createDefaultDocument(contentName, documentTypeId); + await umbracoUi.goToBackOffice(); + await umbracoUi.content.goToSection(ConstantHelper.sections.content); + await umbracoUi.content.goToContentWithName(contentName); + + // Act + await umbracoUi.documentType.goToSection(ConstantHelper.sections.settings); + + // Assert + // We do this to make sure that there is no discard changes button visible, if the discard changes was visible, we would not be able to go to the document type + await umbracoUi.documentType.goToDocumentType(documentTypeName); +}); + diff --git a/tests/Umbraco.Tests.AcceptanceTest/tests/DefaultConfig/Content/BlockList/ContentWithBlockList.spec.ts b/tests/Umbraco.Tests.AcceptanceTest/tests/DefaultConfig/Content/BlockList/ContentWithBlockList.spec.ts index 7fed44f119..6fde9d28b0 100644 --- a/tests/Umbraco.Tests.AcceptanceTest/tests/DefaultConfig/Content/BlockList/ContentWithBlockList.spec.ts +++ b/tests/Umbraco.Tests.AcceptanceTest/tests/DefaultConfig/Content/BlockList/ContentWithBlockList.spec.ts @@ -364,3 +364,21 @@ test('can add a variant block element with invariant RTE Tiptap in the content', await umbracoApi.documentType.ensureNameNotExists(customElementTypeName); await umbracoApi.language.ensureNameNotExists('Danish'); }); + +// Tests regression issue: https://github.com/umbraco/Umbraco-CMS/issues/20680 +test('can move away from a content node with a block list after making no changes without seeing discard unsaved changes', {tag: '@smoke'}, async ({umbracoApi, umbracoUi}) => { + // Arrange + const customDataTypeId = await umbracoApi.dataType.createBlockListDataTypeWithABlock(customDataTypeName, elementTypeId); + const documentTypeId = await umbracoApi.documentType.createDocumentTypeWithPropertyEditor(documentTypeName, customDataTypeName, customDataTypeId); + await umbracoApi.document.createDefaultDocument(contentName, documentTypeId); + await umbracoUi.goToBackOffice(); + await umbracoUi.content.goToSection(ConstantHelper.sections.content); + await umbracoUi.content.goToContentWithName(contentName); + + // Act + await umbracoUi.documentType.goToSection(ConstantHelper.sections.settings); + + // Assert + // We do this to make sure that there is no discard changes button visible, if the discard changes was visible, we would not be able to go to the document type + await umbracoUi.documentType.goToDocumentType(documentTypeName); +});