Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
acbd2ae
add allowed type for element picker
LanThuyNguyen Jun 1, 2026
edb2e1b
update validation and unit test
LanThuyNguyen Jun 2, 2026
6e1cac4
remove redundant code
LanThuyNguyen Jun 2, 2026
fe2758b
update tests name
LanThuyNguyen Jun 2, 2026
40b0d5f
Merge branch 'main' into v18/feature/element-picker-configuration-all…
NguyenThuyLan Jun 2, 2026
ffd2376
Merge branch 'main' of https://github.com/umbraco/Umbraco-CMS into v1…
LanThuyNguyen Jun 2, 2026
a4b4abc
Merge branch 'v18/feature/element-picker-configuration-allowed-types'…
LanThuyNguyen Jun 2, 2026
88f2e6f
revert code GetReferences
LanThuyNguyen Jun 2, 2026
b292b40
remove un-using code and add more check value
LanThuyNguyen Jun 3, 2026
b5ef4fa
Merge branch 'main' of https://github.com/umbraco/Umbraco-CMS into v1…
LanThuyNguyen Jun 3, 2026
60c015a
remove redundant param
LanThuyNguyen Jun 3, 2026
2e353b3
add allowed type for content picker, update validation
LanThuyNguyen Jun 5, 2026
00fd2fe
add min max validation into element and its unit test
LanThuyNguyen Jun 7, 2026
e263f7f
update media picker validation
LanThuyNguyen Jun 7, 2026
8a603fd
split validation runner into other class
LanThuyNguyen Jun 9, 2026
6119e7f
update SystemTextJsonSerializerBase back to old code
LanThuyNguyen Jun 9, 2026
ee9fbdc
update unit tests
LanThuyNguyen Jun 9, 2026
97cbe4c
Resolved some code warnings.
AndyButland Jun 10, 2026
f5c853c
Remove accidentally committed file
AndyButland Jun 10, 2026
3c5b47b
Introduce ITypedValidator and obsolete ITypeJsonValidator to better r…
AndyButland Jun 10, 2026
35a9e72
Merge remote-tracking branch 'origin/main' into v18/feature/element-p…
AndyButland Jun 10, 2026
e179718
Extraced ParseAllowedContentTypeKeys into a common helper.
AndyButland Jun 10, 2026
df760d4
Aligned parameters on AllowedTypeValidator.
AndyButland Jun 10, 2026
d059914
Align parsing of allowed type Ids on client between document and medi…
AndyButland Jun 10, 2026
bf18a0b
Restored validation of media where provided key can't be retrieved.
AndyButland Jun 10, 2026
376e6f5
Aligned document, media and element configuration labels and weights.
AndyButland Jun 10, 2026
a714ec8
Added additional unit tests.
AndyButland Jun 10, 2026
de26982
Addressed code review comments.
AndyButland Jun 10, 2026
64e8ed2
Resolved further code warnings and code tidy.
AndyButland Jun 13, 2026
8d5623e
Resolve potential binary breaking change concern with obsolete ITyped…
AndyButland Jun 13, 2026
02eedd8
Reuse shared DocumentTypePicker for picker allowed-types config.
AndyButland Jun 13, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/Umbraco.Core/EmbeddedResources/Lang/en.xml
Original file line number Diff line number Diff line change
Expand Up @@ -402,6 +402,7 @@
<key alias="invalidMediaType">The chosen media type is invalid.</key>
<key alias="invalidContentType">The chosen content is of invalid type.</key>
<key alias="missingContent">The chosen content does not exist.</key>
<key alias="missingMedia">The chosen media does not exist.</key>
Comment thread
AndyButland marked this conversation as resolved.
<key alias="multipleMediaNotAllowed">Multiple selected media is not allowed.</key>
<key alias="notOneOfOptions">The value '%0%' is not one of the available options.</key>
<key alias="multipleNotOneOfOptions">The values '%0%' are not found in the the available options.</key>
Expand Down
34 changes: 34 additions & 0 deletions src/Umbraco.Core/PropertyEditors/AllowedContentTypeKeysParser.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
using Umbraco.Extensions;

