Merge branch 'release/17.0' into v17/dev

# Conflicts:
#	version.json
This commit is contained in:
Niels Lyngsø
2025-10-29 20:04:40 +01:00
69 changed files with 473 additions and 766 deletions

View File

@@ -8,7 +8,7 @@ namespace Umbraco.Cms.Core.Configuration.Models;
[UmbracoOptions(Constants.Configuration.ConfigDistributedJobs)]
public class DistributedJobSettings
{
internal const string StaticPeriod = "00:00:10";
internal const string StaticPeriod = "00:00:05";
internal const string StaticDelay = "00:01:00";
/// <summary>

View File

@@ -90,6 +90,11 @@ public static partial class Constants
/// </summary>
public const string DateOnly = "Umbraco.DateOnly";
/// <summary>
/// Entity Data Picker
/// </summary>
public const string EntityDataPicker = "Umbraco.EntityDataPicker";
/// <summary>
/// Time Only.
/// </summary>

View File

@@ -0,0 +1,8 @@
namespace Umbraco.Cms.Core.Models;
public sealed class EntityDataPickerValue
{
public required IEnumerable<string> Ids { get; set; }
public required string DataSource { get; set; }
}

View File

@@ -0,0 +1,17 @@
namespace Umbraco.Cms.Core.PropertyEditors;
public sealed class EntityDataPickerConfiguration
{
[ConfigurationField("validationLimit")]
public NumberRange ValidationLimit { get; set; } = new();
[ConfigurationField("umbEditorDataSource")]
public string DataSource { get; set; } = string.Empty;
public class NumberRange
{
public int? Min { get; set; }
public int? Max { get; set; }
}
}

View File

@@ -0,0 +1,11 @@
using Umbraco.Cms.Core.IO;
namespace Umbraco.Cms.Core.PropertyEditors;
internal sealed class EntityDataPickerConfigurationEditor : ConfigurationEditor<EntityDataPickerConfiguration>
{
public EntityDataPickerConfigurationEditor(IIOHelper ioHelper)
: base(ioHelper)
{
}
}

View File

@@ -0,0 +1,126 @@
using System.ComponentModel.DataAnnotations;
using Umbraco.Cms.Core.IO;
using Umbraco.Cms.Core.Models;
using Umbraco.Cms.Core.Models.Validation;
using Umbraco.Cms.Core.PropertyEditors.Validation;
using Umbraco.Cms.Core.Serialization;
using Umbraco.Cms.Core.Services;
using Umbraco.Cms.Core.Strings;
using Umbraco.Extensions;
namespace Umbraco.Cms.Core.PropertyEditors;
/// <summary>
/// Represents an entity data picker property editor.
/// </summary>
[DataEditor(
Constants.PropertyEditors.Aliases.EntityDataPicker,
ValueType = ValueTypes.Json,
ValueEditorIsReusable = true)]
internal sealed class EntityDataPickerPropertyEditor : DataEditor
{
private readonly IIOHelper _ioHelper;
/// <summary>
/// Initializes a new instance of the <see cref="EntityDataPickerPropertyEditor" /> class.
/// </summary>
public EntityDataPickerPropertyEditor(IDataValueEditorFactory dataValueEditorFactory, IIOHelper ioHelper)
: base(dataValueEditorFactory)
{
_ioHelper = ioHelper;
SupportsReadOnly = true;
}
/// <inheritdoc />
public override IPropertyIndexValueFactory PropertyIndexValueFactory { get; } = new NoopPropertyIndexValueFactory();
/// <inheritdoc />
protected override IDataValueEditor CreateValueEditor()
=> DataValueEditorFactory.Create<EntityDataPickerPropertyValueEditor>(Attribute!);
/// <inheritdoc />
protected override IConfigurationEditor CreateConfigurationEditor() => new EntityDataPickerConfigurationEditor(_ioHelper);
/// <summary>
/// Defines the value editor for the entity data picker property editor.
/// </summary>
internal sealed class EntityDataPickerPropertyValueEditor : DataValueEditor
{
/// <summary>
/// Initializes a new instance of the <see cref="EntityDataPickerPropertyValueEditor"/> class.
/// </summary>
public EntityDataPickerPropertyValueEditor(
IShortStringHelper shortStringHelper,
IJsonSerializer jsonSerializer,
IIOHelper ioHelper,
DataEditorAttribute attribute,
ILocalizedTextService localizedTextService)
: base(shortStringHelper, jsonSerializer, ioHelper, attribute)
{
var validators = new TypedJsonValidatorRunner<EntityDataPickerDto, EntityDataPickerConfiguration>(
jsonSerializer,
new MinMaxValidator(localizedTextService));
Validators.Add(validators);
}
/// <summary>
/// Validates the min/max configuration for the entity data picker property editor.
/// </summary>
internal sealed class MinMaxValidator : ITypedJsonValidator<EntityDataPickerDto, EntityDataPickerConfiguration>
{
private readonly ILocalizedTextService _localizedTextService;
/// <summary>
/// Initializes a new instance of the <see cref="MinMaxValidator"/> class.
/// </summary>
public MinMaxValidator(ILocalizedTextService localizedTextService) =>
_localizedTextService = localizedTextService;
/// <inheritdoc/>
public IEnumerable<ValidationResult> Validate(
EntityDataPickerDto? data,
EntityDataPickerConfiguration? configuration,
string? valueType,
PropertyValidationContext validationContext)
{
var validationResults = new List<ValidationResult>();
if (data is null || configuration is null)
{
return validationResults;
}
if (configuration.ValidationLimit.Min is not null
&& data.Ids.Length < configuration.ValidationLimit.Min)
{
validationResults.Add(new ValidationResult(
_localizedTextService.Localize(
"validation",
"entriesShort",
[configuration.ValidationLimit.Min.ToString(), (configuration.ValidationLimit.Min - data.Ids.Length).ToString()]),
["value"]));
}
if (configuration.ValidationLimit.Max is not null
&& data.Ids.Length > configuration.ValidationLimit.Max)
{
validationResults.Add(new ValidationResult(
_localizedTextService.Localize(
"validation",
"entriesExceed",
[configuration.ValidationLimit.Max.ToString(), (data.Ids.Length - configuration.ValidationLimit.Max).ToString()
]),
["value"]));
}
return validationResults;
}
}
}
internal sealed class EntityDataPickerDto
{
public string[] Ids { get; set; } = [];
}
}

View File

@@ -103,6 +103,6 @@ public abstract class WebhookEventBase<TNotification> : IWebhookEvent, INotifica
/// </summary>
/// <param name="notification"></param>
/// <returns></returns>
public virtual object ConvertNotificationToRequestPayload(TNotification notification)
public virtual object? ConvertNotificationToRequestPayload(TNotification notification)
=> notification;
}