Non existing property editor (#19997)

* Initial implementation of non existing property editor

* Adjust `MissingPropertyEditor` to not require registering in PropertyEditorCollection

* Add `MissingPropertyEditor.name` back

* Remove unused dependencies from DataTypeService

* Removed reference to non existing property

* Add parameterless constructor back to MissingPropertyEditor

* Add validation error on document open to property with missing editor

* Update labels

* Removed public editor alias const

* Update src/Umbraco.Web.UI.Client/src/packages/property-editors/missing/manifests.ts

* Add test that checks whether the new MissingPropertyEditor is returned when an editor is not found

* Also check if the editor UI alias is correct in the test

* Apply suggestions from code review

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Share property editor instances between properties

* Only store missing property editors in memory in `ContentMapDefinition.MapValueViewModels()`

* Add value converter for the missing property editor to always return a string (same as the Label did previously)

* Small improvements to code block

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
This commit is contained in:
Laura Neto
2025-09-10 11:20:06 +02:00
committed by GitHub
parent c93d4d9318
commit d6c181457c
22 changed files with 451 additions and 68 deletions

View File

@@ -81,6 +81,9 @@ internal sealed class PublishContentTypeFactoryTest : UmbracoIntegrationTest
{
var dataType = new DataTypeBuilder()
.WithId(0)
.AddEditor()
.WithAlias(Constants.PropertyEditors.Aliases.TextBox)
.Done()
.Build();
dataType.EditorUiAlias = "NotUpdated";
var dataTypeCreateResult = await DataTypeService.CreateAsync(dataType, Constants.Security.SuperUserKey);

View File

@@ -3,6 +3,7 @@
using System.Collections.Generic;
using System.Linq;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Abstractions;
using Microsoft.Extensions.Options;
@@ -103,7 +104,14 @@ internal sealed class DocumentRepositoryTest : UmbracoIntegrationTest
var ctRepository = CreateRepository(scopeAccessor, out contentTypeRepository, out TemplateRepository tr);
var editors = new PropertyEditorCollection(new DataEditorCollection(() => Enumerable.Empty<IDataEditor>()));
dtdRepository = new DataTypeRepository(scopeAccessor, appCaches, editors, LoggerFactory.CreateLogger<DataTypeRepository>(), LoggerFactory, ConfigurationEditorJsonSerializer);
dtdRepository = new DataTypeRepository(
scopeAccessor,
appCaches,
editors,
LoggerFactory.CreateLogger<DataTypeRepository>(),
LoggerFactory,
ConfigurationEditorJsonSerializer,
Services.GetRequiredService<IDataValueEditorFactory>());
return ctRepository;
}

View File

@@ -1,7 +1,6 @@
// Copyright (c) Umbraco.
// See LICENSE for more details.
using System.Linq;
using NUnit.Framework;
using Umbraco.Cms.Core;
using Umbraco.Cms.Core.Models;
@@ -487,4 +486,36 @@ internal sealed class DataTypeServiceTests : UmbracoIntegrationTest
Assert.AreEqual("bodyText", secondResult.NodeAlias);
Assert.AreEqual("Body text", secondResult.NodeName);
}
[Test]
public async Task Gets_MissingPropertyEditor_When_Editor_NotFound()
{
// Arrange
IDataType? dataType = (await DataTypeService.CreateAsync(
new DataType(new TestEditor(DataValueEditorFactory), ConfigurationEditorJsonSerializer)
{
Name = "Test Missing Editor",
DatabaseType = ValueStorageType.Ntext,
},
Constants.Security.SuperUserKey)).Result;
Assert.IsNotNull(dataType);
// Act
IDataType? actual = await DataTypeService.GetAsync(dataType.Key);
// Assert
Assert.NotNull(actual);
Assert.AreEqual(dataType.Key, actual.Key);
Assert.IsAssignableFrom(typeof(MissingPropertyEditor), actual.Editor);
Assert.AreEqual("Test Editor", actual.EditorAlias, "The alias should be the same as the original editor");
Assert.AreEqual("Umb.PropertyEditorUi.Missing", actual.EditorUiAlias, "The editor UI alias should be the Missing Editor UI");
}
private class TestEditor : DataEditor
{
public TestEditor(IDataValueEditorFactory dataValueEditorFactory)
: base(dataValueEditorFactory) =>
Alias = "Test Editor";
}
}