diff --git a/src/Umbraco.Web.UI.Client/src/views/content/overlays/save.controller.js b/src/Umbraco.Web.UI.Client/src/views/content/overlays/save.controller.js
index 308673bf21..1581e5ce1c 100644
--- a/src/Umbraco.Web.UI.Client/src/views/content/overlays/save.controller.js
+++ b/src/Umbraco.Web.UI.Client/src/views/content/overlays/save.controller.js
@@ -7,14 +7,28 @@
vm.loading = true;
vm.hasPristineVariants = false;
vm.isNew = true;
+ vm.saveAll = false;
vm.changeSelection = changeSelection;
+ vm.changeSaveAllSelection = changeSaveAllSelection;
function changeSelection(variant) {
var firstSelected = _.find(vm.variants, function (v) {
return v.save;
});
$scope.model.disableSubmitButton = !firstSelected; //disable submit button if there is none selected
+ updateSaveAllSelectionStatus();
+ }
+
+ function changeSaveAllSelection(){
+ vm.availableVariants.forEach(variant => {
+ variant.save = vm.saveAll;
+ });
+ $scope.model.disableSubmitButton = !vm.saveAll;
+ }
+
+ function updateSaveAllSelectionStatus(){
+ vm.saveAll = vm.availableVariants.every(x => x.save);
}
function allowUpdate (variant) {
@@ -92,6 +106,8 @@
vm.availableVariants = contentEditingHelper.getSortedVariantsAndSegments(vm.availableVariants);
+ updateSaveAllSelectionStatus();
+
} else {
//disable save button if we have nothing to save
$scope.model.disableSubmitButton = true;
diff --git a/src/Umbraco.Web.UI.Client/src/views/content/overlays/save.html b/src/Umbraco.Web.UI.Client/src/views/content/overlays/save.html
index 9153ae1650..1b564cb0b3 100644
--- a/src/Umbraco.Web.UI.Client/src/views/content/overlays/save.html
+++ b/src/Umbraco.Web.UI.Client/src/views/content/overlays/save.html
@@ -13,6 +13,17 @@
+
+
+
+ Select all variants
+
+
+
diff --git a/src/Umbraco.Web.UI.Client/src/views/content/overlays/sendtopublish.controller.js b/src/Umbraco.Web.UI.Client/src/views/content/overlays/sendtopublish.controller.js
index c1c91057da..ce04d20ace 100644
--- a/src/Umbraco.Web.UI.Client/src/views/content/overlays/sendtopublish.controller.js
+++ b/src/Umbraco.Web.UI.Client/src/views/content/overlays/sendtopublish.controller.js
@@ -6,8 +6,10 @@
var vm = this;
vm.loading = true;
vm.selectedVariants = [];
+ vm.sendToPublishAll = false;
vm.changeSelection = changeSelection;
+ vm.changeSendToPublishAllSelection = changeSendToPublishAllSelection;
function onInit() {
@@ -29,8 +31,9 @@
if (vm.availableVariants.length !== 0) {
vm.availableVariants = contentEditingHelper.getSortedVariantsAndSegments(vm.availableVariants);
+ updateSendToPublishAllSelectionStatus();
}
-
+
$scope.model.disableSubmitButton = true;
vm.loading = false;
}
@@ -55,10 +58,39 @@
let firstSelected = vm.variants.find(v => v.save);
$scope.model.disableSubmitButton = !firstSelected;
+ updateSendToPublishAllSelectionStatus();
+ }
+
+ function changeSendToPublishAllSelection(){
+
+ vm.availableVariants.forEach(variant => {
+
+ variant.publish = vm.sendToPublishAll;
+ let foundVariant = vm.selectedVariants.find(x => x.compositeId === variant.compositeId);
+
+ if (foundVariant === undefined) {
+ variant.save = true;
+ vm.selectedVariants.push(variant);
+ } else {
+ if(!vm.sendToPublishAll){
+ variant.save = false;
+ let index = vm.selectedVariants.indexOf(foundVariant);
+ if (index !== -1) {
+ vm.selectedVariants.splice(index, 1);
+ }
+ }
+ }
+ });
+ let firstSelected = vm.variants.find(v => v.save);
+ $scope.model.disableSubmitButton = !firstSelected;
+ }
+
+ function updateSendToPublishAllSelectionStatus(){
+ vm.sendToPublishAll = vm.availableVariants.every(x => x.publish);
}
- function isMandatoryFilter(variant) {
+ function isMandatoryFilter(variant) {
//determine a variant is 'dirty' (meaning it will show up as publish-able) if it's
// * has a mandatory language
// * without having a segment, segments cant be mandatory at current state of code.
diff --git a/src/Umbraco.Web.UI.Client/src/views/content/overlays/sendtopublish.html b/src/Umbraco.Web.UI.Client/src/views/content/overlays/sendtopublish.html
index b9061a8eb6..4d51ae1c30 100644
--- a/src/Umbraco.Web.UI.Client/src/views/content/overlays/sendtopublish.html
+++ b/src/Umbraco.Web.UI.Client/src/views/content/overlays/sendtopublish.html
@@ -10,6 +10,17 @@
+
+
+
+ Select all variants
+
+
+
From beb431900a667deb3eb777aebcfd6ff6e4904b01 Mon Sep 17 00:00:00 2001
From: Owain Jones
Date: Fri, 23 Feb 2024 17:34:53 +0000
Subject: [PATCH 02/18] Update Welsh lang file
---
.../EmbeddedResources/Lang/cy.xml | 77 ++++++++++++++++++-
1 file changed, 75 insertions(+), 2 deletions(-)
diff --git a/src/Umbraco.Core/EmbeddedResources/Lang/cy.xml b/src/Umbraco.Core/EmbeddedResources/Lang/cy.xml
index 1e76e92382..c91dabbad9 100644
--- a/src/Umbraco.Core/EmbeddedResources/Lang/cy.xml
+++ b/src/Umbraco.Core/EmbeddedResources/Lang/cy.xml
@@ -459,9 +459,10 @@
Ydych chi'n sicr?
Ydych chi'n sicr?
Torri
- Golygu Eitem Geiriadur
- Golygu Iaith
+ Golygu Eitem Geiriadur
+ Golygu Iaith
Golygu cyfrwng a dewiswyd
+ Golygu bachyn gwe
Mewnosod dolen leol
Mewnosod nod
Mewnosod pennawd graffig
@@ -504,6 +505,7 @@
Agor y ddolen ddogfen mewn ffenestr neu tab newydd
Dolen i gyfrwng
Dewis nod cychwyn cynnwys
+ Dewis digwyddiad
Dewis cyfrwng
Dewis y math o gyfrwng
Dewis eicon
@@ -857,6 +859,7 @@
Gwybodaeth Umbraco
Neidio i'r dewislen
Neidio i'r cynnwys
+ Prif
Glas
@@ -1061,6 +1064,7 @@ Er mwyn gweinyddu eich gwefan, agorwch swyddfa gefn Umbraco a dechreuwch ychwang
Mewngofnodwch isod
Mewngofnodwch gyda
Sesiwn wedi cyrraedd terfyn amser
+ Wps! Mae mewngofnodi wedi methu. Gwiriwch eich manylion a thrio eto.
© 2001 - %0%
Umbraco.com ]]>
Wedi anghofio eich cyfrinair?
Bydd ebost yn cael ei anfon i'r cyfeiriad darparwyd gyda dolen i ailosod eich cyfrinair
@@ -1424,6 +1428,44 @@ Er mwyn gweinyddu eich gwefan, agorwch swyddfa gefn Umbraco a dechreuwch ychwang
Gallwch ond ddewis eitemau o'r math(au): %0%
Rydych wedi dewis eitem gynnwys sydd naill ai wedi'i ddileu neu yn y bin ailgylchu
Rydych wedi dewis eitemau gynnwys sydd naill ai wedi'u dileu neu yn y bin ailgylchu
+ Nodi gwraidd
+ Dewiswch nod gwraidd
+ Nodi gwraidd efo XPath
+ Nodi Gwraidd Dynamig
+ Nod cychwyn
+ Ymholiad XPath
+
+
+ Ymholiad Gwraidd Dynamig
+ Dewiswch darddiad
+ Diffiniwch darddiad eich Ymholiad Gwraidd Dynamig
+ Gwraidd
+ Nod gwraidd y sesiwn olygu hon
+ Rhiant
+ Nod rhiant y ffynhonnell yn y sesiwn olygu hon
+ Cyfredol
+ Y nod cynnwys sy'n ffynhonnell ar gyfer y sesiwn olygu hon
+ Gwefan
+ Canfod nod agosaf gydag enw gwesteiwr
+ Nod penodol
+ Dewiswch Nod penodol fel tarddiad yr ymholiad hwn
+ Atodwch y cam i'r ymholiad
+ Diffiniwch y cam nesaf yn eich Ymholiad Gwraidd Dynamig
+ Hynafiad Agosaf Neu Hunan
+ Holwch yr hynafiad agosaf neu hunan sy'n cyd-fynd ag un o'r mathau sydd wedi'u ffurfweddu
+ Hynafiad Pellaf Neu Hunan
+ Holwch yr hynafiad pellaf neu'r hunan sy'n cyd-fynd ag un o'r mathau sydd wedi'u ffurfweddu
+ Disgynnydd Agosaf Neu Hunan
+ Holwch y disgynnydd agosaf neu'r hunan sy'n cyd-fynd ag un o'r mathau sydd wedi'u ffurfweddu
+ Disgynnydd Pellaf Neu Hunan
+ Holwch y disgynnydd pellaf neu'r hunan sy'n cyd-fynd ag un o'r mathau sydd wedi'u ffurfweddu
+ Arferiad
+ Ymholiad gan ddefnyddio Cam Ymholiad arferiad
+ Ychwanegu cam ymholiad
+ Sy'n cyfateb i'r mathau:
+ Dim cynnwys cyfatebol
+ Nid yw ffurfweddiad yr eiddo hwn yn cyfateb i unrhyw gynnwys. Creu'r cynnwys coll neu cysylltwch â'ch gweinyddwr i addasu gosodiadau Gwraidd Dynamig ar gyfer yr eiddo hwn.
+ Canslo a chlirio ymholiad
Rydych wedi dewis eitem gyfrwng sydd naill ai wedi'i ddileu neu yn y bin ailgylchu
@@ -1629,6 +1671,7 @@ Er mwyn gweinyddu eich gwefan, agorwch swyddfa gefn Umbraco a dechreuwch ychwang
Digwyddodd gwall wrth analluogi glanhau fersiwn ar gyfer %0%
Mae gwybodaeth eich system wedi'i chopïo'n llwyddiannus i'r clipfwrdd
Methu â chopïo gwybodaeth eich system i'r clipfwrdd
+ Bachyn gwe wedi arbed
Ychwanegu ardull
@@ -1873,6 +1916,33 @@ Er mwyn gweinyddu eich gwefan, agorwch swyddfa gefn Umbraco a dechreuwch ychwang
NODYN! Mae glanhau fersiynau cynnwys hanesyddol wedi'u hanalluogi'n fyd-eang. Ni fydd y gosodiadau hyn yn dod i rym cyn iddo gael ei alluogi.
Mae newid math o ddata gyda gwerthoedd storio wedi'i analluogi. I ganiatáu hyn gallwch newid y gosodiad Umbraco:CMS:DataTypes:CanBeChanged yn appssettings.json.
+
+ Creu bachyn gwe
+ Ychwanegu pennyn bachyn gwe
+ Ychwanegu Math o Ddogfen
+ Ychwanegu Math o Gyfrwng
+ Creu pennawd
+ Danfoniadau
+ Nid oes penawdau bachyn gwe wedi'u hychwanegu
+ Ni chanfuwyd unrhyw ddigwyddiadau.
+ Wedi'i alluogi
+ DigwyddiadauD
+ Digwyddiad
+ Url
+ Mathau
+ Allwedd bachyn gwe
+ Cyfrif o Ailgeision
+ Togl modd dadfygio am ragor o wybodaeth.
+ Cod statws ddim yn OK
+ Yr url i'w alw pan fydd y bachyn gwe yn cael ei sbarduno.
+ Y digwyddiadau y dylid sbarduno'r bachyn gwe.
+ Sbardunwch y bachyn gwe am fath penodol o gynnwys yn unig.
+ A yw'r bachyn gwe wedi'i alluogi?
+ Penawdau arferu i'w cynnwys yn y cais bachyn gwe.
+ Math o Gynnwys
+ Penawdau
+ Dewiswch ddigwyddiad yn gyntaf.
+
Ychwanegu iaith
Iath gorfodol
@@ -2011,6 +2081,7 @@ Er mwyn gweinyddu eich gwefan, agorwch swyddfa gefn Umbraco a dechreuwch ychwang
Gosodiadau
Templedi
Trydydd parti
+ Bachau gwe
Diweddariad newydd yn barod
@@ -2769,6 +2840,8 @@ Er mwyn gweinyddu eich gwefan, agorwch swyddfa gefn Umbraco a dechreuwch ychwang
Ffurfweddu ardal
Dileu ardal
Ychwanegu opsiwn rhychwantu %0% colofn
+ Mewnosod Bloc
+ Arddangos yn fewnol â'r testun
Beth yw Templedi Gynnwys
From 4f9c793d0022731774a154a9cef4706069b3f8c0 Mon Sep 17 00:00:00 2001
From: MihailichenkoPavel
Date: Thu, 29 Feb 2024 13:36:43 +0200
Subject: [PATCH 03/18] fix user login
---
.../src/context/auth.repository.ts | 14 ++++----------
1 file changed, 4 insertions(+), 10 deletions(-)
diff --git a/src/Umbraco.Web.UI.Login/src/context/auth.repository.ts b/src/Umbraco.Web.UI.Login/src/context/auth.repository.ts
index 69743bcee7..f0ec89075d 100644
--- a/src/Umbraco.Web.UI.Login/src/context/auth.repository.ts
+++ b/src/Umbraco.Web.UI.Login/src/context/auth.repository.ts
@@ -25,26 +25,20 @@ export class UmbAuthRepository {
});
const response = await fetch(request);
- const responseData: LoginResponse = {
- status: response.status,
- };
-
- if (!response.ok) {
- responseData.error = await this.#getErrorText(response);
- return responseData;
- }
+ let responseData: any = undefined;
try {
const text = await response.text();
if (text) {
- responseData.data = JSON.parse(this.#removeAngularJSResponseData(text));
+ responseData = JSON.parse(this.#removeAngularJSResponseData(text));
}
} catch {
}
return {
status: response.status,
- data: responseData?.data,
+ error: response.ok ? undefined : await this.#getErrorText(response),
+ data: responseData,
twoFactorView: responseData?.twoFactorView,
};
} catch (error) {
From 0cf436fa5cb8db5edc92d6b058841fee9d6adfbb Mon Sep 17 00:00:00 2001
From: Ethan Nagano
Date: Sat, 16 Dec 2023 22:45:08 -0800
Subject: [PATCH 04/18] Add handling of failed publish.
When publishing, if the selected page does not yet have a page created,
handle the FailedPublishNothingToPublish error so that the user is not
presented with an exception. A warning is shown to the user that some
languages failed to publish due to nothing to publish and to check that
a page has been created for selected languages. Additionally fixed a
validation issue where publish would always succeed if all languages
were selected.
Issue: 15352
---
.../Controllers/ContentController.cs | 10 ++++++++--
1 file changed, 8 insertions(+), 2 deletions(-)
diff --git a/src/Umbraco.Web.BackOffice/Controllers/ContentController.cs b/src/Umbraco.Web.BackOffice/Controllers/ContentController.cs
index a1ed75332b..81b37bb108 100644
--- a/src/Umbraco.Web.BackOffice/Controllers/ContentController.cs
+++ b/src/Umbraco.Web.BackOffice/Controllers/ContentController.cs
@@ -2061,7 +2061,7 @@ public class ContentController : ContentControllerBase
var languageCount = _allLangs.Value.Count();
// If there is no culture specified or the cultures specified are equal to the total amount of languages, publish the content in all cultures.
- if (model.Cultures == null || !model.Cultures.Any() || model.Cultures.Length == languageCount)
+ if (model.Cultures == null || !model.Cultures.Any())
{
return PostPublishById(model.Id);
}
@@ -2322,7 +2322,7 @@ public class ContentController : ContentControllerBase
}
var languageCount = _allLangs.Value.Count();
- if (model.Cultures?.Length == 0 || model.Cultures?.Length == languageCount)
+ if (model.Cultures?.Length == 0)
{
//this means that the entire content item will be unpublished
PublishResult unpublishResult = _contentService.Unpublish(foundContent, userId: _backofficeSecurityAccessor.BackOfficeSecurity?.GetUserId().Result ?? -1);
@@ -2786,6 +2786,7 @@ public class ContentController : ContentControllerBase
case PublishResultType.FailedPublishIsTrashed:
case PublishResultType.FailedPublishContentInvalid:
case PublishResultType.FailedPublishMandatoryCultureMissing:
+ case PublishResultType.FailedPublishNothingToPublish:
//the rest that we are looking for each belong in their own group
return x.Result;
default:
@@ -2928,6 +2929,11 @@ public class ContentController : ContentControllerBase
_localizedTextService.Localize(null, "publish"),
"publish/contentPublishedFailedByCulture");
break;
+ case PublishResultType.FailedPublishNothingToPublish:
+ display.AddWarningNotification(
+ _localizedTextService.Localize(null, "publish"),
+ $"Nothing to publish for some languages. Ensure selected languages have a page created.");
+ break;
default:
throw new IndexOutOfRangeException($"PublishedResultType \"{status.Key}\" was not expected.");
}
From 21126b7ba6b95ea10e4099633ee0e4f4fcd1cee9 Mon Sep 17 00:00:00 2001
From: Kenn Jacobsen
Date: Mon, 4 Mar 2024 12:50:24 +0100
Subject: [PATCH 05/18] Localize validation messages with user lang files
(#15820)
* Localize validation messages with user lang files
* Fixed unit tests
---
.../Mapping/ContentPropertyDisplayMapper.cs | 2 ++
.../Services/PropertyValidationService.cs | 20 +++++++++++++++++--
.../Services/ContentServiceTests.cs | 3 ++-
.../Umbraco.Core/Models/VariationTests.cs | 4 +++-
.../PropertyValidationServiceTests.cs | 3 ++-
5 files changed, 27 insertions(+), 5 deletions(-)
diff --git a/src/Umbraco.Core/Models/Mapping/ContentPropertyDisplayMapper.cs b/src/Umbraco.Core/Models/Mapping/ContentPropertyDisplayMapper.cs
index 237f1f2f40..a3c16ba148 100644
--- a/src/Umbraco.Core/Models/Mapping/ContentPropertyDisplayMapper.cs
+++ b/src/Umbraco.Core/Models/Mapping/ContentPropertyDisplayMapper.cs
@@ -86,5 +86,7 @@ internal class ContentPropertyDisplayMapper : ContentPropertyBasicMapper())
+ {
+ }
+
+ public PropertyValidationService(
+ PropertyEditorCollection propertyEditors,
+ IDataTypeService dataTypeService,
+ ILocalizedTextService textService,
+ IValueEditorCache valueEditorCache,
+ ICultureDictionary cultureDictionary)
{
_propertyEditors = propertyEditors;
_dataTypeService = dataTypeService;
_textService = textService;
_valueEditorCache = valueEditorCache;
+ _cultureDictionary = cultureDictionary;
}
///
@@ -76,13 +92,13 @@ public class PropertyValidationService : IPropertyValidationService
if (isRequired && !string.IsNullOrWhiteSpace(isRequiredMessage) &&
requiredDefaultMessages.Contains(validationResult.ErrorMessage, StringComparer.OrdinalIgnoreCase))
{
- validationResult.ErrorMessage = isRequiredMessage;
+ validationResult.ErrorMessage = _textService.UmbracoDictionaryTranslate(_cultureDictionary, isRequiredMessage);
}
if (!string.IsNullOrWhiteSpace(validationRegExp) && !string.IsNullOrWhiteSpace(validationRegExpMessage) &&
formatDefaultMessages.Contains(validationResult.ErrorMessage, StringComparer.OrdinalIgnoreCase))
{
- validationResult.ErrorMessage = validationRegExpMessage;
+ validationResult.ErrorMessage = _textService.UmbracoDictionaryTranslate(_cultureDictionary, validationRegExpMessage);
}
yield return validationResult;
diff --git a/tests/Umbraco.Tests.Integration/Umbraco.Core/Services/ContentServiceTests.cs b/tests/Umbraco.Tests.Integration/Umbraco.Core/Services/ContentServiceTests.cs
index aba329404a..a624d6d885 100644
--- a/tests/Umbraco.Tests.Integration/Umbraco.Core/Services/ContentServiceTests.cs
+++ b/tests/Umbraco.Tests.Integration/Umbraco.Core/Services/ContentServiceTests.cs
@@ -7,6 +7,7 @@ using Moq;
using NUnit.Framework;
using Umbraco.Cms.Core;
using Umbraco.Cms.Core.Cache;
+using Umbraco.Cms.Core.Dictionary;
using Umbraco.Cms.Core.Events;
using Umbraco.Cms.Core.Models;
using Umbraco.Cms.Core.Notifications;
@@ -1195,7 +1196,7 @@ public class ContentServiceTests : UmbracoIntegrationTestWithContent
// content cannot publish values because they are invalid
var propertyValidationService = new PropertyValidationService(PropertyEditorCollection, DataTypeService,
- TextService, ValueEditorCache);
+ TextService, ValueEditorCache, Mock.Of());
var isValid = propertyValidationService.IsPropertyDataValid(content, out var invalidProperties,
CultureImpact.Invariant);
Assert.IsFalse(isValid);
diff --git a/tests/Umbraco.Tests.UnitTests/Umbraco.Core/Models/VariationTests.cs b/tests/Umbraco.Tests.UnitTests/Umbraco.Core/Models/VariationTests.cs
index ca2ae76428..06edf59d3e 100644
--- a/tests/Umbraco.Tests.UnitTests/Umbraco.Core/Models/VariationTests.cs
+++ b/tests/Umbraco.Tests.UnitTests/Umbraco.Core/Models/VariationTests.cs
@@ -5,6 +5,7 @@ using Moq;
using NUnit.Framework;
using Umbraco.Cms.Core;
using Umbraco.Cms.Core.Cache;
+using Umbraco.Cms.Core.Dictionary;
using Umbraco.Cms.Core.IO;
using Umbraco.Cms.Core.Models;
using Umbraco.Cms.Core.PropertyEditors;
@@ -615,6 +616,7 @@ public class VariationTests
propertyEditorCollection,
dataTypeService,
localizedTextService,
- new ValueEditorCache());
+ new ValueEditorCache(),
+ Mock.Of());
}
}
diff --git a/tests/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Services/PropertyValidationServiceTests.cs b/tests/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Services/PropertyValidationServiceTests.cs
index 736e124324..160e9e7caa 100644
--- a/tests/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Services/PropertyValidationServiceTests.cs
+++ b/tests/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Services/PropertyValidationServiceTests.cs
@@ -6,6 +6,7 @@ using Moq;
using NUnit.Framework;
using Umbraco.Cms.Core;
using Umbraco.Cms.Core.Cache;
+using Umbraco.Cms.Core.Dictionary;
using Umbraco.Cms.Core.IO;
using Umbraco.Cms.Core.Models;
using Umbraco.Cms.Core.PropertyEditors;
@@ -51,7 +52,7 @@ public class PropertyValidationServiceTests
var propEditors = new PropertyEditorCollection(new DataEditorCollection(() => new[] { dataEditor }));
- validationService = new PropertyValidationService(propEditors, dataTypeService.Object, Mock.Of(), new ValueEditorCache());
+ validationService = new PropertyValidationService(propEditors, dataTypeService.Object, Mock.Of(), new ValueEditorCache(), Mock.Of());
}
[Test]
From ca9a3bbf1b06c44e14c9aa51e0ec2b20561e53f3 Mon Sep 17 00:00:00 2001
From: Kenn Jacobsen
Date: Mon, 4 Mar 2024 13:17:38 +0100
Subject: [PATCH 06/18] Use same cache level for MNTP no matter the output
channel (#15828)
---
.../ValueConverters/MultiNodeTreePickerValueConverter.cs | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/Umbraco.Core/PropertyEditors/ValueConverters/MultiNodeTreePickerValueConverter.cs b/src/Umbraco.Core/PropertyEditors/ValueConverters/MultiNodeTreePickerValueConverter.cs
index 7d512fbb2b..3ddb98b40e 100644
--- a/src/Umbraco.Core/PropertyEditors/ValueConverters/MultiNodeTreePickerValueConverter.cs
+++ b/src/Umbraco.Core/PropertyEditors/ValueConverters/MultiNodeTreePickerValueConverter.cs
@@ -181,7 +181,7 @@ public class MultiNodeTreePickerValueConverter : PropertyValueConverterBase, IDe
return source;
}
- public PropertyCacheLevel GetDeliveryApiPropertyCacheLevel(IPublishedPropertyType propertyType) => PropertyCacheLevel.Elements;
+ public PropertyCacheLevel GetDeliveryApiPropertyCacheLevel(IPublishedPropertyType propertyType) => PropertyCacheLevel.Snapshot;
public PropertyCacheLevel GetDeliveryApiPropertyCacheLevelForExpansion(IPublishedPropertyType propertyType) => PropertyCacheLevel.Snapshot;
From 3b4ca0b0f5d2a4ed702bca0f2a5ee840e250d6c7 Mon Sep 17 00:00:00 2001
From: Steve Morgan
Date: Tue, 5 Mar 2024 10:13:44 +0000
Subject: [PATCH 07/18] Media Picker - upload button disabled bug #13383
(#15115)
---
.../mediapicker/mediapicker.controller.js | 92 ++++++++++---------
1 file changed, 49 insertions(+), 43 deletions(-)
diff --git a/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/mediapicker/mediapicker.controller.js b/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/mediapicker/mediapicker.controller.js
index ce6a09fa3f..b3d3bc2dc3 100644
--- a/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/mediapicker/mediapicker.controller.js
+++ b/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/mediapicker/mediapicker.controller.js
@@ -103,43 +103,43 @@ angular.module("umbraco")
$scope.target = dialogOptions.currentTarget;
}
- function setTitle(data) {
- if (!$scope.model.title)
- $scope.model.title = data[0];
- }
-
- function setNavigation(data) {
- if (!vm.navigation.length) {
- vm.navigation = [{
- "alias": "empty",
- "name": data[0],
- "icon": "icon-umb-media",
- "active": true,
- "view": ""
- }];
- if (vm.clipboardItems) {
- vm.navigation.push({
- "alias": "clipboard",
- "name": data[1],
- "icon": "icon-paste-in",
- "view": "",
- "disabled": vm.clipboardItems.length === 0
- });
+ function setTitle(data) {
+ if (!$scope.model.title)
+ $scope.model.title = data[0];
+ }
+
+ function setNavigation(data) {
+ if (!vm.navigation.length) {
+ vm.navigation = [{
+ "alias": "empty",
+ "name": data[0],
+ "icon": "icon-umb-media",
+ "active": true,
+ "view": ""
+ }];
+ if (vm.clipboardItems) {
+ vm.navigation.push({
+ "alias": "clipboard",
+ "name": data[1],
+ "icon": "icon-paste-in",
+ "view": "",
+ "disabled": vm.clipboardItems.length === 0
+ });
+ }
+ vm.activeTab = vm.navigation[0];
+ }
}
- vm.activeTab = vm.navigation[0];
- }
- }
- function onInit() {
+ function onInit() {
- localizationService.localizeMany(["defaultdialogs_selectMedia", "mediaPicker_tabClipboard"])
- .then(function (localizationResult) {
- setTitle(localizationResult);
- setNavigation(localizationResult);
- });
-
+ localizationService.localizeMany(["defaultdialogs_selectMedia", "mediaPicker_tabClipboard"])
+ .then(function (localizationResult) {
+ setTitle(localizationResult);
+ setNavigation(localizationResult);
+ });
+
userService.getCurrentUser().then(function (userData) {
userStartNodes = userData.startMediaIds;
@@ -264,18 +264,24 @@ angular.module("umbraco")
function (f) {
return f.path.indexOf($scope.startNodeId) !== -1;
});
+ folder.path = $scope.path[0].path;
+ performGotoFolder(folder);
});
} else {
$scope.path = [];
+ performGotoFolder(folder);
}
+ }
+ function performGotoFolder(folder) {
mediaTypeHelper.getAllowedImagetypes(folder.id).then(function (types) { vm.acceptedMediatypes = types; });
+
$scope.lockedFolder = (folder.id === -1 && $scope.model.startNodeIsVirtual) || hasFolderAccess(folder) === false;
$scope.currentFolder = folder;
localStorageService.set("umbLastOpenedMediaNodeId", folder.id);
- return getChildren(folder.id);
+ getChildren(folder.id);
}
function toggleListView() {
@@ -431,9 +437,9 @@ angular.module("umbraco")
};
function onNavigationChanged(tab) {
- vm.activeTab.active = false;
- vm.activeTab = tab;
- vm.activeTab.active = true;
+ vm.activeTab.active = false;
+ vm.activeTab = tab;
+ vm.activeTab.active = true;
};
function clickClearClipboard() {
@@ -490,7 +496,7 @@ angular.module("umbraco")
if (data.items) {
var allowedTypes = dialogOptions.filter ? dialogOptions.filter.split(",") : null;
- data.items.forEach(function(mediaItem) {
+ data.items.forEach(function (mediaItem) {
setMediaMetaData(mediaItem);
mediaItem.filtered = allowedTypes && allowedTypes.indexOf(mediaItem.metaData.ContentTypeAlias) < 0;
});
@@ -575,12 +581,12 @@ angular.module("umbraco")
if (item.metaData.MediaPath !== null) {
item.thumbnail = mediaHelper.resolveFileFromEntity(item, true);
item.image = mediaHelper.resolveFileFromEntity(item, false);
- }
- if (item.metaData.UpdateDate !== null) {
- userService.getCurrentUser().then(currentUser => {
- item.updateDate = dateHelper.getLocalDate(item.metaData.UpdateDate, currentUser.locale, "LLL");
- });
-
+ }
+ if (item.metaData.UpdateDate !== null) {
+ userService.getCurrentUser().then(currentUser => {
+ item.updateDate = dateHelper.getLocalDate(item.metaData.UpdateDate, currentUser.locale, "LLL");
+ });
+
}
}
From 7dff3a37553ad1003e8422872e17851b73321586 Mon Sep 17 00:00:00 2001
From: Nikolaj Geisle <70372949+Zeegaan@users.noreply.github.com>
Date: Wed, 6 Mar 2024 11:01:37 +0100
Subject: [PATCH 08/18] bump version
---
version.json | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/version.json b/version.json
index 44ba7dcf8f..3c26ae287d 100644
--- a/version.json
+++ b/version.json
@@ -1,6 +1,6 @@
{
"$schema": "https://raw.githubusercontent.com/dotnet/Nerdbank.GitVersioning/main/src/NerdBank.GitVersioning/version.schema.json",
- "version": "13.2.0-rc2",
+ "version": "13.2.0",
"assemblyVersion": {
"precision": "build"
},
From b86eeb6b520e7e5003e367f0cb875973b28e0a0c Mon Sep 17 00:00:00 2001
From: Nikolaj Geisle <70372949+Zeegaan@users.noreply.github.com>
Date: Thu, 7 Mar 2024 09:54:14 +0100
Subject: [PATCH 09/18] bumb version
---
version.json | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/version.json b/version.json
index 3c26ae287d..f70819e8b4 100644
--- a/version.json
+++ b/version.json
@@ -1,6 +1,6 @@
{
"$schema": "https://raw.githubusercontent.com/dotnet/Nerdbank.GitVersioning/main/src/NerdBank.GitVersioning/version.schema.json",
- "version": "13.2.0",
+ "version": "13.3.0-rc",
"assemblyVersion": {
"precision": "build"
},
From 90820483d5c009cc7075c7f1a641dae783b47f86 Mon Sep 17 00:00:00 2001
From: Elitsa Marinovska <21998037+elit0451@users.noreply.github.com>
Date: Fri, 8 Mar 2024 08:36:00 +0100
Subject: [PATCH 10/18] Try to parse string as int and return
id.ToString(CultureInfo.InvariantCulture) (#15848)
---
src/Umbraco.Examine.Lucene/DeliveryApiContentIndex.cs | 10 ++++++++--
1 file changed, 8 insertions(+), 2 deletions(-)
diff --git a/src/Umbraco.Examine.Lucene/DeliveryApiContentIndex.cs b/src/Umbraco.Examine.Lucene/DeliveryApiContentIndex.cs
index a3508a3fed..c572fc85f7 100644
--- a/src/Umbraco.Examine.Lucene/DeliveryApiContentIndex.cs
+++ b/src/Umbraco.Examine.Lucene/DeliveryApiContentIndex.cs
@@ -1,9 +1,9 @@
+using System.Globalization;
using Examine;
using Examine.Lucene;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
-using Umbraco.Cms.Core;
using Umbraco.Cms.Core.DeliveryApi;
using Umbraco.Cms.Core.DependencyInjection;
using Umbraco.Cms.Core.Hosting;
@@ -125,8 +125,14 @@ public class DeliveryApiContentIndex : UmbracoExamineIndex
private (string? ContentId, string? Culture) ParseItemId(string id)
{
+ if (int.TryParse(id, out _))
+ {
+ return (id, null);
+ }
+
DeliveryApiIndexCompositeIdModel compositeIdModel = _deliveryApiCompositeIdHandler.Decompose(id);
- return (compositeIdModel.Id.ToString() ?? id, compositeIdModel.Culture);
+
+ return (compositeIdModel.Id?.ToString(CultureInfo.InvariantCulture), compositeIdModel.Culture);
}
protected override void OnTransformingIndexValues(IndexingItemEventArgs e)
From ed517ecd861fca7d64193db8a1f6e104aeb1e505 Mon Sep 17 00:00:00 2001
From: Bjarke Berg
Date: Thu, 14 Mar 2024 13:31:30 +0000
Subject: [PATCH 11/18] Update Imagesharp (#15885)
---
src/Directory.Packages.props | 103 +++++++++++++++++------------------
1 file changed, 50 insertions(+), 53 deletions(-)
diff --git a/src/Directory.Packages.props b/src/Directory.Packages.props
index a906a587ef..4d6bf155d3 100644
--- a/src/Directory.Packages.props
+++ b/src/Directory.Packages.props
@@ -4,67 +4,64 @@
true
NU1507
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
-
-
-
+
+
+
-
-
+
\ No newline at end of file
From 659e74d831e6646321f48dda21f97f026b173e53 Mon Sep 17 00:00:00 2001
From: Bjarke Berg
Date: Fri, 15 Mar 2024 08:08:27 +0100
Subject: [PATCH 12/18] Update imagesharp 3
---
src/Directory.Packages.props | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/Directory.Packages.props b/src/Directory.Packages.props
index 152f7cb91e..15801621da 100644
--- a/src/Directory.Packages.props
+++ b/src/Directory.Packages.props
@@ -56,7 +56,7 @@
-
+
From 0e43c43609007786fd82e8993ed109f19e18bdee Mon Sep 17 00:00:00 2001
From: Bjarke Berg
Date: Fri, 15 Mar 2024 08:09:39 +0100
Subject: [PATCH 13/18] Update imagesharp 3
---
src/Directory.Packages.props | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/Directory.Packages.props b/src/Directory.Packages.props
index 15801621da..b149d1d611 100644
--- a/src/Directory.Packages.props
+++ b/src/Directory.Packages.props
@@ -56,8 +56,8 @@
-
-
+
+
From 7585918821f6e0e2f1c40a478736ac1b8a8b1a7e Mon Sep 17 00:00:00 2001
From: Bjarke Berg
Date: Fri, 15 Mar 2024 08:20:50 +0100
Subject: [PATCH 14/18] Revert ImageSharp 3 upgrade due to breaking changes
---
src/Directory.Packages.props | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/Directory.Packages.props b/src/Directory.Packages.props
index b149d1d611..15801621da 100644
--- a/src/Directory.Packages.props
+++ b/src/Directory.Packages.props
@@ -56,8 +56,8 @@
-
-
+
+
From d82e262e139538f5bff26199791c24c9e6af0ed2 Mon Sep 17 00:00:00 2001
From: Bjarke Berg
Date: Fri, 15 Mar 2024 08:22:53 +0100
Subject: [PATCH 15/18] Update imagesharp 3
---
Directory.Packages.props | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/Directory.Packages.props b/Directory.Packages.props
index c80183b9c1..02dbaba948 100644
--- a/Directory.Packages.props
+++ b/Directory.Packages.props
@@ -73,7 +73,7 @@
-
+
@@ -90,4 +90,4 @@
-
\ No newline at end of file
+
From e03ff2661b9bbd5c36e79dda092616f85039ad72 Mon Sep 17 00:00:00 2001
From: Bjarke Berg
Date: Fri, 15 Mar 2024 09:35:19 +0100
Subject: [PATCH 16/18] Ignore test of lazy locks
---
.../Umbraco.Infrastructure/Persistence/LocksTests.cs | 1 +
1 file changed, 1 insertion(+)
diff --git a/tests/Umbraco.Tests.Integration/Umbraco.Infrastructure/Persistence/LocksTests.cs b/tests/Umbraco.Tests.Integration/Umbraco.Infrastructure/Persistence/LocksTests.cs
index 88b48dfaae..8ae6818aeb 100644
--- a/tests/Umbraco.Tests.Integration/Umbraco.Infrastructure/Persistence/LocksTests.cs
+++ b/tests/Umbraco.Tests.Integration/Umbraco.Infrastructure/Persistence/LocksTests.cs
@@ -125,6 +125,7 @@ public class LocksTests : UmbracoIntegrationTest
}
}
+ [NUnit.Framework.Ignore("We currently do not have a way to force lazy locks")]
[Test]
public void GivenNonEagerLocking_WhenNoDbIsAccessed_ThenNoSqlIsExecuted()
{
From 3718a9cdd48ea4e57024b4c433cf2c55a2e91c53 Mon Sep 17 00:00:00 2001
From: Bjarke Berg
Date: Fri, 15 Mar 2024 09:47:18 +0100
Subject: [PATCH 17/18] Revert "Ignore test of lazy locks"
This reverts commit e03ff2661b9bbd5c36e79dda092616f85039ad72.
---
.../Umbraco.Infrastructure/Persistence/LocksTests.cs | 1 -
1 file changed, 1 deletion(-)
diff --git a/tests/Umbraco.Tests.Integration/Umbraco.Infrastructure/Persistence/LocksTests.cs b/tests/Umbraco.Tests.Integration/Umbraco.Infrastructure/Persistence/LocksTests.cs
index 8ae6818aeb..88b48dfaae 100644
--- a/tests/Umbraco.Tests.Integration/Umbraco.Infrastructure/Persistence/LocksTests.cs
+++ b/tests/Umbraco.Tests.Integration/Umbraco.Infrastructure/Persistence/LocksTests.cs
@@ -125,7 +125,6 @@ public class LocksTests : UmbracoIntegrationTest
}
}
- [NUnit.Framework.Ignore("We currently do not have a way to force lazy locks")]
[Test]
public void GivenNonEagerLocking_WhenNoDbIsAccessed_ThenNoSqlIsExecuted()
{
From 2c23e67c65a98e0573924cd1a55bf03df6e13410 Mon Sep 17 00:00:00 2001
From: Bjarke Berg
Date: Fri, 15 Mar 2024 09:56:02 +0000
Subject: [PATCH 18/18] Fixing locking issues for document type saves. (#15854)
* Added ExecuteNonQuery(DbCommand command) on database to ensure we call OnExecutingCommand and OnExecutedCommand when executing DbCommands
* Added Cache Instructions lock, to avoid deadlocks
* Optimized read locks for nucache when only one content type is rebuilt
* Optimized the SqlServer locks, so only one command is executed (and thereby roundtrip) per lock instead of two
* Avoid breaking changes
* Cosmetic changes
* Take locks if everything is rebuild
* Use same lock in scopes, to avoid potential deadlocks between the two
* Use eager locks in PublishedSnapshotService.cs
* Added timeouts to some of the application locks
* Revert "Use eager locks in PublishedSnapshotService.cs"
This reverts commit 01873aae978ffa6e6686d253e482c493715e3a96.
* Revert "Added Cache Instructions lock, to avoid deadlocks"
This reverts commit e3fca7c12a804bb32ca1156b8abd42a957e9dc21.
* Use single readlock call to lock many
* Use eager locks for reads
* Eager write locks
* Ignore test of lazy locks
* Unique timeout exception messages
---------
Co-authored-by: kjac
---
.../SqlServerDistributedLockingMechanism.cs | 10 +++--
.../SqliteDistributedLockingMechanism.cs | 2 +-
src/Umbraco.Core/Cache/ObjectCacheAppCache.cs | 39 +++++++++++++++----
.../Persistence/IUmbracoDatabase.cs | 4 ++
.../Persistence/UmbracoDatabase.cs | 8 ++++
src/Umbraco.Infrastructure/Scoping/Scope.cs | 26 ++++++-------
.../ContentStore.cs | 9 ++++-
.../Persistence/NuCacheContentService.cs | 22 +++++++++--
.../SnapDictionary.cs | 9 ++++-
.../Persistence/LocksTests.cs | 38 +++++++++++++++---
10 files changed, 129 insertions(+), 38 deletions(-)
diff --git a/src/Umbraco.Cms.Persistence.SqlServer/Services/SqlServerDistributedLockingMechanism.cs b/src/Umbraco.Cms.Persistence.SqlServer/Services/SqlServerDistributedLockingMechanism.cs
index 358eae2e38..e0bf4767bf 100644
--- a/src/Umbraco.Cms.Persistence.SqlServer/Services/SqlServerDistributedLockingMechanism.cs
+++ b/src/Umbraco.Cms.Persistence.SqlServer/Services/SqlServerDistributedLockingMechanism.cs
@@ -134,9 +134,10 @@ public class SqlServerDistributedLockingMechanism : IDistributedLockingMechanism
const string query = "SELECT value FROM umbracoLock WITH (REPEATABLEREAD) WHERE id=@id";
- db.Execute("SET LOCK_TIMEOUT " + _timeout.TotalMilliseconds + ";");
+ var lockTimeoutQuery = $"SET LOCK_TIMEOUT {_timeout.TotalMilliseconds}";
- var i = db.ExecuteScalar(query, new { id = LockId });
+ // execute the lock timeout query and the actual query in a single server roundtrip
+ var i = db.ExecuteScalar($"{lockTimeoutQuery};{query}", new { id = LockId });
if (i == null)
{
@@ -169,9 +170,10 @@ public class SqlServerDistributedLockingMechanism : IDistributedLockingMechanism
const string query =
@"UPDATE umbracoLock WITH (REPEATABLEREAD) SET value = (CASE WHEN (value=1) THEN -1 ELSE 1 END) WHERE id=@id";
- db.Execute("SET LOCK_TIMEOUT " + _timeout.TotalMilliseconds + ";");
+ var lockTimeoutQuery = $"SET LOCK_TIMEOUT {_timeout.TotalMilliseconds}";
- var i = db.Execute(query, new { id = LockId });
+ // execute the lock timeout query and the actual query in a single server roundtrip
+ var i = db.Execute($"{lockTimeoutQuery};{query}", new { id = LockId });
if (i == 0)
{
diff --git a/src/Umbraco.Cms.Persistence.Sqlite/Services/SqliteDistributedLockingMechanism.cs b/src/Umbraco.Cms.Persistence.Sqlite/Services/SqliteDistributedLockingMechanism.cs
index c3d6f8b29d..9f25f77c2c 100644
--- a/src/Umbraco.Cms.Persistence.Sqlite/Services/SqliteDistributedLockingMechanism.cs
+++ b/src/Umbraco.Cms.Persistence.Sqlite/Services/SqliteDistributedLockingMechanism.cs
@@ -154,7 +154,7 @@ public class SqliteDistributedLockingMechanism : IDistributedLockingMechanism
try
{
- var i = command.ExecuteNonQuery();
+ var i = db.ExecuteNonQuery(command);
if (i == 0)
{
diff --git a/src/Umbraco.Core/Cache/ObjectCacheAppCache.cs b/src/Umbraco.Core/Cache/ObjectCacheAppCache.cs
index dcd83ece94..ff1c9b3bfd 100644
--- a/src/Umbraco.Core/Cache/ObjectCacheAppCache.cs
+++ b/src/Umbraco.Core/Cache/ObjectCacheAppCache.cs
@@ -9,6 +9,9 @@ namespace Umbraco.Cms.Core.Cache;
///
public class ObjectCacheAppCache : IAppPolicyCache, IDisposable
{
+ private static readonly TimeSpan _readLockTimeout = TimeSpan.FromSeconds(5);
+ private static readonly TimeSpan _writeLockTimeout = TimeSpan.FromSeconds(5);
+
private readonly ReaderWriterLockSlim _locker = new(LockRecursionPolicy.SupportsRecursion);
private bool _disposedValue;
@@ -33,7 +36,10 @@ public class ObjectCacheAppCache : IAppPolicyCache, IDisposable
Lazy