From 643b79c145ad6b6c48a416c57f2736faf4b4a79e Mon Sep 17 00:00:00 2001 From: Jacob Overgaard <752371+iOvergaard@users.noreply.github.com> Date: Thu, 14 Sep 2023 13:17:35 +0200 Subject: [PATCH 1/4] V12: Property editors should only contain layout when in preview mode (#14796) * Revert "Make sure the property editor layout is contained within its container (prevent Z-index bleed-through) (#13583)" This reverts commit 8463d906a747868ddbda3b1c01465f6cee1a589a. * remove seemingly unused attribute readonly * contain everything with contain:layout this is set if the property editor is in preview mode to make sure all overlays work * Revert "remove seemingly unused attribute readonly" This reverts commit 7a2743e8f664e707e8df5022fe754dfd77c508ea. --- .../src/less/components/umb-property-editor.less | 6 +++++- .../src/views/components/property/umb-property-editor.html | 4 ++-- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/less/components/umb-property-editor.less b/src/Umbraco.Web.UI.Client/src/less/components/umb-property-editor.less index d2d6a970b9..c34ada479e 100644 --- a/src/Umbraco.Web.UI.Client/src/less/components/umb-property-editor.less +++ b/src/Umbraco.Web.UI.Client/src/less/components/umb-property-editor.less @@ -1,6 +1,10 @@ .umb-property-editor { position: relative; - contain: layout; + contain: style; + + &.is-preview { + contain: layout; + } } .umb-property-editor--preview { diff --git a/src/Umbraco.Web.UI.Client/src/views/components/property/umb-property-editor.html b/src/Umbraco.Web.UI.Client/src/views/components/property/umb-property-editor.html index 8667fb84c2..b2387e230a 100644 --- a/src/Umbraco.Web.UI.Client/src/views/components/property/umb-property-editor.html +++ b/src/Umbraco.Web.UI.Client/src/views/components/property/umb-property-editor.html @@ -1,4 +1,4 @@ -
+
@@ -13,7 +13,7 @@
- +
From 173d8dcf47fcd18584b80190db14144a363cbdd5 Mon Sep 17 00:00:00 2001 From: Zeegaan Date: Wed, 20 Sep 2023 10:29:50 +0200 Subject: [PATCH 2/4] Bump version --- version.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version.json b/version.json index 4b04b0255b..de4e207d31 100644 --- a/version.json +++ b/version.json @@ -1,6 +1,6 @@ { "$schema": "https://raw.githubusercontent.com/dotnet/Nerdbank.GitVersioning/master/src/NerdBank.GitVersioning/version.schema.json", - "version": "12.2.0-rc", + "version": "12.2.0", "assemblyVersion": { "precision": "build" }, From 2335924b5714ad9b1138222bbd81bc344c439d13 Mon Sep 17 00:00:00 2001 From: Kenn Jacobsen Date: Thu, 21 Sep 2023 09:25:29 +0200 Subject: [PATCH 3/4] Ensure that value type JSON is translated correctly for Delivery API output (#14839) --- .../ValueConverters/JsonValueConverter.cs | 15 ++++++++-- .../DeliveryApi/JsonValueConverterTests.cs | 30 +++++++++++++++++++ .../PropertyEditorValueConverterTests.cs | 17 +++++++++++ 3 files changed, 60 insertions(+), 2 deletions(-) create mode 100644 tests/Umbraco.Tests.UnitTests/Umbraco.Core/DeliveryApi/JsonValueConverterTests.cs diff --git a/src/Umbraco.Infrastructure/PropertyEditors/ValueConverters/JsonValueConverter.cs b/src/Umbraco.Infrastructure/PropertyEditors/ValueConverters/JsonValueConverter.cs index 4eaa24ecf9..e6345ab61d 100644 --- a/src/Umbraco.Infrastructure/PropertyEditors/ValueConverters/JsonValueConverter.cs +++ b/src/Umbraco.Infrastructure/PropertyEditors/ValueConverters/JsonValueConverter.cs @@ -1,10 +1,12 @@ // Copyright (c) Umbraco. // See LICENSE for more details. +using System.Text.Json.Nodes; using Microsoft.Extensions.Logging; using Newtonsoft.Json; using Newtonsoft.Json.Linq; using Umbraco.Cms.Core.Models.PublishedContent; +using Umbraco.Cms.Core.PropertyEditors.DeliveryApi; using Umbraco.Extensions; namespace Umbraco.Cms.Core.PropertyEditors.ValueConverters; @@ -16,7 +18,7 @@ namespace Umbraco.Cms.Core.PropertyEditors.ValueConverters; /// Since this is a default (umbraco) converter it will be ignored if another converter found conflicts with this one. /// [DefaultPropertyValueConverter] -public class JsonValueConverter : PropertyValueConverterBase +public class JsonValueConverter : PropertyValueConverterBase, IDeliveryApiPropertyValueConverter { private readonly ILogger _logger; private readonly PropertyEditorCollection _propertyEditors; @@ -76,5 +78,14 @@ public class JsonValueConverter : PropertyValueConverterBase return sourceString; } - // TODO: Now to convert that to XPath! + public PropertyCacheLevel GetDeliveryApiPropertyCacheLevel(IPublishedPropertyType propertyType) + => GetPropertyCacheLevel(propertyType); + + public Type GetDeliveryApiPropertyValueType(IPublishedPropertyType propertyType) + => typeof(JsonNode); + + public object? ConvertIntermediateToDeliveryApiObject(IPublishedElement owner, IPublishedPropertyType propertyType, PropertyCacheLevel referenceCacheLevel, object? inter, bool preview, bool expanding) + => inter is JObject jObject + ? JsonNode.Parse(jObject.ToString()) + : null; } diff --git a/tests/Umbraco.Tests.UnitTests/Umbraco.Core/DeliveryApi/JsonValueConverterTests.cs b/tests/Umbraco.Tests.UnitTests/Umbraco.Core/DeliveryApi/JsonValueConverterTests.cs new file mode 100644 index 0000000000..ac22f3985f --- /dev/null +++ b/tests/Umbraco.Tests.UnitTests/Umbraco.Core/DeliveryApi/JsonValueConverterTests.cs @@ -0,0 +1,30 @@ +using System.Text.Json.Nodes; +using Microsoft.Extensions.Logging; +using Moq; +using NUnit.Framework; +using Umbraco.Cms.Core.Models; +using Umbraco.Cms.Core.Models.PublishedContent; +using Umbraco.Cms.Core.PropertyEditors; +using Umbraco.Cms.Core.PropertyEditors.ValueConverters; + +namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Core.DeliveryApi; + +[TestFixture] +public class JsonValueConverterTests : PropertyValueConverterTests +{ + [Test] + public void JsonValueConverterTests_ConvertsCustomPropertyWithValueTypeJson() + { + var valueEditor = Mock.Of(x => x.ValueType == ValueTypes.Json); + var dataEditor = Mock.Of(x => x.GetValueEditor() == valueEditor); + var propertyEditors = new PropertyEditorCollection(new DataEditorCollection(() => new[] { dataEditor })); + var propertyType = Mock.Of(x => x.EditorAlias == "My.Custom.Json"); + + var valueConverter = new JsonValueConverter(propertyEditors, Mock.Of>()); + var inter = valueConverter.ConvertSourceToIntermediate(Mock.Of(), propertyType, "{\"message\": \"Hello, JSON\"}", false); + var result = valueConverter.ConvertIntermediateToDeliveryApiObject(Mock.Of(), propertyType, PropertyCacheLevel.Element, inter, false, false); + Assert.IsTrue(result is JsonNode); + JsonNode jsonNode = (JsonNode)result; + Assert.AreEqual("Hello, JSON", jsonNode["message"]!.GetValue()); + } +} diff --git a/tests/Umbraco.Tests.UnitTests/Umbraco.Core/PropertyEditors/PropertyEditorValueConverterTests.cs b/tests/Umbraco.Tests.UnitTests/Umbraco.Core/PropertyEditors/PropertyEditorValueConverterTests.cs index b3537c4659..d046064af2 100644 --- a/tests/Umbraco.Tests.UnitTests/Umbraco.Core/PropertyEditors/PropertyEditorValueConverterTests.cs +++ b/tests/Umbraco.Tests.UnitTests/Umbraco.Core/PropertyEditors/PropertyEditorValueConverterTests.cs @@ -3,7 +3,9 @@ using System.Collections.Generic; using System.Linq; +using Microsoft.Extensions.Logging; using Moq; +using Newtonsoft.Json.Linq; using NUnit.Framework; using Umbraco.Cms.Core.Models; using Umbraco.Cms.Core.Models.PublishedContent; @@ -133,4 +135,19 @@ public class PropertyEditorValueConverterTests Assert.AreEqual(expected, result); } + + [Test] + public void CanConvertManifestBasedPropertyWithValueTypeJson() + { + var valueEditor = Mock.Of(x => x.ValueType == ValueTypes.Json); + var dataEditor = Mock.Of(x => x.GetValueEditor() == valueEditor); + var propertyEditors = new PropertyEditorCollection(new DataEditorCollection(() => new[] { dataEditor })); + var propertyType = Mock.Of(x => x.EditorAlias == "My.Custom.Json"); + + var valueConverter = new JsonValueConverter(propertyEditors, Mock.Of>()); + var inter = valueConverter.ConvertSourceToIntermediate(Mock.Of(), propertyType, "{\"message\": \"Hello, JSON\"}", false); + var result = valueConverter.ConvertIntermediateToObject(Mock.Of(), propertyType, PropertyCacheLevel.Element, inter, false) as JObject; + Assert.IsNotNull(result); + Assert.AreEqual("Hello, JSON", result["message"]!.Value()); + } } From d39502674e95d3a0474517c491b3ebc269bc4e72 Mon Sep 17 00:00:00 2001 From: Bjarke Berg Date: Fri, 22 Sep 2023 10:38:55 +0200 Subject: [PATCH 4/4] Added our own db context pool, that basically bypass the bool until umbraco is in Run mode (#14852) --- ...mbracoEFCoreServiceCollectionExtensions.cs | 18 ++++++- .../UmbracoPooledDbContextFactory.cs | 47 +++++++++++++++++++ 2 files changed, 64 insertions(+), 1 deletion(-) create mode 100644 src/Umbraco.Cms.Persistence.EFCore/Factories/UmbracoPooledDbContextFactory.cs diff --git a/src/Umbraco.Cms.Persistence.EFCore/Extensions/UmbracoEFCoreServiceCollectionExtensions.cs b/src/Umbraco.Cms.Persistence.EFCore/Extensions/UmbracoEFCoreServiceCollectionExtensions.cs index da9c2e59ef..ded5be40fd 100644 --- a/src/Umbraco.Cms.Persistence.EFCore/Extensions/UmbracoEFCoreServiceCollectionExtensions.cs +++ b/src/Umbraco.Cms.Persistence.EFCore/Extensions/UmbracoEFCoreServiceCollectionExtensions.cs @@ -1,11 +1,13 @@ using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.DependencyInjection.Extensions; using Microsoft.Extensions.Options; using Umbraco.Cms.Core; using Umbraco.Cms.Core.Configuration.Models; using Umbraco.Cms.Core.DistributedLocking; +using Umbraco.Cms.Core.Services; +using Umbraco.Cms.Persistence.EFCore.Factories; using Umbraco.Cms.Persistence.EFCore.Locking; -using Umbraco.Cms.Persistence.EFCore.Migrations; using Umbraco.Cms.Persistence.EFCore.Scoping; namespace Umbraco.Extensions; @@ -17,6 +19,13 @@ public static class UmbracoEFCoreServiceCollectionExtensions public static IServiceCollection AddUmbracoEFCoreContext(this IServiceCollection services, DefaultEFCoreOptionsAction? defaultEFCoreOptionsAction = null) where T : DbContext { + var optionsBuilder = new DbContextOptionsBuilder(); + services.TryAddSingleton>( + sp => + { + SetupDbContext(defaultEFCoreOptionsAction, sp, optionsBuilder); + return new UmbracoPooledDbContextFactory(sp.GetRequiredService(),optionsBuilder.Options); + }); services.AddPooledDbContextFactory((provider, builder) => SetupDbContext(defaultEFCoreOptionsAction, provider, builder)); services.AddTransient(services => services.GetRequiredService>().CreateDbContext()); @@ -39,6 +48,13 @@ public static class UmbracoEFCoreServiceCollectionExtensions connectionString = connectionString.Replace(Constants.System.DataDirectoryPlaceholder, dataDirectory); } + var optionsBuilder = new DbContextOptionsBuilder(); + services.TryAddSingleton>( + sp => + { + SetupDbContext(defaultEFCoreOptionsAction, sp, optionsBuilder); + return new UmbracoPooledDbContextFactory(sp.GetRequiredService(),optionsBuilder.Options); + }); services.AddPooledDbContextFactory(options => defaultEFCoreOptionsAction?.Invoke(options, providerName, connectionString)); services.AddTransient(services => services.GetRequiredService>().CreateDbContext()); diff --git a/src/Umbraco.Cms.Persistence.EFCore/Factories/UmbracoPooledDbContextFactory.cs b/src/Umbraco.Cms.Persistence.EFCore/Factories/UmbracoPooledDbContextFactory.cs new file mode 100644 index 0000000000..de0f7db200 --- /dev/null +++ b/src/Umbraco.Cms.Persistence.EFCore/Factories/UmbracoPooledDbContextFactory.cs @@ -0,0 +1,47 @@ +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Umbraco.Cms.Core; +using Umbraco.Cms.Core.Services; + +namespace Umbraco.Cms.Persistence.EFCore.Factories; + +/// +internal class UmbracoPooledDbContextFactory : PooledDbContextFactory + where TContext : DbContext +{ + private readonly IRuntimeState _runtimeState; + private readonly DbContextOptions _options; + + /// + public UmbracoPooledDbContextFactory(IRuntimeState runtimeState, DbContextOptions options, int poolSize = 1024 /*DbContextPool.DefaultPoolSize*/) : base(options, poolSize) + { + _runtimeState = runtimeState; + _options = options; + } + + /// + public override TContext CreateDbContext() + { + if (_runtimeState.Level == RuntimeLevel.Run) + { + return base.CreateDbContext(); + } + else + { + return (TContext?)Activator.CreateInstance(typeof(TContext), _options) ?? throw new InvalidOperationException("Unable to create DbContext"); + } + } + + /// + public override async Task CreateDbContextAsync(CancellationToken cancellationToken = default) + { + if (_runtimeState.Level == RuntimeLevel.Run) + { + return await base.CreateDbContextAsync(cancellationToken); + } + else + { + return (TContext?)Activator.CreateInstance(typeof(TContext), _options) ?? throw new InvalidOperationException("Unable to create DbContext"); + } + } +}