Use data type configuration to determine default value for empty toggle and slider property values (#17854)

* Use data type configuration to determine default value for empty toggle property values.

* Added/updated unit tests.

* Fixed failing integration tests.

* Applied similar default value display for the slider property editor and aligned implementation of true/false with this.

* Fixed unit tests.

* Removed "duplicate" JsonPropertyName attributes and added a custom TypeInfoResolver for data type configuration so we can re-use the existing ConfigurationField attributes.

* Minor cleanup

---------

Co-authored-by: nikolajlauridsen <nikolajlauridsen@protonmail.ch>
This commit is contained in:
Andy Butland
2025-01-08 11:42:13 +01:00
committed by GitHub
parent b7f424756c
commit 413398afc6
9 changed files with 192 additions and 41 deletions

View File

@@ -1,5 +1,7 @@
using System.Text.Json;
using System.Text.Json.Serialization;
using System.Text.Json.Serialization.Metadata;
using Umbraco.Cms.Core.PropertyEditors;
using Umbraco.Cms.Core.Serialization;
namespace Umbraco.Cms.Infrastructure.Serialization;
@@ -16,8 +18,9 @@ public sealed class SystemTextConfigurationEditorJsonSerializer : SystemTextJson
=> _jsonSerializerOptions = new JsonSerializerOptions()
{
PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
// in some cases, configs aren't camel cased in the DB, so we have to resort to case insensitive
// property name resolving when creating configuration objects (deserializing DB configs)
// In some cases, configs aren't camel cased in the DB, so we have to resort to case insensitive
// property name resolving when creating configuration objects (deserializing DB configs).
PropertyNameCaseInsensitive = true,
NumberHandling = JsonNumberHandling.AllowReadingFromString,
Converters =
@@ -26,9 +29,42 @@ public sealed class SystemTextConfigurationEditorJsonSerializer : SystemTextJson
new JsonObjectConverter(),
new JsonUdiConverter(),
new JsonUdiRangeConverter(),
new JsonBooleanConverter()
}
new JsonBooleanConverter(),
},
// Properties of data type configuration objects are annotated with [ConfigurationField] attributes
// that provide the serialized name. Rather than decorating them as well with [JsonPropertyName] attributes
// when they differ from the property name, we'll define a custom type info resolver to use the
// existing attribute.
TypeInfoResolver = new DefaultJsonTypeInfoResolver()
.WithAddedModifier(UseAttributeConfiguredPropertyNames()),
};
protected override JsonSerializerOptions JsonSerializerOptions => _jsonSerializerOptions;
/// <summary>
/// A custom action used to provide property names when they are overridden by
/// <see cref="ConfigurationField"/> attributes.
/// </summary>
/// <remarks>
/// Hat-tip: https://stackoverflow.com/a/78063664
/// </remarks>
private static Action<JsonTypeInfo> UseAttributeConfiguredPropertyNames() => typeInfo =>
{
if (typeInfo.Kind is not JsonTypeInfoKind.Object)
{
return;
}
foreach (JsonPropertyInfo property in typeInfo.Properties)
{
if (property.AttributeProvider?.GetCustomAttributes(typeof(ConfigurationFieldAttribute), true) is { } attributes)
{
foreach (ConfigurationFieldAttribute attribute in attributes)
{
property.Name = attribute.Key;
}
}
}
};
}