Skip to content

Instantly share code, notes, and snippets.

@rickbutterfield
Created October 16, 2025 10:31
Show Gist options
  • Save rickbutterfield/93364ed67b9f428477a49a6da94d7b05 to your computer and use it in GitHub Desktop.
Save rickbutterfield/93364ed67b9f428477a49a6da94d7b05 to your computer and use it in GitHub Desktop.
Load a UI Builder Repository as a Forms PreValueSource
using System.Text.Json;
using System.Text.Json.Serialization;
using Umbraco.Cms.Core.Models;
using Umbraco.Forms.Core;
using Umbraco.Forms.Core.Attributes;
using Umbraco.Forms.Core.Models;
using Umbraco.UIBuilder.Configuration;
using Umbraco.UIBuilder.Services;
namespace Umbraco.Forms.UIBuilder.Core.PreValues
{
public class UIBuilderRepository : FieldPreValueSourceType
{
private readonly UIBuilderConfig _config;
private readonly EntityService _entityService;
public UIBuilderRepository(
UIBuilderConfig config,
EntityService entityService)
{
Id = new Guid("ED56A31B-56FD-41EA-9D21-755750879D13");
Name = "UI Builder Repository";
Alias = "uiBuilderRepository";
Description = "Use a UI Builder repository as a prevalue source.";
Icon = "icon-file-cabinet";
_config = config;
_entityService = entityService;
}
[Setting("Source", Description = "Select the source section, collection and data view", View = "UiBuilder.PropertyEditorUi.EntityPicker.SectionConfiguration", IsMandatory = true, DisplayOrder = 10)]
public virtual string Source { get; set; } = string.Empty;
public override Task<List<PreValue>> GetPreValuesAsync(Field? field, Form? form)
{
var result = new List<PreValue>();
UIBuilderSectionConfiguration? configuration = ParseSourceConfiguration();
if (configuration != null)
{
if (!string.IsNullOrEmpty(configuration.Collection))
{
CollectionConfig collectionConfig = _config.Collections[configuration.Collection];
IEnumerable<object> entities;
if (string.IsNullOrEmpty(configuration.DataView))
{
entities = _entityService.GetAllEntities(collectionConfig);
}
else
{
var allEntities = new List<object>();
const int pageSize = 100;
int pageNumber = 1;
long totalPages = 0;
while (pageNumber == 1 || pageNumber <= totalPages)
{
PagedResult<object> pagedResult = _entityService.FindEntities(
collectionConfig,
pageNumber: pageNumber,
pageSize: pageSize,
dataViewAlias: configuration.DataView);
if (pagedResult.Items != null)
{
allEntities.AddRange(pagedResult.Items);
}
if (pageNumber == 1)
{
totalPages = pagedResult.TotalPages;
}
pageNumber++;
}
entities = allEntities;
}
foreach (var entity in entities)
{
var id = GetPropertyValue(collectionConfig.IdProperty, entity);
var name = GetPropertyValue(collectionConfig.NameProperty, entity);
result.Add(new PreValue()
{
Id = id?.ToString() ?? string.Empty,
Caption = name?.ToString() ?? string.Empty,
Value = id?.ToString() ?? string.Empty
});
}
}
}
result = result.OrderBy(x => x.Id).ToList();
return Task.FromResult(result);
}
public override List<Exception> ValidateSettings()
{
var exceptions = new List<Exception>();
UIBuilderSectionConfiguration? configuration = ParseSourceConfiguration();
if (configuration != null)
{
if (string.IsNullOrEmpty(configuration.Section))
{
exceptions.Add(new Exception("'Section' setting has not been set"));
}
if (string.IsNullOrEmpty(configuration.Collection))
{
exceptions.Add(new Exception("'Collection' setting has not been set"));
}
}
return exceptions;
}
private UIBuilderSectionConfiguration? ParseSourceConfiguration()
{
if (string.IsNullOrEmpty(Source))
{
return null;
}
List<UIBuilderSectionConfigItem>? config = JsonSerializer.Deserialize<List<UIBuilderSectionConfigItem>>(Source);
var result = new UIBuilderSectionConfiguration();
if (config != null)
{
foreach (UIBuilderSectionConfigItem item in config)
{
switch (item.Alias)
{
case "section":
result.Section = item.Value;
break;
case "collection":
result.Collection = item.Value;
break;
case "dataView":
result.DataView = item.Value;
break;
case "labels":
if (!string.IsNullOrEmpty(item.Value))
{
result.Labels = JsonSerializer.Deserialize<UIBuilderLabels>(item.Value);
}
break;
}
}
}
return result;
}
private static object? GetPropertyValue(PropertyConfig? propertyConfig, object entity)
{
if (propertyConfig == null)
{
return null;
}
return propertyConfig.PropertyGetter?.Invoke(entity) ?? propertyConfig.PropertyExpression.Compile().DynamicInvoke(entity);
}
}
internal class UIBuilderSectionConfigItem
{
[JsonPropertyName("alias")]
public string? Alias { get; set; }
[JsonPropertyName("value")]
public string? Value { get; set; }
}
internal class UIBuilderSectionConfiguration
{
public string? Section { get; set; }
public string? Collection { get; set; }
public string? DataView { get; set; }
public UIBuilderLabels? Labels { get; set; }
}
internal class UIBuilderLabels
{
[JsonPropertyName("plural")]
public string? Plural { get; set; }
[JsonPropertyName("singular")]
public string? Singular { get; set; }
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment