From 7777ba40fd13d025bb578099eaff456f9ba1e384 Mon Sep 17 00:00:00 2001 From: Kenn Jacobsen Date: Mon, 10 Oct 2022 12:58:50 +0200 Subject: [PATCH 01/53] Fix broken selectable state for list view items (#13148) --- .../src/views/content/apps/listview/listview.controller.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/views/content/apps/listview/listview.controller.js b/src/Umbraco.Web.UI.Client/src/views/content/apps/listview/listview.controller.js index 5dd205790c..3114d0d1ce 100644 --- a/src/Umbraco.Web.UI.Client/src/views/content/apps/listview/listview.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/content/apps/listview/listview.controller.js @@ -9,9 +9,9 @@ function propertyEditorReadonly () { // check for permission to update - return !(typeof $scope.variantContent !== 'undefined' && $scope.variantContent.allowedActions.includes('A')); + return $scope.variantContent && !$scope.variantContent.allowedActions.includes('A'); } - + } angular.module("umbraco").controller("Umbraco.Editors.Content.Apps.ListViewController", ContentAppListViewController); From b8c73e755089617488b633c0f304aeccfd9cbfb3 Mon Sep 17 00:00:00 2001 From: Kenn Jacobsen Date: Wed, 12 Oct 2022 10:06:43 +0200 Subject: [PATCH 02/53] Add sync rendering extensions for block grid and async ones for block list (#13168) --- .../Extensions/BlockGridTemplateExtensions.cs | 65 +++++++++++++++---- .../Extensions/BlockListTemplateExtensions.cs | 51 ++++++++++++--- 2 files changed, 96 insertions(+), 20 deletions(-) diff --git a/src/Umbraco.Web.Common/Extensions/BlockGridTemplateExtensions.cs b/src/Umbraco.Web.Common/Extensions/BlockGridTemplateExtensions.cs index 4cae63426b..c8afbf0e68 100644 --- a/src/Umbraco.Web.Common/Extensions/BlockGridTemplateExtensions.cs +++ b/src/Umbraco.Web.Common/Extensions/BlockGridTemplateExtensions.cs @@ -15,6 +15,8 @@ public static class BlockGridTemplateExtensions public const string DefaultItemsTemplate = "items"; public const string DefaultItemAreasTemplate = "areas"; + #region Async + public static async Task GetBlockGridHtmlAsync(this IHtmlHelper html, BlockGridModel? model, string template = DefaultTemplate) { if (model?.Count == 0) @@ -22,8 +24,7 @@ public static class BlockGridTemplateExtensions return new HtmlString(string.Empty); } - var view = $"{DefaultFolder}{template}"; - return await html.PartialAsync(view, model); + return await html.PartialAsync(DefaultFolderTemplate(template), model); } public static async Task GetBlockGridHtmlAsync(this IHtmlHelper html, IPublishedProperty property, string template = DefaultTemplate) @@ -33,6 +34,54 @@ public static class BlockGridTemplateExtensions => await GetBlockGridHtmlAsync(html, contentItem, propertyAlias, DefaultTemplate); public static async Task GetBlockGridHtmlAsync(this IHtmlHelper html, IPublishedContent contentItem, string propertyAlias, string template) + { + IPublishedProperty prop = GetRequiredProperty(contentItem, propertyAlias); + return await GetBlockGridHtmlAsync(html, prop.GetValue() as BlockGridModel, template); + } + + public static async Task GetBlockGridItemsHtmlAsync(this IHtmlHelper html, IEnumerable items, string template = DefaultItemsTemplate) + => await html.PartialAsync(DefaultFolderTemplate(template), items); + + public static async Task GetBlockGridItemAreasHtmlAsync(this IHtmlHelper html, BlockGridItem item, string template = DefaultItemAreasTemplate) + => await html.PartialAsync(DefaultFolderTemplate(template), item); + + #endregion + + #region Sync + + public static IHtmlContent GetBlockGridHtml(this IHtmlHelper html, BlockGridModel? model, string template = DefaultTemplate) + { + if (model?.Count == 0) + { + return new HtmlString(string.Empty); + } + + return html.Partial(DefaultFolderTemplate(template), model); + } + + public static IHtmlContent GetBlockGridHtml(this IHtmlHelper html, IPublishedProperty property, string template = DefaultTemplate) + => GetBlockGridHtml(html, property.GetValue() as BlockGridModel, template); + + public static IHtmlContent GetBlockGridHtml(this IHtmlHelper html, IPublishedContent contentItem, string propertyAlias) + => GetBlockGridHtml(html, contentItem, propertyAlias, DefaultTemplate); + + public static IHtmlContent GetBlockGridHtml(this IHtmlHelper html, IPublishedContent contentItem, string propertyAlias, string template) + { + IPublishedProperty prop = GetRequiredProperty(contentItem, propertyAlias); + return GetBlockGridHtml(html, prop.GetValue() as BlockGridModel, template); + } + + public static IHtmlContent GetBlockGridItemsHtml(this IHtmlHelper html, IEnumerable items, string template = DefaultItemsTemplate) + => html.Partial(DefaultFolderTemplate(template), items); + + public static IHtmlContent GetBlockGridItemAreasHtml(this IHtmlHelper html, BlockGridItem item, string template = DefaultItemAreasTemplate) + => html.Partial(DefaultFolderTemplate(template), item); + + #endregion + + private static string DefaultFolderTemplate(string template) => $"{DefaultFolder}{template}"; + + private static IPublishedProperty GetRequiredProperty(IPublishedContent contentItem, string propertyAlias) { ArgumentNullException.ThrowIfNull(propertyAlias); @@ -43,18 +92,12 @@ public static class BlockGridTemplateExtensions nameof(propertyAlias)); } - IPublishedProperty? prop = contentItem.GetProperty(propertyAlias); - if (prop == null) + IPublishedProperty? property = contentItem.GetProperty(propertyAlias); + if (property == null) { throw new InvalidOperationException("No property type found with alias " + propertyAlias); } - return await GetBlockGridHtmlAsync(html, prop.GetValue() as BlockGridModel, template); + return property; } - - public static async Task GetBlockGridItemsHtmlAsync(this IHtmlHelper html, IEnumerable items, string template = DefaultItemsTemplate) - => await html.PartialAsync($"{DefaultFolder}{template}", items); - - public static async Task GetBlockGridItemAreasHtmlAsync(this IHtmlHelper html, BlockGridItem item, string template = DefaultItemAreasTemplate) - => await html.PartialAsync($"{DefaultFolder}{template}", item); } diff --git a/src/Umbraco.Web.Common/Extensions/BlockListTemplateExtensions.cs b/src/Umbraco.Web.Common/Extensions/BlockListTemplateExtensions.cs index 17b620ab51..edf3055159 100644 --- a/src/Umbraco.Web.Common/Extensions/BlockListTemplateExtensions.cs +++ b/src/Umbraco.Web.Common/Extensions/BlockListTemplateExtensions.cs @@ -10,6 +10,33 @@ public static class BlockListTemplateExtensions public const string DefaultFolder = "blocklist/"; public const string DefaultTemplate = "default"; + #region Async + + public static async Task GetBlockListHtmlAsync(this IHtmlHelper html, BlockListModel? model, string template = DefaultTemplate) + { + if (model?.Count == 0) + { + return new HtmlString(string.Empty); + } + + return await html.PartialAsync(DefaultFolderTemplate(template), model); + } + + public static async Task GetBlockListHtmlAsync(this IHtmlHelper html, IPublishedProperty property, string template = DefaultTemplate) + => await GetBlockListHtmlAsync(html, property.GetValue() as BlockListModel, template); + + public static async Task GetBlockListHtmlAsync(this IHtmlHelper html, IPublishedContent contentItem, string propertyAlias) + => await GetBlockListHtmlAsync(html, contentItem, propertyAlias, DefaultTemplate); + + public static async Task GetBlockListHtmlAsync(this IHtmlHelper html, IPublishedContent contentItem, string propertyAlias, string template) + { + IPublishedProperty property = GetRequiredProperty(contentItem, propertyAlias); + return await GetBlockListHtmlAsync(html, property.GetValue() as BlockListModel, template); + } + #endregion + + #region Sync + public static IHtmlContent GetBlockListHtml(this IHtmlHelper html, BlockListModel? model, string template = DefaultTemplate) { if (model?.Count == 0) @@ -17,8 +44,7 @@ public static class BlockListTemplateExtensions return new HtmlString(string.Empty); } - var view = DefaultFolder + template; - return html.Partial(view, model); + return html.Partial(DefaultFolderTemplate(template), model); } public static IHtmlContent GetBlockListHtml(this IHtmlHelper html, IPublishedProperty property, string template = DefaultTemplate) @@ -29,10 +55,17 @@ public static class BlockListTemplateExtensions public static IHtmlContent GetBlockListHtml(this IHtmlHelper html, IPublishedContent contentItem, string propertyAlias, string template) { - if (propertyAlias == null) - { - throw new ArgumentNullException(nameof(propertyAlias)); - } + IPublishedProperty property = GetRequiredProperty(contentItem, propertyAlias); + return GetBlockListHtml(html, property.GetValue() as BlockListModel, template); + } + + #endregion + + private static string DefaultFolderTemplate(string template) => $"{DefaultFolder}{template}"; + + private static IPublishedProperty GetRequiredProperty(IPublishedContent contentItem, string propertyAlias) + { + ArgumentNullException.ThrowIfNull(propertyAlias); if (string.IsNullOrWhiteSpace(propertyAlias)) { @@ -41,12 +74,12 @@ public static class BlockListTemplateExtensions nameof(propertyAlias)); } - IPublishedProperty? prop = contentItem.GetProperty(propertyAlias); - if (prop == null) + IPublishedProperty? property = contentItem.GetProperty(propertyAlias); + if (property == null) { throw new InvalidOperationException("No property type found with alias " + propertyAlias); } - return GetBlockListHtml(html, prop.GetValue() as BlockListModel, template); + return property; } } From d13a55762a7cb1130cdfee15982dc40da0f4b74b Mon Sep 17 00:00:00 2001 From: Nikolaj Date: Wed, 12 Oct 2022 10:29:46 +0200 Subject: [PATCH 03/53] Re-add IsPackable to Umbraco.Tests.Integration --- tests/Umbraco.Tests.Integration/Umbraco.Tests.Integration.csproj | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/Umbraco.Tests.Integration/Umbraco.Tests.Integration.csproj b/tests/Umbraco.Tests.Integration/Umbraco.Tests.Integration.csproj index 10424d2c14..76f030d6bc 100644 --- a/tests/Umbraco.Tests.Integration/Umbraco.Tests.Integration.csproj +++ b/tests/Umbraco.Tests.Integration/Umbraco.Tests.Integration.csproj @@ -3,6 +3,7 @@ Umbraco.Cms.Tests.Integration Umbraco CMS - Integration tests Contains helper classes for integration tests with Umbraco CMS, including all internal integration tests. + true true Umbraco.Cms.Tests.Integration From 4a412bb432a9dd05629bec3daa8fe7c86573ea63 Mon Sep 17 00:00:00 2001 From: Jacob Overgaard <752371+iOvergaard@users.noreply.github.com> Date: Wed, 12 Oct 2022 12:39:11 +0200 Subject: [PATCH 04/53] Fix for potential race condition in packages search (#13153) * search on input allowing to wait for copy/paste etc * invoke resourcePromise() with correct parameters * return the xhrStatus allowing the caller to check if the request was aborted * fix: send in canceler.promise to allow the timeout to work * catch any errors and ignore aborts if they happen * move the logic to handle cancellations outside Angulars $scope.$apply * remove file accidentally committed --- .../ourpackagerrepository.resource.js | 8 ++-- .../services/umbrequesthelper.service.js | 3 +- .../views/packages/views/repo.controller.js | 38 +++++++++++++------ .../src/views/packages/views/repo.html | 2 +- 4 files changed, 34 insertions(+), 17 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/common/resources/ourpackagerrepository.resource.js b/src/Umbraco.Web.UI.Client/src/common/resources/ourpackagerrepository.resource.js index be13e6d0ec..430f05c2c4 100644 --- a/src/Umbraco.Web.UI.Client/src/common/resources/ourpackagerrepository.resource.js +++ b/src/Umbraco.Web.UI.Client/src/common/resources/ourpackagerrepository.resource.js @@ -57,7 +57,7 @@ function ourPackageRepositoryResource($q, $http, umbDataFormatter, umbRequestHel if (canceler) { httpConfig["timeout"] = canceler; } - + if (category === undefined) { category = ""; } @@ -69,8 +69,10 @@ function ourPackageRepositoryResource($q, $http, umbDataFormatter, umbRequestHel var order = !orderBy ? "&order=Default" : ("&order=" + orderBy); return umbRequestHelper.resourcePromise( - $http.get(baseurl + "?pageIndex=" + pageIndex + "&pageSize=" + pageSize + "&category=" + category + "&query=" + query + order + "&version=" + Umbraco.Sys.ServerVariables.application.version), - httpConfig, + $http.get( + baseurl + "?pageIndex=" + pageIndex + "&pageSize=" + pageSize + "&category=" + category + "&query=" + query + order + "&version=" + Umbraco.Sys.ServerVariables.application.version, + httpConfig + ), 'Failed to query packages'); } diff --git a/src/Umbraco.Web.UI.Client/src/common/services/umbrequesthelper.service.js b/src/Umbraco.Web.UI.Client/src/common/services/umbrequesthelper.service.js index 2b5447cdf6..b419600653 100644 --- a/src/Umbraco.Web.UI.Client/src/common/services/umbrequesthelper.service.js +++ b/src/Umbraco.Web.UI.Client/src/common/services/umbrequesthelper.service.js @@ -197,7 +197,8 @@ function umbRequestHelper($http, $q, notificationsService, eventsService, formHe return $q.reject({ errorMsg: result.errorMsg, data: result.data, - status: result.status + status: result.status, + xhrStatus: response.xhrStatus }); }); diff --git a/src/Umbraco.Web.UI.Client/src/views/packages/views/repo.controller.js b/src/Umbraco.Web.UI.Client/src/views/packages/views/repo.controller.js index 8360663be6..b690efacdf 100644 --- a/src/Umbraco.Web.UI.Client/src/views/packages/views/repo.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/packages/views/repo.controller.js @@ -1,7 +1,7 @@ (function () { "use strict"; - function PackagesRepoController($scope, $timeout, ourPackageRepositoryResource, $q, localizationService) { + function PackagesRepoController($scope, $timeout, ourPackageRepositoryResource, $q, localizationService, notificationsService) { var vm = this; @@ -197,18 +197,14 @@ var searchDebounced = _.debounce(function (e) { + //a canceler exists, so perform the cancelation operation and reset + if (canceler) { + canceler.resolve(); + } - $scope.$apply(function () { - - //a canceler exists, so perform the cancelation operation and reset - if (canceler) { - canceler.resolve(); - canceler = $q.defer(); - } - else { - canceler = $q.defer(); - } + canceler = $q.defer(); + $scope.$apply(function () { currSort = vm.searchQuery ? "Default" : "Latest"; ourPackageRepositoryResource.search(vm.pagination.pageNumber - 1, @@ -216,7 +212,7 @@ currSort, "", vm.searchQuery, - canceler) + canceler.promise) .then(function (pack) { vm.packages = pack.packages; vm.pagination.totalPages = Math.ceil(pack.total / vm.pagination.pageSize); @@ -224,6 +220,24 @@ vm.loading = false; //set back to null so it can be re-created canceler = null; + }) + .catch(function (err) { + canceler = null; + + if (err) { + // If an abort happened, ignore it since it happened because of a new search + if (err.xhrStatus === 'abort') { + return; + } + + // Otherwise, show the error + if (err.errorMsg) { + notificationsService.error(err.errorMsg); + return; + } + } + + console.error(err); }); }); diff --git a/src/Umbraco.Web.UI.Client/src/views/packages/views/repo.html b/src/Umbraco.Web.UI.Client/src/views/packages/views/repo.html index f7e976de1e..1c3e3ec5d8 100644 --- a/src/Umbraco.Web.UI.Client/src/views/packages/views/repo.html +++ b/src/Umbraco.Web.UI.Client/src/views/packages/views/repo.html @@ -17,7 +17,7 @@ localize="placeholder" placeholder="@packager_packageSearch" ng-model="vm.searchQuery" - ng-change="vm.search()" + ng-on-input="vm.search()" no-dirty-check /> From 6e7ecd0a7725646dbd294cf05d0d2eae688a621a Mon Sep 17 00:00:00 2001 From: Jacob Overgaard <752371+iOvergaard@users.noreply.github.com> Date: Wed, 12 Oct 2022 12:39:11 +0200 Subject: [PATCH 05/53] Fix for potential race condition in packages search (#13153) * search on input allowing to wait for copy/paste etc * invoke resourcePromise() with correct parameters * return the xhrStatus allowing the caller to check if the request was aborted * fix: send in canceler.promise to allow the timeout to work * catch any errors and ignore aborts if they happen * move the logic to handle cancellations outside Angulars $scope.$apply * remove file accidentally committed (cherry picked from commit 4a412bb432a9dd05629bec3daa8fe7c86573ea63) --- .../ourpackagerrepository.resource.js | 8 ++-- .../services/umbrequesthelper.service.js | 3 +- .../views/packages/views/repo.controller.js | 38 +++++++++++++------ .../src/views/packages/views/repo.html | 2 +- 4 files changed, 34 insertions(+), 17 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/common/resources/ourpackagerrepository.resource.js b/src/Umbraco.Web.UI.Client/src/common/resources/ourpackagerrepository.resource.js index be13e6d0ec..430f05c2c4 100644 --- a/src/Umbraco.Web.UI.Client/src/common/resources/ourpackagerrepository.resource.js +++ b/src/Umbraco.Web.UI.Client/src/common/resources/ourpackagerrepository.resource.js @@ -57,7 +57,7 @@ function ourPackageRepositoryResource($q, $http, umbDataFormatter, umbRequestHel if (canceler) { httpConfig["timeout"] = canceler; } - + if (category === undefined) { category = ""; } @@ -69,8 +69,10 @@ function ourPackageRepositoryResource($q, $http, umbDataFormatter, umbRequestHel var order = !orderBy ? "&order=Default" : ("&order=" + orderBy); return umbRequestHelper.resourcePromise( - $http.get(baseurl + "?pageIndex=" + pageIndex + "&pageSize=" + pageSize + "&category=" + category + "&query=" + query + order + "&version=" + Umbraco.Sys.ServerVariables.application.version), - httpConfig, + $http.get( + baseurl + "?pageIndex=" + pageIndex + "&pageSize=" + pageSize + "&category=" + category + "&query=" + query + order + "&version=" + Umbraco.Sys.ServerVariables.application.version, + httpConfig + ), 'Failed to query packages'); } diff --git a/src/Umbraco.Web.UI.Client/src/common/services/umbrequesthelper.service.js b/src/Umbraco.Web.UI.Client/src/common/services/umbrequesthelper.service.js index 2b5447cdf6..b419600653 100644 --- a/src/Umbraco.Web.UI.Client/src/common/services/umbrequesthelper.service.js +++ b/src/Umbraco.Web.UI.Client/src/common/services/umbrequesthelper.service.js @@ -197,7 +197,8 @@ function umbRequestHelper($http, $q, notificationsService, eventsService, formHe return $q.reject({ errorMsg: result.errorMsg, data: result.data, - status: result.status + status: result.status, + xhrStatus: response.xhrStatus }); }); diff --git a/src/Umbraco.Web.UI.Client/src/views/packages/views/repo.controller.js b/src/Umbraco.Web.UI.Client/src/views/packages/views/repo.controller.js index 8360663be6..b690efacdf 100644 --- a/src/Umbraco.Web.UI.Client/src/views/packages/views/repo.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/packages/views/repo.controller.js @@ -1,7 +1,7 @@ (function () { "use strict"; - function PackagesRepoController($scope, $timeout, ourPackageRepositoryResource, $q, localizationService) { + function PackagesRepoController($scope, $timeout, ourPackageRepositoryResource, $q, localizationService, notificationsService) { var vm = this; @@ -197,18 +197,14 @@ var searchDebounced = _.debounce(function (e) { + //a canceler exists, so perform the cancelation operation and reset + if (canceler) { + canceler.resolve(); + } - $scope.$apply(function () { - - //a canceler exists, so perform the cancelation operation and reset - if (canceler) { - canceler.resolve(); - canceler = $q.defer(); - } - else { - canceler = $q.defer(); - } + canceler = $q.defer(); + $scope.$apply(function () { currSort = vm.searchQuery ? "Default" : "Latest"; ourPackageRepositoryResource.search(vm.pagination.pageNumber - 1, @@ -216,7 +212,7 @@ currSort, "", vm.searchQuery, - canceler) + canceler.promise) .then(function (pack) { vm.packages = pack.packages; vm.pagination.totalPages = Math.ceil(pack.total / vm.pagination.pageSize); @@ -224,6 +220,24 @@ vm.loading = false; //set back to null so it can be re-created canceler = null; + }) + .catch(function (err) { + canceler = null; + + if (err) { + // If an abort happened, ignore it since it happened because of a new search + if (err.xhrStatus === 'abort') { + return; + } + + // Otherwise, show the error + if (err.errorMsg) { + notificationsService.error(err.errorMsg); + return; + } + } + + console.error(err); }); }); diff --git a/src/Umbraco.Web.UI.Client/src/views/packages/views/repo.html b/src/Umbraco.Web.UI.Client/src/views/packages/views/repo.html index f7e976de1e..1c3e3ec5d8 100644 --- a/src/Umbraco.Web.UI.Client/src/views/packages/views/repo.html +++ b/src/Umbraco.Web.UI.Client/src/views/packages/views/repo.html @@ -17,7 +17,7 @@ localize="placeholder" placeholder="@packager_packageSearch" ng-model="vm.searchQuery" - ng-change="vm.search()" + ng-on-input="vm.search()" no-dirty-check /> From 29ae87ec6129387cba4a0c81c3402a85ccefc502 Mon Sep 17 00:00:00 2001 From: Mole Date: Thu, 13 Oct 2022 08:17:02 +0200 Subject: [PATCH 06/53] V10: Fix request accessor memory leak (#13152) * Dispose OnChange event registration when disposing the notification handler * Ensure that the ApplicationUrl is only initialized once Since notifications handlers are transient,_hasAppUrl and _isInit defaults to false on every request causing it to always be called. * Make notification handler and EnsureApplicationUrl internal --- ...ationUrlRequestBeginNotificationHandler.cs | 26 ++++++++++++++ .../AspNetCore/AspNetCoreRequestAccessor.cs | 35 +++++++++++++------ .../UmbracoBuilderExtensions.cs | 1 + 3 files changed, 51 insertions(+), 11 deletions(-) create mode 100644 src/Umbraco.Web.Common/AspNetCore/ApplicationUrlRequestBeginNotificationHandler.cs diff --git a/src/Umbraco.Web.Common/AspNetCore/ApplicationUrlRequestBeginNotificationHandler.cs b/src/Umbraco.Web.Common/AspNetCore/ApplicationUrlRequestBeginNotificationHandler.cs new file mode 100644 index 0000000000..0472d31592 --- /dev/null +++ b/src/Umbraco.Web.Common/AspNetCore/ApplicationUrlRequestBeginNotificationHandler.cs @@ -0,0 +1,26 @@ +using Umbraco.Cms.Core.Events; +using Umbraco.Cms.Core.Notifications; +using Umbraco.Cms.Core.Web; + +namespace Umbraco.Cms.Web.Common.AspNetCore; + +/// +/// Notification handler which will listen to the , and ensure that +/// the applicationUrl is set on the first request. +/// +internal class ApplicationUrlRequestBeginNotificationHandler : INotificationHandler +{ + private readonly IRequestAccessor _requestAccessor; + + public ApplicationUrlRequestBeginNotificationHandler(IRequestAccessor requestAccessor) => + _requestAccessor = requestAccessor; + + public void Handle(UmbracoRequestBeginNotification notification) + { + // If someone has replaced the AspNetCoreRequestAccessor we'll do nothing and assume they handle it themselves. + if (_requestAccessor is AspNetCoreRequestAccessor accessor) + { + accessor.EnsureApplicationUrl(); + } + } +} diff --git a/src/Umbraco.Web.Common/AspNetCore/AspNetCoreRequestAccessor.cs b/src/Umbraco.Web.Common/AspNetCore/AspNetCoreRequestAccessor.cs index 38d67ff2f0..de47999835 100644 --- a/src/Umbraco.Web.Common/AspNetCore/AspNetCoreRequestAccessor.cs +++ b/src/Umbraco.Web.Common/AspNetCore/AspNetCoreRequestAccessor.cs @@ -9,7 +9,7 @@ using Umbraco.Extensions; namespace Umbraco.Cms.Web.Common.AspNetCore; -public class AspNetCoreRequestAccessor : IRequestAccessor, INotificationHandler +public class AspNetCoreRequestAccessor : IRequestAccessor, INotificationHandler, IDisposable { private readonly ISet _applicationUrls = new HashSet(); private readonly IHttpContextAccessor _httpContextAccessor; @@ -18,6 +18,7 @@ public class AspNetCoreRequestAccessor : IRequestAccessor, INotificationHandler< private object _initLocker = new(); private bool _isInit; private WebRoutingSettings _webRoutingSettings; + private readonly IDisposable? _onChangeDisposable; /// /// Initializes a new instance of the class. @@ -28,20 +29,19 @@ public class AspNetCoreRequestAccessor : IRequestAccessor, INotificationHandler< { _httpContextAccessor = httpContextAccessor; _webRoutingSettings = webRoutingSettings.CurrentValue; - webRoutingSettings.OnChange(x => _webRoutingSettings = x); + _onChangeDisposable = webRoutingSettings.OnChange(x => _webRoutingSettings = x); } /// - /// This just initializes the application URL on first request attempt - /// TODO: This doesn't belong here, the GetApplicationUrl doesn't belong to IRequestAccessor - /// this should be part of middleware not a lazy init based on an INotification + /// + /// This is now a NoOp, and is no longer used, instead ApplicationUrlRequestBeginNotificationHandler is used + /// /// + [Obsolete("This is no longer used, AspNetCoreRequestAccessor will no longer implement INotificationHandler in V12, see ApplicationUrlRequestBeginNotificationHandler instead.")] public void Handle(UmbracoRequestBeginNotification notification) - => LazyInitializer.EnsureInitialized(ref _hasAppUrl, ref _isInit, ref _initLocker, () => - { - GetApplicationUrl(); - return true; - }); + { + // NoOP + } /// public string GetRequestValue(string name) => GetFormValue(name) ?? GetQueryStringValue(name); @@ -54,6 +54,17 @@ public class AspNetCoreRequestAccessor : IRequestAccessor, INotificationHandler< ? new Uri(_httpContextAccessor.HttpContext.Request.GetEncodedUrl()) : null; + /// + /// Ensure that the ApplicationUrl is set on the first request, this is using a LazyInitializer, so the code will only be run the first time + /// + /// TODO: This doesn't belong here, the GetApplicationUrl doesn't belong to IRequestAccessor + internal void EnsureApplicationUrl() => + LazyInitializer.EnsureInitialized(ref _hasAppUrl, ref _isInit, ref _initLocker, () => + { + GetApplicationUrl(); + return true; + }); + public Uri? GetApplicationUrl() { // Fixme: This causes problems with site swap on azure because azure pre-warms a site by calling into `localhost` and when it does that @@ -63,7 +74,7 @@ public class AspNetCoreRequestAccessor : IRequestAccessor, INotificationHandler< // see U4-10626 - in some cases we want to reset the application url // (this is a simplified version of what was in 7.x) // note: should this be optional? is it expensive? - if (!(_webRoutingSettings.UmbracoApplicationUrl is null)) + if (_webRoutingSettings.UmbracoApplicationUrl is not null) { return new Uri(_webRoutingSettings.UmbracoApplicationUrl); } @@ -96,4 +107,6 @@ public class AspNetCoreRequestAccessor : IRequestAccessor, INotificationHandler< return request.Form[name]; } + + public void Dispose() => _onChangeDisposable?.Dispose(); } diff --git a/src/Umbraco.Web.Common/DependencyInjection/UmbracoBuilderExtensions.cs b/src/Umbraco.Web.Common/DependencyInjection/UmbracoBuilderExtensions.cs index 40b84a0987..d454e5d6c5 100644 --- a/src/Umbraco.Web.Common/DependencyInjection/UmbracoBuilderExtensions.cs +++ b/src/Umbraco.Web.Common/DependencyInjection/UmbracoBuilderExtensions.cs @@ -298,6 +298,7 @@ public static partial class UmbracoBuilderExtensions // AspNetCore specific services builder.Services.AddUnique(); builder.AddNotificationHandler(); + builder.AddNotificationHandler(); // Password hasher builder.Services.AddUnique(); From 9f6d5e954340ca737294450b6355390647d07693 Mon Sep 17 00:00:00 2001 From: Mole Date: Thu, 13 Oct 2022 08:24:50 +0200 Subject: [PATCH 07/53] Add missing ForceLeft and ForceRight (#13190) --- .../Models/Blocks/BlockGridLayoutItem.cs | 6 ++++++ .../ValueConverters/BlockGridPropertyValueConverter.cs | 2 ++ 2 files changed, 8 insertions(+) diff --git a/src/Umbraco.Infrastructure/Models/Blocks/BlockGridLayoutItem.cs b/src/Umbraco.Infrastructure/Models/Blocks/BlockGridLayoutItem.cs index 30494b03f7..9014e2789a 100644 --- a/src/Umbraco.Infrastructure/Models/Blocks/BlockGridLayoutItem.cs +++ b/src/Umbraco.Infrastructure/Models/Blocks/BlockGridLayoutItem.cs @@ -25,6 +25,12 @@ public class BlockGridLayoutItem : IBlockLayoutItem [JsonProperty("rowSpan", NullValueHandling = NullValueHandling.Ignore)] public int? RowSpan { get; set; } + [JsonProperty("forceLeft")] + public bool ForceLeft { get; set; } + + [JsonProperty("forceRight")] + public bool ForceRight { get; set; } + [JsonProperty("areas", NullValueHandling = NullValueHandling.Ignore)] public BlockGridLayoutAreaItem[] Areas { get; set; } = Array.Empty(); } diff --git a/src/Umbraco.Infrastructure/PropertyEditors/ValueConverters/BlockGridPropertyValueConverter.cs b/src/Umbraco.Infrastructure/PropertyEditors/ValueConverters/BlockGridPropertyValueConverter.cs index ae330870fa..6cd2d4bd38 100644 --- a/src/Umbraco.Infrastructure/PropertyEditors/ValueConverters/BlockGridPropertyValueConverter.cs +++ b/src/Umbraco.Infrastructure/PropertyEditors/ValueConverters/BlockGridPropertyValueConverter.cs @@ -49,6 +49,8 @@ namespace Umbraco.Cms.Core.PropertyEditors.ValueConverters blockItem.RowSpan = layoutItem.RowSpan!.Value; blockItem.ColumnSpan = layoutItem.ColumnSpan!.Value; + blockItem.ForceLeft = layoutItem.ForceLeft; + blockItem.ForceRight = layoutItem.ForceRight; blockItem.AreaGridColumns = blockConfig.AreaGridColumns; blockItem.GridColumns = configuration.GridColumns; blockItem.Areas = layoutItem.Areas.Select(area => From 0b3a06ff0da01e0730ae81c7206f9b428a6a744f Mon Sep 17 00:00:00 2001 From: Mole Date: Thu, 13 Oct 2022 08:17:02 +0200 Subject: [PATCH 08/53] V10: Fix request accessor memory leak (#13152) * Dispose OnChange event registration when disposing the notification handler * Ensure that the ApplicationUrl is only initialized once Since notifications handlers are transient,_hasAppUrl and _isInit defaults to false on every request causing it to always be called. * Make notification handler and EnsureApplicationUrl internal --- ...ationUrlRequestBeginNotificationHandler.cs | 26 ++++++++++++++ .../AspNetCore/AspNetCoreRequestAccessor.cs | 35 +++++++++++++------ .../UmbracoBuilderExtensions.cs | 1 + 3 files changed, 51 insertions(+), 11 deletions(-) create mode 100644 src/Umbraco.Web.Common/AspNetCore/ApplicationUrlRequestBeginNotificationHandler.cs diff --git a/src/Umbraco.Web.Common/AspNetCore/ApplicationUrlRequestBeginNotificationHandler.cs b/src/Umbraco.Web.Common/AspNetCore/ApplicationUrlRequestBeginNotificationHandler.cs new file mode 100644 index 0000000000..0472d31592 --- /dev/null +++ b/src/Umbraco.Web.Common/AspNetCore/ApplicationUrlRequestBeginNotificationHandler.cs @@ -0,0 +1,26 @@ +using Umbraco.Cms.Core.Events; +using Umbraco.Cms.Core.Notifications; +using Umbraco.Cms.Core.Web; + +namespace Umbraco.Cms.Web.Common.AspNetCore; + +/// +/// Notification handler which will listen to the , and ensure that +/// the applicationUrl is set on the first request. +/// +internal class ApplicationUrlRequestBeginNotificationHandler : INotificationHandler +{ + private readonly IRequestAccessor _requestAccessor; + + public ApplicationUrlRequestBeginNotificationHandler(IRequestAccessor requestAccessor) => + _requestAccessor = requestAccessor; + + public void Handle(UmbracoRequestBeginNotification notification) + { + // If someone has replaced the AspNetCoreRequestAccessor we'll do nothing and assume they handle it themselves. + if (_requestAccessor is AspNetCoreRequestAccessor accessor) + { + accessor.EnsureApplicationUrl(); + } + } +} diff --git a/src/Umbraco.Web.Common/AspNetCore/AspNetCoreRequestAccessor.cs b/src/Umbraco.Web.Common/AspNetCore/AspNetCoreRequestAccessor.cs index 38d67ff2f0..de47999835 100644 --- a/src/Umbraco.Web.Common/AspNetCore/AspNetCoreRequestAccessor.cs +++ b/src/Umbraco.Web.Common/AspNetCore/AspNetCoreRequestAccessor.cs @@ -9,7 +9,7 @@ using Umbraco.Extensions; namespace Umbraco.Cms.Web.Common.AspNetCore; -public class AspNetCoreRequestAccessor : IRequestAccessor, INotificationHandler +public class AspNetCoreRequestAccessor : IRequestAccessor, INotificationHandler, IDisposable { private readonly ISet _applicationUrls = new HashSet(); private readonly IHttpContextAccessor _httpContextAccessor; @@ -18,6 +18,7 @@ public class AspNetCoreRequestAccessor : IRequestAccessor, INotificationHandler< private object _initLocker = new(); private bool _isInit; private WebRoutingSettings _webRoutingSettings; + private readonly IDisposable? _onChangeDisposable; /// /// Initializes a new instance of the class. @@ -28,20 +29,19 @@ public class AspNetCoreRequestAccessor : IRequestAccessor, INotificationHandler< { _httpContextAccessor = httpContextAccessor; _webRoutingSettings = webRoutingSettings.CurrentValue; - webRoutingSettings.OnChange(x => _webRoutingSettings = x); + _onChangeDisposable = webRoutingSettings.OnChange(x => _webRoutingSettings = x); } /// - /// This just initializes the application URL on first request attempt - /// TODO: This doesn't belong here, the GetApplicationUrl doesn't belong to IRequestAccessor - /// this should be part of middleware not a lazy init based on an INotification + /// + /// This is now a NoOp, and is no longer used, instead ApplicationUrlRequestBeginNotificationHandler is used + /// /// + [Obsolete("This is no longer used, AspNetCoreRequestAccessor will no longer implement INotificationHandler in V12, see ApplicationUrlRequestBeginNotificationHandler instead.")] public void Handle(UmbracoRequestBeginNotification notification) - => LazyInitializer.EnsureInitialized(ref _hasAppUrl, ref _isInit, ref _initLocker, () => - { - GetApplicationUrl(); - return true; - }); + { + // NoOP + } /// public string GetRequestValue(string name) => GetFormValue(name) ?? GetQueryStringValue(name); @@ -54,6 +54,17 @@ public class AspNetCoreRequestAccessor : IRequestAccessor, INotificationHandler< ? new Uri(_httpContextAccessor.HttpContext.Request.GetEncodedUrl()) : null; + /// + /// Ensure that the ApplicationUrl is set on the first request, this is using a LazyInitializer, so the code will only be run the first time + /// + /// TODO: This doesn't belong here, the GetApplicationUrl doesn't belong to IRequestAccessor + internal void EnsureApplicationUrl() => + LazyInitializer.EnsureInitialized(ref _hasAppUrl, ref _isInit, ref _initLocker, () => + { + GetApplicationUrl(); + return true; + }); + public Uri? GetApplicationUrl() { // Fixme: This causes problems with site swap on azure because azure pre-warms a site by calling into `localhost` and when it does that @@ -63,7 +74,7 @@ public class AspNetCoreRequestAccessor : IRequestAccessor, INotificationHandler< // see U4-10626 - in some cases we want to reset the application url // (this is a simplified version of what was in 7.x) // note: should this be optional? is it expensive? - if (!(_webRoutingSettings.UmbracoApplicationUrl is null)) + if (_webRoutingSettings.UmbracoApplicationUrl is not null) { return new Uri(_webRoutingSettings.UmbracoApplicationUrl); } @@ -96,4 +107,6 @@ public class AspNetCoreRequestAccessor : IRequestAccessor, INotificationHandler< return request.Form[name]; } + + public void Dispose() => _onChangeDisposable?.Dispose(); } diff --git a/src/Umbraco.Web.Common/DependencyInjection/UmbracoBuilderExtensions.cs b/src/Umbraco.Web.Common/DependencyInjection/UmbracoBuilderExtensions.cs index 40b84a0987..d454e5d6c5 100644 --- a/src/Umbraco.Web.Common/DependencyInjection/UmbracoBuilderExtensions.cs +++ b/src/Umbraco.Web.Common/DependencyInjection/UmbracoBuilderExtensions.cs @@ -298,6 +298,7 @@ public static partial class UmbracoBuilderExtensions // AspNetCore specific services builder.Services.AddUnique(); builder.AddNotificationHandler(); + builder.AddNotificationHandler(); // Password hasher builder.Services.AddUnique(); From 213dd7114daf4318f7da6489e5a9bce22acd225a Mon Sep 17 00:00:00 2001 From: Mole Date: Thu, 13 Oct 2022 08:24:50 +0200 Subject: [PATCH 09/53] Add missing ForceLeft and ForceRight (#13190) --- .../Models/Blocks/BlockGridLayoutItem.cs | 6 ++++++ .../ValueConverters/BlockGridPropertyValueConverter.cs | 2 ++ 2 files changed, 8 insertions(+) diff --git a/src/Umbraco.Infrastructure/Models/Blocks/BlockGridLayoutItem.cs b/src/Umbraco.Infrastructure/Models/Blocks/BlockGridLayoutItem.cs index 30494b03f7..9014e2789a 100644 --- a/src/Umbraco.Infrastructure/Models/Blocks/BlockGridLayoutItem.cs +++ b/src/Umbraco.Infrastructure/Models/Blocks/BlockGridLayoutItem.cs @@ -25,6 +25,12 @@ public class BlockGridLayoutItem : IBlockLayoutItem [JsonProperty("rowSpan", NullValueHandling = NullValueHandling.Ignore)] public int? RowSpan { get; set; } + [JsonProperty("forceLeft")] + public bool ForceLeft { get; set; } + + [JsonProperty("forceRight")] + public bool ForceRight { get; set; } + [JsonProperty("areas", NullValueHandling = NullValueHandling.Ignore)] public BlockGridLayoutAreaItem[] Areas { get; set; } = Array.Empty(); } diff --git a/src/Umbraco.Infrastructure/PropertyEditors/ValueConverters/BlockGridPropertyValueConverter.cs b/src/Umbraco.Infrastructure/PropertyEditors/ValueConverters/BlockGridPropertyValueConverter.cs index ae330870fa..6cd2d4bd38 100644 --- a/src/Umbraco.Infrastructure/PropertyEditors/ValueConverters/BlockGridPropertyValueConverter.cs +++ b/src/Umbraco.Infrastructure/PropertyEditors/ValueConverters/BlockGridPropertyValueConverter.cs @@ -49,6 +49,8 @@ namespace Umbraco.Cms.Core.PropertyEditors.ValueConverters blockItem.RowSpan = layoutItem.RowSpan!.Value; blockItem.ColumnSpan = layoutItem.ColumnSpan!.Value; + blockItem.ForceLeft = layoutItem.ForceLeft; + blockItem.ForceRight = layoutItem.ForceRight; blockItem.AreaGridColumns = blockConfig.AreaGridColumns; blockItem.GridColumns = configuration.GridColumns; blockItem.Areas = layoutItem.Areas.Select(area => From 63af4c487c7e6e3179fcb11e2607133c8ea2eebf Mon Sep 17 00:00:00 2001 From: Nikolaj Geisle <70372949+Zeegaan@users.noreply.github.com> Date: Mon, 10 Oct 2022 16:15:53 +0200 Subject: [PATCH 10/53] Pass the node property to umb-property & umb-property-editor (#13151) Co-authored-by: Zeegaan --- .../src/views/components/content/umb-tabbed-content.html | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/Umbraco.Web.UI.Client/src/views/components/content/umb-tabbed-content.html b/src/Umbraco.Web.UI.Client/src/views/components/content/umb-tabbed-content.html index f161c76ee0..8215c66691 100644 --- a/src/Umbraco.Web.UI.Client/src/views/components/content/umb-tabbed-content.html +++ b/src/Umbraco.Web.UI.Client/src/views/components/content/umb-tabbed-content.html @@ -11,17 +11,19 @@ data-element="property-{{property.alias}}" ng-repeat="property in tab.properties track by property.alias" property="property" + node="contentNodeModel" show-inherit="contentNodeModel.variants.length > 1 && property.variation !== 'CultureAndSegment'" inherits-from="defaultVariant.displayName"> - + From 76b54c4b63f2a6e498a49c4ed8c84e1aff07dd1a Mon Sep 17 00:00:00 2001 From: Nikolaj Geisle <70372949+Zeegaan@users.noreply.github.com> Date: Tue, 11 Oct 2022 15:57:01 +0200 Subject: [PATCH 11/53] V10: 13099 fix validation error (#13170) * Add validation error message to Viewpicker * Add help-inline class to make validation-text red Co-authored-by: Zeegaan --- .../views/dataTypes/views/datatype.settings.html | 8 ++++---- .../macros/views/macro.settings.controller.js | 8 ++++---- .../src/views/macros/views/settings.html | 15 ++++++++++----- 3 files changed, 18 insertions(+), 13 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/views/dataTypes/views/datatype.settings.html b/src/Umbraco.Web.UI.Client/src/views/dataTypes/views/datatype.settings.html index b4422dc49e..f0eb5b535b 100644 --- a/src/Umbraco.Web.UI.Client/src/views/dataTypes/views/datatype.settings.html +++ b/src/Umbraco.Web.UI.Client/src/views/dataTypes/views/datatype.settings.html @@ -8,9 +8,9 @@ -
@@ -23,7 +23,7 @@ ng-click="vm.openPropertyEditorPicker()"> -
+
Required diff --git a/src/Umbraco.Web.UI.Client/src/views/macros/views/macro.settings.controller.js b/src/Umbraco.Web.UI.Client/src/views/macros/views/macro.settings.controller.js index 5f633a6e4b..fd7889a7a6 100644 --- a/src/Umbraco.Web.UI.Client/src/views/macros/views/macro.settings.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/macros/views/macro.settings.controller.js @@ -14,11 +14,11 @@ function MacrosSettingsController($scope, editorService, localizationService) { //vm.removeMacroView = removeMacroView; $scope.model.openViewPicker = openViewPicker; $scope.model.removeMacroView = removeMacroView; - var labels = {}; - + vm.macroPartialViewPickerProperty = { alias : "macroPartialViewPickerProperty", description: "", label: "Macro partial view", validation: {mandatory : true}} localizationService.localizeMany(["macro_selectViewFile"]).then(function(data) { labels.selectViewFile = data[0]; + vm.macroPartialViewPickerProperty.description = data[0]; }); function openViewPicker() { @@ -45,7 +45,7 @@ function MacrosSettingsController($scope, editorService, localizationService) { name: $scope.model.macro.view }; - //$scope.model.submit($scope.model); + //$scope.model.submit($scope.model); editorService.close(); }, @@ -63,7 +63,7 @@ function MacrosSettingsController($scope, editorService, localizationService) { } function init() { - + } init(); diff --git a/src/Umbraco.Web.UI.Client/src/views/macros/views/settings.html b/src/Umbraco.Web.UI.Client/src/views/macros/views/settings.html index c152c33193..9b79061654 100644 --- a/src/Umbraco.Web.UI.Client/src/views/macros/views/settings.html +++ b/src/Umbraco.Web.UI.Client/src/views/macros/views/settings.html @@ -5,10 +5,9 @@
- - - + + - + - +
+ + Required + +
+ +
From ab8d94b4666dae923e6eeef5bad7e1d11eb1cd58 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niels=20Lyngs=C3=B8?= Date: Thu, 13 Oct 2022 08:41:31 +0200 Subject: [PATCH 12/53] move clear:both; to the flexbox example (#13194) --- .../src/views/propertyeditors/blockgrid/blockgridui.less | 6 +----- .../blockgrid/umbraco-blockgridlayout-flexbox.css | 5 +++++ 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/blockgrid/blockgridui.less b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/blockgrid/blockgridui.less index f23632389c..78b7852540 100644 --- a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/blockgrid/blockgridui.less +++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/blockgrid/blockgridui.less @@ -633,8 +633,6 @@ umb-block-grid-block { border-radius: @baseBorderRadius; box-sizing: border-box; - clear: both;// needed for layouts using float. - &:hover { border-color: transparent; > button { @@ -651,7 +649,6 @@ umb-block-grid-block { > button { position: relative; display: flex; - //width: 100%; align-items: center; justify-content: center; @@ -687,7 +684,7 @@ umb-block-grid-block { &.umb-block-grid__clipboard-button { margin-left: 0; padding: 5px 12px; - font-size: 18px;// Align with block action buttons. + font-size: 18px; border-top-left-radius: 0; border-bottom-left-radius: 0; @@ -739,7 +736,6 @@ umb-block-grid-block { > button { position: relative; display: flex; - //width: 100%; align-items: center; justify-content: center; diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/blockgrid/umbraco-blockgridlayout-flexbox.css b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/blockgrid/umbraco-blockgridlayout-flexbox.css index 94974a9111..962126b969 100644 --- a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/blockgrid/umbraco-blockgridlayout-flexbox.css +++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/blockgrid/umbraco-blockgridlayout-flexbox.css @@ -33,4 +33,9 @@ .umb-block-grid__area { --umb-block-grid__area-calc: calc(var(--umb-block-grid--area-column-span) / var(--umb-block-grid--area-grid-columns, 1)); width: calc(var(--umb-block-grid__area-calc) * 100%); +} + + +.umb-block-grid__actions { + clear: both; } \ No newline at end of file From ff75fcd36e900d7ffd5f183147398f1c3058d3d6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niels=20Lyngs=C3=B8?= Date: Thu, 13 Oct 2022 08:42:49 +0200 Subject: [PATCH 13/53] remove pointer-events from Image, to make drag n' drop work on firefox. (#13193) --- .../umbBlockGridDemoImageBlock.html | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Umbraco.Cms.StaticAssets/wwwroot/App_Plugins/Umbraco.BlockGridEditor.DefaultCustomViews/umbBlockGridDemoImageBlock.html b/src/Umbraco.Cms.StaticAssets/wwwroot/App_Plugins/Umbraco.BlockGridEditor.DefaultCustomViews/umbBlockGridDemoImageBlock.html index 521d7c9b09..e02ae35c85 100644 --- a/src/Umbraco.Cms.StaticAssets/wwwroot/App_Plugins/Umbraco.BlockGridEditor.DefaultCustomViews/umbBlockGridDemoImageBlock.html +++ b/src/Umbraco.Cms.StaticAssets/wwwroot/App_Plugins/Umbraco.BlockGridEditor.DefaultCustomViews/umbBlockGridDemoImageBlock.html @@ -35,7 +35,6 @@ color: #2152A3;// TODO: Set right colors: } img { - pointer-events: none; object-fit: cover; height: 100%; width: 100%; From a0931d2042a76cb6fc2d3b3bc248b44430301736 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niels=20Lyngs=C3=B8?= Date: Thu, 13 Oct 2022 08:43:43 +0200 Subject: [PATCH 14/53] area permission min-max inputs width increase (#13195) --- .../prevalue/umb-block-grid-area-allowance-editor.less | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/blockgrid/prevalue/umb-block-grid-area-allowance-editor.less b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/blockgrid/prevalue/umb-block-grid-area-allowance-editor.less index 11907dfcb0..9389906fac 100644 --- a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/blockgrid/prevalue/umb-block-grid-area-allowance-editor.less +++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/blockgrid/prevalue/umb-block-grid-area-allowance-editor.less @@ -20,7 +20,7 @@ margin: 0 3px; } input { - width: 40px; + width: 60px; } } From cdc994dd8ee16f539e0115c514f8b1168f48fd10 Mon Sep 17 00:00:00 2001 From: Elitsa Marinovska <21998037+elit0451@users.noreply.github.com> Date: Thu, 13 Oct 2022 08:59:53 +0200 Subject: [PATCH 15/53] Fix tags with CSV storage type (#13188) * Fixing null check as default(NRT) is null => default(configuration?.Delimiter) is also null and we were counting on it being the same as default(char) * Adding tests to check cases with multiple tags (or tag made of comma separated values) --- .../Models/PropertyTagsExtensions.cs | 2 +- .../Services/ContentServiceTagsTests.cs | 73 +++++++++++++++++++ 2 files changed, 74 insertions(+), 1 deletion(-) diff --git a/src/Umbraco.Core/Models/PropertyTagsExtensions.cs b/src/Umbraco.Core/Models/PropertyTagsExtensions.cs index 9ad98d66c0..d36baed604 100644 --- a/src/Umbraco.Core/Models/PropertyTagsExtensions.cs +++ b/src/Umbraco.Core/Models/PropertyTagsExtensions.cs @@ -33,7 +33,7 @@ public static class PropertyTagsExtensions : dataTypeService.GetDataType(property.PropertyType.DataTypeId)?.Configuration; TagConfiguration? configuration = ConfigurationEditor.ConfigurationAs(configurationObject); - if (configuration?.Delimiter == default && configuration?.Delimiter is not null) + if (configuration is not null && configuration.Delimiter == default) { configuration.Delimiter = tagAttribute.Delimiter; } diff --git a/tests/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/ContentServiceTagsTests.cs b/tests/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/ContentServiceTagsTests.cs index 25e7aa1009..9179b6cd69 100644 --- a/tests/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/ContentServiceTagsTests.cs +++ b/tests/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/ContentServiceTagsTests.cs @@ -638,6 +638,9 @@ public class ContentServiceTagsTests : UmbracoIntegrationTest var dataType = DataTypeService.GetDataType(1041); dataType.Configuration = new TagConfiguration { Group = "test", StorageType = TagsStorageType.Csv }; + // updating the data type with the new configuration + DataTypeService.Save(dataType); + var template = TemplateBuilder.CreateTextPageTemplate(); FileService.SaveTemplate(template); @@ -822,6 +825,76 @@ public class ContentServiceTagsTests : UmbracoIntegrationTest } } + [Test] + public void Does_Not_Save_Multiple_Tags_As_One_When_CSV_Storage() + { + // Arrange + // set configuration + var dataType = DataTypeService.GetDataType(1041); + dataType.Configuration = new TagConfiguration { Group = "test", StorageType = TagsStorageType.Csv }; + + // updating the data type with the new configuration + DataTypeService.Save(dataType); + + var template = TemplateBuilder.CreateTextPageTemplate(); + FileService.SaveTemplate(template); + + var contentType = ContentTypeBuilder.CreateSimpleContentType("umbMandatory", "Mandatory Doc Type", + mandatoryProperties: true, defaultTemplateId: template.Id); + CreateAndAddTagsPropertyType(contentType); + + ContentTypeService.Save(contentType); + + IContent content = ContentBuilder.CreateSimpleContent(contentType, "Tagged content"); + content.AssignTags(PropertyEditorCollection, DataTypeService, Serializer, "tags", + new[] { "hello,world,tags", "new"}); + + ContentService.SaveAndPublish(content); + + // Act + content = ContentService.GetById(content.Id); + var savedTags = content.Properties["tags"].GetTagsValue(PropertyEditorCollection, DataTypeService, Serializer) + .ToArray(); + + // Assert + Assert.AreEqual(4, savedTags.Length); + } + + [Test] + public void Can_Save_Tag_With_Comma_Separated_Values_As_One_When_JSON_Storage() + { + // Arrange + // set configuration + var dataType = DataTypeService.GetDataType(1041); + dataType.Configuration = new TagConfiguration { Group = "test", StorageType = TagsStorageType.Json }; + + // updating the data type with the new configuration + DataTypeService.Save(dataType); + + var template = TemplateBuilder.CreateTextPageTemplate(); + FileService.SaveTemplate(template); + + var contentType = ContentTypeBuilder.CreateSimpleContentType("umbMandatory", "Mandatory Doc Type", + mandatoryProperties: true, defaultTemplateId: template.Id); + CreateAndAddTagsPropertyType(contentType); + + ContentTypeService.Save(contentType); + + IContent content = ContentBuilder.CreateSimpleContent(contentType, "Tagged content"); + content.AssignTags(PropertyEditorCollection, DataTypeService, Serializer, "tags", + new[] { "hello,world,tags", "new"}); + + ContentService.SaveAndPublish(content); + + // Act + content = ContentService.GetById(content.Id); + var savedTags = content.Properties["tags"].GetTagsValue(PropertyEditorCollection, DataTypeService, Serializer) + .ToArray(); + + // Assert + Assert.AreEqual(2, savedTags.Length); + } + private PropertyType CreateAndAddTagsPropertyType(ContentType contentType, ContentVariation variations = ContentVariation.Nothing) { From 0fe2c225cb8fc0dde74dd9a511b05b66c21c6430 Mon Sep 17 00:00:00 2001 From: Elitsa Marinovska <21998037+elit0451@users.noreply.github.com> Date: Thu, 13 Oct 2022 08:59:53 +0200 Subject: [PATCH 16/53] Fix tags with CSV storage type (#13188) * Fixing null check as default(NRT) is null => default(configuration?.Delimiter) is also null and we were counting on it being the same as default(char) * Adding tests to check cases with multiple tags (or tag made of comma separated values) --- .../Models/PropertyTagsExtensions.cs | 2 +- .../Services/ContentServiceTagsTests.cs | 73 +++++++++++++++++++ 2 files changed, 74 insertions(+), 1 deletion(-) diff --git a/src/Umbraco.Core/Models/PropertyTagsExtensions.cs b/src/Umbraco.Core/Models/PropertyTagsExtensions.cs index 9ad98d66c0..d36baed604 100644 --- a/src/Umbraco.Core/Models/PropertyTagsExtensions.cs +++ b/src/Umbraco.Core/Models/PropertyTagsExtensions.cs @@ -33,7 +33,7 @@ public static class PropertyTagsExtensions : dataTypeService.GetDataType(property.PropertyType.DataTypeId)?.Configuration; TagConfiguration? configuration = ConfigurationEditor.ConfigurationAs(configurationObject); - if (configuration?.Delimiter == default && configuration?.Delimiter is not null) + if (configuration is not null && configuration.Delimiter == default) { configuration.Delimiter = tagAttribute.Delimiter; } diff --git a/tests/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/ContentServiceTagsTests.cs b/tests/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/ContentServiceTagsTests.cs index 25e7aa1009..9179b6cd69 100644 --- a/tests/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/ContentServiceTagsTests.cs +++ b/tests/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/ContentServiceTagsTests.cs @@ -638,6 +638,9 @@ public class ContentServiceTagsTests : UmbracoIntegrationTest var dataType = DataTypeService.GetDataType(1041); dataType.Configuration = new TagConfiguration { Group = "test", StorageType = TagsStorageType.Csv }; + // updating the data type with the new configuration + DataTypeService.Save(dataType); + var template = TemplateBuilder.CreateTextPageTemplate(); FileService.SaveTemplate(template); @@ -822,6 +825,76 @@ public class ContentServiceTagsTests : UmbracoIntegrationTest } } + [Test] + public void Does_Not_Save_Multiple_Tags_As_One_When_CSV_Storage() + { + // Arrange + // set configuration + var dataType = DataTypeService.GetDataType(1041); + dataType.Configuration = new TagConfiguration { Group = "test", StorageType = TagsStorageType.Csv }; + + // updating the data type with the new configuration + DataTypeService.Save(dataType); + + var template = TemplateBuilder.CreateTextPageTemplate(); + FileService.SaveTemplate(template); + + var contentType = ContentTypeBuilder.CreateSimpleContentType("umbMandatory", "Mandatory Doc Type", + mandatoryProperties: true, defaultTemplateId: template.Id); + CreateAndAddTagsPropertyType(contentType); + + ContentTypeService.Save(contentType); + + IContent content = ContentBuilder.CreateSimpleContent(contentType, "Tagged content"); + content.AssignTags(PropertyEditorCollection, DataTypeService, Serializer, "tags", + new[] { "hello,world,tags", "new"}); + + ContentService.SaveAndPublish(content); + + // Act + content = ContentService.GetById(content.Id); + var savedTags = content.Properties["tags"].GetTagsValue(PropertyEditorCollection, DataTypeService, Serializer) + .ToArray(); + + // Assert + Assert.AreEqual(4, savedTags.Length); + } + + [Test] + public void Can_Save_Tag_With_Comma_Separated_Values_As_One_When_JSON_Storage() + { + // Arrange + // set configuration + var dataType = DataTypeService.GetDataType(1041); + dataType.Configuration = new TagConfiguration { Group = "test", StorageType = TagsStorageType.Json }; + + // updating the data type with the new configuration + DataTypeService.Save(dataType); + + var template = TemplateBuilder.CreateTextPageTemplate(); + FileService.SaveTemplate(template); + + var contentType = ContentTypeBuilder.CreateSimpleContentType("umbMandatory", "Mandatory Doc Type", + mandatoryProperties: true, defaultTemplateId: template.Id); + CreateAndAddTagsPropertyType(contentType); + + ContentTypeService.Save(contentType); + + IContent content = ContentBuilder.CreateSimpleContent(contentType, "Tagged content"); + content.AssignTags(PropertyEditorCollection, DataTypeService, Serializer, "tags", + new[] { "hello,world,tags", "new"}); + + ContentService.SaveAndPublish(content); + + // Act + content = ContentService.GetById(content.Id); + var savedTags = content.Properties["tags"].GetTagsValue(PropertyEditorCollection, DataTypeService, Serializer) + .ToArray(); + + // Assert + Assert.AreEqual(2, savedTags.Length); + } + private PropertyType CreateAndAddTagsPropertyType(ContentType contentType, ContentVariation variations = ContentVariation.Nothing) { From 0a925fd3ba2f0f4656bddb523fcc10a44561122c Mon Sep 17 00:00:00 2001 From: Kenn Jacobsen Date: Thu, 13 Oct 2022 10:02:27 +0200 Subject: [PATCH 17/53] Add documentation for default block grid partial views in the rendering extension methods (#13184) --- .../Extensions/BlockGridTemplateExtensions.cs | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/src/Umbraco.Web.Common/Extensions/BlockGridTemplateExtensions.cs b/src/Umbraco.Web.Common/Extensions/BlockGridTemplateExtensions.cs index c8afbf0e68..ee0375da4f 100644 --- a/src/Umbraco.Web.Common/Extensions/BlockGridTemplateExtensions.cs +++ b/src/Umbraco.Web.Common/Extensions/BlockGridTemplateExtensions.cs @@ -17,6 +17,19 @@ public static class BlockGridTemplateExtensions #region Async + /// + /// Renders a block grid model into a grid layout + /// + /// + /// By default this method uses a set of built-in partial views for rendering the blocks and areas in the grid model. + /// These partial views are embedded in the static assets (Umbraco.Cms.StaticAssets), so they won't show up in the + /// Views folder on your local disk. + /// + /// If you need to tweak the grid rendering output, you can copy the partial views from GitHub to your local disk. + /// The partial views are found in "/src/Umbraco.Cms.StaticAssets/Views/Partials/blockgrid/" on GitHub and should + /// be copied to "Views/Partials/BlockGrid/" on your local disk. + /// + /// public static async Task GetBlockGridHtmlAsync(this IHtmlHelper html, BlockGridModel? model, string template = DefaultTemplate) { if (model?.Count == 0) @@ -27,9 +40,11 @@ public static class BlockGridTemplateExtensions return await html.PartialAsync(DefaultFolderTemplate(template), model); } + /// public static async Task GetBlockGridHtmlAsync(this IHtmlHelper html, IPublishedProperty property, string template = DefaultTemplate) => await GetBlockGridHtmlAsync(html, property.GetValue() as BlockGridModel, template); + /// public static async Task GetBlockGridHtmlAsync(this IHtmlHelper html, IPublishedContent contentItem, string propertyAlias) => await GetBlockGridHtmlAsync(html, contentItem, propertyAlias, DefaultTemplate); @@ -49,6 +64,7 @@ public static class BlockGridTemplateExtensions #region Sync + /// public static IHtmlContent GetBlockGridHtml(this IHtmlHelper html, BlockGridModel? model, string template = DefaultTemplate) { if (model?.Count == 0) @@ -59,9 +75,11 @@ public static class BlockGridTemplateExtensions return html.Partial(DefaultFolderTemplate(template), model); } + /// public static IHtmlContent GetBlockGridHtml(this IHtmlHelper html, IPublishedProperty property, string template = DefaultTemplate) => GetBlockGridHtml(html, property.GetValue() as BlockGridModel, template); + /// public static IHtmlContent GetBlockGridHtml(this IHtmlHelper html, IPublishedContent contentItem, string propertyAlias) => GetBlockGridHtml(html, contentItem, propertyAlias, DefaultTemplate); From 2fa61fe811ef3fd1411cc96bb017588e4394fb44 Mon Sep 17 00:00:00 2001 From: Nikolaj Geisle <70372949+Zeegaan@users.noreply.github.com> Date: Thu, 13 Oct 2022 10:29:50 +0200 Subject: [PATCH 18/53] Add data-element to umb property so we can find it (#13199) Co-authored-by: Zeegaan --- .../src/views/components/property/umb-property.html | 6 +++--- .../src/views/macros/views/settings.html | 1 + .../tests/DefaultConfig/Settings/macro.spec.ts | 2 +- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/views/components/property/umb-property.html b/src/Umbraco.Web.UI.Client/src/views/components/property/umb-property.html index 8d0087b395..f00ba725b2 100644 --- a/src/Umbraco.Web.UI.Client/src/views/components/property/umb-property.html +++ b/src/Umbraco.Web.UI.Client/src/views/components/property/umb-property.html @@ -9,7 +9,7 @@
- + @@ -41,11 +41,11 @@ {{ vm.property.culture }} - + - + {{ vm.property.segment }} Default diff --git a/src/Umbraco.Web.UI.Client/src/views/macros/views/settings.html b/src/Umbraco.Web.UI.Client/src/views/macros/views/settings.html index 9b79061654..0975da878a 100644 --- a/src/Umbraco.Web.UI.Client/src/views/macros/views/settings.html +++ b/src/Umbraco.Web.UI.Client/src/views/macros/views/settings.html @@ -21,6 +21,7 @@ diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/blocklist/prevalue/blocklist.blockconfiguration.overlay.html b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/blocklist/prevalue/blocklist.blockconfiguration.overlay.html index cc324f70d5..58ca11b716 100644 --- a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/blocklist/prevalue/blocklist.blockconfiguration.overlay.html +++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/blocklist/prevalue/blocklist.blockconfiguration.overlay.html @@ -26,9 +26,9 @@
- +
- +
@@ -36,7 +36,7 @@
- + Overwrite how this block appears in the BackOffice UI. Pick a .html file containing your presentation. @@ -50,7 +50,7 @@
-
@@ -60,7 +60,7 @@
- +
@@ -71,7 +71,7 @@
-
@@ -81,9 +81,9 @@
- +
- @@ -107,12 +107,12 @@
- +
-
@@ -124,7 +124,7 @@
- +
@@ -137,7 +137,7 @@
-
@@ -157,9 +157,10 @@
- +
@@ -171,9 +172,10 @@
- +
@@ -185,7 +187,7 @@
- +
@@ -196,7 +198,7 @@
-
@@ -218,9 +220,13 @@
- +
- + +
From 37424a63ec2bd420bf35a99b7cc07374147f9577 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niels=20Lyngs=C3=B8?= Date: Mon, 17 Oct 2022 13:55:22 +0200 Subject: [PATCH 22/53] make Area fit within block row (#13221) --- .../umbBlockGridDemoImageBlock.html | 1 - .../src/views/propertyeditors/blockgrid/blockgridui.less | 3 ++- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Umbraco.Cms.StaticAssets/wwwroot/App_Plugins/Umbraco.BlockGridEditor.DefaultCustomViews/umbBlockGridDemoImageBlock.html b/src/Umbraco.Cms.StaticAssets/wwwroot/App_Plugins/Umbraco.BlockGridEditor.DefaultCustomViews/umbBlockGridDemoImageBlock.html index e02ae35c85..c9da7ab143 100644 --- a/src/Umbraco.Cms.StaticAssets/wwwroot/App_Plugins/Umbraco.BlockGridEditor.DefaultCustomViews/umbBlockGridDemoImageBlock.html +++ b/src/Umbraco.Cms.StaticAssets/wwwroot/App_Plugins/Umbraco.BlockGridEditor.DefaultCustomViews/umbBlockGridDemoImageBlock.html @@ -19,7 +19,6 @@ justify-content: center; width: 100%; height: 100%; - min-height: 100%; cursor: pointer; color: black; background-color: transparent; diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/blockgrid/blockgridui.less b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/blockgrid/blockgridui.less index 78b7852540..41628aca5e 100644 --- a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/blockgrid/blockgridui.less +++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/blockgrid/blockgridui.less @@ -279,7 +279,8 @@ ng-form.ng-invalid > .umb-block-grid__block:not(.--active) > .umb-block-grid__bl .umb-block-grid__block--view { height: 100%; width: 100%; - display: block; + display: flex; + flex-direction: column; } .umb-block-grid__block--context { From 8d8e4e0b24ab2012854d671b5f666e6e8feed2a9 Mon Sep 17 00:00:00 2001 From: Matt Darby Date: Mon, 17 Oct 2022 13:02:25 +0100 Subject: [PATCH 23/53] 10.3.0-RC: Change grid area input to number + change generic label (#13203) Co-authored-by: Bjarne Fyrstenborg --- .../prevalue/blockgrid.blockconfiguration.overlay.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/blockgrid/prevalue/blockgrid.blockconfiguration.overlay.html b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/blockgrid/prevalue/blockgrid.blockconfiguration.overlay.html index 29b3f4b53f..4b05e4ad43 100644 --- a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/blockgrid/prevalue/blockgrid.blockconfiguration.overlay.html +++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/blockgrid/prevalue/blockgrid.blockconfiguration.overlay.html @@ -260,12 +260,12 @@
- + Define how many layout columns that will be available for areas. If not defined, the number of layout columns defined for the entire layout will be used.
- +
From 96bf197642dd71cb8c46d5da130574ccb0b79ddd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niels=20Lyngs=C3=B8?= Date: Mon, 17 Oct 2022 14:35:59 +0200 Subject: [PATCH 24/53] move below center, to make room (#13222) --- .../blockgrid/prevalue/umb-block-grid-area-editor.less | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/blockgrid/prevalue/umb-block-grid-area-editor.less b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/blockgrid/prevalue/umb-block-grid-area-editor.less index d4a1487b40..bf66c34661 100644 --- a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/blockgrid/prevalue/umb-block-grid-area-editor.less +++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/blockgrid/prevalue/umb-block-grid-area-editor.less @@ -163,9 +163,10 @@ Grid part: .umb-block-grid-area-editor__scale-label { position: absolute; display: block; - left: 100%; - margin-left: 6px; + right: 0; + top: 100%; margin-top: 6px; + transform: translateX(50%); z-index: 2; background-color: white; From 2993f1bb6d022a4b99172d6bd50ddf5b8698c8bc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niels=20Lyngs=C3=B8?= Date: Tue, 18 Oct 2022 08:21:54 +0200 Subject: [PATCH 25/53] highlight areas in dragging-mode for modern browsers (#13224) --- .../blockgrid/blockgridui.less | 35 +++++++++++++++---- .../umbblockgridentries.component.js | 1 + 2 files changed, 30 insertions(+), 6 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/blockgrid/blockgridui.less b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/blockgrid/blockgridui.less index 41628aca5e..6cfdb05482 100644 --- a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/blockgrid/blockgridui.less +++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/blockgrid/blockgridui.less @@ -234,26 +234,29 @@ ng-form.ng-invalid-val-server-match-content > .umb-block-grid__block:not(.--acti &:not(.--hovering-area):focus, &:not(.--hovering-area):focus-within, &.--active { + + /** Avoid displaying hover when dragging-mode */ + --umb-block-grid--block_ui-opacity: calc(1 - var(--umb-block-grid--dragging-mode, 0)); > .umb-block-grid__block--context { - opacity: 1; + opacity: var(--umb-block-grid--block_ui-opacity); } &:not(.--scale-mode) { > .umb-block-grid__block--actions { - opacity: 1; + opacity: var(--umb-block-grid--block_ui-opacity); } > umb-block-grid-block > umb-block-grid-entries > .umb-block-grid__layout-container > .umb-block-grid__area-actions { - opacity: 1; + opacity: var(--umb-block-grid--block_ui-opacity); } } > .umb-block-grid__scale-handler { - opacity: 1; + opacity: var(--umb-block-grid--block_ui-opacity); } > .umb-block-grid__force-left, > .umb-block-grid__force-right { - opacity: 1; + opacity: var(--umb-block-grid--block_ui-opacity); } } @@ -584,6 +587,9 @@ umb-block-grid-block { top: 0px; position: absolute; z-index: 1; + + /** Avoid showing inline-create in dragging-mode */ + opacity: calc(1 - var(--umb-block-grid--dragging-mode, 0)); } .umb-block-grid__block--inline-create-button.--above { left: 0; @@ -776,7 +782,8 @@ umb-block-grid-block { background: transparent; border-radius: 3px; - border: @blueDark solid 1px; + border: solid 1px; + border-color: rgba(@blueDark, .5); border-radius: 3px; height: 100%; @@ -862,9 +869,25 @@ umb-block-grid-block { transition: opacity 240ms; } .umb-block-grid__area.--highlight::after { + /** Avoid displaying highlight when in dragging-mode */ + opacity: calc(1 - var(--umb-block-grid--dragging-mode, 0)); + border-color: @blueDark; + box-shadow: 0 0 0 1px rgba(255, 255, 255, .7), inset 0 0 0 1px rgba(255, 255, 255, .7); +} +.umb-block-grid__area:has( .umb-block-grid__layout-item-placeholder )::after { opacity: 1; border-color: @blueDark; box-shadow: 0 0 0 1px rgba(255, 255, 255, .7), inset 0 0 0 1px rgba(255, 255, 255, .7); + + /* Moved back to edge for this case */ + top: 0; + bottom: 0; + + animation: umb-block-grid__area-after__border-pulse 400ms ease-in-out alternate infinite; + @keyframes umb-block-grid__area-after__border-pulse { + 0% { border-color: rgba(@blueDark, 1); } + 100% { border-color: rgba(@blueDark, 0.66); } + } } .umb-block-grid__scalebox-backdrop { diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/blockgrid/umbblockgridentries.component.js b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/blockgrid/umbblockgridentries.component.js index c105b98fcb..c1e2c43619 100644 --- a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/blockgrid/umbblockgridentries.component.js +++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/blockgrid/umbblockgridentries.component.js @@ -619,6 +619,7 @@ } window.removeEventListener('drag', _onDragMove); window.removeEventListener('dragover', _onDragMove); + document.documentElement.style.setProperty("--umb-block-grid--dragging-mode", 0); if(ghostElIndicateForceLeft) { ghostEl.removeChild(ghostElIndicateForceLeft); From 733f0b8e0988a4d5001ad776d6743c9023a4d04f Mon Sep 17 00:00:00 2001 From: Elitsa Marinovska <21998037+elit0451@users.noreply.github.com> Date: Tue, 18 Oct 2022 08:22:27 +0200 Subject: [PATCH 26/53] Collect new .xml language files from different sources (#13212) * Collecting new language files from different sources * Apply suggestions from review * Adding TODO for merging the language files locations to one when packages are not concerned --- .../LocalizedTextServiceFileSources.cs | 23 +++++++++---- ...lizedTextServiceSupplementaryFileSource.cs | 15 ++++++++- .../UmbracoBuilder.Services.cs | 7 ++++ .../UmbracoBuilder.LocalizedText.cs | 33 ++++++++++++------- 4 files changed, 59 insertions(+), 19 deletions(-) diff --git a/src/Umbraco.Core/Services/LocalizedTextServiceFileSources.cs b/src/Umbraco.Core/Services/LocalizedTextServiceFileSources.cs index 26a2e9fb60..ea75f369af 100644 --- a/src/Umbraco.Core/Services/LocalizedTextServiceFileSources.cs +++ b/src/Umbraco.Core/Services/LocalizedTextServiceFileSources.cs @@ -1,4 +1,5 @@ using System.Globalization; +using System.Text.RegularExpressions; using System.Xml; using System.Xml.Linq; using Microsoft.Extensions.FileProviders; @@ -166,7 +167,7 @@ public class LocalizedTextServiceFileSources } /// - /// returns all xml sources for all culture files found in the folder + /// Returns all xml sources for all culture files found in the folder. /// /// public IDictionary> GetXmlSources() => _xmlSources.Value; @@ -179,7 +180,15 @@ public class LocalizedTextServiceFileSources { result.AddRange( new PhysicalDirectoryContents(_fileSourceFolder.FullName) - .Where(x => !x.IsDirectory && x.Name.EndsWith(".xml"))); + .Where(x => !x.IsDirectory && !x.Name.Contains("user") && x.Name.EndsWith(".xml"))); // Filter out *.user.xml + } + + if (_supplementFileSources is not null) + { + // Get only the .xml files and filter out the user defined language files (*.user.xml) that overwrite the default + result.AddRange(_supplementFileSources + .Where(x => !x.FileInfo.Name.Contains("user") && x.FileInfo.Name.EndsWith(".xml")) + .Select(x => x.FileInfo)); } if (_directoryContents.Exists) @@ -236,8 +245,8 @@ public class LocalizedTextServiceFileSources // now load in supplementary IEnumerable found = _supplementFileSources.Where(x => { - var extension = Path.GetExtension(x.File.FullName); - var fileCultureName = Path.GetFileNameWithoutExtension(x.File.FullName).Replace("_", "-") + var extension = Path.GetExtension(x.FileInfo.Name); + var fileCultureName = Path.GetFileNameWithoutExtension(x.FileInfo.Name).Replace("_", "-") .Replace(".user", string.Empty); return extension.InvariantEquals(".xml") && ( fileCultureName.InvariantEquals(culture.Name) @@ -246,16 +255,16 @@ public class LocalizedTextServiceFileSources foreach (LocalizedTextServiceSupplementaryFileSource supplementaryFile in found) { - using (FileStream fs = supplementaryFile.File.OpenRead()) + using (Stream stream = supplementaryFile.FileInfo.CreateReadStream()) { XDocument xChildDoc; try { - xChildDoc = XDocument.Load(fs); + xChildDoc = XDocument.Load(stream); } catch (Exception ex) { - _logger.LogError(ex, "Could not load file into XML {File}", supplementaryFile.File.FullName); + _logger.LogError(ex, "Could not load file into XML {File}", supplementaryFile.FileInfo.Name); continue; } diff --git a/src/Umbraco.Core/Services/LocalizedTextServiceSupplementaryFileSource.cs b/src/Umbraco.Core/Services/LocalizedTextServiceSupplementaryFileSource.cs index cff9a55234..3ada83dc3c 100644 --- a/src/Umbraco.Core/Services/LocalizedTextServiceSupplementaryFileSource.cs +++ b/src/Umbraco.Core/Services/LocalizedTextServiceSupplementaryFileSource.cs @@ -1,14 +1,27 @@ +using Microsoft.Extensions.FileProviders; +using Microsoft.Extensions.FileProviders.Physical; + namespace Umbraco.Cms.Core.Services; public class LocalizedTextServiceSupplementaryFileSource { + [Obsolete("Use other ctor. Will be removed in Umbraco 12")] public LocalizedTextServiceSupplementaryFileSource(FileInfo file, bool overwriteCoreKeys) + : this(new PhysicalFileInfo(file), overwriteCoreKeys) { - File = file ?? throw new ArgumentNullException("file"); + } + + public LocalizedTextServiceSupplementaryFileSource(IFileInfo file, bool overwriteCoreKeys) + { + FileInfo = file ?? throw new ArgumentNullException(nameof(file)); + File = file is PhysicalFileInfo ? new FileInfo(file.PhysicalPath) : null!; OverwriteCoreKeys = overwriteCoreKeys; } + [Obsolete("Use FileInfo instead. Will be removed in Umbraco 12")] public FileInfo File { get; } + public IFileInfo FileInfo { get; } + public bool OverwriteCoreKeys { get; } } diff --git a/src/Umbraco.Infrastructure/DependencyInjection/UmbracoBuilder.Services.cs b/src/Umbraco.Infrastructure/DependencyInjection/UmbracoBuilder.Services.cs index dd5b77abec..c9208b5bdc 100644 --- a/src/Umbraco.Infrastructure/DependencyInjection/UmbracoBuilder.Services.cs +++ b/src/Umbraco.Infrastructure/DependencyInjection/UmbracoBuilder.Services.cs @@ -102,7 +102,14 @@ public static partial class UmbracoBuilderExtensions IServiceProvider container) { IHostingEnvironment hostingEnvironment = container.GetRequiredService(); + + // TODO: (for >= v13) Rethink whether all language files (.xml and .user.xml) should be located in ~/config/lang + // instead of ~/umbraco/config/lang and ~/config/lang. + // Currently when extending Umbraco, a new language file that the backoffice will be available in, should be placed + // in ~/umbraco/config/lang, while 'user' translation files for overrides are in ~/config/lang (according to our docs). + // Such change will be breaking and we would need to document this clearly. var subPath = WebPath.Combine(Constants.SystemDirectories.Umbraco, "config", "lang"); + var mainLangFolder = new DirectoryInfo(hostingEnvironment.MapPathContentRoot(subPath)); return new LocalizedTextServiceFileSources( diff --git a/src/Umbraco.Web.BackOffice/DependencyInjection/UmbracoBuilder.LocalizedText.cs b/src/Umbraco.Web.BackOffice/DependencyInjection/UmbracoBuilder.LocalizedText.cs index 54e25240e0..60a946a553 100644 --- a/src/Umbraco.Web.BackOffice/DependencyInjection/UmbracoBuilder.LocalizedText.cs +++ b/src/Umbraco.Web.BackOffice/DependencyInjection/UmbracoBuilder.LocalizedText.cs @@ -1,6 +1,8 @@ +using System.IO; using Microsoft.AspNetCore.Hosting; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.FileProviders; +using Umbraco.Cms.Core.Configuration.Models; using Umbraco.Cms.Core.DependencyInjection; using Umbraco.Cms.Core.Routing; using Umbraco.Cms.Core.Services; @@ -42,20 +44,30 @@ namespace Umbraco.Extensions // gets all langs files in /app_plugins real or virtual locations IEnumerable pluginLangFileSources = GetPluginLanguageFileSources(webFileProvider, Cms.Core.Constants.SystemDirectories.AppPlugins, false); - // user defined langs that overwrite the default, these should not be used by plugin creators + // user defined language files that overwrite the default, these should not be used by plugin creators var userConfigLangFolder = Cms.Core.Constants.SystemDirectories.Config .TrimStart(Cms.Core.Constants.CharArrays.Tilde); - IEnumerable userLangFileSources = contentFileProvider.GetDirectoryContents(userConfigLangFolder) - .Where(x => x.IsDirectory && x.Name.InvariantEquals("lang")) - .Select(x => new DirectoryInfo(x.PhysicalPath)) - .SelectMany(x => x.GetFiles("*.user.xml", SearchOption.TopDirectoryOnly)) - .Select(x => new LocalizedTextServiceSupplementaryFileSource(x, true)); + var configLangFileSources = new List(); + + foreach (IFileInfo langFileSource in contentFileProvider.GetDirectoryContents(userConfigLangFolder)) + { + if (langFileSource.IsDirectory && langFileSource.Name.InvariantEquals("lang")) + { + foreach (IFileInfo langFile in contentFileProvider.GetDirectoryContents($"{userConfigLangFolder}/{langFileSource.Name}")) + { + if (langFile.Name.InvariantEndsWith(".xml") && langFile.PhysicalPath is not null) + { + configLangFileSources.Add(new LocalizedTextServiceSupplementaryFileSource(langFile, true)); + } + } + } + } return localPluginFileSources .Concat(pluginLangFileSources) - .Concat(userLangFileSources); + .Concat(configLangFileSources); } @@ -83,13 +95,12 @@ namespace Umbraco.Extensions foreach (var langFolder in GetLangFolderPaths(fileProvider, pluginFolderPath)) { // request all the files out of the path, these will have physicalPath set. - IEnumerable localizationFiles = fileProvider + IEnumerable localizationFiles = fileProvider .GetDirectoryContents(langFolder) .Where(x => !string.IsNullOrEmpty(x.PhysicalPath)) - .Where(x => x.Name.InvariantEndsWith(".xml")) - .Select(x => new FileInfo(x.PhysicalPath)); + .Where(x => x.Name.InvariantEndsWith(".xml")); - foreach (FileInfo file in localizationFiles) + foreach (IFileInfo file in localizationFiles) { yield return new LocalizedTextServiceSupplementaryFileSource(file, overwriteCoreKeys); } From 5e9601114032f382ccdaef5f05c31d04192be78b Mon Sep 17 00:00:00 2001 From: Elitsa Marinovska <21998037+elit0451@users.noreply.github.com> Date: Tue, 18 Oct 2022 08:22:27 +0200 Subject: [PATCH 27/53] Collect new .xml language files from different sources (#13212) * Collecting new language files from different sources * Apply suggestions from review * Adding TODO for merging the language files locations to one when packages are not concerned --- .../LocalizedTextServiceFileSources.cs | 23 +++++++++---- ...lizedTextServiceSupplementaryFileSource.cs | 15 ++++++++- .../UmbracoBuilder.Services.cs | 7 ++++ .../UmbracoBuilder.LocalizedText.cs | 33 ++++++++++++------- 4 files changed, 59 insertions(+), 19 deletions(-) diff --git a/src/Umbraco.Core/Services/LocalizedTextServiceFileSources.cs b/src/Umbraco.Core/Services/LocalizedTextServiceFileSources.cs index 26a2e9fb60..ea75f369af 100644 --- a/src/Umbraco.Core/Services/LocalizedTextServiceFileSources.cs +++ b/src/Umbraco.Core/Services/LocalizedTextServiceFileSources.cs @@ -1,4 +1,5 @@ using System.Globalization; +using System.Text.RegularExpressions; using System.Xml; using System.Xml.Linq; using Microsoft.Extensions.FileProviders; @@ -166,7 +167,7 @@ public class LocalizedTextServiceFileSources } /// - /// returns all xml sources for all culture files found in the folder + /// Returns all xml sources for all culture files found in the folder. /// /// public IDictionary> GetXmlSources() => _xmlSources.Value; @@ -179,7 +180,15 @@ public class LocalizedTextServiceFileSources { result.AddRange( new PhysicalDirectoryContents(_fileSourceFolder.FullName) - .Where(x => !x.IsDirectory && x.Name.EndsWith(".xml"))); + .Where(x => !x.IsDirectory && !x.Name.Contains("user") && x.Name.EndsWith(".xml"))); // Filter out *.user.xml + } + + if (_supplementFileSources is not null) + { + // Get only the .xml files and filter out the user defined language files (*.user.xml) that overwrite the default + result.AddRange(_supplementFileSources + .Where(x => !x.FileInfo.Name.Contains("user") && x.FileInfo.Name.EndsWith(".xml")) + .Select(x => x.FileInfo)); } if (_directoryContents.Exists) @@ -236,8 +245,8 @@ public class LocalizedTextServiceFileSources // now load in supplementary IEnumerable found = _supplementFileSources.Where(x => { - var extension = Path.GetExtension(x.File.FullName); - var fileCultureName = Path.GetFileNameWithoutExtension(x.File.FullName).Replace("_", "-") + var extension = Path.GetExtension(x.FileInfo.Name); + var fileCultureName = Path.GetFileNameWithoutExtension(x.FileInfo.Name).Replace("_", "-") .Replace(".user", string.Empty); return extension.InvariantEquals(".xml") && ( fileCultureName.InvariantEquals(culture.Name) @@ -246,16 +255,16 @@ public class LocalizedTextServiceFileSources foreach (LocalizedTextServiceSupplementaryFileSource supplementaryFile in found) { - using (FileStream fs = supplementaryFile.File.OpenRead()) + using (Stream stream = supplementaryFile.FileInfo.CreateReadStream()) { XDocument xChildDoc; try { - xChildDoc = XDocument.Load(fs); + xChildDoc = XDocument.Load(stream); } catch (Exception ex) { - _logger.LogError(ex, "Could not load file into XML {File}", supplementaryFile.File.FullName); + _logger.LogError(ex, "Could not load file into XML {File}", supplementaryFile.FileInfo.Name); continue; } diff --git a/src/Umbraco.Core/Services/LocalizedTextServiceSupplementaryFileSource.cs b/src/Umbraco.Core/Services/LocalizedTextServiceSupplementaryFileSource.cs index cff9a55234..3ada83dc3c 100644 --- a/src/Umbraco.Core/Services/LocalizedTextServiceSupplementaryFileSource.cs +++ b/src/Umbraco.Core/Services/LocalizedTextServiceSupplementaryFileSource.cs @@ -1,14 +1,27 @@ +using Microsoft.Extensions.FileProviders; +using Microsoft.Extensions.FileProviders.Physical; + namespace Umbraco.Cms.Core.Services; public class LocalizedTextServiceSupplementaryFileSource { + [Obsolete("Use other ctor. Will be removed in Umbraco 12")] public LocalizedTextServiceSupplementaryFileSource(FileInfo file, bool overwriteCoreKeys) + : this(new PhysicalFileInfo(file), overwriteCoreKeys) { - File = file ?? throw new ArgumentNullException("file"); + } + + public LocalizedTextServiceSupplementaryFileSource(IFileInfo file, bool overwriteCoreKeys) + { + FileInfo = file ?? throw new ArgumentNullException(nameof(file)); + File = file is PhysicalFileInfo ? new FileInfo(file.PhysicalPath) : null!; OverwriteCoreKeys = overwriteCoreKeys; } + [Obsolete("Use FileInfo instead. Will be removed in Umbraco 12")] public FileInfo File { get; } + public IFileInfo FileInfo { get; } + public bool OverwriteCoreKeys { get; } } diff --git a/src/Umbraco.Infrastructure/DependencyInjection/UmbracoBuilder.Services.cs b/src/Umbraco.Infrastructure/DependencyInjection/UmbracoBuilder.Services.cs index dd5b77abec..c9208b5bdc 100644 --- a/src/Umbraco.Infrastructure/DependencyInjection/UmbracoBuilder.Services.cs +++ b/src/Umbraco.Infrastructure/DependencyInjection/UmbracoBuilder.Services.cs @@ -102,7 +102,14 @@ public static partial class UmbracoBuilderExtensions IServiceProvider container) { IHostingEnvironment hostingEnvironment = container.GetRequiredService(); + + // TODO: (for >= v13) Rethink whether all language files (.xml and .user.xml) should be located in ~/config/lang + // instead of ~/umbraco/config/lang and ~/config/lang. + // Currently when extending Umbraco, a new language file that the backoffice will be available in, should be placed + // in ~/umbraco/config/lang, while 'user' translation files for overrides are in ~/config/lang (according to our docs). + // Such change will be breaking and we would need to document this clearly. var subPath = WebPath.Combine(Constants.SystemDirectories.Umbraco, "config", "lang"); + var mainLangFolder = new DirectoryInfo(hostingEnvironment.MapPathContentRoot(subPath)); return new LocalizedTextServiceFileSources( diff --git a/src/Umbraco.Web.BackOffice/DependencyInjection/UmbracoBuilder.LocalizedText.cs b/src/Umbraco.Web.BackOffice/DependencyInjection/UmbracoBuilder.LocalizedText.cs index 54e25240e0..60a946a553 100644 --- a/src/Umbraco.Web.BackOffice/DependencyInjection/UmbracoBuilder.LocalizedText.cs +++ b/src/Umbraco.Web.BackOffice/DependencyInjection/UmbracoBuilder.LocalizedText.cs @@ -1,6 +1,8 @@ +using System.IO; using Microsoft.AspNetCore.Hosting; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.FileProviders; +using Umbraco.Cms.Core.Configuration.Models; using Umbraco.Cms.Core.DependencyInjection; using Umbraco.Cms.Core.Routing; using Umbraco.Cms.Core.Services; @@ -42,20 +44,30 @@ namespace Umbraco.Extensions // gets all langs files in /app_plugins real or virtual locations IEnumerable pluginLangFileSources = GetPluginLanguageFileSources(webFileProvider, Cms.Core.Constants.SystemDirectories.AppPlugins, false); - // user defined langs that overwrite the default, these should not be used by plugin creators + // user defined language files that overwrite the default, these should not be used by plugin creators var userConfigLangFolder = Cms.Core.Constants.SystemDirectories.Config .TrimStart(Cms.Core.Constants.CharArrays.Tilde); - IEnumerable userLangFileSources = contentFileProvider.GetDirectoryContents(userConfigLangFolder) - .Where(x => x.IsDirectory && x.Name.InvariantEquals("lang")) - .Select(x => new DirectoryInfo(x.PhysicalPath)) - .SelectMany(x => x.GetFiles("*.user.xml", SearchOption.TopDirectoryOnly)) - .Select(x => new LocalizedTextServiceSupplementaryFileSource(x, true)); + var configLangFileSources = new List(); + + foreach (IFileInfo langFileSource in contentFileProvider.GetDirectoryContents(userConfigLangFolder)) + { + if (langFileSource.IsDirectory && langFileSource.Name.InvariantEquals("lang")) + { + foreach (IFileInfo langFile in contentFileProvider.GetDirectoryContents($"{userConfigLangFolder}/{langFileSource.Name}")) + { + if (langFile.Name.InvariantEndsWith(".xml") && langFile.PhysicalPath is not null) + { + configLangFileSources.Add(new LocalizedTextServiceSupplementaryFileSource(langFile, true)); + } + } + } + } return localPluginFileSources .Concat(pluginLangFileSources) - .Concat(userLangFileSources); + .Concat(configLangFileSources); } @@ -83,13 +95,12 @@ namespace Umbraco.Extensions foreach (var langFolder in GetLangFolderPaths(fileProvider, pluginFolderPath)) { // request all the files out of the path, these will have physicalPath set. - IEnumerable localizationFiles = fileProvider + IEnumerable localizationFiles = fileProvider .GetDirectoryContents(langFolder) .Where(x => !string.IsNullOrEmpty(x.PhysicalPath)) - .Where(x => x.Name.InvariantEndsWith(".xml")) - .Select(x => new FileInfo(x.PhysicalPath)); + .Where(x => x.Name.InvariantEndsWith(".xml")); - foreach (FileInfo file in localizationFiles) + foreach (IFileInfo file in localizationFiles) { yield return new LocalizedTextServiceSupplementaryFileSource(file, overwriteCoreKeys); } From af468b6f2812b25656a254a0ec5b2031ea956fa5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niels=20Lyngs=C3=B8?= Date: Tue, 18 Oct 2022 12:47:08 +0200 Subject: [PATCH 28/53] Resync editors if content model changed (#13230) --- .../src/common/directives/components/content/edit.controller.js | 2 +- .../components/content/umbvariantcontenteditors.directive.js | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/components/content/edit.controller.js b/src/Umbraco.Web.UI.Client/src/common/directives/components/content/edit.controller.js index ae9f0121ca..872aad3f53 100644 --- a/src/Umbraco.Web.UI.Client/src/common/directives/components/content/edit.controller.js +++ b/src/Umbraco.Web.UI.Client/src/common/directives/components/content/edit.controller.js @@ -232,6 +232,7 @@ appendRuntimeData(); init(); + startWatches($scope.content); syncTreeNode($scope.content, $scope.content.path, true); @@ -565,7 +566,6 @@ $scope.page.loading = true; loadContent().then(function () { - startWatches($scope.content); $scope.page.loading = false; }); } diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/components/content/umbvariantcontenteditors.directive.js b/src/Umbraco.Web.UI.Client/src/common/directives/components/content/umbvariantcontenteditors.directive.js index 71bf151b89..7ed5e4120f 100644 --- a/src/Umbraco.Web.UI.Client/src/common/directives/components/content/umbvariantcontenteditors.directive.js +++ b/src/Umbraco.Web.UI.Client/src/common/directives/components/content/umbvariantcontenteditors.directive.js @@ -64,6 +64,8 @@ setActiveVariant(); } else if (changes.segment && !changes.segment.isFirstChange() && changes.segment.currentValue !== changes.segment.previousValue) { setActiveVariant(); + } else if (changes.content) { + setActiveVariant(); } } From 4e9aa8dac22742829c424abe5066b7fdb127510c Mon Sep 17 00:00:00 2001 From: Mole Date: Tue, 18 Oct 2022 12:53:32 +0200 Subject: [PATCH 29/53] Disable BlockGridEditor (#13229) * Disable BlockGridEditor * Fix typeloader test * Update src/Umbraco.Core/Models/Blocks/BlockGridItem.cs Co-authored-by: Kenn Jacobsen * Apply suggestions from code review Co-authored-by: Kenn Jacobsen Co-authored-by: Kenn Jacobsen --- src/Umbraco.Core/Constants-PropertyEditors.cs | 2 ++ .../Models/Blocks/BlockGridArea.cs | 2 ++ .../Models/Blocks/BlockGridItem.cs | 6 +++--- .../Models/Blocks/BlockGridModel.cs | 2 ++ .../Blocks/BlockGridEditorDataConverter.cs | 2 ++ .../Models/Blocks/BlockGridLayoutAreaItem.cs | 4 +++- .../Models/Blocks/BlockGridLayoutItem.cs | 2 ++ .../BlockGridPropertyEditor.cs | 19 ++++++++++++------- .../BlockGridPropertyEditorBase.cs | 6 +++++- .../Extensions/BlockGridTemplateExtensions.cs | 2 ++ .../Umbraco.Core/Composing/TypeLoaderTests.cs | 3 ++- 11 files changed, 37 insertions(+), 13 deletions(-) diff --git a/src/Umbraco.Core/Constants-PropertyEditors.cs b/src/Umbraco.Core/Constants-PropertyEditors.cs index a42f2d198e..d86faa6fdd 100644 --- a/src/Umbraco.Core/Constants-PropertyEditors.cs +++ b/src/Umbraco.Core/Constants-PropertyEditors.cs @@ -1,3 +1,4 @@ +using System.ComponentModel; using Umbraco.Cms.Core.PropertyEditors; namespace Umbraco.Cms.Core; @@ -43,6 +44,7 @@ public static partial class Constants /// /// Block Grid. /// + [EditorBrowsable(EditorBrowsableState.Never)] // TODO: Remove this for V11/V10.4 public const string BlockGrid = "Umbraco.BlockGrid"; /// diff --git a/src/Umbraco.Core/Models/Blocks/BlockGridArea.cs b/src/Umbraco.Core/Models/Blocks/BlockGridArea.cs index 8cc2e5231b..3a9f86a606 100644 --- a/src/Umbraco.Core/Models/Blocks/BlockGridArea.cs +++ b/src/Umbraco.Core/Models/Blocks/BlockGridArea.cs @@ -1,11 +1,13 @@ // Copyright (c) Umbraco. // See LICENSE for more details. +using System.ComponentModel; using System.Runtime.Serialization; namespace Umbraco.Cms.Core.Models.Blocks; [DataContract(Name = "area", Namespace = "")] +[EditorBrowsable(EditorBrowsableState.Never)] // TODO: Remove this for V11/V10.4 public class BlockGridArea : BlockModelCollection { /// diff --git a/src/Umbraco.Core/Models/Blocks/BlockGridItem.cs b/src/Umbraco.Core/Models/Blocks/BlockGridItem.cs index 59021f5e38..86e0c40874 100644 --- a/src/Umbraco.Core/Models/Blocks/BlockGridItem.cs +++ b/src/Umbraco.Core/Models/Blocks/BlockGridItem.cs @@ -1,6 +1,7 @@ // Copyright (c) Umbraco. // See LICENSE for more details. +using System.ComponentModel; using System.Runtime.Serialization; using Umbraco.Cms.Core.Models.PublishedContent; @@ -9,8 +10,9 @@ namespace Umbraco.Cms.Core.Models.Blocks /// /// Represents a layout item for the Block Grid editor. /// - /// + /// [DataContract(Name = "block", Namespace = "")] + [EditorBrowsable(EditorBrowsableState.Never)] // TODO: Remove this for V11/V10.4 public class BlockGridItem : IBlockReference { /// @@ -116,7 +118,6 @@ namespace Umbraco.Cms.Core.Models.Blocks /// Represents a layout item with a generic content type for the Block List editor. /// /// The type of the content. - /// public class BlockGridItem : BlockGridItem where T : IPublishedElement { @@ -149,7 +150,6 @@ namespace Umbraco.Cms.Core.Models.Blocks /// /// The type of the content. /// The type of the settings. - /// public class BlockGridItem : BlockGridItem where TContent : IPublishedElement where TSettings : IPublishedElement diff --git a/src/Umbraco.Core/Models/Blocks/BlockGridModel.cs b/src/Umbraco.Core/Models/Blocks/BlockGridModel.cs index 5d645a17c9..20c41c4744 100644 --- a/src/Umbraco.Core/Models/Blocks/BlockGridModel.cs +++ b/src/Umbraco.Core/Models/Blocks/BlockGridModel.cs @@ -2,6 +2,7 @@ // See LICENSE for more details. using System.Collections.ObjectModel; +using System.ComponentModel; using System.Runtime.Serialization; namespace Umbraco.Cms.Core.Models.Blocks; @@ -11,6 +12,7 @@ namespace Umbraco.Cms.Core.Models.Blocks; /// /// [DataContract(Name = "blockgrid", Namespace = "")] +[EditorBrowsable(EditorBrowsableState.Never)] // TODO: Remove this for V11/V10.4 public class BlockGridModel : BlockModelCollection { /// diff --git a/src/Umbraco.Infrastructure/Models/Blocks/BlockGridEditorDataConverter.cs b/src/Umbraco.Infrastructure/Models/Blocks/BlockGridEditorDataConverter.cs index b5200c9f24..016046abff 100644 --- a/src/Umbraco.Infrastructure/Models/Blocks/BlockGridEditorDataConverter.cs +++ b/src/Umbraco.Infrastructure/Models/Blocks/BlockGridEditorDataConverter.cs @@ -1,6 +1,7 @@ // Copyright (c) Umbraco. // See LICENSE for more details. +using System.ComponentModel; using Newtonsoft.Json.Linq; using Umbraco.Cms.Core.Serialization; @@ -9,6 +10,7 @@ namespace Umbraco.Cms.Core.Models.Blocks; /// /// Data converter for the block grid property editor /// +[EditorBrowsable(EditorBrowsableState.Never)] // TODO: Remove this for V11/V10.4 public class BlockGridEditorDataConverter : BlockEditorDataConverter { private readonly IJsonSerializer _jsonSerializer; diff --git a/src/Umbraco.Infrastructure/Models/Blocks/BlockGridLayoutAreaItem.cs b/src/Umbraco.Infrastructure/Models/Blocks/BlockGridLayoutAreaItem.cs index 3a4d1ba135..473482f028 100644 --- a/src/Umbraco.Infrastructure/Models/Blocks/BlockGridLayoutAreaItem.cs +++ b/src/Umbraco.Infrastructure/Models/Blocks/BlockGridLayoutAreaItem.cs @@ -1,7 +1,9 @@ -using Newtonsoft.Json; +using System.ComponentModel; +using Newtonsoft.Json; namespace Umbraco.Cms.Core.Models.Blocks; +[EditorBrowsable(EditorBrowsableState.Never)] // TODO: Remove this for V11/V10.4 public class BlockGridLayoutAreaItem { [JsonProperty("key", NullValueHandling = NullValueHandling.Ignore)] diff --git a/src/Umbraco.Infrastructure/Models/Blocks/BlockGridLayoutItem.cs b/src/Umbraco.Infrastructure/Models/Blocks/BlockGridLayoutItem.cs index 9014e2789a..c06942822e 100644 --- a/src/Umbraco.Infrastructure/Models/Blocks/BlockGridLayoutItem.cs +++ b/src/Umbraco.Infrastructure/Models/Blocks/BlockGridLayoutItem.cs @@ -1,6 +1,7 @@ // Copyright (c) Umbraco. // See LICENSE for more details. +using System.ComponentModel; using Newtonsoft.Json; using Umbraco.Cms.Infrastructure.Serialization; @@ -9,6 +10,7 @@ namespace Umbraco.Cms.Core.Models.Blocks; /// /// Used for deserializing the block grid layout /// +[EditorBrowsable(EditorBrowsableState.Never)] // TODO: Remove this for V11/V10.4 public class BlockGridLayoutItem : IBlockLayoutItem { [JsonProperty("contentUdi", Required = Required.Always)] diff --git a/src/Umbraco.Infrastructure/PropertyEditors/BlockGridPropertyEditor.cs b/src/Umbraco.Infrastructure/PropertyEditors/BlockGridPropertyEditor.cs index 8881ce82a9..0b465499f8 100644 --- a/src/Umbraco.Infrastructure/PropertyEditors/BlockGridPropertyEditor.cs +++ b/src/Umbraco.Infrastructure/PropertyEditors/BlockGridPropertyEditor.cs @@ -1,6 +1,8 @@ // Copyright (c) Umbraco. // See LICENSE for more details. +using System.ComponentModel; +using Umbraco.Cms.Core.Composing; using Umbraco.Cms.Core.IO; namespace Umbraco.Cms.Core.PropertyEditors; @@ -8,13 +10,16 @@ namespace Umbraco.Cms.Core.PropertyEditors; /// /// Represents a block list property editor. /// -[DataEditor( - Constants.PropertyEditors.Aliases.BlockGrid, - "Block Grid", - "blockgrid", - ValueType = ValueTypes.Json, - Group = Constants.PropertyEditors.Groups.RichContent, - Icon = "icon-layout")] +// TODO: Re-add this DataEditor attribute to re-enable the BlockGridEditor for V11/V10.4 +// [DataEditor( +// Constants.PropertyEditors.Aliases.BlockGrid, +// "Block Grid", +// "blockgrid", +// ValueType = ValueTypes.Json, +// Group = Constants.PropertyEditors.Groups.RichContent, +// Icon = "icon-layout")] +[HideFromTypeFinder] +[EditorBrowsable(EditorBrowsableState.Never)] public class BlockGridPropertyEditor : BlockGridPropertyEditorBase { private readonly IIOHelper _ioHelper; diff --git a/src/Umbraco.Infrastructure/PropertyEditors/BlockGridPropertyEditorBase.cs b/src/Umbraco.Infrastructure/PropertyEditors/BlockGridPropertyEditorBase.cs index 42a5931a2b..138c3b7320 100644 --- a/src/Umbraco.Infrastructure/PropertyEditors/BlockGridPropertyEditorBase.cs +++ b/src/Umbraco.Infrastructure/PropertyEditors/BlockGridPropertyEditorBase.cs @@ -1,8 +1,10 @@ // Copyright (c) Umbraco. // See LICENSE for more details. +using System.ComponentModel; using System.ComponentModel.DataAnnotations; using Microsoft.Extensions.Logging; +using Umbraco.Cms.Core.Composing; using Umbraco.Cms.Core.IO; using Umbraco.Cms.Core.Models; using Umbraco.Cms.Core.Models.Blocks; @@ -16,7 +18,9 @@ namespace Umbraco.Cms.Core.PropertyEditors; /// /// Abstract base class for block grid based editors. -/// +// /// +[HideFromTypeFinder] +[EditorBrowsable(EditorBrowsableState.Never)] public abstract class BlockGridPropertyEditorBase : DataEditor { protected BlockGridPropertyEditorBase(IDataValueEditorFactory dataValueEditorFactory) diff --git a/src/Umbraco.Web.Common/Extensions/BlockGridTemplateExtensions.cs b/src/Umbraco.Web.Common/Extensions/BlockGridTemplateExtensions.cs index ee0375da4f..ed40a30766 100644 --- a/src/Umbraco.Web.Common/Extensions/BlockGridTemplateExtensions.cs +++ b/src/Umbraco.Web.Common/Extensions/BlockGridTemplateExtensions.cs @@ -1,6 +1,7 @@ // Copyright (c) Umbraco. // See LICENSE for more details. +using System.ComponentModel; using Microsoft.AspNetCore.Html; using Microsoft.AspNetCore.Mvc.Rendering; using Umbraco.Cms.Core.Models.Blocks; @@ -8,6 +9,7 @@ using Umbraco.Cms.Core.Models.PublishedContent; namespace Umbraco.Extensions; +[EditorBrowsable(EditorBrowsableState.Never)] public static class BlockGridTemplateExtensions { public const string DefaultFolder = "blockgrid/"; diff --git a/tests/Umbraco.Tests.UnitTests/Umbraco.Core/Composing/TypeLoaderTests.cs b/tests/Umbraco.Tests.UnitTests/Umbraco.Core/Composing/TypeLoaderTests.cs index af6dbb1f1c..4d098b5992 100644 --- a/tests/Umbraco.Tests.UnitTests/Umbraco.Core/Composing/TypeLoaderTests.cs +++ b/tests/Umbraco.Tests.UnitTests/Umbraco.Core/Composing/TypeLoaderTests.cs @@ -174,7 +174,8 @@ public class TypeLoaderTests public void GetDataEditors() { var types = _typeLoader.GetDataEditors(); - Assert.AreEqual(42, types.Count()); + // TODO: Increase this to 42 when BlockGridEditor is re-added + Assert.AreEqual(41, types.Count()); } /// From 629cc631c6b9c02ad216f43d42546762cf3de08f Mon Sep 17 00:00:00 2001 From: Mole Date: Tue, 18 Oct 2022 14:59:08 +0200 Subject: [PATCH 30/53] V10.4: Re-enable block grid editor (#13231) * Revert "Disable BlockGridEditor (#13229)" This reverts commit 4e9aa8dac22742829c424abe5066b7fdb127510c. * Re-do xml comments fix --- src/Umbraco.Core/Constants-PropertyEditors.cs | 2 -- .../Models/Blocks/BlockGridArea.cs | 2 -- .../Models/Blocks/BlockGridItem.cs | 2 -- .../Models/Blocks/BlockGridModel.cs | 2 -- .../Blocks/BlockGridEditorDataConverter.cs | 2 -- .../Models/Blocks/BlockGridLayoutAreaItem.cs | 4 +--- .../Models/Blocks/BlockGridLayoutItem.cs | 2 -- .../BlockGridPropertyEditor.cs | 19 +++++++------------ .../BlockGridPropertyEditorBase.cs | 6 +----- .../Extensions/BlockGridTemplateExtensions.cs | 2 -- .../Umbraco.Core/Composing/TypeLoaderTests.cs | 3 +-- 11 files changed, 10 insertions(+), 36 deletions(-) diff --git a/src/Umbraco.Core/Constants-PropertyEditors.cs b/src/Umbraco.Core/Constants-PropertyEditors.cs index d86faa6fdd..a42f2d198e 100644 --- a/src/Umbraco.Core/Constants-PropertyEditors.cs +++ b/src/Umbraco.Core/Constants-PropertyEditors.cs @@ -1,4 +1,3 @@ -using System.ComponentModel; using Umbraco.Cms.Core.PropertyEditors; namespace Umbraco.Cms.Core; @@ -44,7 +43,6 @@ public static partial class Constants /// /// Block Grid. /// - [EditorBrowsable(EditorBrowsableState.Never)] // TODO: Remove this for V11/V10.4 public const string BlockGrid = "Umbraco.BlockGrid"; /// diff --git a/src/Umbraco.Core/Models/Blocks/BlockGridArea.cs b/src/Umbraco.Core/Models/Blocks/BlockGridArea.cs index 3a9f86a606..8cc2e5231b 100644 --- a/src/Umbraco.Core/Models/Blocks/BlockGridArea.cs +++ b/src/Umbraco.Core/Models/Blocks/BlockGridArea.cs @@ -1,13 +1,11 @@ // Copyright (c) Umbraco. // See LICENSE for more details. -using System.ComponentModel; using System.Runtime.Serialization; namespace Umbraco.Cms.Core.Models.Blocks; [DataContract(Name = "area", Namespace = "")] -[EditorBrowsable(EditorBrowsableState.Never)] // TODO: Remove this for V11/V10.4 public class BlockGridArea : BlockModelCollection { /// diff --git a/src/Umbraco.Core/Models/Blocks/BlockGridItem.cs b/src/Umbraco.Core/Models/Blocks/BlockGridItem.cs index 86e0c40874..097882c5ab 100644 --- a/src/Umbraco.Core/Models/Blocks/BlockGridItem.cs +++ b/src/Umbraco.Core/Models/Blocks/BlockGridItem.cs @@ -1,7 +1,6 @@ // Copyright (c) Umbraco. // See LICENSE for more details. -using System.ComponentModel; using System.Runtime.Serialization; using Umbraco.Cms.Core.Models.PublishedContent; @@ -12,7 +11,6 @@ namespace Umbraco.Cms.Core.Models.Blocks /// /// [DataContract(Name = "block", Namespace = "")] - [EditorBrowsable(EditorBrowsableState.Never)] // TODO: Remove this for V11/V10.4 public class BlockGridItem : IBlockReference { /// diff --git a/src/Umbraco.Core/Models/Blocks/BlockGridModel.cs b/src/Umbraco.Core/Models/Blocks/BlockGridModel.cs index 20c41c4744..5d645a17c9 100644 --- a/src/Umbraco.Core/Models/Blocks/BlockGridModel.cs +++ b/src/Umbraco.Core/Models/Blocks/BlockGridModel.cs @@ -2,7 +2,6 @@ // See LICENSE for more details. using System.Collections.ObjectModel; -using System.ComponentModel; using System.Runtime.Serialization; namespace Umbraco.Cms.Core.Models.Blocks; @@ -12,7 +11,6 @@ namespace Umbraco.Cms.Core.Models.Blocks; /// /// [DataContract(Name = "blockgrid", Namespace = "")] -[EditorBrowsable(EditorBrowsableState.Never)] // TODO: Remove this for V11/V10.4 public class BlockGridModel : BlockModelCollection { /// diff --git a/src/Umbraco.Infrastructure/Models/Blocks/BlockGridEditorDataConverter.cs b/src/Umbraco.Infrastructure/Models/Blocks/BlockGridEditorDataConverter.cs index 016046abff..b5200c9f24 100644 --- a/src/Umbraco.Infrastructure/Models/Blocks/BlockGridEditorDataConverter.cs +++ b/src/Umbraco.Infrastructure/Models/Blocks/BlockGridEditorDataConverter.cs @@ -1,7 +1,6 @@ // Copyright (c) Umbraco. // See LICENSE for more details. -using System.ComponentModel; using Newtonsoft.Json.Linq; using Umbraco.Cms.Core.Serialization; @@ -10,7 +9,6 @@ namespace Umbraco.Cms.Core.Models.Blocks; /// /// Data converter for the block grid property editor /// -[EditorBrowsable(EditorBrowsableState.Never)] // TODO: Remove this for V11/V10.4 public class BlockGridEditorDataConverter : BlockEditorDataConverter { private readonly IJsonSerializer _jsonSerializer; diff --git a/src/Umbraco.Infrastructure/Models/Blocks/BlockGridLayoutAreaItem.cs b/src/Umbraco.Infrastructure/Models/Blocks/BlockGridLayoutAreaItem.cs index 473482f028..3a4d1ba135 100644 --- a/src/Umbraco.Infrastructure/Models/Blocks/BlockGridLayoutAreaItem.cs +++ b/src/Umbraco.Infrastructure/Models/Blocks/BlockGridLayoutAreaItem.cs @@ -1,9 +1,7 @@ -using System.ComponentModel; -using Newtonsoft.Json; +using Newtonsoft.Json; namespace Umbraco.Cms.Core.Models.Blocks; -[EditorBrowsable(EditorBrowsableState.Never)] // TODO: Remove this for V11/V10.4 public class BlockGridLayoutAreaItem { [JsonProperty("key", NullValueHandling = NullValueHandling.Ignore)] diff --git a/src/Umbraco.Infrastructure/Models/Blocks/BlockGridLayoutItem.cs b/src/Umbraco.Infrastructure/Models/Blocks/BlockGridLayoutItem.cs index c06942822e..9014e2789a 100644 --- a/src/Umbraco.Infrastructure/Models/Blocks/BlockGridLayoutItem.cs +++ b/src/Umbraco.Infrastructure/Models/Blocks/BlockGridLayoutItem.cs @@ -1,7 +1,6 @@ // Copyright (c) Umbraco. // See LICENSE for more details. -using System.ComponentModel; using Newtonsoft.Json; using Umbraco.Cms.Infrastructure.Serialization; @@ -10,7 +9,6 @@ namespace Umbraco.Cms.Core.Models.Blocks; /// /// Used for deserializing the block grid layout /// -[EditorBrowsable(EditorBrowsableState.Never)] // TODO: Remove this for V11/V10.4 public class BlockGridLayoutItem : IBlockLayoutItem { [JsonProperty("contentUdi", Required = Required.Always)] diff --git a/src/Umbraco.Infrastructure/PropertyEditors/BlockGridPropertyEditor.cs b/src/Umbraco.Infrastructure/PropertyEditors/BlockGridPropertyEditor.cs index 0b465499f8..8881ce82a9 100644 --- a/src/Umbraco.Infrastructure/PropertyEditors/BlockGridPropertyEditor.cs +++ b/src/Umbraco.Infrastructure/PropertyEditors/BlockGridPropertyEditor.cs @@ -1,8 +1,6 @@ // Copyright (c) Umbraco. // See LICENSE for more details. -using System.ComponentModel; -using Umbraco.Cms.Core.Composing; using Umbraco.Cms.Core.IO; namespace Umbraco.Cms.Core.PropertyEditors; @@ -10,16 +8,13 @@ namespace Umbraco.Cms.Core.PropertyEditors; /// /// Represents a block list property editor. /// -// TODO: Re-add this DataEditor attribute to re-enable the BlockGridEditor for V11/V10.4 -// [DataEditor( -// Constants.PropertyEditors.Aliases.BlockGrid, -// "Block Grid", -// "blockgrid", -// ValueType = ValueTypes.Json, -// Group = Constants.PropertyEditors.Groups.RichContent, -// Icon = "icon-layout")] -[HideFromTypeFinder] -[EditorBrowsable(EditorBrowsableState.Never)] +[DataEditor( + Constants.PropertyEditors.Aliases.BlockGrid, + "Block Grid", + "blockgrid", + ValueType = ValueTypes.Json, + Group = Constants.PropertyEditors.Groups.RichContent, + Icon = "icon-layout")] public class BlockGridPropertyEditor : BlockGridPropertyEditorBase { private readonly IIOHelper _ioHelper; diff --git a/src/Umbraco.Infrastructure/PropertyEditors/BlockGridPropertyEditorBase.cs b/src/Umbraco.Infrastructure/PropertyEditors/BlockGridPropertyEditorBase.cs index 138c3b7320..42a5931a2b 100644 --- a/src/Umbraco.Infrastructure/PropertyEditors/BlockGridPropertyEditorBase.cs +++ b/src/Umbraco.Infrastructure/PropertyEditors/BlockGridPropertyEditorBase.cs @@ -1,10 +1,8 @@ // Copyright (c) Umbraco. // See LICENSE for more details. -using System.ComponentModel; using System.ComponentModel.DataAnnotations; using Microsoft.Extensions.Logging; -using Umbraco.Cms.Core.Composing; using Umbraco.Cms.Core.IO; using Umbraco.Cms.Core.Models; using Umbraco.Cms.Core.Models.Blocks; @@ -18,9 +16,7 @@ namespace Umbraco.Cms.Core.PropertyEditors; /// /// Abstract base class for block grid based editors. -// /// -[HideFromTypeFinder] -[EditorBrowsable(EditorBrowsableState.Never)] +/// public abstract class BlockGridPropertyEditorBase : DataEditor { protected BlockGridPropertyEditorBase(IDataValueEditorFactory dataValueEditorFactory) diff --git a/src/Umbraco.Web.Common/Extensions/BlockGridTemplateExtensions.cs b/src/Umbraco.Web.Common/Extensions/BlockGridTemplateExtensions.cs index ed40a30766..ee0375da4f 100644 --- a/src/Umbraco.Web.Common/Extensions/BlockGridTemplateExtensions.cs +++ b/src/Umbraco.Web.Common/Extensions/BlockGridTemplateExtensions.cs @@ -1,7 +1,6 @@ // Copyright (c) Umbraco. // See LICENSE for more details. -using System.ComponentModel; using Microsoft.AspNetCore.Html; using Microsoft.AspNetCore.Mvc.Rendering; using Umbraco.Cms.Core.Models.Blocks; @@ -9,7 +8,6 @@ using Umbraco.Cms.Core.Models.PublishedContent; namespace Umbraco.Extensions; -[EditorBrowsable(EditorBrowsableState.Never)] public static class BlockGridTemplateExtensions { public const string DefaultFolder = "blockgrid/"; diff --git a/tests/Umbraco.Tests.UnitTests/Umbraco.Core/Composing/TypeLoaderTests.cs b/tests/Umbraco.Tests.UnitTests/Umbraco.Core/Composing/TypeLoaderTests.cs index 4d098b5992..af6dbb1f1c 100644 --- a/tests/Umbraco.Tests.UnitTests/Umbraco.Core/Composing/TypeLoaderTests.cs +++ b/tests/Umbraco.Tests.UnitTests/Umbraco.Core/Composing/TypeLoaderTests.cs @@ -174,8 +174,7 @@ public class TypeLoaderTests public void GetDataEditors() { var types = _typeLoader.GetDataEditors(); - // TODO: Increase this to 42 when BlockGridEditor is re-added - Assert.AreEqual(41, types.Count()); + Assert.AreEqual(42, types.Count()); } /// From ea783bbc417d277b7ea5d086438cd52a1ef225a9 Mon Sep 17 00:00:00 2001 From: Nikolaj Geisle <70372949+Zeegaan@users.noreply.github.com> Date: Thu, 13 Oct 2022 19:29:00 +0200 Subject: [PATCH 31/53] V11: fix failing acceptance tests (#13204) * Fix macro in RTE test * Update test-helper version Co-authored-by: Zeegaan --- .../Umbraco.Tests.AcceptanceTest/package-lock.json | 14 +++++++------- tests/Umbraco.Tests.AcceptanceTest/package.json | 2 +- .../tests/DefaultConfig/Content/content.spec.ts | 4 ++-- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/tests/Umbraco.Tests.AcceptanceTest/package-lock.json b/tests/Umbraco.Tests.AcceptanceTest/package-lock.json index d9d26331d6..5d3837949a 100644 --- a/tests/Umbraco.Tests.AcceptanceTest/package-lock.json +++ b/tests/Umbraco.Tests.AcceptanceTest/package-lock.json @@ -8,7 +8,7 @@ "hasInstallScript": true, "dependencies": { "@umbraco/json-models-builders": "^1.0.0", - "@umbraco/playwright-testhelpers": "^1.0.3", + "@umbraco/playwright-testhelpers": "^1.0.4", "camelize": "^1.0.0", "dotenv": "^16.0.2", "faker": "^4.1.0", @@ -101,9 +101,9 @@ } }, "node_modules/@umbraco/playwright-testhelpers": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@umbraco/playwright-testhelpers/-/playwright-testhelpers-1.0.3.tgz", - "integrity": "sha512-PmUnIaoKitxAC4JWSiPEOPg74Ypt6DNLjUQEATV0n9yVbw5aFQhql+KrdN4F30gFNr1c6Gw6I5iDXzNmq5/zfg==", + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@umbraco/playwright-testhelpers/-/playwright-testhelpers-1.0.4.tgz", + "integrity": "sha512-OBAUzscj+v1w0TwUcWAUeUou6t1wz/7ZXDhMPq6gL8jzAXSFobWRShfC4zqCiWoGLZ8721UN55Q01WFyWiuOSg==", "dependencies": { "@umbraco/json-models-builders": "^1.0.0", "camelize": "^1.0.0", @@ -906,9 +906,9 @@ } }, "@umbraco/playwright-testhelpers": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@umbraco/playwright-testhelpers/-/playwright-testhelpers-1.0.3.tgz", - "integrity": "sha512-PmUnIaoKitxAC4JWSiPEOPg74Ypt6DNLjUQEATV0n9yVbw5aFQhql+KrdN4F30gFNr1c6Gw6I5iDXzNmq5/zfg==", + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@umbraco/playwright-testhelpers/-/playwright-testhelpers-1.0.4.tgz", + "integrity": "sha512-OBAUzscj+v1w0TwUcWAUeUou6t1wz/7ZXDhMPq6gL8jzAXSFobWRShfC4zqCiWoGLZ8721UN55Q01WFyWiuOSg==", "requires": { "@umbraco/json-models-builders": "^1.0.0", "camelize": "^1.0.0", diff --git a/tests/Umbraco.Tests.AcceptanceTest/package.json b/tests/Umbraco.Tests.AcceptanceTest/package.json index 7464e119e0..44aa367595 100644 --- a/tests/Umbraco.Tests.AcceptanceTest/package.json +++ b/tests/Umbraco.Tests.AcceptanceTest/package.json @@ -19,7 +19,7 @@ }, "dependencies": { "@umbraco/json-models-builders": "^1.0.0", - "@umbraco/playwright-testhelpers": "^1.0.3", + "@umbraco/playwright-testhelpers": "^1.0.4", "camelize": "^1.0.0", "faker": "^4.1.0", "form-data": "^4.0.0", diff --git a/tests/Umbraco.Tests.AcceptanceTest/tests/DefaultConfig/Content/content.spec.ts b/tests/Umbraco.Tests.AcceptanceTest/tests/DefaultConfig/Content/content.spec.ts index ea95f45dc3..a93d263107 100644 --- a/tests/Umbraco.Tests.AcceptanceTest/tests/DefaultConfig/Content/content.spec.ts +++ b/tests/Umbraco.Tests.AcceptanceTest/tests/DefaultConfig/Content/content.spec.ts @@ -624,7 +624,7 @@ test.describe('Content tests', () => { await umbracoUi.clickElement(umbracoUi.getTreeItem("content", [viewMacroName])); // Insert macro - await page.locator('#mceu_13-button').click(); + await page.locator('[title="Insert macro"]').click(); await page.locator('.umb-card-grid-item', {hasText: viewMacroName}).click(); // cy.get('.umb-card-grid-item').contains(viewMacroName).click(); @@ -633,7 +633,7 @@ test.describe('Content tests', () => { await umbracoUi.isSuccessNotificationVisible(); // Ensure that the view gets rendered correctly - const expected = `

Acceptance test

 

`; + const expected = `

 

Acceptance test

 

`; await expect(await umbracoApi.content.verifyRenderedContent('/', expected, true)).toBeTruthy(); // Cleanup From 58fb223a45840052adcf1250b7e1e5f0ae387a80 Mon Sep 17 00:00:00 2001 From: Nikolaj Geisle <70372949+Zeegaan@users.noreply.github.com> Date: Fri, 14 Oct 2022 08:48:20 +0200 Subject: [PATCH 32/53] Close success notifications after they pop up --- .../ModelsBuilder/modelsbuilder.spec.ts | 282 ++++++++++++++++++ 1 file changed, 282 insertions(+) create mode 100644 tests/Umbraco.Tests.AcceptanceTest/tests/DefaultConfig/ModelsBuilder/modelsbuilder.spec.ts diff --git a/tests/Umbraco.Tests.AcceptanceTest/tests/DefaultConfig/ModelsBuilder/modelsbuilder.spec.ts b/tests/Umbraco.Tests.AcceptanceTest/tests/DefaultConfig/ModelsBuilder/modelsbuilder.spec.ts new file mode 100644 index 0000000000..43adbc21fe --- /dev/null +++ b/tests/Umbraco.Tests.AcceptanceTest/tests/DefaultConfig/ModelsBuilder/modelsbuilder.spec.ts @@ -0,0 +1,282 @@ +import {AliasHelper, ApiHelpers, ConstantHelper, test, UiHelpers} from '@umbraco/playwright-testhelpers'; +import { + ContentBuilder, + DocumentTypeBuilder, +} from "@umbraco/json-models-builders"; + +test.describe('Modelsbuilder tests', () => { + + test.beforeEach(async ({page, umbracoApi}) => { + await umbracoApi.login(); + }); + + test('Can create and render content', async ({page, umbracoApi, umbracoUi}) => { + const docTypeName = "TestDocument"; + const docTypeAlias = AliasHelper.toAlias(docTypeName); + const contentName = "Home"; + + await umbracoApi.content.deleteAllContent(); + await umbracoApi.documentTypes.ensureNameNotExists(docTypeName); + await umbracoApi.templates.ensureNameNotExists(docTypeName); + + const docType = new DocumentTypeBuilder() + .withName(docTypeName) + .withAlias(docTypeAlias) + .withAllowAsRoot(true) + .withDefaultTemplate(docTypeAlias) + .addTab() + .withName("Content") + .addTextBoxProperty() + .withAlias("title") + .done() + .done() + .build(); + + await umbracoApi.documentTypes.save(docType); + await umbracoApi.templates.edit(docTypeName, `@using Umbraco.Cms.Web.Common.PublishedModels; +@inherits Umbraco.Cms.Web.Common.Views.UmbracoViewPage +@using ContentModels = Umbraco.Cms.Web.Common.PublishedModels; +@{ +\tLayout = null; +} + +

@Model.Title

`); + + // Time to manually create the content + await umbracoUi.createContentWithDocumentType(docTypeName); + await umbracoUi.setEditorHeaderName(contentName); + // Fortunately for us the input field of a text box has the alias of the property as an id :) + await page.locator("#title").type("Hello world!") + await umbracoUi.clickElement(umbracoUi.getButtonByLabelKey(ConstantHelper.buttons.saveAndPublish)); + await umbracoUi.isSuccessNotificationVisible(); + // Ensure that we can render it on the frontend = we can compile the models and views + await umbracoApi.content.verifyRenderedContent("/", "

Hello world!

", true); + + await umbracoApi.content.deleteAllContent(); + await umbracoApi.documentTypes.ensureNameNotExists(docTypeName); + await umbracoApi.templates.ensureNameNotExists(docTypeName); + }); + + test('Can update document type without updating view', async ({page, umbracoApi, umbracoUi}) => { + const docTypeName = "TestDocument"; + const docTypeAlias = AliasHelper.toAlias(docTypeName); + const propertyAlias = "title"; + const propertyValue = "Hello world!" + + await umbracoApi.content.deleteAllContent(); + await umbracoApi.documentTypes.ensureNameNotExists(docTypeName); + await umbracoApi.templates.ensureNameNotExists(docTypeName); + + const docType = new DocumentTypeBuilder() + .withName(docTypeName) + .withAlias(docTypeAlias) + .withAllowAsRoot(true) + .withDefaultTemplate(docTypeAlias) + .addTab() + .withName("Content") + .addTextBoxProperty() + .withAlias(propertyAlias) + .done() + .done() + .build(); + + const savedDocType = await umbracoApi.documentTypes.save(docType); + await umbracoApi.templates.edit(docTypeName, `@using Umbraco.Cms.Web.Common.PublishedModels; +@inherits Umbraco.Cms.Web.Common.Views.UmbracoViewPage +@using ContentModels = Umbraco.Cms.Web.Common.PublishedModels; +@{ +\tLayout = null; +} + +

@Model.Title

`); + + const content = new ContentBuilder() + .withContentTypeAlias(savedDocType["alias"]) + .withAction("publishNew") + .addVariant() + .withName("Home") + .withSave(true) + .withPublish(true) + .addProperty() + .withAlias(propertyAlias) + .withValue(propertyValue) + .done() + .done() + .build() + + await umbracoApi.content.save(content); + + // Navigate to the document type + await umbracoUi.goToSection(ConstantHelper.sections.settings); + await umbracoUi.clickElement(umbracoUi.getTreeItem("settings", ["Document Types", docTypeName])); + // Add a new property (this might cause a version error if the viewcache is not cleared, hence this test + await page.locator('.umb-box-content >> [data-element="property-add"]').click(); + await page.locator('[data-element="property-name"]').type("Second Title"); + await page.locator('[data-element="editor-add"]').click(); + await page.locator('[input-id="datatype-search"]').type("Textstring"); + await page.locator('.umb-card-grid >> [title="Textstring"]').click(); + await umbracoUi.clickElement(umbracoUi.getButtonByLabelKey(ConstantHelper.buttons.submit)); + await umbracoUi.clickElement(umbracoUi.getButtonByLabelKey(ConstantHelper.buttons.save)); + await umbracoUi.isSuccessNotificationVisible(); + + // Now that the content is updated and the models are rebuilt, ensure that we can still render the frontend. + await umbracoApi.content.verifyRenderedContent("/", "

" + propertyValue + "

", true) + + await umbracoApi.content.deleteAllContent(); + await umbracoApi.documentTypes.ensureNameNotExists(docTypeName); + await umbracoApi.templates.ensureNameNotExists(docTypeName); + }); + + test('Can update view without updating document type', async ({page, umbracoApi, umbracoUi}) => { + const docTypeName = "TestDocument"; + const docTypeAlias = AliasHelper.toAlias(docTypeName); + const propertyAlias = "title"; + const propertyValue = "Hello world!" + + await umbracoApi.content.deleteAllContent(); + await umbracoApi.documentTypes.ensureNameNotExists(docTypeName); + await umbracoApi.templates.ensureNameNotExists(docTypeName); + + const docType = new DocumentTypeBuilder() + .withName(docTypeName) + .withAlias(docTypeAlias) + .withAllowAsRoot(true) + .withDefaultTemplate(docTypeAlias) + .addTab() + .withName("Content") + .addTextBoxProperty() + .withAlias(propertyAlias) + .done() + .done() + .build(); + + const savedDocType = await umbracoApi.documentTypes.save(docType); + await umbracoApi.templates.edit(docTypeName, `@using Umbraco.Cms.Web.Common.PublishedModels; +@inherits Umbraco.Cms.Web.Common.Views.UmbracoViewPage +@using ContentModels = Umbraco.Cms.Web.Common.PublishedModels; +@{ +\tLayout = null; +} + +

@Model.Title

`); + + const content = new ContentBuilder() + .withContentTypeAlias(savedDocType["alias"]) + .withAction("publishNew") + .addVariant() + .withName("Home") + .withSave(true) + .withPublish(true) + .addProperty() + .withAlias(propertyAlias) + .withValue(propertyValue) + .done() + .done() + .build() + + await umbracoApi.content.save(content); + + // Navigate to the document type + await umbracoUi.goToSection(ConstantHelper.sections.settings); + await umbracoUi.clickElement(umbracoUi.getTreeItem("settings", ["templates", docTypeName])); + const editor = await page.locator('.ace_content'); + await editor.click(); + // We only have to type out the opening tag, the editor adds the closing tag automatically. + await editor.type("

Edited") + await umbracoUi.clickElement(umbracoUi.getButtonByLabelKey(ConstantHelper.buttons.save)) + + await umbracoUi.isSuccessNotificationVisible(); + await umbracoApi.content.verifyRenderedContent("/", "

" + propertyValue + "

Edited

", true) + + await umbracoApi.content.deleteAllContent(); + await umbracoApi.documentTypes.ensureNameNotExists(docTypeName); + await umbracoApi.templates.ensureNameNotExists(docTypeName); + }); + + test('Can update view and document type', async ({page, umbracoApi, umbracoUi}) => { + const docTypeName = "TestDocument"; + const docTypeAlias = AliasHelper.toAlias(docTypeName); + const propertyAlias = "title"; + const propertyValue = "Hello world!" + const contentName = "Home"; + + await umbracoApi.content.deleteAllContent(); + await umbracoApi.documentTypes.ensureNameNotExists(docTypeName); + await umbracoApi.templates.ensureNameNotExists(docTypeName); + + const docType = new DocumentTypeBuilder() + .withName(docTypeName) + .withAlias(docTypeAlias) + .withAllowAsRoot(true) + .withDefaultTemplate(docTypeAlias) + .addTab() + .withName("Content") + .addTextBoxProperty() + .withAlias(propertyAlias) + .done() + .done() + .build(); + + const savedDocType = await umbracoApi.documentTypes.save(docType); + await umbracoApi.templates.edit(docTypeName, `@using Umbraco.Cms.Web.Common.PublishedModels; +@inherits Umbraco.Cms.Web.Common.Views.UmbracoViewPage +@using ContentModels = Umbraco.Cms.Web.Common.PublishedModels; +@{ +\tLayout = null; +} + +

@Model.Title

`); + + const content = new ContentBuilder() + .withContentTypeAlias(savedDocType["alias"]) + .withAction("publishNew") + .addVariant() + .withName(contentName) + .withSave(true) + .withPublish(true) + .addProperty() + .withAlias(propertyAlias) + .withValue(propertyValue) + .done() + .done() + .build() + + await umbracoApi.content.save(content); + + // Navigate to the document type + await umbracoUi.goToSection(ConstantHelper.sections.settings); + await umbracoUi.clickElement(umbracoUi.getTreeItem("settings", ["Document Types", docTypeName])); + // Add a new property (this might cause a version error if the viewcache is not cleared, hence this test + await page.locator('.umb-box-content >> [data-element="property-add"]').click(); + await page.locator('[data-element="property-name"]').type("Bod"); + await page.locator('[data-element="editor-add"]').click(); + await page.locator('[input-id="datatype-search"]').type("Textstring"); + await page.locator('.umb-card-grid >> [title="Textstring"]').click(); + await umbracoUi.clickElement(umbracoUi.getButtonByLabelKey(ConstantHelper.buttons.submit)); + await umbracoUi.clickElement(umbracoUi.getButtonByLabelKey(ConstantHelper.buttons.save)); + await umbracoUi.isSuccessNotificationVisible(); + await page.locator('span:has-text("×")').click(); + + // Update the template + await umbracoUi.clickElement(umbracoUi.getTreeItem("settings", ["templates", docTypeName])); + const editor = await page.locator('.ace_content'); + await editor.click(); + // We only have to type out the opening tag, the editor adds the closing tag automatically. + await editor.type("

@Model.Bod") + await umbracoUi.clickElement(umbracoUi.getButtonByLabelKey(ConstantHelper.buttons.save)) + await umbracoUi.isSuccessNotificationVisible(); + await page.locator('span:has-text("×")').click(); + + // Navigate to the content section and update the content + await umbracoUi.goToSection(ConstantHelper.sections.content); + await umbracoUi.refreshContentTree(); + await umbracoUi.clickElement(umbracoUi.getTreeItem("content", [contentName])); + await page.locator("#bod").type("Fancy body text"); + + await umbracoApi.content.verifyRenderedContent("/", "

" + propertyValue + "

Fancy body text

", true); + + await umbracoApi.content.deleteAllContent(); + await umbracoApi.documentTypes.ensureNameNotExists(docTypeName); + await umbracoApi.templates.ensureNameNotExists(docTypeName) + }); +}); From c3964c218344f97d8c4367a88432f922833f7732 Mon Sep 17 00:00:00 2001 From: Nikolaj Geisle <70372949+Zeegaan@users.noreply.github.com> Date: Fri, 14 Oct 2022 09:06:12 +0200 Subject: [PATCH 33/53] Update tests to close success notifications --- tests/Umbraco.Tests.AcceptanceTest/playwright.config.ts | 2 +- .../tests/DefaultConfig/Content/content.spec.ts | 1 + .../tests/DefaultConfig/DataTypes/dataTypes.spec.ts | 1 + 3 files changed, 3 insertions(+), 1 deletion(-) diff --git a/tests/Umbraco.Tests.AcceptanceTest/playwright.config.ts b/tests/Umbraco.Tests.AcceptanceTest/playwright.config.ts index f5c9bf5fde..88de91b8e7 100644 --- a/tests/Umbraco.Tests.AcceptanceTest/playwright.config.ts +++ b/tests/Umbraco.Tests.AcceptanceTest/playwright.config.ts @@ -21,7 +21,7 @@ const config: PlaywrightTestConfig = { /* Fail the build on CI if you accidentally left test.only in the source code. */ forbidOnly: !!process.env.CI, /* Retry on CI only */ - retries: process.env.CI ? 5 : 2, + retries: process.env.CI ? 5 : 0, // We don't want to run parallel, as tests might differ in state workers: 1, /* Reporter to use. See https://playwright.dev/docs/test-reporters */ diff --git a/tests/Umbraco.Tests.AcceptanceTest/tests/DefaultConfig/Content/content.spec.ts b/tests/Umbraco.Tests.AcceptanceTest/tests/DefaultConfig/Content/content.spec.ts index a93d263107..6362a583d9 100644 --- a/tests/Umbraco.Tests.AcceptanceTest/tests/DefaultConfig/Content/content.spec.ts +++ b/tests/Umbraco.Tests.AcceptanceTest/tests/DefaultConfig/Content/content.spec.ts @@ -290,6 +290,7 @@ test.describe('Content tests', () => { await umbracoUi.setEditorHeaderName(newNodeName); await umbracoUi.clickElement(umbracoUi.getButtonByLabelKey(ConstantHelper.buttons.saveAndPublish)); await umbracoUi.isSuccessNotificationVisible(); + await page.locator('span:has-text("×")').click(); await umbracoUi.clickElement(umbracoUi.getButtonByLabelKey(ConstantHelper.buttons.rollback)); // Not a very nice selector, but there's sadly no alternative :( diff --git a/tests/Umbraco.Tests.AcceptanceTest/tests/DefaultConfig/DataTypes/dataTypes.spec.ts b/tests/Umbraco.Tests.AcceptanceTest/tests/DefaultConfig/DataTypes/dataTypes.spec.ts index 1da0c016f0..59ff5b7a7f 100644 --- a/tests/Umbraco.Tests.AcceptanceTest/tests/DefaultConfig/DataTypes/dataTypes.spec.ts +++ b/tests/Umbraco.Tests.AcceptanceTest/tests/DefaultConfig/DataTypes/dataTypes.spec.ts @@ -48,6 +48,7 @@ test.describe('DataTypes', () => { // Save await umbracoUi.clickElement(umbracoUi.getButtonByLabelKey(ConstantHelper.buttons.saveAndPublish)); await umbracoUi.isSuccessNotificationVisible(); + await page.locator('span:has-text("×")').click(); // Assert const expected = `

Lorem ipsum dolor sit amet

`; From d5278ca9feda69c0bbbf79e9a2220e44bc2b4e45 Mon Sep 17 00:00:00 2001 From: Nikolaj Geisle <70372949+Zeegaan@users.noreply.github.com> Date: Fri, 14 Oct 2022 09:09:49 +0200 Subject: [PATCH 34/53] Dont commit playwright.config.ts --- tests/Umbraco.Tests.AcceptanceTest/playwright.config.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/Umbraco.Tests.AcceptanceTest/playwright.config.ts b/tests/Umbraco.Tests.AcceptanceTest/playwright.config.ts index 88de91b8e7..f5c9bf5fde 100644 --- a/tests/Umbraco.Tests.AcceptanceTest/playwright.config.ts +++ b/tests/Umbraco.Tests.AcceptanceTest/playwright.config.ts @@ -21,7 +21,7 @@ const config: PlaywrightTestConfig = { /* Fail the build on CI if you accidentally left test.only in the source code. */ forbidOnly: !!process.env.CI, /* Retry on CI only */ - retries: process.env.CI ? 5 : 0, + retries: process.env.CI ? 5 : 2, // We don't want to run parallel, as tests might differ in state workers: 1, /* Reporter to use. See https://playwright.dev/docs/test-reporters */ From c071fc03baa9f8e1b04697abb36ddfdd3a9990d1 Mon Sep 17 00:00:00 2001 From: Nikolaj Geisle <70372949+Zeegaan@users.noreply.github.com> Date: Fri, 14 Oct 2022 09:51:33 +0200 Subject: [PATCH 35/53] Update testhelpers version --- .../Umbraco.Tests.AcceptanceTest/package-lock.json | 14 +++++++------- tests/Umbraco.Tests.AcceptanceTest/package.json | 2 +- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/tests/Umbraco.Tests.AcceptanceTest/package-lock.json b/tests/Umbraco.Tests.AcceptanceTest/package-lock.json index 5d3837949a..dec235bb50 100644 --- a/tests/Umbraco.Tests.AcceptanceTest/package-lock.json +++ b/tests/Umbraco.Tests.AcceptanceTest/package-lock.json @@ -8,7 +8,7 @@ "hasInstallScript": true, "dependencies": { "@umbraco/json-models-builders": "^1.0.0", - "@umbraco/playwright-testhelpers": "^1.0.4", + "@umbraco/playwright-testhelpers": "^1.0.5", "camelize": "^1.0.0", "dotenv": "^16.0.2", "faker": "^4.1.0", @@ -101,9 +101,9 @@ } }, "node_modules/@umbraco/playwright-testhelpers": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/@umbraco/playwright-testhelpers/-/playwright-testhelpers-1.0.4.tgz", - "integrity": "sha512-OBAUzscj+v1w0TwUcWAUeUou6t1wz/7ZXDhMPq6gL8jzAXSFobWRShfC4zqCiWoGLZ8721UN55Q01WFyWiuOSg==", + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@umbraco/playwright-testhelpers/-/playwright-testhelpers-1.0.5.tgz", + "integrity": "sha512-OGV83Clpj3OQgPks3uczcL1JSVW8eF16nRtTKcBSNeg4QaN/021DbluqoVOYtlFYAw3NtOoorAVIGCDhxKECOw==", "dependencies": { "@umbraco/json-models-builders": "^1.0.0", "camelize": "^1.0.0", @@ -906,9 +906,9 @@ } }, "@umbraco/playwright-testhelpers": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/@umbraco/playwright-testhelpers/-/playwright-testhelpers-1.0.4.tgz", - "integrity": "sha512-OBAUzscj+v1w0TwUcWAUeUou6t1wz/7ZXDhMPq6gL8jzAXSFobWRShfC4zqCiWoGLZ8721UN55Q01WFyWiuOSg==", + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@umbraco/playwright-testhelpers/-/playwright-testhelpers-1.0.5.tgz", + "integrity": "sha512-OGV83Clpj3OQgPks3uczcL1JSVW8eF16nRtTKcBSNeg4QaN/021DbluqoVOYtlFYAw3NtOoorAVIGCDhxKECOw==", "requires": { "@umbraco/json-models-builders": "^1.0.0", "camelize": "^1.0.0", diff --git a/tests/Umbraco.Tests.AcceptanceTest/package.json b/tests/Umbraco.Tests.AcceptanceTest/package.json index 44aa367595..812e448a70 100644 --- a/tests/Umbraco.Tests.AcceptanceTest/package.json +++ b/tests/Umbraco.Tests.AcceptanceTest/package.json @@ -19,7 +19,7 @@ }, "dependencies": { "@umbraco/json-models-builders": "^1.0.0", - "@umbraco/playwright-testhelpers": "^1.0.4", + "@umbraco/playwright-testhelpers": "^1.0.5", "camelize": "^1.0.0", "faker": "^4.1.0", "form-data": "^4.0.0", From f8f9646e62e2c61b7ff9118b617c27812f1a2187 Mon Sep 17 00:00:00 2001 From: Nikolaj Geisle <70372949+Zeegaan@users.noreply.github.com> Date: Fri, 14 Oct 2022 09:51:45 +0200 Subject: [PATCH 36/53] Add proper expect to download button --- .../tests/DefaultConfig/Packages/packages.spec.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/Umbraco.Tests.AcceptanceTest/tests/DefaultConfig/Packages/packages.spec.ts b/tests/Umbraco.Tests.AcceptanceTest/tests/DefaultConfig/Packages/packages.spec.ts index ba91e6ba82..86eff05eec 100644 --- a/tests/Umbraco.Tests.AcceptanceTest/tests/DefaultConfig/Packages/packages.spec.ts +++ b/tests/Umbraco.Tests.AcceptanceTest/tests/DefaultConfig/Packages/packages.spec.ts @@ -88,7 +88,8 @@ test.describe('Packages', () => { // Navigate pack to packages and Assert the file is created // Waits until the button download is visible - await page.locator('[label-key="general_download"]').isVisible(); + await expect(await page.locator('[label-key="general_download"]')).toBeVisible({timeout: 60000}); + // Checks if the packages was created const doesExist = await umbracoApi.packages.doesNameExist(packageName); await expect(doesExist).toBe(true); From 84eecf5ee4923d3a00e717ecdd522192bafe230b Mon Sep 17 00:00:00 2001 From: Nikolaj Geisle <70372949+Zeegaan@users.noreply.github.com> Date: Fri, 14 Oct 2022 10:28:21 +0200 Subject: [PATCH 37/53] Close success notification --- .../tests/DefaultConfig/DataTypes/dataTypes.spec.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/Umbraco.Tests.AcceptanceTest/tests/DefaultConfig/DataTypes/dataTypes.spec.ts b/tests/Umbraco.Tests.AcceptanceTest/tests/DefaultConfig/DataTypes/dataTypes.spec.ts index 59ff5b7a7f..ba6637c693 100644 --- a/tests/Umbraco.Tests.AcceptanceTest/tests/DefaultConfig/DataTypes/dataTypes.spec.ts +++ b/tests/Umbraco.Tests.AcceptanceTest/tests/DefaultConfig/DataTypes/dataTypes.spec.ts @@ -159,6 +159,7 @@ test.describe('DataTypes', () => { await umbracoUi.setEditorHeaderName('UrlPickerContent'); await umbracoUi.clickElement(umbracoUi.getButtonByLabelKey(ConstantHelper.buttons.saveAndPublish)); await umbracoUi.isSuccessNotificationVisible(); + await page.locator('span:has-text("×")').click(); await page.locator('.umb-node-preview-add').click(); // Should really try and find a better way to do this, but umbracoTreeItem tries to click the content pane in the background From cf68d499efaf8f937635d3e0a0fb01b87211a4f1 Mon Sep 17 00:00:00 2001 From: Nikolaj Geisle <70372949+Zeegaan@users.noreply.github.com> Date: Fri, 14 Oct 2022 23:58:47 +0200 Subject: [PATCH 38/53] Assert that the item is loaded before trying to click rollback --- .../tests/DefaultConfig/Content/content.spec.ts | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/tests/Umbraco.Tests.AcceptanceTest/tests/DefaultConfig/Content/content.spec.ts b/tests/Umbraco.Tests.AcceptanceTest/tests/DefaultConfig/Content/content.spec.ts index 6362a583d9..c2b9be27aa 100644 --- a/tests/Umbraco.Tests.AcceptanceTest/tests/DefaultConfig/Content/content.spec.ts +++ b/tests/Umbraco.Tests.AcceptanceTest/tests/DefaultConfig/Content/content.spec.ts @@ -295,7 +295,9 @@ test.describe('Content tests', () => { await umbracoUi.clickElement(umbracoUi.getButtonByLabelKey(ConstantHelper.buttons.rollback)); // Not a very nice selector, but there's sadly no alternative :( await page.locator('.-selectable.cursor-pointer').first().click(); - // Sadly can't use the button by label key here since there's another one in the DOM + // Sadly can't use the button by label key here since there's another one in the DOM + const helpText = await page.locator('[key="rollback_diffHelp"]'); + await expect(helpText).toBeVisible(); await page.locator('[action="vm.rollback()"]').click(); await umbracoUi.refreshContentTree(); @@ -664,10 +666,10 @@ test.describe('Content tests', () => { .build(); const alias = AliasHelper.toAlias(name); - + // Save grid and get the ID const dataType = await umbracoApi.dataTypes.save(grid) - + // Create a document type using the data type const docType = new DocumentTypeBuilder() .withName(name) @@ -691,7 +693,7 @@ test.describe('Content tests', () => { .build(); await umbracoApi.content.save(contentNode); - + // Ugly wait but we have to wait for cache to rebuild await page.waitForTimeout(1000); @@ -720,7 +722,7 @@ test.describe('Content tests', () => { // Save and publish await umbracoUi.clickElement(umbracoUi.getButtonByLabelKey(ConstantHelper.buttons.saveAndPublish)); await umbracoUi.isSuccessNotificationVisible(); - + const expected = `
From 3f07612306e188cbe00e1ce78c0e97c6b91655ce Mon Sep 17 00:00:00 2001 From: Nikolaj Geisle <70372949+Zeegaan@users.noreply.github.com> Date: Mon, 17 Oct 2022 10:37:40 +0200 Subject: [PATCH 39/53] Update playwright-testhelpers version --- .../Umbraco.Tests.AcceptanceTest/package-lock.json | 14 +++++++------- tests/Umbraco.Tests.AcceptanceTest/package.json | 2 +- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/tests/Umbraco.Tests.AcceptanceTest/package-lock.json b/tests/Umbraco.Tests.AcceptanceTest/package-lock.json index dec235bb50..61695fb98f 100644 --- a/tests/Umbraco.Tests.AcceptanceTest/package-lock.json +++ b/tests/Umbraco.Tests.AcceptanceTest/package-lock.json @@ -8,7 +8,7 @@ "hasInstallScript": true, "dependencies": { "@umbraco/json-models-builders": "^1.0.0", - "@umbraco/playwright-testhelpers": "^1.0.5", + "@umbraco/playwright-testhelpers": "^1.0.6", "camelize": "^1.0.0", "dotenv": "^16.0.2", "faker": "^4.1.0", @@ -101,9 +101,9 @@ } }, "node_modules/@umbraco/playwright-testhelpers": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/@umbraco/playwright-testhelpers/-/playwright-testhelpers-1.0.5.tgz", - "integrity": "sha512-OGV83Clpj3OQgPks3uczcL1JSVW8eF16nRtTKcBSNeg4QaN/021DbluqoVOYtlFYAw3NtOoorAVIGCDhxKECOw==", + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/@umbraco/playwright-testhelpers/-/playwright-testhelpers-1.0.6.tgz", + "integrity": "sha512-KHc56WSsyLhqBcdaxSKYwjVkTuE9dgIVoc7ixwYUMLxxP2wlPxcn/gcYA7xa+mLVKgXmQYaP2zoA317j7oBz/Q==", "dependencies": { "@umbraco/json-models-builders": "^1.0.0", "camelize": "^1.0.0", @@ -906,9 +906,9 @@ } }, "@umbraco/playwright-testhelpers": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/@umbraco/playwright-testhelpers/-/playwright-testhelpers-1.0.5.tgz", - "integrity": "sha512-OGV83Clpj3OQgPks3uczcL1JSVW8eF16nRtTKcBSNeg4QaN/021DbluqoVOYtlFYAw3NtOoorAVIGCDhxKECOw==", + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/@umbraco/playwright-testhelpers/-/playwright-testhelpers-1.0.6.tgz", + "integrity": "sha512-KHc56WSsyLhqBcdaxSKYwjVkTuE9dgIVoc7ixwYUMLxxP2wlPxcn/gcYA7xa+mLVKgXmQYaP2zoA317j7oBz/Q==", "requires": { "@umbraco/json-models-builders": "^1.0.0", "camelize": "^1.0.0", diff --git a/tests/Umbraco.Tests.AcceptanceTest/package.json b/tests/Umbraco.Tests.AcceptanceTest/package.json index 812e448a70..0b067d6aa2 100644 --- a/tests/Umbraco.Tests.AcceptanceTest/package.json +++ b/tests/Umbraco.Tests.AcceptanceTest/package.json @@ -19,7 +19,7 @@ }, "dependencies": { "@umbraco/json-models-builders": "^1.0.0", - "@umbraco/playwright-testhelpers": "^1.0.5", + "@umbraco/playwright-testhelpers": "^1.0.6", "camelize": "^1.0.0", "faker": "^4.1.0", "form-data": "^4.0.0", From 477f4724c72bce04cd147a1c0f95b82f0c936829 Mon Sep 17 00:00:00 2001 From: Nikolaj Geisle <70372949+Zeegaan@users.noreply.github.com> Date: Mon, 17 Oct 2022 11:10:05 +0200 Subject: [PATCH 40/53] Dont remove whitespace --- .../tests/DefaultConfig/DataTypes/dataTypes.spec.ts | 4 ++-- .../tests/DefaultConfig/ModelsBuilder/modelsbuilder.spec.ts | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/Umbraco.Tests.AcceptanceTest/tests/DefaultConfig/DataTypes/dataTypes.spec.ts b/tests/Umbraco.Tests.AcceptanceTest/tests/DefaultConfig/DataTypes/dataTypes.spec.ts index ba6637c693..417ddb410f 100644 --- a/tests/Umbraco.Tests.AcceptanceTest/tests/DefaultConfig/DataTypes/dataTypes.spec.ts +++ b/tests/Umbraco.Tests.AcceptanceTest/tests/DefaultConfig/DataTypes/dataTypes.spec.ts @@ -65,7 +65,7 @@ test.describe('DataTypes', () => { // Assert const expected2 = '

Lorem ipsum dolor sit amet

'; - await expect(await umbracoApi.content.verifyRenderedContent('/', expected2, true)).toBeTruthy(); + await expect(await umbracoApi.content.verifyRenderedContent('/', expected2)).toBeTruthy(); // Clean await umbracoApi.documentTypes.ensureNameNotExists(name); @@ -176,7 +176,7 @@ test.describe('DataTypes', () => { // Testing if the edits match the expected results const expected = 'UrlPickerContent'; - await expect(await umbracoApi.content.verifyRenderedContent('/', expected, true)).toBeTruthy(); + await expect(await umbracoApi.content.verifyRenderedContent('/', expected)).toBeTruthy(); // Clean await umbracoApi.documentTypes.ensureNameNotExists(urlPickerDocTypeName); diff --git a/tests/Umbraco.Tests.AcceptanceTest/tests/DefaultConfig/ModelsBuilder/modelsbuilder.spec.ts b/tests/Umbraco.Tests.AcceptanceTest/tests/DefaultConfig/ModelsBuilder/modelsbuilder.spec.ts index 43adbc21fe..f97cf3eb4b 100644 --- a/tests/Umbraco.Tests.AcceptanceTest/tests/DefaultConfig/ModelsBuilder/modelsbuilder.spec.ts +++ b/tests/Umbraco.Tests.AcceptanceTest/tests/DefaultConfig/ModelsBuilder/modelsbuilder.spec.ts @@ -50,7 +50,7 @@ test.describe('Modelsbuilder tests', () => { await umbracoUi.clickElement(umbracoUi.getButtonByLabelKey(ConstantHelper.buttons.saveAndPublish)); await umbracoUi.isSuccessNotificationVisible(); // Ensure that we can render it on the frontend = we can compile the models and views - await umbracoApi.content.verifyRenderedContent("/", "

Hello world!

", true); + await umbracoApi.content.verifyRenderedContent("/", "

Hello world!

"); await umbracoApi.content.deleteAllContent(); await umbracoApi.documentTypes.ensureNameNotExists(docTypeName); From 01b24e238c1c2354240366433d7150c59dbbbb7e Mon Sep 17 00:00:00 2001 From: Nikolaj Geisle <70372949+Zeegaan@users.noreply.github.com> Date: Mon, 17 Oct 2022 12:13:55 +0200 Subject: [PATCH 41/53] Update test-helpers version --- .../Umbraco.Tests.AcceptanceTest/package-lock.json | 14 +++++++------- tests/Umbraco.Tests.AcceptanceTest/package.json | 2 +- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/tests/Umbraco.Tests.AcceptanceTest/package-lock.json b/tests/Umbraco.Tests.AcceptanceTest/package-lock.json index 61695fb98f..afdceb5d91 100644 --- a/tests/Umbraco.Tests.AcceptanceTest/package-lock.json +++ b/tests/Umbraco.Tests.AcceptanceTest/package-lock.json @@ -8,7 +8,7 @@ "hasInstallScript": true, "dependencies": { "@umbraco/json-models-builders": "^1.0.0", - "@umbraco/playwright-testhelpers": "^1.0.6", + "@umbraco/playwright-testhelpers": "^1.0.7", "camelize": "^1.0.0", "dotenv": "^16.0.2", "faker": "^4.1.0", @@ -101,9 +101,9 @@ } }, "node_modules/@umbraco/playwright-testhelpers": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/@umbraco/playwright-testhelpers/-/playwright-testhelpers-1.0.6.tgz", - "integrity": "sha512-KHc56WSsyLhqBcdaxSKYwjVkTuE9dgIVoc7ixwYUMLxxP2wlPxcn/gcYA7xa+mLVKgXmQYaP2zoA317j7oBz/Q==", + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/@umbraco/playwright-testhelpers/-/playwright-testhelpers-1.0.7.tgz", + "integrity": "sha512-6kv4w5cshC2WjcD6+WS/c6OETC7nM1G6W2oopl7oHE/JUWGqftulDsq9ZDFYDVn+4q+Edcf6griu7Y1vdhiKtQ==", "dependencies": { "@umbraco/json-models-builders": "^1.0.0", "camelize": "^1.0.0", @@ -906,9 +906,9 @@ } }, "@umbraco/playwright-testhelpers": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/@umbraco/playwright-testhelpers/-/playwright-testhelpers-1.0.6.tgz", - "integrity": "sha512-KHc56WSsyLhqBcdaxSKYwjVkTuE9dgIVoc7ixwYUMLxxP2wlPxcn/gcYA7xa+mLVKgXmQYaP2zoA317j7oBz/Q==", + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/@umbraco/playwright-testhelpers/-/playwright-testhelpers-1.0.7.tgz", + "integrity": "sha512-6kv4w5cshC2WjcD6+WS/c6OETC7nM1G6W2oopl7oHE/JUWGqftulDsq9ZDFYDVn+4q+Edcf6griu7Y1vdhiKtQ==", "requires": { "@umbraco/json-models-builders": "^1.0.0", "camelize": "^1.0.0", diff --git a/tests/Umbraco.Tests.AcceptanceTest/package.json b/tests/Umbraco.Tests.AcceptanceTest/package.json index 0b067d6aa2..8624a83769 100644 --- a/tests/Umbraco.Tests.AcceptanceTest/package.json +++ b/tests/Umbraco.Tests.AcceptanceTest/package.json @@ -19,7 +19,7 @@ }, "dependencies": { "@umbraco/json-models-builders": "^1.0.0", - "@umbraco/playwright-testhelpers": "^1.0.6", + "@umbraco/playwright-testhelpers": "^1.0.7", "camelize": "^1.0.0", "faker": "^4.1.0", "form-data": "^4.0.0", From 17de2ff98e24ff3a3fc17441f1e1e7a1de3c15c0 Mon Sep 17 00:00:00 2001 From: Nikolaj Geisle <70372949+Zeegaan@users.noreply.github.com> Date: Mon, 17 Oct 2022 12:17:31 +0200 Subject: [PATCH 42/53] Bumb testhelpers version --- .../Umbraco.Tests.AcceptanceTest/package-lock.json | 14 +++++++------- tests/Umbraco.Tests.AcceptanceTest/package.json | 2 +- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/tests/Umbraco.Tests.AcceptanceTest/package-lock.json b/tests/Umbraco.Tests.AcceptanceTest/package-lock.json index afdceb5d91..97a7c145fe 100644 --- a/tests/Umbraco.Tests.AcceptanceTest/package-lock.json +++ b/tests/Umbraco.Tests.AcceptanceTest/package-lock.json @@ -8,7 +8,7 @@ "hasInstallScript": true, "dependencies": { "@umbraco/json-models-builders": "^1.0.0", - "@umbraco/playwright-testhelpers": "^1.0.7", + "@umbraco/playwright-testhelpers": "^1.0.8", "camelize": "^1.0.0", "dotenv": "^16.0.2", "faker": "^4.1.0", @@ -101,9 +101,9 @@ } }, "node_modules/@umbraco/playwright-testhelpers": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/@umbraco/playwright-testhelpers/-/playwright-testhelpers-1.0.7.tgz", - "integrity": "sha512-6kv4w5cshC2WjcD6+WS/c6OETC7nM1G6W2oopl7oHE/JUWGqftulDsq9ZDFYDVn+4q+Edcf6griu7Y1vdhiKtQ==", + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/@umbraco/playwright-testhelpers/-/playwright-testhelpers-1.0.8.tgz", + "integrity": "sha512-zzwxgJGmQQckF3pi4EQPeeUxGfXRDMefK2LjfDfQHesaRMBoTf4ah73w4nAOKuoREuE1yZIDwf7bzz3pNOEXiw==", "dependencies": { "@umbraco/json-models-builders": "^1.0.0", "camelize": "^1.0.0", @@ -906,9 +906,9 @@ } }, "@umbraco/playwright-testhelpers": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/@umbraco/playwright-testhelpers/-/playwright-testhelpers-1.0.7.tgz", - "integrity": "sha512-6kv4w5cshC2WjcD6+WS/c6OETC7nM1G6W2oopl7oHE/JUWGqftulDsq9ZDFYDVn+4q+Edcf6griu7Y1vdhiKtQ==", + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/@umbraco/playwright-testhelpers/-/playwright-testhelpers-1.0.8.tgz", + "integrity": "sha512-zzwxgJGmQQckF3pi4EQPeeUxGfXRDMefK2LjfDfQHesaRMBoTf4ah73w4nAOKuoREuE1yZIDwf7bzz3pNOEXiw==", "requires": { "@umbraco/json-models-builders": "^1.0.0", "camelize": "^1.0.0", diff --git a/tests/Umbraco.Tests.AcceptanceTest/package.json b/tests/Umbraco.Tests.AcceptanceTest/package.json index 8624a83769..30edac0506 100644 --- a/tests/Umbraco.Tests.AcceptanceTest/package.json +++ b/tests/Umbraco.Tests.AcceptanceTest/package.json @@ -19,7 +19,7 @@ }, "dependencies": { "@umbraco/json-models-builders": "^1.0.0", - "@umbraco/playwright-testhelpers": "^1.0.7", + "@umbraco/playwright-testhelpers": "^1.0.8", "camelize": "^1.0.0", "faker": "^4.1.0", "form-data": "^4.0.0", From fff2b54203354154135be39cbf2408618c511d85 Mon Sep 17 00:00:00 2001 From: Nikolaj Geisle <70372949+Zeegaan@users.noreply.github.com> Date: Mon, 17 Oct 2022 13:01:54 +0200 Subject: [PATCH 43/53] Remove whitespace from response --- .../tests/DefaultConfig/DataTypes/dataTypes.spec.ts | 4 ++-- .../tests/DefaultConfig/ModelsBuilder/modelsbuilder.spec.ts | 4 +++- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/tests/Umbraco.Tests.AcceptanceTest/tests/DefaultConfig/DataTypes/dataTypes.spec.ts b/tests/Umbraco.Tests.AcceptanceTest/tests/DefaultConfig/DataTypes/dataTypes.spec.ts index 417ddb410f..ba6637c693 100644 --- a/tests/Umbraco.Tests.AcceptanceTest/tests/DefaultConfig/DataTypes/dataTypes.spec.ts +++ b/tests/Umbraco.Tests.AcceptanceTest/tests/DefaultConfig/DataTypes/dataTypes.spec.ts @@ -65,7 +65,7 @@ test.describe('DataTypes', () => { // Assert const expected2 = '

Lorem ipsum dolor sit amet

'; - await expect(await umbracoApi.content.verifyRenderedContent('/', expected2)).toBeTruthy(); + await expect(await umbracoApi.content.verifyRenderedContent('/', expected2, true)).toBeTruthy(); // Clean await umbracoApi.documentTypes.ensureNameNotExists(name); @@ -176,7 +176,7 @@ test.describe('DataTypes', () => { // Testing if the edits match the expected results const expected = 'UrlPickerContent'; - await expect(await umbracoApi.content.verifyRenderedContent('/', expected)).toBeTruthy(); + await expect(await umbracoApi.content.verifyRenderedContent('/', expected, true)).toBeTruthy(); // Clean await umbracoApi.documentTypes.ensureNameNotExists(urlPickerDocTypeName); diff --git a/tests/Umbraco.Tests.AcceptanceTest/tests/DefaultConfig/ModelsBuilder/modelsbuilder.spec.ts b/tests/Umbraco.Tests.AcceptanceTest/tests/DefaultConfig/ModelsBuilder/modelsbuilder.spec.ts index f97cf3eb4b..ada1773bd8 100644 --- a/tests/Umbraco.Tests.AcceptanceTest/tests/DefaultConfig/ModelsBuilder/modelsbuilder.spec.ts +++ b/tests/Umbraco.Tests.AcceptanceTest/tests/DefaultConfig/ModelsBuilder/modelsbuilder.spec.ts @@ -50,7 +50,7 @@ test.describe('Modelsbuilder tests', () => { await umbracoUi.clickElement(umbracoUi.getButtonByLabelKey(ConstantHelper.buttons.saveAndPublish)); await umbracoUi.isSuccessNotificationVisible(); // Ensure that we can render it on the frontend = we can compile the models and views - await umbracoApi.content.verifyRenderedContent("/", "

Hello world!

"); + await umbracoApi.content.verifyRenderedContent("/", "

Hello world!

", true); await umbracoApi.content.deleteAllContent(); await umbracoApi.documentTypes.ensureNameNotExists(docTypeName); @@ -243,6 +243,7 @@ test.describe('Modelsbuilder tests', () => { await umbracoApi.content.save(content); + await page.pause(); // Navigate to the document type await umbracoUi.goToSection(ConstantHelper.sections.settings); await umbracoUi.clickElement(umbracoUi.getTreeItem("settings", ["Document Types", docTypeName])); @@ -272,6 +273,7 @@ test.describe('Modelsbuilder tests', () => { await umbracoUi.refreshContentTree(); await umbracoUi.clickElement(umbracoUi.getTreeItem("content", [contentName])); await page.locator("#bod").type("Fancy body text"); + await umbracoUi.clickElement(umbracoUi.getButtonByLabelKey(ConstantHelper.buttons.saveAndPublish)) await umbracoApi.content.verifyRenderedContent("/", "

" + propertyValue + "

Fancy body text

", true); From e8456e36b246cd7515ff5057845b2b57b5bf342a Mon Sep 17 00:00:00 2001 From: Nikolaj Geisle <70372949+Zeegaan@users.noreply.github.com> Date: Mon, 17 Oct 2022 14:29:03 +0200 Subject: [PATCH 44/53] Bumb testhelpers package --- .../Umbraco.Tests.AcceptanceTest/package-lock.json | 14 +++++++------- tests/Umbraco.Tests.AcceptanceTest/package.json | 2 +- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/tests/Umbraco.Tests.AcceptanceTest/package-lock.json b/tests/Umbraco.Tests.AcceptanceTest/package-lock.json index 97a7c145fe..971d3b2534 100644 --- a/tests/Umbraco.Tests.AcceptanceTest/package-lock.json +++ b/tests/Umbraco.Tests.AcceptanceTest/package-lock.json @@ -8,7 +8,7 @@ "hasInstallScript": true, "dependencies": { "@umbraco/json-models-builders": "^1.0.0", - "@umbraco/playwright-testhelpers": "^1.0.8", + "@umbraco/playwright-testhelpers": "^1.0.9", "camelize": "^1.0.0", "dotenv": "^16.0.2", "faker": "^4.1.0", @@ -101,9 +101,9 @@ } }, "node_modules/@umbraco/playwright-testhelpers": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/@umbraco/playwright-testhelpers/-/playwright-testhelpers-1.0.8.tgz", - "integrity": "sha512-zzwxgJGmQQckF3pi4EQPeeUxGfXRDMefK2LjfDfQHesaRMBoTf4ah73w4nAOKuoREuE1yZIDwf7bzz3pNOEXiw==", + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/@umbraco/playwright-testhelpers/-/playwright-testhelpers-1.0.9.tgz", + "integrity": "sha512-+w0jisYmKWfBojTZ6UJeIGub9N67x+j/atA1vVjABv2+69KDMZ+lby7ZfA51gitOpFGZpt4w6DvYiO85+93kvA==", "dependencies": { "@umbraco/json-models-builders": "^1.0.0", "camelize": "^1.0.0", @@ -906,9 +906,9 @@ } }, "@umbraco/playwright-testhelpers": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/@umbraco/playwright-testhelpers/-/playwright-testhelpers-1.0.8.tgz", - "integrity": "sha512-zzwxgJGmQQckF3pi4EQPeeUxGfXRDMefK2LjfDfQHesaRMBoTf4ah73w4nAOKuoREuE1yZIDwf7bzz3pNOEXiw==", + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/@umbraco/playwright-testhelpers/-/playwright-testhelpers-1.0.9.tgz", + "integrity": "sha512-+w0jisYmKWfBojTZ6UJeIGub9N67x+j/atA1vVjABv2+69KDMZ+lby7ZfA51gitOpFGZpt4w6DvYiO85+93kvA==", "requires": { "@umbraco/json-models-builders": "^1.0.0", "camelize": "^1.0.0", diff --git a/tests/Umbraco.Tests.AcceptanceTest/package.json b/tests/Umbraco.Tests.AcceptanceTest/package.json index 30edac0506..7cb2322bac 100644 --- a/tests/Umbraco.Tests.AcceptanceTest/package.json +++ b/tests/Umbraco.Tests.AcceptanceTest/package.json @@ -19,7 +19,7 @@ }, "dependencies": { "@umbraco/json-models-builders": "^1.0.0", - "@umbraco/playwright-testhelpers": "^1.0.8", + "@umbraco/playwright-testhelpers": "^1.0.9", "camelize": "^1.0.0", "faker": "^4.1.0", "form-data": "^4.0.0", From 8f70276cf72c742fc42788a977fb6f6972872481 Mon Sep 17 00:00:00 2001 From: Nikolaj Geisle <70372949+Zeegaan@users.noreply.github.com> Date: Mon, 17 Oct 2022 14:53:41 +0200 Subject: [PATCH 45/53] Update maximum test time-out --- tests/Umbraco.Tests.AcceptanceTest/playwright.config.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/Umbraco.Tests.AcceptanceTest/playwright.config.ts b/tests/Umbraco.Tests.AcceptanceTest/playwright.config.ts index f5c9bf5fde..dfa3fc61c1 100644 --- a/tests/Umbraco.Tests.AcceptanceTest/playwright.config.ts +++ b/tests/Umbraco.Tests.AcceptanceTest/playwright.config.ts @@ -10,7 +10,7 @@ dotenv.config(); const config: PlaywrightTestConfig = { testDir: './tests/', /* Maximum time one test can run for. */ - timeout: 30 * 1000, + timeout: 120 * 1000, expect: { /** * Maximum time expect() should wait for the condition to be met. From ad67616f66962f6735186e2730f800b6a885cfc6 Mon Sep 17 00:00:00 2001 From: Nikolaj Geisle <70372949+Zeegaan@users.noreply.github.com> Date: Mon, 17 Oct 2022 15:27:26 +0200 Subject: [PATCH 46/53] Reset maximum timeout to 30s --- tests/Umbraco.Tests.AcceptanceTest/playwright.config.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/Umbraco.Tests.AcceptanceTest/playwright.config.ts b/tests/Umbraco.Tests.AcceptanceTest/playwright.config.ts index dfa3fc61c1..f5c9bf5fde 100644 --- a/tests/Umbraco.Tests.AcceptanceTest/playwright.config.ts +++ b/tests/Umbraco.Tests.AcceptanceTest/playwright.config.ts @@ -10,7 +10,7 @@ dotenv.config(); const config: PlaywrightTestConfig = { testDir: './tests/', /* Maximum time one test can run for. */ - timeout: 120 * 1000, + timeout: 30 * 1000, expect: { /** * Maximum time expect() should wait for the condition to be met. From 39f349fc9922ae31dbd778f48ab3c9c1befc64a1 Mon Sep 17 00:00:00 2001 From: Nikolaj Geisle <70372949+Zeegaan@users.noreply.github.com> Date: Mon, 17 Oct 2022 15:42:00 +0200 Subject: [PATCH 47/53] Bumb playwright-testhelper version --- .../Umbraco.Tests.AcceptanceTest/package-lock.json | 14 +++++++------- tests/Umbraco.Tests.AcceptanceTest/package.json | 2 +- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/tests/Umbraco.Tests.AcceptanceTest/package-lock.json b/tests/Umbraco.Tests.AcceptanceTest/package-lock.json index 971d3b2534..480c6e60fb 100644 --- a/tests/Umbraco.Tests.AcceptanceTest/package-lock.json +++ b/tests/Umbraco.Tests.AcceptanceTest/package-lock.json @@ -8,7 +8,7 @@ "hasInstallScript": true, "dependencies": { "@umbraco/json-models-builders": "^1.0.0", - "@umbraco/playwright-testhelpers": "^1.0.9", + "@umbraco/playwright-testhelpers": "^1.0.10", "camelize": "^1.0.0", "dotenv": "^16.0.2", "faker": "^4.1.0", @@ -101,9 +101,9 @@ } }, "node_modules/@umbraco/playwright-testhelpers": { - "version": "1.0.9", - "resolved": "https://registry.npmjs.org/@umbraco/playwright-testhelpers/-/playwright-testhelpers-1.0.9.tgz", - "integrity": "sha512-+w0jisYmKWfBojTZ6UJeIGub9N67x+j/atA1vVjABv2+69KDMZ+lby7ZfA51gitOpFGZpt4w6DvYiO85+93kvA==", + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/@umbraco/playwright-testhelpers/-/playwright-testhelpers-1.0.10.tgz", + "integrity": "sha512-4NTuMbbNWGcawZIuYnDdPUGN4W2F9iw0EvsyJ2Pr5rYj8Rg1PCu2MXW77r27fGhfr31PYDEL6RSL9zp8SyxfJg==", "dependencies": { "@umbraco/json-models-builders": "^1.0.0", "camelize": "^1.0.0", @@ -906,9 +906,9 @@ } }, "@umbraco/playwright-testhelpers": { - "version": "1.0.9", - "resolved": "https://registry.npmjs.org/@umbraco/playwright-testhelpers/-/playwright-testhelpers-1.0.9.tgz", - "integrity": "sha512-+w0jisYmKWfBojTZ6UJeIGub9N67x+j/atA1vVjABv2+69KDMZ+lby7ZfA51gitOpFGZpt4w6DvYiO85+93kvA==", + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/@umbraco/playwright-testhelpers/-/playwright-testhelpers-1.0.10.tgz", + "integrity": "sha512-4NTuMbbNWGcawZIuYnDdPUGN4W2F9iw0EvsyJ2Pr5rYj8Rg1PCu2MXW77r27fGhfr31PYDEL6RSL9zp8SyxfJg==", "requires": { "@umbraco/json-models-builders": "^1.0.0", "camelize": "^1.0.0", diff --git a/tests/Umbraco.Tests.AcceptanceTest/package.json b/tests/Umbraco.Tests.AcceptanceTest/package.json index 7cb2322bac..55da15670c 100644 --- a/tests/Umbraco.Tests.AcceptanceTest/package.json +++ b/tests/Umbraco.Tests.AcceptanceTest/package.json @@ -19,7 +19,7 @@ }, "dependencies": { "@umbraco/json-models-builders": "^1.0.0", - "@umbraco/playwright-testhelpers": "^1.0.9", + "@umbraco/playwright-testhelpers": "^1.0.10", "camelize": "^1.0.0", "faker": "^4.1.0", "form-data": "^4.0.0", From 514497ffab1f6f018d390854075b9c1beaf2a74b Mon Sep 17 00:00:00 2001 From: Nikolaj Geisle <70372949+Zeegaan@users.noreply.github.com> Date: Tue, 18 Oct 2022 08:19:23 +0200 Subject: [PATCH 48/53] Update tests/Umbraco.Tests.AcceptanceTest/tests/DefaultConfig/ModelsBuilder/modelsbuilder.spec.ts --- .../tests/DefaultConfig/ModelsBuilder/modelsbuilder.spec.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/Umbraco.Tests.AcceptanceTest/tests/DefaultConfig/ModelsBuilder/modelsbuilder.spec.ts b/tests/Umbraco.Tests.AcceptanceTest/tests/DefaultConfig/ModelsBuilder/modelsbuilder.spec.ts index ada1773bd8..998a738e2f 100644 --- a/tests/Umbraco.Tests.AcceptanceTest/tests/DefaultConfig/ModelsBuilder/modelsbuilder.spec.ts +++ b/tests/Umbraco.Tests.AcceptanceTest/tests/DefaultConfig/ModelsBuilder/modelsbuilder.spec.ts @@ -243,7 +243,6 @@ test.describe('Modelsbuilder tests', () => { await umbracoApi.content.save(content); - await page.pause(); // Navigate to the document type await umbracoUi.goToSection(ConstantHelper.sections.settings); await umbracoUi.clickElement(umbracoUi.getTreeItem("settings", ["Document Types", docTypeName])); From 7ba94847059195c2176c5f798d915a8b326ce8d2 Mon Sep 17 00:00:00 2001 From: Zeegaan Date: Tue, 18 Oct 2022 11:18:05 +0200 Subject: [PATCH 49/53] Added proper save assert instead of checking on the route --- .../tests/DefaultConfig/Settings/relationTypes.spec.ts | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/tests/Umbraco.Tests.AcceptanceTest/tests/DefaultConfig/Settings/relationTypes.spec.ts b/tests/Umbraco.Tests.AcceptanceTest/tests/DefaultConfig/Settings/relationTypes.spec.ts index d1a375ef6e..e49cecde54 100644 --- a/tests/Umbraco.Tests.AcceptanceTest/tests/DefaultConfig/Settings/relationTypes.spec.ts +++ b/tests/Umbraco.Tests.AcceptanceTest/tests/DefaultConfig/Settings/relationTypes.spec.ts @@ -30,11 +30,9 @@ test.describe('Relation Types', () => { await page.selectOption('select[name="relationType-child"]', {label: "Media"}); await form.locator('[name="relationType-isdependency"]').last().click({force: true}); await form.locator('.btn-primary').click(); + await umbracoUi.clickElement(umbracoUi.getButtonByLabelKey(ConstantHelper.buttons.save)) + await umbracoUi.isSuccessNotificationVisible(); - await page.waitForNavigation(); - - expect(page.url()).toContain("#/settings/relationTypes/edit/"); - //Clean up await umbracoApi.relationTypes.ensureNameNotExists(name); }); From 61415b5c314237a46e29a396ca6f3cc5e9d7e539 Mon Sep 17 00:00:00 2001 From: Zeegaan Date: Wed, 19 Oct 2022 07:46:15 +0200 Subject: [PATCH 50/53] Add back the v10 locator that was updated in v11 --- .../tests/DefaultConfig/Settings/macro.spec.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tests/Umbraco.Tests.AcceptanceTest/tests/DefaultConfig/Settings/macro.spec.ts b/tests/Umbraco.Tests.AcceptanceTest/tests/DefaultConfig/Settings/macro.spec.ts index c54907d315..b4a9608547 100644 --- a/tests/Umbraco.Tests.AcceptanceTest/tests/DefaultConfig/Settings/macro.spec.ts +++ b/tests/Umbraco.Tests.AcceptanceTest/tests/DefaultConfig/Settings/macro.spec.ts @@ -30,7 +30,9 @@ test.describe('Macros', () => { await form.locator(".btn-primary").click(); // Adds partial view to macro - await page.locator('[data-element="property-label-macroPartialViewPickerProperty"]').click(); + // THIS SHOULD BE await page.locator('[data-element="property-label-macroPartialViewPickerProperty"]').click(); IN V11 + await page.locator('[label="Macro partial view"]').click(); + await page.locator('[data-element="tree-item-' + partialViewName + '.cshtml"]').click(); await umbracoUi.clickElement(umbracoUi.getButtonByLabelKey(ConstantHelper.buttons.save)); From cb9c165794cb6275531a84ec88843e6a63f690e3 Mon Sep 17 00:00:00 2001 From: Zeegaan Date: Wed, 19 Oct 2022 07:51:24 +0200 Subject: [PATCH 51/53] Add back macro locator --- .../tests/DefaultConfig/Settings/macro.spec.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tests/Umbraco.Tests.AcceptanceTest/tests/DefaultConfig/Settings/macro.spec.ts b/tests/Umbraco.Tests.AcceptanceTest/tests/DefaultConfig/Settings/macro.spec.ts index b4a9608547..895bff5366 100644 --- a/tests/Umbraco.Tests.AcceptanceTest/tests/DefaultConfig/Settings/macro.spec.ts +++ b/tests/Umbraco.Tests.AcceptanceTest/tests/DefaultConfig/Settings/macro.spec.ts @@ -30,8 +30,7 @@ test.describe('Macros', () => { await form.locator(".btn-primary").click(); // Adds partial view to macro - // THIS SHOULD BE await page.locator('[data-element="property-label-macroPartialViewPickerProperty"]').click(); IN V11 - await page.locator('[label="Macro partial view"]').click(); + await page.locator('[data-element="property-label-macroPartialViewPickerProperty"]').click(); await page.locator('[data-element="tree-item-' + partialViewName + '.cshtml"]').click(); From 08982709b3e50ca862ceda9f331691d8d3d66450 Mon Sep 17 00:00:00 2001 From: Zeegaan Date: Wed, 19 Oct 2022 07:52:14 +0200 Subject: [PATCH 52/53] Revert "V11: fix failing acceptance tests (#13204)" This reverts commit ea783bbc --- .../tests/DefaultConfig/Content/content.spec.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/Umbraco.Tests.AcceptanceTest/tests/DefaultConfig/Content/content.spec.ts b/tests/Umbraco.Tests.AcceptanceTest/tests/DefaultConfig/Content/content.spec.ts index c2b9be27aa..c3a78183cf 100644 --- a/tests/Umbraco.Tests.AcceptanceTest/tests/DefaultConfig/Content/content.spec.ts +++ b/tests/Umbraco.Tests.AcceptanceTest/tests/DefaultConfig/Content/content.spec.ts @@ -627,7 +627,7 @@ test.describe('Content tests', () => { await umbracoUi.clickElement(umbracoUi.getTreeItem("content", [viewMacroName])); // Insert macro - await page.locator('[title="Insert macro"]').click(); + await page.locator('#mceu_13-button').click(); await page.locator('.umb-card-grid-item', {hasText: viewMacroName}).click(); // cy.get('.umb-card-grid-item').contains(viewMacroName).click(); @@ -636,7 +636,7 @@ test.describe('Content tests', () => { await umbracoUi.isSuccessNotificationVisible(); // Ensure that the view gets rendered correctly - const expected = `

 

Acceptance test

 

`; + const expected = `

Acceptance test

 

`; await expect(await umbracoApi.content.verifyRenderedContent('/', expected, true)).toBeTruthy(); // Cleanup From a696d7081596ca84620f46927ed29f5cae744e0b Mon Sep 17 00:00:00 2001 From: Mole Date: Wed, 19 Oct 2022 14:13:56 +0200 Subject: [PATCH 53/53] Add default BlockGrid partial views to disk (#13227) * Add migration that adds BlockGrid files to disk * Add partial views to disk when creating sample * Refactor upgrade to use IPartialViewPopulator * Add blockgrid default rendering partial views when creating a new project from template * Remove views from static assets Co-authored-by: Elitsa Marinovska --- .../umbBlockGridDemoHeadlineBlock.cshtml | 0 .../umbBlockGridDemoImageBlock.cshtml | 0 .../umbBlockGridDemoRichTextBlock.cshtml | 0 ...mbBlockGridDemoTwoColumnLayoutBlock.cshtml | 0 .../EmbeddedResources/BlockGrid}/areas.cshtml | 0 .../BlockGrid}/default.cshtml | 0 .../EmbeddedResources/BlockGrid}/items.cshtml | 0 .../UmbracoBuilder.Services.cs | 2 + .../Migrations/Upgrade/UmbracoPlan.cs | 4 + .../V_10_3_0/AddBlockGridPartialViews.cs | 31 +++++++ .../PartialViews/IPartialViewPopulator.cs | 21 +++++ .../PartialViews/PartialViewPopulator.cs | 51 +++++++++++ .../Controllers/BlockGridSampleHelper.cs | 34 ++++++- .../Controllers/ContentTypeController.cs | 90 +++++++++++++++---- .../UmbracoBuilderExtensions.cs | 2 + .../Views/Partials/blockgrid/areas.cshtml | 19 ++++ .../Views/Partials/blockgrid/default.cshtml | 11 +++ .../Views/Partials/blockgrid/items.cshtml | 39 ++++++++ templates/Umbraco.Templates.csproj | 4 + 19 files changed, 286 insertions(+), 22 deletions(-) rename src/{Umbraco.Cms.StaticAssets/Views/Partials/blockgrid => Umbraco.Core/EmbeddedResources/BlockGrid}/Components/umbBlockGridDemoHeadlineBlock.cshtml (100%) rename src/{Umbraco.Cms.StaticAssets/Views/Partials/blockgrid => Umbraco.Core/EmbeddedResources/BlockGrid}/Components/umbBlockGridDemoImageBlock.cshtml (100%) rename src/{Umbraco.Cms.StaticAssets/Views/Partials/blockgrid => Umbraco.Core/EmbeddedResources/BlockGrid}/Components/umbBlockGridDemoRichTextBlock.cshtml (100%) rename src/{Umbraco.Cms.StaticAssets/Views/Partials/blockgrid => Umbraco.Core/EmbeddedResources/BlockGrid}/Components/umbBlockGridDemoTwoColumnLayoutBlock.cshtml (100%) rename src/{Umbraco.Cms.StaticAssets/Views/Partials/blockgrid => Umbraco.Core/EmbeddedResources/BlockGrid}/areas.cshtml (100%) rename src/{Umbraco.Cms.StaticAssets/Views/Partials/blockgrid => Umbraco.Core/EmbeddedResources/BlockGrid}/default.cshtml (100%) rename src/{Umbraco.Cms.StaticAssets/Views/Partials/blockgrid => Umbraco.Core/EmbeddedResources/BlockGrid}/items.cshtml (100%) create mode 100644 src/Umbraco.Infrastructure/Migrations/Upgrade/V_10_3_0/AddBlockGridPartialViews.cs create mode 100644 src/Umbraco.Infrastructure/Templates/PartialViews/IPartialViewPopulator.cs create mode 100644 src/Umbraco.Infrastructure/Templates/PartialViews/PartialViewPopulator.cs create mode 100644 src/Umbraco.Web.UI/Views/Partials/blockgrid/areas.cshtml create mode 100644 src/Umbraco.Web.UI/Views/Partials/blockgrid/default.cshtml create mode 100644 src/Umbraco.Web.UI/Views/Partials/blockgrid/items.cshtml diff --git a/src/Umbraco.Cms.StaticAssets/Views/Partials/blockgrid/Components/umbBlockGridDemoHeadlineBlock.cshtml b/src/Umbraco.Core/EmbeddedResources/BlockGrid/Components/umbBlockGridDemoHeadlineBlock.cshtml similarity index 100% rename from src/Umbraco.Cms.StaticAssets/Views/Partials/blockgrid/Components/umbBlockGridDemoHeadlineBlock.cshtml rename to src/Umbraco.Core/EmbeddedResources/BlockGrid/Components/umbBlockGridDemoHeadlineBlock.cshtml diff --git a/src/Umbraco.Cms.StaticAssets/Views/Partials/blockgrid/Components/umbBlockGridDemoImageBlock.cshtml b/src/Umbraco.Core/EmbeddedResources/BlockGrid/Components/umbBlockGridDemoImageBlock.cshtml similarity index 100% rename from src/Umbraco.Cms.StaticAssets/Views/Partials/blockgrid/Components/umbBlockGridDemoImageBlock.cshtml rename to src/Umbraco.Core/EmbeddedResources/BlockGrid/Components/umbBlockGridDemoImageBlock.cshtml diff --git a/src/Umbraco.Cms.StaticAssets/Views/Partials/blockgrid/Components/umbBlockGridDemoRichTextBlock.cshtml b/src/Umbraco.Core/EmbeddedResources/BlockGrid/Components/umbBlockGridDemoRichTextBlock.cshtml similarity index 100% rename from src/Umbraco.Cms.StaticAssets/Views/Partials/blockgrid/Components/umbBlockGridDemoRichTextBlock.cshtml rename to src/Umbraco.Core/EmbeddedResources/BlockGrid/Components/umbBlockGridDemoRichTextBlock.cshtml diff --git a/src/Umbraco.Cms.StaticAssets/Views/Partials/blockgrid/Components/umbBlockGridDemoTwoColumnLayoutBlock.cshtml b/src/Umbraco.Core/EmbeddedResources/BlockGrid/Components/umbBlockGridDemoTwoColumnLayoutBlock.cshtml similarity index 100% rename from src/Umbraco.Cms.StaticAssets/Views/Partials/blockgrid/Components/umbBlockGridDemoTwoColumnLayoutBlock.cshtml rename to src/Umbraco.Core/EmbeddedResources/BlockGrid/Components/umbBlockGridDemoTwoColumnLayoutBlock.cshtml diff --git a/src/Umbraco.Cms.StaticAssets/Views/Partials/blockgrid/areas.cshtml b/src/Umbraco.Core/EmbeddedResources/BlockGrid/areas.cshtml similarity index 100% rename from src/Umbraco.Cms.StaticAssets/Views/Partials/blockgrid/areas.cshtml rename to src/Umbraco.Core/EmbeddedResources/BlockGrid/areas.cshtml diff --git a/src/Umbraco.Cms.StaticAssets/Views/Partials/blockgrid/default.cshtml b/src/Umbraco.Core/EmbeddedResources/BlockGrid/default.cshtml similarity index 100% rename from src/Umbraco.Cms.StaticAssets/Views/Partials/blockgrid/default.cshtml rename to src/Umbraco.Core/EmbeddedResources/BlockGrid/default.cshtml diff --git a/src/Umbraco.Cms.StaticAssets/Views/Partials/blockgrid/items.cshtml b/src/Umbraco.Core/EmbeddedResources/BlockGrid/items.cshtml similarity index 100% rename from src/Umbraco.Cms.StaticAssets/Views/Partials/blockgrid/items.cshtml rename to src/Umbraco.Core/EmbeddedResources/BlockGrid/items.cshtml diff --git a/src/Umbraco.Infrastructure/DependencyInjection/UmbracoBuilder.Services.cs b/src/Umbraco.Infrastructure/DependencyInjection/UmbracoBuilder.Services.cs index c9208b5bdc..7a793c74cd 100644 --- a/src/Umbraco.Infrastructure/DependencyInjection/UmbracoBuilder.Services.cs +++ b/src/Umbraco.Infrastructure/DependencyInjection/UmbracoBuilder.Services.cs @@ -23,6 +23,7 @@ using Umbraco.Cms.Infrastructure.Services; using Umbraco.Cms.Infrastructure.Services.Implement; using Umbraco.Cms.Infrastructure.Telemetry.Providers; using Umbraco.Cms.Infrastructure.Templates; +using Umbraco.Cms.Infrastructure.Templates.PartialViews; using Umbraco.Extensions; using CacheInstructionService = Umbraco.Cms.Core.Services.Implement.CacheInstructionService; @@ -58,6 +59,7 @@ public static partial class UmbracoBuilderExtensions builder.Services.AddUnique(); builder.Services.AddTransient(); builder.Services.AddSingleton(); + builder.Services.AddTransient(); return builder; } diff --git a/src/Umbraco.Infrastructure/Migrations/Upgrade/UmbracoPlan.cs b/src/Umbraco.Infrastructure/Migrations/Upgrade/UmbracoPlan.cs index a7d0b708df..d0aefade84 100644 --- a/src/Umbraco.Infrastructure/Migrations/Upgrade/UmbracoPlan.cs +++ b/src/Umbraco.Infrastructure/Migrations/Upgrade/UmbracoPlan.cs @@ -5,6 +5,7 @@ using Umbraco.Cms.Core.Semver; using Umbraco.Cms.Infrastructure.Migrations.Upgrade.Common; using Umbraco.Cms.Infrastructure.Migrations.Upgrade.V_10_0_0; using Umbraco.Cms.Infrastructure.Migrations.Upgrade.V_10_2_0; +using Umbraco.Cms.Infrastructure.Migrations.Upgrade.V_10_3_0; using Umbraco.Cms.Infrastructure.Migrations.Upgrade.V_8_0_0; using Umbraco.Cms.Infrastructure.Migrations.Upgrade.V_8_0_1; using Umbraco.Cms.Infrastructure.Migrations.Upgrade.V_8_1_0; @@ -293,5 +294,8 @@ public class UmbracoPlan : MigrationPlan // TO 10.2.0 To("{D0B3D29D-F4D5-43E3-BA67-9D49256F3266}"); To("{79D8217B-5920-4C0E-8E9A-3CF8FA021882}"); + + // To 10.3.0 + To("{56833770-3B7E-4FD5-A3B6-3416A26A7A3F}"); } } diff --git a/src/Umbraco.Infrastructure/Migrations/Upgrade/V_10_3_0/AddBlockGridPartialViews.cs b/src/Umbraco.Infrastructure/Migrations/Upgrade/V_10_3_0/AddBlockGridPartialViews.cs new file mode 100644 index 0000000000..c99f5cfe81 --- /dev/null +++ b/src/Umbraco.Infrastructure/Migrations/Upgrade/V_10_3_0/AddBlockGridPartialViews.cs @@ -0,0 +1,31 @@ +using Umbraco.Cms.Infrastructure.Templates.PartialViews; + +namespace Umbraco.Cms.Infrastructure.Migrations.Upgrade.V_10_3_0; + +public class AddBlockGridPartialViews : MigrationBase +{ + private readonly IPartialViewPopulator _partialViewPopulator; + private const string FolderPath = "/Views/Partials/blockgrid"; + private static readonly string[] _filesToAdd = + { + "areas.cshtml", + "default.cshtml", + "items.cshtml", + }; + + public AddBlockGridPartialViews(IMigrationContext context, IPartialViewPopulator partialViewPopulator) : base(context) + => _partialViewPopulator = partialViewPopulator; + + protected override void Migrate() + { + var embeddedBasePath = _partialViewPopulator.CoreEmbeddedPath + ".BlockGrid"; + + foreach (var fileName in _filesToAdd) + { + _partialViewPopulator.CopyPartialViewIfNotExists( + _partialViewPopulator.GetCoreAssembly(), + $"{embeddedBasePath}.{fileName}", + $"{FolderPath}/{fileName}"); + } + } +} diff --git a/src/Umbraco.Infrastructure/Templates/PartialViews/IPartialViewPopulator.cs b/src/Umbraco.Infrastructure/Templates/PartialViews/IPartialViewPopulator.cs new file mode 100644 index 0000000000..5693e53c61 --- /dev/null +++ b/src/Umbraco.Infrastructure/Templates/PartialViews/IPartialViewPopulator.cs @@ -0,0 +1,21 @@ +using System.Reflection; + +namespace Umbraco.Cms.Infrastructure.Templates.PartialViews; + +/// +/// Populates the Partial View file system using other sources, such as RCL. +/// +public interface IPartialViewPopulator +{ + /// + /// Copies a partial view from the assembly path within the provided assembly, to the file system path. But only if it does not exist yet. + /// + /// The assembly to look for embedded resources in. + /// Path to resource as assembly path I.E Umbraco.Cms.Core.EmbeddedResources. + /// The partial view filesystem path to copy the file to, I.E. /Views/Partials/blockgrid. + void CopyPartialViewIfNotExists(Assembly assembly, string embeddedPath, string fileSystemPath); + + Assembly GetCoreAssembly(); + + string CoreEmbeddedPath { get; } +} diff --git a/src/Umbraco.Infrastructure/Templates/PartialViews/PartialViewPopulator.cs b/src/Umbraco.Infrastructure/Templates/PartialViews/PartialViewPopulator.cs new file mode 100644 index 0000000000..4cc8e038c6 --- /dev/null +++ b/src/Umbraco.Infrastructure/Templates/PartialViews/PartialViewPopulator.cs @@ -0,0 +1,51 @@ +using System.Reflection; +using System.Text; +using Umbraco.Cms.Core; +using Umbraco.Cms.Core.Models; +using Umbraco.Cms.Core.Services; + +namespace Umbraco.Cms.Infrastructure.Templates.PartialViews; + +/// +internal sealed class PartialViewPopulator : IPartialViewPopulator +{ + private readonly IFileService _fileService; + + public PartialViewPopulator(IFileService fileService) + { + _fileService = fileService; + } + + public Assembly GetCoreAssembly() => typeof(Constants).Assembly; + + public string CoreEmbeddedPath => "Umbraco.Cms.Core.EmbeddedResources"; + + /// + public void CopyPartialViewIfNotExists(Assembly assembly, string embeddedPath, string fileSystemPath) + { + Stream? content = assembly.GetManifestResourceStream(embeddedPath); + if (content is not null) + { + + // We have to ensure that this is idempotent, so only save the view if it does not already exist + // We don't want to overwrite any changes made. + IPartialView? existingView = _fileService.GetPartialView(fileSystemPath); + if (existingView is null) + { + var view = new PartialView(PartialViewType.PartialView, fileSystemPath) + { + Content = GetTextFromStream(content) + }; + + _fileService.SavePartialView(view); + } + } + } + + private string GetTextFromStream(Stream stream) + { + stream.Seek(0, SeekOrigin.Begin); + var streamReader = new StreamReader(stream, Encoding.UTF8); + return streamReader.ReadToEnd(); + } +} diff --git a/src/Umbraco.Web.BackOffice/Controllers/BlockGridSampleHelper.cs b/src/Umbraco.Web.BackOffice/Controllers/BlockGridSampleHelper.cs index a2ed4bdb58..c1e976204b 100644 --- a/src/Umbraco.Web.BackOffice/Controllers/BlockGridSampleHelper.cs +++ b/src/Umbraco.Web.BackOffice/Controllers/BlockGridSampleHelper.cs @@ -5,23 +5,31 @@ using Umbraco.Cms.Core.Models.ContentEditing; using Umbraco.Cms.Core.PropertyEditors; using Umbraco.Cms.Core.Security; using Umbraco.Cms.Core.Services; +using Umbraco.Cms.Infrastructure.Templates.PartialViews; using Umbraco.Cms.Web.Common.ActionsResults; using Umbraco.Extensions; namespace Umbraco.Cms.Web.BackOffice.Controllers; -internal class BlockGridSampleHelper +// Unfortunately this has to be public to be injected into a controller +public sealed class BlockGridSampleHelper { private const string ContainerName = "Umbraco Block Grid Demo"; private readonly IContentTypeService _contentTypeService; private readonly IDataTypeService _dataTypeService; private readonly IBackOfficeSecurityAccessor _backOfficeSecurityAccessor; + private readonly IPartialViewPopulator _partialViewPopulator; - public BlockGridSampleHelper(IContentTypeService contentTypeService, IDataTypeService dataTypeService, IBackOfficeSecurityAccessor backOfficeSecurityAccessor) + public BlockGridSampleHelper( + IContentTypeService contentTypeService, + IDataTypeService dataTypeService, + IBackOfficeSecurityAccessor backOfficeSecurityAccessor, + IPartialViewPopulator partialViewPopulator) { _contentTypeService = contentTypeService; _backOfficeSecurityAccessor = backOfficeSecurityAccessor; + _partialViewPopulator = partialViewPopulator; _dataTypeService = dataTypeService; } @@ -35,7 +43,7 @@ internal class BlockGridSampleHelper /// The function that will perform the actual element creation /// If an error occurs, this message will describe that error /// A mapping table between element aliases and the created element UDIs, or null if an error occurs - public Dictionary? CreateSampleElements(Func> createElement, out string errorMessage) + internal Dictionary? CreateSampleElements(Func> createElement, out string errorMessage) { errorMessage = string.Empty; @@ -161,6 +169,26 @@ internal class BlockGridSampleHelper return elementUdisByAlias; } + internal void CreateSamplePartialViews() + { + var embeddedBasePath = $"{_partialViewPopulator.CoreEmbeddedPath}.BlockGrid.Components"; + var fileSystemBasePath = "/Views/partials/blockgrid/Components"; + var filesToMove = new[] + { + "umbBlockGridDemoHeadlineBlock.cshtml", + "umbBlockGridDemoImageBlock.cshtml", + "umbBlockGridDemoRichTextBlock.cshtml", + "umbBlockGridDemoTwoColumnLayoutBlock.cshtml", + }; + + foreach (var fileName in filesToMove) + { + var embeddedPath = $"{embeddedBasePath}.{fileName}"; + var fileSystemPath = $"{fileSystemBasePath}/{fileName}"; + _partialViewPopulator.CopyPartialViewIfNotExists(_partialViewPopulator.GetCoreAssembly(), embeddedPath, fileSystemPath); + } + } + private EntityContainer? GetOrCreateContainer() { var userId = _backOfficeSecurityAccessor.BackOfficeSecurity?.CurrentUser?.Id ?? -1; diff --git a/src/Umbraco.Web.BackOffice/Controllers/ContentTypeController.cs b/src/Umbraco.Web.BackOffice/Controllers/ContentTypeController.cs index b2e402eaad..e14ac00fff 100644 --- a/src/Umbraco.Web.BackOffice/Controllers/ContentTypeController.cs +++ b/src/Umbraco.Web.BackOffice/Controllers/ContentTypeController.cs @@ -5,6 +5,7 @@ using System.Xml.Linq; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; +using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using Umbraco.Cms.Core; using Umbraco.Cms.Core.Dictionary; @@ -21,6 +22,7 @@ using Umbraco.Cms.Infrastructure.Packaging; using Umbraco.Cms.Web.BackOffice.Filters; using Umbraco.Cms.Web.Common.Attributes; using Umbraco.Cms.Web.Common.Authorization; +using Umbraco.Cms.Web.Common.DependencyInjection; using Umbraco.Extensions; using ContentType = Umbraco.Cms.Core.Models.ContentType; @@ -43,6 +45,7 @@ public class ContentTypeController : ContentTypeControllerBase private readonly ILocalizedTextService _localizedTextService; private readonly ILogger _logger; private readonly PackageDataInstallation _packageDataInstallation; + private readonly BlockGridSampleHelper _blockGridSampleHelper; private readonly PropertyEditorCollection _propertyEditors; // TODO: Split this controller apart so that authz is consistent, currently we need to authz each action individually. @@ -52,6 +55,7 @@ public class ContentTypeController : ContentTypeControllerBase private readonly IShortStringHelper _shortStringHelper; private readonly IUmbracoMapper _umbracoMapper; + [Obsolete("Use constructor that takes BlockGridSampleHelper as a parameter")] public ContentTypeController( ICultureDictionary cultureDictionary, IContentTypeService contentTypeService, @@ -71,31 +75,77 @@ public class ContentTypeController : ContentTypeControllerBase IHostingEnvironment hostingEnvironment, EditorValidatorCollection editorValidatorCollection, PackageDataInstallation packageDataInstallation) - : base( + : this( cultureDictionary, - editorValidatorCollection, contentTypeService, mediaTypeService, memberTypeService, umbracoMapper, - localizedTextService) + localizedTextService, + serializer, + propertyEditors, + backofficeSecurityAccessor, + dataTypeService, + shortStringHelper, + fileService, + logger, + contentService, + contentTypeBaseServiceProvider, + hostingEnvironment, + editorValidatorCollection, + packageDataInstallation, + StaticServiceProvider.Instance.GetRequiredService() + ) { - _serializer = serializer; - _propertyEditors = propertyEditors; - _contentTypeService = contentTypeService; - _umbracoMapper = umbracoMapper; - _backofficeSecurityAccessor = backofficeSecurityAccessor; - _dataTypeService = dataTypeService; - _shortStringHelper = shortStringHelper; - _localizedTextService = localizedTextService; - _fileService = fileService; - _logger = logger; - _contentService = contentService; - _contentTypeBaseServiceProvider = contentTypeBaseServiceProvider; - _hostingEnvironment = hostingEnvironment; - _packageDataInstallation = packageDataInstallation; } + [ActivatorUtilitiesConstructor] + public ContentTypeController( + ICultureDictionary cultureDictionary, + IContentTypeService contentTypeService, + IMediaTypeService mediaTypeService, + IMemberTypeService memberTypeService, + IUmbracoMapper umbracoMapper, + ILocalizedTextService localizedTextService, + IEntityXmlSerializer serializer, + PropertyEditorCollection propertyEditors, + IBackOfficeSecurityAccessor backofficeSecurityAccessor, + IDataTypeService dataTypeService, + IShortStringHelper shortStringHelper, + IFileService fileService, + ILogger logger, + IContentService contentService, + IContentTypeBaseServiceProvider contentTypeBaseServiceProvider, + IHostingEnvironment hostingEnvironment, + EditorValidatorCollection editorValidatorCollection, + PackageDataInstallation packageDataInstallation, + BlockGridSampleHelper blockGridSampleHelper) + : base( + cultureDictionary, + editorValidatorCollection, + contentTypeService, + mediaTypeService, + memberTypeService, + umbracoMapper, + localizedTextService) + { + _serializer = serializer; + _propertyEditors = propertyEditors; + _contentTypeService = contentTypeService; + _umbracoMapper = umbracoMapper; + _backofficeSecurityAccessor = backofficeSecurityAccessor; + _dataTypeService = dataTypeService; + _shortStringHelper = shortStringHelper; + _localizedTextService = localizedTextService; + _fileService = fileService; + _logger = logger; + _contentService = contentService; + _contentTypeBaseServiceProvider = contentTypeBaseServiceProvider; + _hostingEnvironment = hostingEnvironment; + _packageDataInstallation = packageDataInstallation; + _blockGridSampleHelper = blockGridSampleHelper; + } + [Authorize(Policy = AuthorizationPolicies.TreeAccessDocumentTypes)] public int GetCount() => _contentTypeService.Count(); @@ -654,14 +704,16 @@ public class ContentTypeController : ContentTypeControllerBase [Authorize(Policy = AuthorizationPolicies.TreeAccessDocumentTypes)] public ActionResult PostCreateBlockGridSample() { - var sampleHelper = new BlockGridSampleHelper(_contentTypeService, _dataTypeService, _backofficeSecurityAccessor); - Dictionary? elementUdisByAlias = sampleHelper.CreateSampleElements( + Dictionary? elementUdisByAlias = _blockGridSampleHelper.CreateSampleElements( documentTypeSave => PerformPostSave( documentTypeSave, i => _contentTypeService.Get(i), type => _contentTypeService.Save(type)), out string errorMessage); + // Create the partial views if they don't exist + _blockGridSampleHelper.CreateSamplePartialViews(); + return elementUdisByAlias != null ? Ok(elementUdisByAlias) : ValidationProblem(errorMessage); } } diff --git a/src/Umbraco.Web.BackOffice/DependencyInjection/UmbracoBuilderExtensions.cs b/src/Umbraco.Web.BackOffice/DependencyInjection/UmbracoBuilderExtensions.cs index 0d8cc49bdf..994493e761 100644 --- a/src/Umbraco.Web.BackOffice/DependencyInjection/UmbracoBuilderExtensions.cs +++ b/src/Umbraco.Web.BackOffice/DependencyInjection/UmbracoBuilderExtensions.cs @@ -8,6 +8,7 @@ using Umbraco.Cms.Core.Notifications; using Umbraco.Cms.Core.Services; using Umbraco.Cms.Infrastructure.DependencyInjection; using Umbraco.Cms.Infrastructure.Examine.DependencyInjection; +using Umbraco.Cms.Infrastructure.Templates.PartialViews; using Umbraco.Cms.Infrastructure.WebAssets; using Umbraco.Cms.Web.BackOffice.Controllers; using Umbraco.Cms.Web.BackOffice.Filters; @@ -116,6 +117,7 @@ public static partial class UmbracoBuilderExtensions builder.Services.AddUnique(); builder.Services.AddUnique(); builder.Services.AddSingleton(); + builder.Services.AddTransient(); return builder; } diff --git a/src/Umbraco.Web.UI/Views/Partials/blockgrid/areas.cshtml b/src/Umbraco.Web.UI/Views/Partials/blockgrid/areas.cshtml new file mode 100644 index 0000000000..94eef55ad8 --- /dev/null +++ b/src/Umbraco.Web.UI/Views/Partials/blockgrid/areas.cshtml @@ -0,0 +1,19 @@ +@using Umbraco.Extensions +@inherits Umbraco.Cms.Web.Common.Views.UmbracoViewPage +@{ + if (Model?.Areas.Any() != true) { return; } +} + +
+ @foreach (var area in Model.Areas) + { +
+ @await Html.GetBlockGridItemsHtmlAsync(area) +
+ } +
diff --git a/src/Umbraco.Web.UI/Views/Partials/blockgrid/default.cshtml b/src/Umbraco.Web.UI/Views/Partials/blockgrid/default.cshtml new file mode 100644 index 0000000000..e25839ebb1 --- /dev/null +++ b/src/Umbraco.Web.UI/Views/Partials/blockgrid/default.cshtml @@ -0,0 +1,11 @@ +@using Umbraco.Extensions +@inherits Umbraco.Cms.Web.Common.Views.UmbracoViewPage +@{ + if (Model?.Any() != true) { return; } +} + +
+ @await Html.GetBlockGridItemsHtmlAsync(Model) +
diff --git a/src/Umbraco.Web.UI/Views/Partials/blockgrid/items.cshtml b/src/Umbraco.Web.UI/Views/Partials/blockgrid/items.cshtml new file mode 100644 index 0000000000..2831c1462e --- /dev/null +++ b/src/Umbraco.Web.UI/Views/Partials/blockgrid/items.cshtml @@ -0,0 +1,39 @@ +@using Umbraco.Cms.Core.Models.Blocks +@inherits Umbraco.Cms.Web.Common.Views.UmbracoViewPage> +@{ + if (Model?.Any() != true) { return; } +} + +
+ @foreach (var item in Model) + { + bool attrForceLeft = item.ForceLeft; + bool attrForceRight = item.ForceRight; +
+ @{ + var partialViewName = "blockgrid/Components/" + item.Content.ContentType.Alias; + try + { + @await Html.PartialAsync(partialViewName, item) + } + catch (InvalidOperationException) + { +

+ Could not render component of type: @(item.Content.ContentType.Alias) +
+ This likely happened because the partial view @partialViewName could not be found. +

+ } + } +
+ } +
diff --git a/templates/Umbraco.Templates.csproj b/templates/Umbraco.Templates.csproj index 2f96bdf61f..10bbd666d1 100644 --- a/templates/Umbraco.Templates.csproj +++ b/templates/Umbraco.Templates.csproj @@ -29,6 +29,10 @@ UmbracoProject\Views\Partials\grid\%(RecursiveDir)%(Filename)%(Extension) UmbracoProject\Views\Partials\grid + + UmbracoProject\Views\Partials\blockgrid\%(RecursiveDir)%(Filename)%(Extension) + UmbracoProject\Views\Partials\blockgrid + UmbracoProject\Views\_ViewImports.cshtml UmbracoProject\Views