namespace Umbraco.Cms.Core.PropertyEditors;

/// <summary>
/// Parses the comma-separated content type keys stored in a picker's "allowed content types" configuration value
/// (e.g. <see cref="ContentPickerConfiguration.AllowedContentTypeIds"/> or <see cref="ElementPickerConfiguration.AllowedContentTypeIds"/>).
/// </summary>
internal static class AllowedContentTypeKeysParser
{
/// <summary>
/// Parses the configured value into the set of allowed content type keys.
/// </summary>
/// <param name="configValue">The comma-separated configuration value. Non-GUID entries are ignored.</param>
/// <returns>The set of allowed content type keys, or an empty set when nothing is configured.</returns>
public static HashSet<Guid> Parse(string? configValue)
{
if (configValue.IsNullOrWhiteSpace())
{
return [];
}

var result = new HashSet<Guid>();
foreach (var entry in configValue.Split(Constants.CharArrays.Comma, StringSplitOptions.RemoveEmptyEntries))
{
if (Guid.TryParse(entry, out Guid guid))
{
result.Add(guid);
}
}

return result;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,10 @@ public class ContentPickerConfiguration : IIgnoreUserStartNodesConfig
/// <inheritdoc />
[ConfigurationField(Constants.DataTypes.ReservedPreValueKeys.IgnoreUserStartNodes)]
public bool IgnoreUserStartNodes { get; set; }

/// <summary>
/// Gets or sets the content type filter for allowed selections.
/// </summary>
[ConfigurationField("allowedContentTypes")]
public string? AllowedContentTypeIds { get; set; }
}
71 changes: 70 additions & 1 deletion src/Umbraco.Core/PropertyEditors/ContentPickerPropertyEditor.cs
Original file line number Diff line number Diff line change
@@ -1,12 +1,16 @@
// Copyright (c) Umbraco.
// See LICENSE for more details.

using System.ComponentModel.DataAnnotations;
using System.Text.Json.Nodes;
using Microsoft.Extensions.DependencyInjection;
using Umbraco.Cms.Core.DependencyInjection;
using Umbraco.Cms.Core.IO;
using Umbraco.Cms.Core.Models;
using Umbraco.Cms.Core.Models.Editors;
using Umbraco.Cms.Core.Models.Validation;
using Umbraco.Cms.Core.PropertyEditors.Validation;
using Umbraco.Cms.Core.Scoping;
using Umbraco.Cms.Core.Serialization;
using Umbraco.Cms.Core.Services;
using Umbraco.Cms.Core.Strings;
Expand Down Expand Up @@ -70,13 +74,21 @@
/// <param name="jsonSerializer">The JSON serializer.</param>
/// <param name="ioHelper">The IO helper.</param>
/// <param name="attribute">The data editor attribute.</param>
/// <param name="coreScopeProvider">The core scope provider.</param>
/// <param name="contentService">The content service.</param>
/// <param name="localizedTextService">The localized text service.</param>
public ContentPickerPropertyValueEditor(
IShortStringHelper shortStringHelper,
IJsonSerializer jsonSerializer,
IIOHelper ioHelper,
DataEditorAttribute attribute)
DataEditorAttribute attribute,
ICoreScopeProvider coreScopeProvider,
IContentService contentService,
ILocalizedTextService localizedTextService)
: base(shortStringHelper, jsonSerializer, ioHelper, attribute)
{
Validators.Add(new TypedValidatorRunner<string, ContentPickerConfiguration>(
new AllowedTypeValidator(localizedTextService, contentService, coreScopeProvider)));

Check warning on line 91 in src/Umbraco.Core/PropertyEditors/ContentPickerPropertyEditor.cs

View check run for this annotation

CodeScene Delta Analysis / CodeScene Code Health Review (main)

❌ New issue: Constructor Over-Injection

ContentPickerPropertyValueEditor has 7 arguments, max arguments = 5. This constructor has too many arguments, indicating an object with low cohesion or missing function argument abstraction. Avoid adding more arguments.
}

/// <inheritdoc />
Expand Down Expand Up @@ -134,4 +146,61 @@
return guidUdi.Guid;
}
}

