From 65caa6049625c68a1fb3dd4295f9ddcae3922557 Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Mon, 28 Apr 2025 15:21:05 +0200 Subject: [PATCH 1/7] Add copy to clipboard success notification (#19179) * add localization * show notification * Update clipboard.property-context.ts --- .../src/assets/lang/en.ts | 1 + .../copy/copy-to-clipboard.property-action.ts | 2 +- .../context/clipboard.property-context.ts | 23 ++++++++++++++++++- 3 files changed, 24 insertions(+), 2 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/assets/lang/en.ts b/src/Umbraco.Web.UI.Client/src/assets/lang/en.ts index 89c1abdcef..5b3140ecd8 100644 --- a/src/Umbraco.Web.UI.Client/src/assets/lang/en.ts +++ b/src/Umbraco.Web.UI.Client/src/assets/lang/en.ts @@ -2457,6 +2457,7 @@ export default { labelForCopyToClipboard: 'Copy to clipboard', confirmDeleteHeadline: 'Delete from clipboard', confirmDeleteDescription: 'Are you sure you want to delete {0} from the clipboard?', + copySuccessHeadline: 'Copied to clipboard', }, propertyActions: { tooltipForPropertyActionsMenu: 'Open Property Actions', diff --git a/src/Umbraco.Web.UI.Client/src/packages/clipboard/property/actions/copy/copy-to-clipboard.property-action.ts b/src/Umbraco.Web.UI.Client/src/packages/clipboard/property/actions/copy/copy-to-clipboard.property-action.ts index b872617e87..f1e4357160 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/clipboard/property/actions/copy/copy-to-clipboard.property-action.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/clipboard/property/actions/copy/copy-to-clipboard.property-action.ts @@ -62,7 +62,7 @@ export class UmbCopyToClipboardPropertyAction extends UmbPropertyActionBase; + #localize = new UmbLocalizationController(this); constructor(host: UmbControllerHost) { super(host, UMB_CLIPBOARD_PROPERTY_CONTEXT); @@ -104,7 +107,25 @@ export class UmbClipboardPropertyContext extends UmbContextBase { icon: args.icon, }; - return await clipboardContext.write(entryPreset); + const notificationContext = await this.getContext(UMB_NOTIFICATION_CONTEXT); + if (!notificationContext) { + throw new Error('Notification context is required'); + } + + try { + const clipboardEntry = await clipboardContext.write(entryPreset); + + notificationContext.peek('positive', { + data: { message: this.#localize.term('clipboard_copySuccessHeadline') }, + }); + + return clipboardEntry; + } catch (error) { + const errorMessage = error instanceof Error ? error.message : String(error); + notificationContext.peek('danger', { data: { message: errorMessage } }); + } + + return undefined; } /** From 758a9cf1ec0e23c1976e634694f54983f568e531 Mon Sep 17 00:00:00 2001 From: Andy Butland Date: Mon, 28 Apr 2025 15:50:03 +0200 Subject: [PATCH 2/7] Allow deselection of color picker property. (#19174) --- .../color-picker/property-editor-ui-color-picker.element.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/packages/property-editors/color-picker/property-editor-ui-color-picker.element.ts b/src/Umbraco.Web.UI.Client/src/packages/property-editors/color-picker/property-editor-ui-color-picker.element.ts index 3408865657..3b0519ed92 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/property-editors/color-picker/property-editor-ui-color-picker.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/property-editors/color-picker/property-editor-ui-color-picker.element.ts @@ -17,8 +17,7 @@ export class UmbPropertyEditorUIColorPickerElement extends UmbLitElement impleme @property({ type: Object }) public set value(value: UmbSwatchDetails | undefined) { - if (!value) return; - this.#value = this.#ensureHashPrefix(value); + this.#value = value ? this.#ensureHashPrefix(value) : undefined; } public get value(): UmbSwatchDetails | undefined { return this.#value; From ae54b92005c86128fbb011954b1f155de3544cfd Mon Sep 17 00:00:00 2001 From: Kenn Jacobsen Date: Tue, 29 Apr 2025 07:01:07 +0200 Subject: [PATCH 3/7] Output culture variant update dates from the Delivery API (#19180) --- .../DeliveryApi/ApiContentBuilder.cs | 26 ++++- .../DeliveryApi/ApiContentResponseBuilder.cs | 30 ++++- .../Request/ApiContentResponseBuilderTests.cs | 103 ++++++++++++++++++ .../DeliveryApi/ContentBuilderTests.cs | 47 +++++++- .../ContentPickerValueConverterTests.cs | 2 +- .../DeliveryApi/DeliveryApiTests.cs | 3 + .../MultiNodeTreePickerValueConverterTests.cs | 2 +- .../OutputExpansionStrategyTestBase.cs | 12 +- .../OutputExpansionStrategyTests.cs | 6 +- .../OutputExpansionStrategyV2Tests.cs | 16 +-- 10 files changed, 218 insertions(+), 29 deletions(-) create mode 100644 tests/Umbraco.Tests.Integration/Umbraco.Core/DeliveryApi/Request/ApiContentResponseBuilderTests.cs diff --git a/src/Umbraco.Core/DeliveryApi/ApiContentBuilder.cs b/src/Umbraco.Core/DeliveryApi/ApiContentBuilder.cs index 135afe068a..64c1029b02 100644 --- a/src/Umbraco.Core/DeliveryApi/ApiContentBuilder.cs +++ b/src/Umbraco.Core/DeliveryApi/ApiContentBuilder.cs @@ -1,15 +1,35 @@ +using Umbraco.Cms.Core.DependencyInjection; using Umbraco.Cms.Core.Models.DeliveryApi; using Umbraco.Cms.Core.Models.PublishedContent; +using Umbraco.Extensions; namespace Umbraco.Cms.Core.DeliveryApi; public sealed class ApiContentBuilder : ApiContentBuilderBase, IApiContentBuilder { - public ApiContentBuilder(IApiContentNameProvider apiContentNameProvider, IApiContentRouteBuilder apiContentRouteBuilder, IOutputExpansionStrategyAccessor outputExpansionStrategyAccessor) - : base(apiContentNameProvider, apiContentRouteBuilder, outputExpansionStrategyAccessor) + private readonly IVariationContextAccessor _variationContextAccessor; + + [Obsolete("Please use the constructor that takes an IVariationContextAccessor instead. Scheduled for removal in V17.")] + public ApiContentBuilder( + IApiContentNameProvider apiContentNameProvider, + IApiContentRouteBuilder apiContentRouteBuilder, + IOutputExpansionStrategyAccessor outputExpansionStrategyAccessor) + : this( + apiContentNameProvider, + apiContentRouteBuilder, + outputExpansionStrategyAccessor, + StaticServiceProvider.Instance.CreateInstance()) { } + public ApiContentBuilder( + IApiContentNameProvider apiContentNameProvider, + IApiContentRouteBuilder apiContentRouteBuilder, + IOutputExpansionStrategyAccessor outputExpansionStrategyAccessor, + IVariationContextAccessor variationContextAccessor) + : base(apiContentNameProvider, apiContentRouteBuilder, outputExpansionStrategyAccessor) + => _variationContextAccessor = variationContextAccessor; + protected override IApiContent Create(IPublishedContent content, string name, IApiContentRoute route, IDictionary properties) - => new ApiContent(content.Key, name, content.ContentType.Alias, content.CreateDate, content.UpdateDate, route, properties); + => new ApiContent(content.Key, name, content.ContentType.Alias, content.CreateDate, content.CultureDate(_variationContextAccessor), route, properties); } diff --git a/src/Umbraco.Core/DeliveryApi/ApiContentResponseBuilder.cs b/src/Umbraco.Core/DeliveryApi/ApiContentResponseBuilder.cs index 68bb01c012..833d7f2016 100644 --- a/src/Umbraco.Core/DeliveryApi/ApiContentResponseBuilder.cs +++ b/src/Umbraco.Core/DeliveryApi/ApiContentResponseBuilder.cs @@ -1,4 +1,5 @@ -using Umbraco.Cms.Core.Models.DeliveryApi; +using Umbraco.Cms.Core.DependencyInjection; +using Umbraco.Cms.Core.Models.DeliveryApi; using Umbraco.Cms.Core.Models.PublishedContent; using Umbraco.Extensions; @@ -7,15 +8,36 @@ namespace Umbraco.Cms.Core.DeliveryApi; public class ApiContentResponseBuilder : ApiContentBuilderBase, IApiContentResponseBuilder { private readonly IApiContentRouteBuilder _apiContentRouteBuilder; + private readonly IVariationContextAccessor _variationContextAccessor; - public ApiContentResponseBuilder(IApiContentNameProvider apiContentNameProvider, IApiContentRouteBuilder apiContentRouteBuilder, IOutputExpansionStrategyAccessor outputExpansionStrategyAccessor) + [Obsolete("Please use the constructor that takes an IVariationContextAccessor instead. Scheduled for removal in V17.")] + public ApiContentResponseBuilder( + IApiContentNameProvider apiContentNameProvider, + IApiContentRouteBuilder apiContentRouteBuilder, + IOutputExpansionStrategyAccessor outputExpansionStrategyAccessor) + : this( + apiContentNameProvider, + apiContentRouteBuilder, + outputExpansionStrategyAccessor, + StaticServiceProvider.Instance.CreateInstance()) + { + } + + public ApiContentResponseBuilder( + IApiContentNameProvider apiContentNameProvider, + IApiContentRouteBuilder apiContentRouteBuilder, + IOutputExpansionStrategyAccessor outputExpansionStrategyAccessor, + IVariationContextAccessor variationContextAccessor) : base(apiContentNameProvider, apiContentRouteBuilder, outputExpansionStrategyAccessor) - => _apiContentRouteBuilder = apiContentRouteBuilder; + { + _apiContentRouteBuilder = apiContentRouteBuilder; + _variationContextAccessor = variationContextAccessor; + } protected override IApiContentResponse Create(IPublishedContent content, string name, IApiContentRoute route, IDictionary properties) { IDictionary cultures = GetCultures(content); - return new ApiContentResponse(content.Key, name, content.ContentType.Alias, content.CreateDate, content.UpdateDate, route, properties, cultures); + return new ApiContentResponse(content.Key, name, content.ContentType.Alias, content.CreateDate, content.CultureDate(_variationContextAccessor), route, properties, cultures); } protected virtual IDictionary GetCultures(IPublishedContent content) diff --git a/tests/Umbraco.Tests.Integration/Umbraco.Core/DeliveryApi/Request/ApiContentResponseBuilderTests.cs b/tests/Umbraco.Tests.Integration/Umbraco.Core/DeliveryApi/Request/ApiContentResponseBuilderTests.cs new file mode 100644 index 0000000000..02319df2a1 --- /dev/null +++ b/tests/Umbraco.Tests.Integration/Umbraco.Core/DeliveryApi/Request/ApiContentResponseBuilderTests.cs @@ -0,0 +1,103 @@ +using Microsoft.AspNetCore.Http; +using NUnit.Framework; +using Umbraco.Cms.Core; +using Umbraco.Cms.Core.Cache; +using Umbraco.Cms.Core.DeliveryApi; +using Umbraco.Cms.Core.Models; +using Umbraco.Cms.Core.Models.PublishedContent; +using Umbraco.Cms.Core.Services; +using Umbraco.Cms.Core.Services.Changes; +using Umbraco.Cms.Core.Web; +using Umbraco.Cms.Tests.Common.Builders; +using Umbraco.Cms.Tests.Common.Builders.Extensions; +using Umbraco.Cms.Tests.Common.Testing; +using Umbraco.Cms.Tests.Integration.Testing; + +namespace Umbraco.Cms.Tests.Integration.Umbraco.Core.DeliveryApi.Request; + +[TestFixture] +[UmbracoTest(Database = UmbracoTestOptions.Database.NewSchemaPerTest)] +public class ApiContentResponseBuilderTests : UmbracoIntegrationTest +{ + private IContentService ContentService => GetRequiredService(); + + private IContentTypeService ContentTypeService => GetRequiredService(); + + private IApiContentResponseBuilder ApiContentResponseBuilder => GetRequiredService(); + + protected IUmbracoContextAccessor UmbracoContextAccessor => GetRequiredService(); + + protected IUmbracoContextFactory UmbracoContextFactory => GetRequiredService(); + + protected IVariationContextAccessor VariationContextAccessor => GetRequiredService(); + + protected override void CustomTestSetup(IUmbracoBuilder builder) + { + builder.AddUmbracoHybridCache(); + builder.AddDeliveryApi(); + } + + [SetUp] + public void SetUpTest() + { + var httpContextAccessor = GetRequiredService(); + + httpContextAccessor.HttpContext = new DefaultHttpContext + { + Request = + { + Scheme = "https", + Host = new HostString("localhost"), + Path = "/", + QueryString = new QueryString(string.Empty) + }, + RequestServices = Services + }; + } + + [Test] + public async Task ContentBuilder_MapsContentDatesCorrectlyForCultureVariance() + { + await GetRequiredService().CreateAsync(new Language("da-DK", "Danish"), Constants.Security.SuperUserKey); + + var contentType = new ContentTypeBuilder() + .WithAlias("theContentType") + .WithContentVariation(ContentVariation.Culture) + .Build(); + contentType.AllowedAsRoot = true; + await ContentTypeService.CreateAsync(contentType, Constants.Security.SuperUserKey); + + var content = new ContentBuilder() + .WithContentType(contentType) + .WithCultureName("en-US", "Content EN") + .WithCultureName("da-DK", "Content DA") + .Build(); + ContentService.Save(content); + ContentService.Publish(content, ["*"]); + + Thread.Sleep(200); + content.SetCultureName("Content DA updated", "da-DK"); + ContentService.Save(content); + ContentService.Publish(content, ["da-DK"]); + + RefreshContentCache(); + + UmbracoContextAccessor.Clear(); + var umbracoContext = UmbracoContextFactory.EnsureUmbracoContext().UmbracoContext; + var publishedContent = umbracoContext.Content.GetById(content.Key); + Assert.IsNotNull(publishedContent); + + VariationContextAccessor.VariationContext = new VariationContext(culture: "en-US"); + var enResult = ApiContentResponseBuilder.Build(publishedContent); + Assert.IsNotNull(enResult); + + VariationContextAccessor.VariationContext = new VariationContext(culture: "da-DK"); + var daResult = ApiContentResponseBuilder.Build(publishedContent); + Assert.IsNotNull(daResult); + + Assert.GreaterOrEqual((daResult.UpdateDate - enResult.UpdateDate).TotalMilliseconds, 200); + } + + private void RefreshContentCache() + => GetRequiredService().Refresh([new ContentCacheRefresher.JsonPayload { ChangeTypes = TreeChangeTypes.RefreshAll }]); +} diff --git a/tests/Umbraco.Tests.UnitTests/Umbraco.Core/DeliveryApi/ContentBuilderTests.cs b/tests/Umbraco.Tests.UnitTests/Umbraco.Core/DeliveryApi/ContentBuilderTests.cs index 91b67673d9..6591e7efbd 100644 --- a/tests/Umbraco.Tests.UnitTests/Umbraco.Core/DeliveryApi/ContentBuilderTests.cs +++ b/tests/Umbraco.Tests.UnitTests/Umbraco.Core/DeliveryApi/ContentBuilderTests.cs @@ -1,11 +1,13 @@ using Moq; using NUnit.Framework; using Umbraco.Cms.Core.DeliveryApi; +using Umbraco.Cms.Core.Models; using Umbraco.Cms.Core.Models.DeliveryApi; using Umbraco.Cms.Core.Models.PublishedContent; using Umbraco.Cms.Core.PropertyEditors; using Umbraco.Cms.Core.PublishedCache; using Umbraco.Cms.Core.Services.Navigation; +using Umbraco.Cms.Tests.Common; namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Core.DeliveryApi; @@ -42,7 +44,7 @@ public class ContentBuilderTests : DeliveryApiTests var routeBuilder = CreateContentRouteBuilder(apiContentRouteProvider.Object, CreateGlobalSettings(), navigationQueryService: navigationQueryServiceMock.Object); - var builder = new ApiContentBuilder(new ApiContentNameProvider(), routeBuilder, CreateOutputExpansionStrategyAccessor()); + var builder = new ApiContentBuilder(new ApiContentNameProvider(), routeBuilder, CreateOutputExpansionStrategyAccessor(), CreateVariationContextAccessor()); var result = builder.Build(content.Object); Assert.NotNull(result); @@ -57,6 +59,45 @@ public class ContentBuilderTests : DeliveryApiTests Assert.AreEqual(new DateTime(2023, 07, 12), result.UpdateDate); } + [TestCase("en-US", "2023-08-04")] + [TestCase("da-DK", "2023-09-08")] + public void ContentBuilder_MapsContentDatesCorrectlyForCultureVariance(string culture, string expectedUpdateDate) + { + var content = new Mock(); + + var contentType = new Mock(); + contentType.SetupGet(c => c.Alias).Returns("thePageType"); + contentType.SetupGet(c => c.ItemType).Returns(PublishedItemType.Content); + contentType.SetupGet(c => c.Variations).Returns(ContentVariation.Culture); + + var key = Guid.NewGuid(); + var urlSegment = "url-segment"; + var name = "The page"; + ConfigurePublishedContentMock(content, key, name, urlSegment, contentType.Object, []); + content.SetupGet(c => c.CreateDate).Returns(new DateTime(2023, 07, 02)); + content + .SetupGet(c => c.Cultures) + .Returns(new Dictionary + { + { "en-US", new PublishedCultureInfo("en-US", "EN Name", "en-url-segment", new DateTime(2023, 08, 04)) }, + { "da-DK", new PublishedCultureInfo("da-DK", "DA Name", "da-url-segment", new DateTime(2023, 09, 08)) }, + }); + + var routeBuilder = new Mock(); + routeBuilder + .Setup(r => r.Build(content.Object, It.IsAny())) + .Returns(new ApiContentRoute(content.Object.UrlSegment!, new ApiContentStartItem(Guid.NewGuid(), "/"))); + + var variationContextAccessor = new TestVariationContextAccessor { VariationContext = new VariationContext(culture) }; + + var builder = new ApiContentBuilder(new ApiContentNameProvider(), routeBuilder.Object, CreateOutputExpansionStrategyAccessor(), variationContextAccessor); + var result = builder.Build(content.Object); + + Assert.NotNull(result); + Assert.AreEqual(new DateTime(2023, 07, 02), result.CreateDate); + Assert.AreEqual(DateTime.Parse(expectedUpdateDate), result.UpdateDate); + } + [Test] public void ContentBuilder_CanCustomizeContentNameInDeliveryApiOutput() { @@ -75,7 +116,7 @@ public class ContentBuilderTests : DeliveryApiTests .Setup(r => r.Build(content.Object, It.IsAny())) .Returns(new ApiContentRoute(content.Object.UrlSegment!, new ApiContentStartItem(Guid.NewGuid(), "/"))); - var builder = new ApiContentBuilder(customNameProvider.Object, routeBuilder.Object, CreateOutputExpansionStrategyAccessor()); + var builder = new ApiContentBuilder(customNameProvider.Object, routeBuilder.Object, CreateOutputExpansionStrategyAccessor(), CreateVariationContextAccessor()); var result = builder.Build(content.Object); Assert.NotNull(result); @@ -97,7 +138,7 @@ public class ContentBuilderTests : DeliveryApiTests .Setup(r => r.Build(content.Object, It.IsAny())) .Returns((ApiContentRoute)null); - var builder = new ApiContentBuilder(new ApiContentNameProvider(), routeBuilder.Object, CreateOutputExpansionStrategyAccessor()); + var builder = new ApiContentBuilder(new ApiContentNameProvider(), routeBuilder.Object, CreateOutputExpansionStrategyAccessor(), CreateVariationContextAccessor()); var result = builder.Build(content.Object); Assert.Null(result); diff --git a/tests/Umbraco.Tests.UnitTests/Umbraco.Core/DeliveryApi/ContentPickerValueConverterTests.cs b/tests/Umbraco.Tests.UnitTests/Umbraco.Core/DeliveryApi/ContentPickerValueConverterTests.cs index 1aca987862..354c44cb1c 100644 --- a/tests/Umbraco.Tests.UnitTests/Umbraco.Core/DeliveryApi/ContentPickerValueConverterTests.cs +++ b/tests/Umbraco.Tests.UnitTests/Umbraco.Core/DeliveryApi/ContentPickerValueConverterTests.cs @@ -19,7 +19,7 @@ public class ContentPickerValueConverterTests : PropertyValueConverterTests new ApiContentBuilder( nameProvider ?? new ApiContentNameProvider(), CreateContentRouteBuilder(ApiContentPathProvider, CreateGlobalSettings()), - CreateOutputExpansionStrategyAccessor())); + CreateOutputExpansionStrategyAccessor(), CreateVariationContextAccessor())); [Test] public void ContentPickerValueConverter_BuildsDeliveryApiOutput() diff --git a/tests/Umbraco.Tests.UnitTests/Umbraco.Core/DeliveryApi/DeliveryApiTests.cs b/tests/Umbraco.Tests.UnitTests/Umbraco.Core/DeliveryApi/DeliveryApiTests.cs index 26cc1d7edc..3c5b6d8ca0 100644 --- a/tests/Umbraco.Tests.UnitTests/Umbraco.Core/DeliveryApi/DeliveryApiTests.cs +++ b/tests/Umbraco.Tests.UnitTests/Umbraco.Core/DeliveryApi/DeliveryApiTests.cs @@ -11,6 +11,7 @@ using Umbraco.Cms.Core.PropertyEditors.DeliveryApi; using Umbraco.Cms.Core.PublishedCache; using Umbraco.Cms.Core.Services; using Umbraco.Cms.Core.Services.Navigation; +using Umbraco.Cms.Tests.Common; using Umbraco.Extensions; namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Core.DeliveryApi; @@ -92,6 +93,8 @@ public class DeliveryApiTests protected IOutputExpansionStrategyAccessor CreateOutputExpansionStrategyAccessor() => new NoopOutputExpansionStrategyAccessor(); + protected IVariationContextAccessor CreateVariationContextAccessor() => new TestVariationContextAccessor(); + protected IOptions CreateGlobalSettings(bool hideTopLevelNodeFromPath = true) { var globalSettings = new GlobalSettings { HideTopLevelNodeFromPath = hideTopLevelNodeFromPath }; diff --git a/tests/Umbraco.Tests.UnitTests/Umbraco.Core/DeliveryApi/MultiNodeTreePickerValueConverterTests.cs b/tests/Umbraco.Tests.UnitTests/Umbraco.Core/DeliveryApi/MultiNodeTreePickerValueConverterTests.cs index e83bd28514..59dd0cee87 100644 --- a/tests/Umbraco.Tests.UnitTests/Umbraco.Core/DeliveryApi/MultiNodeTreePickerValueConverterTests.cs +++ b/tests/Umbraco.Tests.UnitTests/Umbraco.Core/DeliveryApi/MultiNodeTreePickerValueConverterTests.cs @@ -25,7 +25,7 @@ public class MultiNodeTreePickerValueConverterTests : PropertyValueConverterTest return new MultiNodeTreePickerValueConverter( Mock.Of(), Mock.Of(), - new ApiContentBuilder(contentNameProvider, routeBuilder, expansionStrategyAccessor), + new ApiContentBuilder(contentNameProvider, routeBuilder, expansionStrategyAccessor, CreateVariationContextAccessor()), new ApiMediaBuilder(contentNameProvider, apiUrProvider, Mock.Of(), expansionStrategyAccessor), CacheManager.Content, CacheManager.Media, diff --git a/tests/Umbraco.Tests.UnitTests/Umbraco.Core/DeliveryApi/OutputExpansionStrategyTestBase.cs b/tests/Umbraco.Tests.UnitTests/Umbraco.Core/DeliveryApi/OutputExpansionStrategyTestBase.cs index 7e4c874523..3051bced8a 100644 --- a/tests/Umbraco.Tests.UnitTests/Umbraco.Core/DeliveryApi/OutputExpansionStrategyTestBase.cs +++ b/tests/Umbraco.Tests.UnitTests/Umbraco.Core/DeliveryApi/OutputExpansionStrategyTestBase.cs @@ -43,7 +43,7 @@ public abstract class OutputExpansionStrategyTestBase : PropertyValueConverterTe public void OutputExpansionStrategy_ExpandsNothingByDefault() { var accessor = CreateOutputExpansionStrategyAccessor(false); - var apiContentBuilder = new ApiContentBuilder(new ApiContentNameProvider(), ApiContentRouteBuilder(), accessor); + var apiContentBuilder = new ApiContentBuilder(new ApiContentNameProvider(), ApiContentRouteBuilder(), accessor, CreateVariationContextAccessor()); var content = new Mock(); var prop1 = new PublishedElementPropertyBase(DeliveryApiPropertyType, content.Object, false, PropertyCacheLevel.None, VariationContext, CacheManager); @@ -69,7 +69,7 @@ public abstract class OutputExpansionStrategyTestBase : PropertyValueConverterTe public void OutputExpansionStrategy_CanExpandSpecificContent() { var accessor = CreateOutputExpansionStrategyAccessor(false, new[] { "contentPickerTwo" }); - var apiContentBuilder = new ApiContentBuilder(new ApiContentNameProvider(), ApiContentRouteBuilder(), accessor); + var apiContentBuilder = new ApiContentBuilder(new ApiContentNameProvider(), ApiContentRouteBuilder(), accessor, CreateVariationContextAccessor()); var content = new Mock(); @@ -142,7 +142,7 @@ public abstract class OutputExpansionStrategyTestBase : PropertyValueConverterTe public void OutputExpansionStrategy_CanExpandAllContent() { var accessor = CreateOutputExpansionStrategyAccessor(true); - var apiContentBuilder = new ApiContentBuilder(new ApiContentNameProvider(), ApiContentRouteBuilder(), accessor); + var apiContentBuilder = new ApiContentBuilder(new ApiContentNameProvider(), ApiContentRouteBuilder(), accessor, CreateVariationContextAccessor()); var content = new Mock(); @@ -177,7 +177,7 @@ public abstract class OutputExpansionStrategyTestBase : PropertyValueConverterTe public void OutputExpansionStrategy_DoesNotExpandNestedContentPicker(string rootPropertyTypeAlias, string nestedPropertyTypeAlias) { var accessor = CreateOutputExpansionStrategyAccessor(false, new[] { rootPropertyTypeAlias, nestedPropertyTypeAlias }); - var apiContentBuilder = new ApiContentBuilder(new ApiContentNameProvider(), ApiContentRouteBuilder(), accessor); + var apiContentBuilder = new ApiContentBuilder(new ApiContentNameProvider(), ApiContentRouteBuilder(), accessor, CreateVariationContextAccessor()); var content = new Mock(); @@ -207,7 +207,7 @@ public abstract class OutputExpansionStrategyTestBase : PropertyValueConverterTe public void OutputExpansionStrategy_DoesNotExpandElementsByDefault() { var accessor = CreateOutputExpansionStrategyAccessor(false); - var apiContentBuilder = new ApiContentBuilder(new ApiContentNameProvider(), ApiContentRouteBuilder(), accessor); + var apiContentBuilder = new ApiContentBuilder(new ApiContentNameProvider(), ApiContentRouteBuilder(), accessor, CreateVariationContextAccessor()); var apiElementBuilder = new ApiElementBuilder(accessor); var contentPickerValue = CreateSimplePickedContent(111, 222); @@ -283,7 +283,7 @@ public abstract class OutputExpansionStrategyTestBase : PropertyValueConverterTe public void OutputExpansionStrategy_ForwardsExpansionStateToPropertyValueConverter(bool expanding) { var accessor = CreateOutputExpansionStrategyAccessor(false, new[] { expanding ? "theAlias" : "noSuchAlias" }); - var apiContentBuilder = new ApiContentBuilder(new ApiContentNameProvider(), ApiContentRouteBuilder(), accessor); + var apiContentBuilder = new ApiContentBuilder(new ApiContentNameProvider(), ApiContentRouteBuilder(), accessor, CreateVariationContextAccessor()); var content = new Mock(); diff --git a/tests/Umbraco.Tests.UnitTests/Umbraco.Core/DeliveryApi/OutputExpansionStrategyTests.cs b/tests/Umbraco.Tests.UnitTests/Umbraco.Core/DeliveryApi/OutputExpansionStrategyTests.cs index 34258a362f..c94fea9e0f 100644 --- a/tests/Umbraco.Tests.UnitTests/Umbraco.Core/DeliveryApi/OutputExpansionStrategyTests.cs +++ b/tests/Umbraco.Tests.UnitTests/Umbraco.Core/DeliveryApi/OutputExpansionStrategyTests.cs @@ -20,7 +20,7 @@ public class OutputExpansionStrategyTests : OutputExpansionStrategyTestBase public void OutputExpansionStrategy_CanExpandSpecifiedElement() { var accessor = CreateOutputExpansionStrategyAccessor(false, new[] { "element" }); - var apiContentBuilder = new ApiContentBuilder(new ApiContentNameProvider(), ApiContentRouteBuilder(), accessor); + var apiContentBuilder = new ApiContentBuilder(new ApiContentNameProvider(), ApiContentRouteBuilder(), accessor, CreateVariationContextAccessor()); var apiElementBuilder = new ApiElementBuilder(accessor); var contentPickerValue = CreateSimplePickedContent(111, 222); @@ -63,7 +63,7 @@ public class OutputExpansionStrategyTests : OutputExpansionStrategyTestBase public void OutputExpansionStrategy_CanExpandAllElements() { var accessor = CreateOutputExpansionStrategyAccessor(true ); - var apiContentBuilder = new ApiContentBuilder(new ApiContentNameProvider(), ApiContentRouteBuilder(), accessor); + var apiContentBuilder = new ApiContentBuilder(new ApiContentNameProvider(), ApiContentRouteBuilder(), accessor, CreateVariationContextAccessor()); var apiElementBuilder = new ApiElementBuilder(accessor); var contentPickerValue = CreateSimplePickedContent(111, 222); @@ -120,7 +120,7 @@ public class OutputExpansionStrategyTests : OutputExpansionStrategyTestBase public void OutputExpansionStrategy_DoesNotExpandElementNestedContentPicker() { var accessor = CreateOutputExpansionStrategyAccessor(false, new[] { "element" }); - var apiContentBuilder = new ApiContentBuilder(new ApiContentNameProvider(), ApiContentRouteBuilder(), accessor); + var apiContentBuilder = new ApiContentBuilder(new ApiContentNameProvider(), ApiContentRouteBuilder(), accessor, CreateVariationContextAccessor()); var apiElementBuilder = new ApiElementBuilder(accessor); var nestedContentPickerValue = CreateSimplePickedContent(111, 222); diff --git a/tests/Umbraco.Tests.UnitTests/Umbraco.Core/DeliveryApi/OutputExpansionStrategyV2Tests.cs b/tests/Umbraco.Tests.UnitTests/Umbraco.Core/DeliveryApi/OutputExpansionStrategyV2Tests.cs index 7619d1055a..cd5f4f6761 100644 --- a/tests/Umbraco.Tests.UnitTests/Umbraco.Core/DeliveryApi/OutputExpansionStrategyV2Tests.cs +++ b/tests/Umbraco.Tests.UnitTests/Umbraco.Core/DeliveryApi/OutputExpansionStrategyV2Tests.cs @@ -22,7 +22,7 @@ public class OutputExpansionStrategyV2Tests : OutputExpansionStrategyTestBase public void OutputExpansionStrategy_CanExpandNestedContentPicker(string rootPropertyTypeAlias, string nestedPropertyTypeAlias) { var accessor = CreateOutputExpansionStrategyAccessor($"properties[{rootPropertyTypeAlias}[properties[{nestedPropertyTypeAlias}]]]"); - var apiContentBuilder = new ApiContentBuilder(new ApiContentNameProvider(), ApiContentRouteBuilder(), accessor); + var apiContentBuilder = new ApiContentBuilder(new ApiContentNameProvider(), ApiContentRouteBuilder(), accessor, CreateVariationContextAccessor()); var content = new Mock(); @@ -55,7 +55,7 @@ public class OutputExpansionStrategyV2Tests : OutputExpansionStrategyTestBase { // var accessor = CreateOutputExpansionStrategyAccessor(false, new[] { "element" }); var accessor = CreateOutputExpansionStrategyAccessor("properties[element[properties[$all]]]"); - var apiContentBuilder = new ApiContentBuilder(new ApiContentNameProvider(), ApiContentRouteBuilder(), accessor); + var apiContentBuilder = new ApiContentBuilder(new ApiContentNameProvider(), ApiContentRouteBuilder(), accessor, CreateVariationContextAccessor()); var apiElementBuilder = new ApiElementBuilder(accessor); var contentPickerValue = CreateSimplePickedContent(111, 222); @@ -98,7 +98,7 @@ public class OutputExpansionStrategyV2Tests : OutputExpansionStrategyTestBase public void OutputExpansionStrategy_CanExpandAllElements() { var accessor = CreateOutputExpansionStrategyAccessor("properties[element[properties[$all]],element2[properties[$all]]]" ); - var apiContentBuilder = new ApiContentBuilder(new ApiContentNameProvider(), ApiContentRouteBuilder(), accessor); + var apiContentBuilder = new ApiContentBuilder(new ApiContentNameProvider(), ApiContentRouteBuilder(), accessor, CreateVariationContextAccessor()); var apiElementBuilder = new ApiElementBuilder(accessor); var contentPickerValue = CreateSimplePickedContent(111, 222); @@ -155,7 +155,7 @@ public class OutputExpansionStrategyV2Tests : OutputExpansionStrategyTestBase public void OutputExpansionStrategy_DoesNotExpandElementNestedContentPicker() { var accessor = CreateOutputExpansionStrategyAccessor("properties[element[properties[contentPicker]]]" ); - var apiContentBuilder = new ApiContentBuilder(new ApiContentNameProvider(), ApiContentRouteBuilder(), accessor); + var apiContentBuilder = new ApiContentBuilder(new ApiContentNameProvider(), ApiContentRouteBuilder(), accessor, CreateVariationContextAccessor()); var apiElementBuilder = new ApiElementBuilder(accessor); var nestedContentPickerValue = CreateSimplePickedContent(111, 222); @@ -187,7 +187,7 @@ public class OutputExpansionStrategyV2Tests : OutputExpansionStrategyTestBase public void OutputExpansionStrategy_CanExpandElementNestedContentPicker() { var accessor = CreateOutputExpansionStrategyAccessor("properties[element[properties[contentPicker[properties[nestedContentPicker]]]]]"); - var apiContentBuilder = new ApiContentBuilder(new ApiContentNameProvider(), ApiContentRouteBuilder(), accessor); + var apiContentBuilder = new ApiContentBuilder(new ApiContentNameProvider(), ApiContentRouteBuilder(), accessor, CreateVariationContextAccessor()); var apiElementBuilder = new ApiElementBuilder(accessor); var nestedContentPickerValue = CreateSimplePickedContent(111, 222); @@ -221,7 +221,7 @@ public class OutputExpansionStrategyV2Tests : OutputExpansionStrategyTestBase public void OutputExpansionStrategy_CanExpandContentPickerBeyondTwoLevels() { var accessor = CreateOutputExpansionStrategyAccessor($"properties[level1Picker[properties[level2Picker[properties[level3Picker[properties[level4Picker]]]]]]]"); - var apiContentBuilder = new ApiContentBuilder(new ApiContentNameProvider(), ApiContentRouteBuilder(), accessor); + var apiContentBuilder = new ApiContentBuilder(new ApiContentNameProvider(), ApiContentRouteBuilder(), accessor, CreateVariationContextAccessor()); var content = new Mock(); @@ -268,7 +268,7 @@ public class OutputExpansionStrategyV2Tests : OutputExpansionStrategyTestBase public void OutputExpansionStrategy_CanLimitDirectFields(string includedField) { var accessor = CreateOutputExpansionStrategyAccessor(fields: $"properties[{includedField}]"); - var apiContentBuilder = new ApiContentBuilder(new ApiContentNameProvider(), ApiContentRouteBuilder(), accessor); + var apiContentBuilder = new ApiContentBuilder(new ApiContentNameProvider(), ApiContentRouteBuilder(), accessor, CreateVariationContextAccessor()); var content = CreateSimplePickedContent(123, 456); @@ -284,7 +284,7 @@ public class OutputExpansionStrategyV2Tests : OutputExpansionStrategyTestBase public void OutputExpansionStrategy_CanLimitFieldsOfExpandedContent(bool expand) { var accessor = CreateOutputExpansionStrategyAccessor(expand ? "properties[$all]" : null, "properties[contentPickerOne[properties[numberOne]],contentPickerTwo[properties[numberTwo]]]"); - var apiContentBuilder = new ApiContentBuilder(new ApiContentNameProvider(), ApiContentRouteBuilder(), accessor); + var apiContentBuilder = new ApiContentBuilder(new ApiContentNameProvider(), ApiContentRouteBuilder(), accessor, CreateVariationContextAccessor()); var content = new Mock(); From 9e481f3e4f4e7ffb58f7ac5e530a9669c0ab17aa Mon Sep 17 00:00:00 2001 From: Jacob Overgaard <752371+iOvergaard@users.noreply.github.com> Date: Tue, 29 Apr 2025 13:04:24 +0200 Subject: [PATCH 4/7] build: restores some of the behavior from V13 in relation to StaticAssets (#19189) In v13, the StaticAssets build was only triggered based on the existence of either the output folder or a preserve.* marker file. Here, we also additionally check for the node_modules/.package-lock.json file before reinstalling npm dependencies. We also now only run `npm install` rather than `npm ci` to optimise the build. --- .../Umbraco.Cms.StaticAssets.csproj | 77 +++++++++++++++---- 1 file changed, 62 insertions(+), 15 deletions(-) diff --git a/src/Umbraco.Cms.StaticAssets/Umbraco.Cms.StaticAssets.csproj b/src/Umbraco.Cms.StaticAssets/Umbraco.Cms.StaticAssets.csproj index d6fbf7ab37..3193533266 100644 --- a/src/Umbraco.Cms.StaticAssets/Umbraco.Cms.StaticAssets.csproj +++ b/src/Umbraco.Cms.StaticAssets/Umbraco.Cms.StaticAssets.csproj @@ -26,23 +26,36 @@ - + + + + + + + + ..\Umbraco.Web.UI.Client\ - wwwroot\umbraco\backoffice + $(ProjectDir)wwwroot\umbraco\backoffice - - - - + + + + + - + + + + + + @@ -61,27 +74,46 @@ - + + + + + + + + + + + + + + + + + + ..\Umbraco.Web.UI.Login\ - wwwroot\umbraco\login + $(ProjectDir)wwwroot\umbraco\login - - - - + + + + + + - + - + @@ -99,4 +131,19 @@ + + + + + + + + + + + + + + + From 30f0b2a1a915e6e6f7f83b0a2be051a2455d2a3d Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Tue, 29 Apr 2025 15:18:16 +0200 Subject: [PATCH 5/7] Open entity actions menu as pop up instead of modal (#19185) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Open entity actions menu as pop up instead of modal * Update entity-actions-bundle.element.ts * Update entity-actions-bundle.element.ts * ensure no indent for the menu items of the entity actions menu * add scroll container --------- Co-authored-by: Niels Lyngsø --- .../entity-actions-bundle.element.ts | 59 ++++++------------- .../entity-action-list.element.ts | 1 + 2 files changed, 18 insertions(+), 42 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/components/entity-actions-bundle/entity-actions-bundle.element.ts b/src/Umbraco.Web.UI.Client/src/packages/core/components/entity-actions-bundle/entity-actions-bundle.element.ts index 50f0b0cfee..1467fee2b9 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/components/entity-actions-bundle/entity-actions-bundle.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/components/entity-actions-bundle/entity-actions-bundle.element.ts @@ -1,9 +1,7 @@ import { UmbEntityContext } from '../../entity/entity.context.js'; import type { UmbEntityAction, ManifestEntityActionDefaultKind } from '@umbraco-cms/backoffice/entity-action'; import type { PropertyValueMap } from '@umbraco-cms/backoffice/external/lit'; -import { html, nothing, customElement, property, state, ifDefined } from '@umbraco-cms/backoffice/external/lit'; -import type { UmbSectionSidebarContext } from '@umbraco-cms/backoffice/section'; -import { UMB_SECTION_SIDEBAR_CONTEXT } from '@umbraco-cms/backoffice/section'; +import { html, nothing, customElement, property, state, ifDefined, css } from '@umbraco-cms/backoffice/external/lit'; import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element'; import { umbExtensionsRegistry } from '@umbraco-cms/backoffice/extension-registry'; import { UmbExtensionsManifestInitializer, createExtensionApi } from '@umbraco-cms/backoffice/extension-api'; @@ -34,19 +32,9 @@ export class UmbEntityActionsBundleElement extends UmbLitElement { @state() _dropdownIsOpen = false; - #sectionSidebarContext?: UmbSectionSidebarContext; - // TODO: provide the entity context on a higher level, like the root element of this entity, tree-item/workspace/... [NL] #entityContext = new UmbEntityContext(this); - constructor() { - super(); - - this.consumeContext(UMB_SECTION_SIDEBAR_CONTEXT, (sectionContext) => { - this.#sectionSidebarContext = sectionContext; - }); - } - protected override updated(_changedProperties: PropertyValueMap | Map): void { if (_changedProperties.has('entityType') && _changedProperties.has('unique')) { this.#entityContext.setEntityType(this.entityType); @@ -80,24 +68,7 @@ export class UmbEntityActionsBundleElement extends UmbLitElement { this._firstActionHref = await this._firstActionApi?.getHref(); } - #openContextMenu() { - if (!this.entityType) throw new Error('Entity type is not defined'); - if (this.unique === undefined) throw new Error('Unique is not defined'); - - if (this.#sectionSidebarContext) { - this.#sectionSidebarContext.toggleContextMenu(this, { - entityType: this.entityType, - unique: this.unique, - headline: this.label, - }); - } else { - this._dropdownIsOpen = !this._dropdownIsOpen; - } - } - async #onFirstActionClick(event: PointerEvent) { - this.#sectionSidebarContext?.closeContextMenu(); - // skip if href is defined if (this._firstActionHref) { return; @@ -123,19 +94,15 @@ export class UmbEntityActionsBundleElement extends UmbLitElement { #renderMore() { if (this._numberOfActions === 1) return nothing; - if (this.#sectionSidebarContext) { - return html` - - `; - } - return html` - - - + + + + + `; } @@ -149,6 +116,14 @@ export class UmbEntityActionsBundleElement extends UmbLitElement { `; } + + static override styles = [ + css` + uui-scroll-container { + max-height: 700px; + } + `, + ]; } declare global { diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/entity-action/entity-action-list.element.ts b/src/Umbraco.Web.UI.Client/src/packages/core/entity-action/entity-action-list.element.ts index 5d8549e1ec..83e181f67e 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/entity-action/entity-action-list.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/entity-action/entity-action-list.element.ts @@ -90,6 +90,7 @@ export class UmbEntityActionListElement extends UmbLitElement { static override styles = [ css` :host { + --uui-menu-item-indent: 0; --uui-menu-item-flat-structure: 1; } `, From 0a7d00182bb2c4904d522754fdfae201f8868fd0 Mon Sep 17 00:00:00 2001 From: Andy Butland Date: Tue, 29 Apr 2025 18:10:44 +0200 Subject: [PATCH 6/7] V13: Clear Member Username Cache in Load Balanced Environments (#19191) * Clear usernamekey * Odd explaining comment * Update src/Umbraco.Core/Cache/Refreshers/Implement/MemberCacheRefresher.cs Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Make UserNameCachePrefix readonly for better immutabilityly * Move prefix to CacheKeys constants --------- Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> # Conflicts: # src/Umbraco.Core/Cache/CacheKeys.cs --- src/Umbraco.Core/Cache/CacheKeys.cs | 2 ++ .../Implement/MemberCacheRefresher.cs | 17 ++++++++++++++--- .../Repositories/Implement/MemberRepository.cs | 7 +++---- 3 files changed, 19 insertions(+), 7 deletions(-) diff --git a/src/Umbraco.Core/Cache/CacheKeys.cs b/src/Umbraco.Core/Cache/CacheKeys.cs index 7f8484fca4..0e75b6820d 100644 --- a/src/Umbraco.Core/Cache/CacheKeys.cs +++ b/src/Umbraco.Core/Cache/CacheKeys.cs @@ -22,4 +22,6 @@ public static class CacheKeys public const string PreviewPropertyCacheKeyPrefix = "Cache.Property.CacheValues[D:"; public const string PropertyCacheKeyPrefix = "Cache.Property.CacheValues[P:"; + + public const string MemberUserNameCachePrefix = "uRepo_userNameKey+"; } diff --git a/src/Umbraco.Core/Cache/Refreshers/Implement/MemberCacheRefresher.cs b/src/Umbraco.Core/Cache/Refreshers/Implement/MemberCacheRefresher.cs index 18809a6bbe..1c19f62576 100644 --- a/src/Umbraco.Core/Cache/Refreshers/Implement/MemberCacheRefresher.cs +++ b/src/Umbraco.Core/Cache/Refreshers/Implement/MemberCacheRefresher.cs @@ -71,11 +71,22 @@ public sealed class MemberCacheRefresher : PayloadCacheRefresherBase(p.Id)); - memberCache.Result?.Clear(RepositoryCacheKeys.GetKey(p.Username)); + continue; } + + memberCache.Result?.Clear(RepositoryCacheKeys.GetKey(p.Id)); + memberCache.Result?.Clear(RepositoryCacheKeys.GetKey(p.Username)); + + // This specific cache key was introduced to fix an issue where the member username could not be the same as the member id, because the cache keys collided. + // This is done in a bit of a hacky way, because the cache key is created internally in the repository, but we need to clear it here. + // Ideally, we want to use a shared way of generating the key between this and the repository. + // Additionally, the RepositoryCacheKeys actually caches the string to avoid re-allocating memory; we would like to also use this in the repository + // See: + // https://github.com/umbraco/Umbraco-CMS/pull/17350 + // https://github.com/umbraco/Umbraco-CMS/pull/17815 + memberCache.Result?.Clear(RepositoryCacheKeys.GetKey(CacheKeys.MemberUserNameCachePrefix + p.Username)); } } } diff --git a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/MemberRepository.cs b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/MemberRepository.cs index 75ea4f365d..9adc60426f 100644 --- a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/MemberRepository.cs +++ b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/MemberRepository.cs @@ -39,7 +39,6 @@ public class MemberRepository : ContentRepositoryBase - _memberByUsernameCachePolicy.GetByUserName(UsernameCacheKey, username, PerformGetByUsername, PerformGetAllByUsername); + _memberByUsernameCachePolicy.GetByUserName(CacheKeys.MemberUserNameCachePrefix, username, PerformGetByUsername, PerformGetAllByUsername); public int[] GetMemberIds(string[] usernames) { @@ -609,7 +608,7 @@ public class MemberRepository : ContentRepositoryBase Date: Wed, 30 Apr 2025 09:58:17 +0200 Subject: [PATCH 7/7] Ensure picker search config query params are always included in the server request (#19194) * ensure picker search config query params are always included * fix type error --- src/Umbraco.Web.UI.Client/src/packages/core/modal/types.ts | 4 ++-- .../core/picker/search/manager/picker-search.manager.ts | 4 +++- .../src/packages/core/picker/search/manager/types.ts | 3 ++- .../tree/tree-picker-modal/tree-picker-modal.element.ts | 7 ------- 4 files changed, 7 insertions(+), 11 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/modal/types.ts b/src/Umbraco.Web.UI.Client/src/packages/core/modal/types.ts index 061086786c..97b3ebb81e 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/modal/types.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/modal/types.ts @@ -10,9 +10,9 @@ export interface UmbPickerModalData { search?: UmbPickerModalSearchConfig; } -export interface UmbPickerModalSearchConfig { +export interface UmbPickerModalSearchConfig> { providerAlias: string; - queryParams?: object; + queryParams?: QueryParamsType; } export interface UmbPickerModalValue { diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/picker/search/manager/picker-search.manager.ts b/src/Umbraco.Web.UI.Client/src/packages/core/picker/search/manager/picker-search.manager.ts index c2c593269d..290f596a25 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/picker/search/manager/picker-search.manager.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/picker/search/manager/picker-search.manager.ts @@ -183,8 +183,10 @@ export class UmbPickerSearchManager< } const args = { - searchFrom: this.#config?.searchFrom, ...query, + // ensure that config params are always included + ...this.#config?.queryParams, + searchFrom: this.#config?.searchFrom, }; const { data } = await this.#searchProvider.search(args); diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/picker/search/manager/types.ts b/src/Umbraco.Web.UI.Client/src/packages/core/picker/search/manager/types.ts index a8ef1e5a67..452fe3a538 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/picker/search/manager/types.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/picker/search/manager/types.ts @@ -1,6 +1,7 @@ import type { UmbEntityModel } from '@umbraco-cms/backoffice/entity'; -export interface UmbPickerSearchManagerConfig { +export interface UmbPickerSearchManagerConfig> { providerAlias: string; searchFrom?: UmbEntityModel; + queryParams?: QueryParamsType; } diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/tree/tree-picker-modal/tree-picker-modal.element.ts b/src/Umbraco.Web.UI.Client/src/packages/core/tree/tree-picker-modal/tree-picker-modal.element.ts index 2e81abbbea..bb1fe200de 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/tree/tree-picker-modal/tree-picker-modal.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/tree/tree-picker-modal/tree-picker-modal.element.ts @@ -58,13 +58,6 @@ export class UmbTreePickerModalElement