Property Editors: Improve Missing Property Editor UI and allow save/publish (#20104)
* 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 * Adjust property validation to accept missing property editors * Return the current value when trying to update a property with a missing editor Same logic as for when the property is readonly. * Fix failing unit tests * Small fix * Add unit test * Remove client validation * UI adjustments * Adjustments from code review * Adjust test --------- Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
This commit is contained in:
@@ -10,6 +10,7 @@ using Umbraco.Cms.Core.Configuration.Models;
|
||||
using Umbraco.Cms.Core.Dictionary;
|
||||
using Umbraco.Cms.Core.IO;
|
||||
using Umbraco.Cms.Core.Models;
|
||||
using Umbraco.Cms.Core.Models.Validation;
|
||||
using Umbraco.Cms.Core.PropertyEditors;
|
||||
using Umbraco.Cms.Core.PropertyEditors.Validators;
|
||||
using Umbraco.Cms.Core.Serialization;
|
||||
@@ -27,16 +28,14 @@ public class PropertyValidationServiceTests
|
||||
private void MockObjects(out PropertyValidationService validationService, out IDataType dt)
|
||||
{
|
||||
var dataTypeService = new Mock<IDataTypeService>();
|
||||
var dataType = Mock.Of<IDataType>(
|
||||
x => x.ConfigurationObject == string.Empty // irrelevant but needs a value
|
||||
&& x.DatabaseType == ValueStorageType.Nvarchar
|
||||
&& x.EditorAlias == Constants.PropertyEditors.Aliases.TextBox);
|
||||
var dataType = Mock.Of<IDataType>(x => x.ConfigurationObject == string.Empty // irrelevant but needs a value
|
||||
&& x.DatabaseType == ValueStorageType.Nvarchar
|
||||
&& x.EditorAlias == Constants.PropertyEditors.Aliases.TextBox);
|
||||
dataTypeService.Setup(x => x.GetDataType(It.IsAny<int>())).Returns(() => dataType);
|
||||
dt = dataType;
|
||||
|
||||
// new data editor that returns a TextOnlyValueEditor which will do the validation for the properties
|
||||
var dataEditor = Mock.Of<IDataEditor>(
|
||||
x => x.Alias == Constants.PropertyEditors.Aliases.TextBox);
|
||||
var dataEditor = Mock.Of<IDataEditor>(x => x.Alias == Constants.PropertyEditors.Aliases.TextBox);
|
||||
Mock.Get(dataEditor).Setup(x => x.GetValueEditor(It.IsAny<object>()))
|
||||
.Returns(new CustomTextOnlyValueEditor(
|
||||
new DataEditorAttribute(Constants.PropertyEditors.Aliases.TextBox),
|
||||
@@ -44,7 +43,15 @@ public class PropertyValidationServiceTests
|
||||
new SystemTextJsonSerializer(new DefaultJsonSerializerEncoderFactory()),
|
||||
Mock.Of<IIOHelper>()));
|
||||
|
||||
var propEditors = new PropertyEditorCollection(new DataEditorCollection(() => new[] { dataEditor }));
|
||||
var languageService = new Mock<ILanguageService>();
|
||||
languageService
|
||||
.Setup(s => s.GetDefaultIsoCodeAsync())
|
||||
.ReturnsAsync(() => "en-US");
|
||||
|
||||
var propEditors = new PropertyEditorCollection(new DataEditorCollection(() => [dataEditor]));
|
||||
|
||||
var contentSettings = new Mock<IOptions<ContentSettings>>();
|
||||
contentSettings.Setup(x => x.Value).Returns(new ContentSettings());
|
||||
|
||||
validationService = new PropertyValidationService(
|
||||
propEditors,
|
||||
@@ -52,8 +59,8 @@ public class PropertyValidationServiceTests
|
||||
Mock.Of<ILocalizedTextService>(),
|
||||
new ValueEditorCache(),
|
||||
Mock.Of<ICultureDictionary>(),
|
||||
Mock.Of<ILanguageService>(),
|
||||
Mock.Of<IOptions<ContentSettings>>());
|
||||
languageService.Object,
|
||||
contentSettings.Object);
|
||||
}
|
||||
|
||||
[Test]
|
||||
@@ -279,6 +286,23 @@ public class PropertyValidationServiceTests
|
||||
Assert.AreEqual(4, invalid.Length);
|
||||
}
|
||||
|
||||
[TestCase(null)]
|
||||
[TestCase(24)]
|
||||
[TestCase("test")]
|
||||
[TestCase("{\"test\": true}")]
|
||||
public void ValidatePropertyValue_Always_Returns_No_Validation_Errors_For_Missing_Editor(object? value)
|
||||
{
|
||||
MockObjects(out var validationService, out _);
|
||||
|
||||
var p1 = new PropertyType(ShortStringHelper, "Missing.Alias", ValueStorageType.Ntext)
|
||||
{
|
||||
Variations = ContentVariation.Nothing,
|
||||
};
|
||||
|
||||
var result = validationService.ValidatePropertyValue(p1, value, PropertyValidationContext.Empty());
|
||||
Assert.AreEqual(0, result.Count());
|
||||
}
|
||||
|
||||
// used so we can inject a mock - we should fix the base class DataValueEditor to be able to have the ILocalizedTextField passed
|
||||
// in to create the Requried and Regex validators so we aren't using singletons
|
||||
private class CustomTextOnlyValueEditor : TextOnlyValueEditor
|
||||
|
||||
Reference in New Issue
Block a user