/// <summary>
/// Validates that the selected content matches the allowed content types configured for the property editor.
/// </summary>
/// <param name="localizedTextService">The localized text service.</param>
/// <param name="contentService">The content service.</param>
/// <param name="coreScopeProvider">The core scope provider.</param>
internal sealed class AllowedTypeValidator(ILocalizedTextService localizedTextService, IContentService contentService, ICoreScopeProvider coreScopeProvider)
: ITypedValidator<string, ContentPickerConfiguration>
{
/// <inheritdoc/>
public IEnumerable<ValidationResult> Validate(
string? value,
ContentPickerConfiguration? configuration,
string? valueType,
PropertyValidationContext validationContext)
{
if (string.IsNullOrEmpty(value) ||
configuration is null ||

Check warning on line 167 in src/Umbraco.Core/PropertyEditors/ContentPickerPropertyEditor.cs

View check run for this annotation

CodeScene Delta Analysis / CodeScene Code Health Review (main)

❌ New issue: Complex Conditional

Validate has 1 complex conditionals with 2 branches, threshold = 2. A complex conditional is an expression inside a branch (e.g. if, for, while) which consists of multiple, logical operators such as AND/OR. The more logical operators in an expression, the more severe the code smell.
Guid.TryParse(value, out Guid id) is false)

Check warning on line 168 in src/Umbraco.Core/PropertyEditors/ContentPickerPropertyEditor.cs

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Remove the unnecessary Boolean literal(s).

See more on https://sonarcloud.io/project/issues?id=umbraco_Umbraco-CMS&issues=AZ7A9I0zlFS2SonGOAE8&open=AZ7A9I0zlFS2SonGOAE8&pullRequest=23026
{
return [];
}

HashSet<Guid> allowedContentTypeKeys = AllowedContentTypeKeysParser.Parse(configuration.AllowedContentTypeIds);

// No filter configured — all content types are allowed.
if (allowedContentTypeKeys.Count == 0)
{
return [];
}

using ICoreScope scope = coreScopeProvider.CreateCoreScope();
Guid? key = contentService.GetById(id)?.ContentType?.Key;
scope.Complete();

if (key is null)
{
return [new ValidationResult(
localizedTextService.Localize(
"validation",
"missingContent"),
["value"])];
}

if (allowedContentTypeKeys.Contains(key.Value) is false)

Check warning on line 194 in src/Umbraco.Core/PropertyEditors/ContentPickerPropertyEditor.cs

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Remove the unnecessary Boolean literal(s).

See more on https://sonarcloud.io/project/issues?id=umbraco_Umbraco-CMS&issues=AZ6qt9qJIJMnO2KV1mk0&open=AZ6qt9qJIJMnO2KV1mk0&pullRequest=23026
{
return [new ValidationResult(
localizedTextService.Localize(
"validation",
"invalidObjectType"),
["value"])];
}

return [];
}
}
}
28 changes: 28 additions & 0 deletions src/Umbraco.Core/PropertyEditors/ElementPickerConfiguration.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,32 @@ public class ElementPickerConfiguration : IIgnoreUserStartNodesConfig
/// <inheritdoc />
[ConfigurationField(Constants.DataTypes.ReservedPreValueKeys.IgnoreUserStartNodes)]
public bool IgnoreUserStartNodes { get; set; }

/// <summary>
/// Gets or sets the validation limits for the number of elements allowed.
/// </summary>
[ConfigurationField("validationLimit")]
public NumberRange? ValidationLimit { get; set; }

/// <summary>
/// Gets or sets the content type filter for allowed selections.
/// </summary>
[ConfigurationField("allowedContentTypes")]
public string? AllowedContentTypeIds { get; set; }

/// <summary>
/// Represents a numeric range with optional minimum and maximum values.
/// </summary>
public class NumberRange
{
/// <summary>
/// Gets or sets the minimum value of the range.
/// </summary>
public int? Min { get; set; }

/// <summary>
/// Gets or sets the maximum value of the range.
/// </summary>
public int? Max { get; set; }
}
}
Loading
Loading