From c5ba23a15c360eada010553c39809d8dbf26ba1e Mon Sep 17 00:00:00 2001 From: Ronald Barendse Date: Wed, 13 Oct 2021 13:32:30 +0200 Subject: [PATCH 01/52] Add Constants.Sql.MaxParameterCount --- src/Umbraco.Core/Constants-Sql.cs | 17 +++++++++++++++++ src/Umbraco.Core/Umbraco.Core.csproj | 3 ++- 2 files changed, 19 insertions(+), 1 deletion(-) create mode 100644 src/Umbraco.Core/Constants-Sql.cs diff --git a/src/Umbraco.Core/Constants-Sql.cs b/src/Umbraco.Core/Constants-Sql.cs new file mode 100644 index 000000000000..366dfbe44ab4 --- /dev/null +++ b/src/Umbraco.Core/Constants-Sql.cs @@ -0,0 +1,17 @@ +namespace Umbraco.Core +{ + public static partial class Constants + { + public static class Sql + { + /// + /// The maximum amount of parameters that can be used in a query. + /// + /// + /// The actual limit is 2100 (https://docs.microsoft.com/en-us/sql/sql-server/maximum-capacity-specifications-for-sql-server), + /// but we want to ensure there's room for additional parameters if this value is used to create groups/batches. + /// + public const int MaxParameterCount = 2000; + } + } +} diff --git a/src/Umbraco.Core/Umbraco.Core.csproj b/src/Umbraco.Core/Umbraco.Core.csproj index 77eeaaa85329..e2679c222351 100755 --- a/src/Umbraco.Core/Umbraco.Core.csproj +++ b/src/Umbraco.Core/Umbraco.Core.csproj @@ -132,6 +132,7 @@ + @@ -1665,4 +1666,4 @@ - + \ No newline at end of file From a6b04a941ced30381230c3d37e0c667960a2bfda Mon Sep 17 00:00:00 2001 From: Ronald Barendse Date: Wed, 13 Oct 2021 13:42:18 +0200 Subject: [PATCH 02/52] Replace arbitrary group size with constant --- .../Persistence/NPocoDatabaseExtensions-Bulk.cs | 2 +- .../Repositories/Implement/AuditEntryRepository.cs | 2 +- .../Repositories/Implement/ContentRepositoryBase.cs | 4 ++-- .../Repositories/Implement/ContentTypeRepositoryBase.cs | 8 ++++---- .../Repositories/Implement/DictionaryRepository.cs | 3 +-- .../Repositories/Implement/DocumentRepository.cs | 6 +++--- .../Repositories/Implement/EntityContainerRepository.cs | 2 +- .../Repositories/Implement/EntityRepository.cs | 2 +- .../Repositories/Implement/PermissionRepository.cs | 9 ++++----- .../Repositories/Implement/RedirectUrlRepository.cs | 5 +++-- .../Repositories/Implement/RepositoryBaseOfTIdTEntity.cs | 5 ++--- .../Persistence/Repositories/Implement/TagRepository.cs | 2 +- src/Umbraco.Web/Models/Mapping/UserMapDefinition.cs | 2 +- 13 files changed, 25 insertions(+), 27 deletions(-) diff --git a/src/Umbraco.Core/Persistence/NPocoDatabaseExtensions-Bulk.cs b/src/Umbraco.Core/Persistence/NPocoDatabaseExtensions-Bulk.cs index 77cc0d66019b..a50e3c2aaa9f 100644 --- a/src/Umbraco.Core/Persistence/NPocoDatabaseExtensions-Bulk.cs +++ b/src/Umbraco.Core/Persistence/NPocoDatabaseExtensions-Bulk.cs @@ -137,7 +137,7 @@ internal static IDbCommand[] GenerateBulkInsertCommands(this IUmbracoDatabase // Math.Floor(2100 / 8) = 262 record per command // 4168 / 262 = 15.908... = there will be 16 command in total // (if we have disabled db parameters, then all records will be included, in only one command) - var recordsPerCommand = paramsPerRecord == 0 ? int.MaxValue : Convert.ToInt32(Math.Floor(2000.00 / paramsPerRecord)); + var recordsPerCommand = paramsPerRecord == 0 ? int.MaxValue : Convert.ToInt32(Math.Floor((double)Constants.Sql.MaxParameterCount / paramsPerRecord)); var commandsCount = Convert.ToInt32(Math.Ceiling((double)records.Length / recordsPerCommand)); var commands = new IDbCommand[commandsCount]; diff --git a/src/Umbraco.Core/Persistence/Repositories/Implement/AuditEntryRepository.cs b/src/Umbraco.Core/Persistence/Repositories/Implement/AuditEntryRepository.cs index c3d34cc3e9f8..d921bb6d5153 100644 --- a/src/Umbraco.Core/Persistence/Repositories/Implement/AuditEntryRepository.cs +++ b/src/Umbraco.Core/Persistence/Repositories/Implement/AuditEntryRepository.cs @@ -54,7 +54,7 @@ protected override IEnumerable PerformGetAll(params int[] ids) var entries = new List(); - foreach (var group in ids.InGroupsOf(2000)) + foreach (var group in ids.InGroupsOf(Constants.Sql.MaxParameterCount)) { var sql = Sql() .Select() diff --git a/src/Umbraco.Core/Persistence/Repositories/Implement/ContentRepositoryBase.cs b/src/Umbraco.Core/Persistence/Repositories/Implement/ContentRepositoryBase.cs index 85814ef681cf..a6b08c2bfd2b 100644 --- a/src/Umbraco.Core/Persistence/Repositories/Implement/ContentRepositoryBase.cs +++ b/src/Umbraco.Core/Persistence/Repositories/Implement/ContentRepositoryBase.cs @@ -638,7 +638,7 @@ protected IDictionary GetPropertyCollections(List(versions, 2000, batch => + var allPropertyDataDtos = Database.FetchByGroups(versions, Constants.Sql.MaxParameterCount, batch => SqlContext.Sql() .Select() .From() @@ -647,7 +647,7 @@ protected IDictionary GetPropertyCollections(List x.PropertyTypeId).Distinct().ToList(); - var allPropertyTypeDtos = Database.FetchByGroups(allPropertyTypeIds, 2000, batch => + var allPropertyTypeDtos = Database.FetchByGroups(allPropertyTypeIds, Constants.Sql.MaxParameterCount, batch => SqlContext.Sql() .Select(r => r.Select(x => x.DataTypeDto)) .From() diff --git a/src/Umbraco.Core/Persistence/Repositories/Implement/ContentTypeRepositoryBase.cs b/src/Umbraco.Core/Persistence/Repositories/Implement/ContentTypeRepositoryBase.cs index aff53e44b0af..8835f8c647a4 100644 --- a/src/Umbraco.Core/Persistence/Repositories/Implement/ContentTypeRepositoryBase.cs +++ b/src/Umbraco.Core/Persistence/Repositories/Implement/ContentTypeRepositoryBase.cs @@ -768,7 +768,7 @@ private void CopyTagData(int? sourceLanguageId, int? targetLanguageId, IReadOnly // note: important to use SqlNullableEquals for nullable types, cannot directly compare language identifiers var whereInArgsCount = propertyTypeIds.Count + (contentTypeIds?.Count ?? 0); - if (whereInArgsCount > 2000) + if (whereInArgsCount > Constants.Sql.MaxParameterCount) throw new NotSupportedException("Too many property/content types."); // delete existing relations (for target language) @@ -906,7 +906,7 @@ private void CopyPropertyData(int? sourceLanguageId, int? targetLanguageId, IRea // note: important to use SqlNullableEquals for nullable types, cannot directly compare language identifiers // var whereInArgsCount = propertyTypeIds.Count + (contentTypeIds?.Count ?? 0); - if (whereInArgsCount > 2000) + if (whereInArgsCount > Constants.Sql.MaxParameterCount) throw new NotSupportedException("Too many property/content types."); //first clear out any existing property data that might already exists under the target language @@ -1005,7 +1005,7 @@ private void RenormalizeDocumentEditedFlags(IReadOnlyCollection propertyTyp //based on the current variance of each item to see if it's 'edited' value should be true/false. var whereInArgsCount = propertyTypeIds.Count + (contentTypeIds?.Count ?? 0); - if (whereInArgsCount > 2000) + if (whereInArgsCount > Constants.Sql.MaxParameterCount) throw new NotSupportedException("Too many property/content types."); var propertySql = Sql() @@ -1095,7 +1095,7 @@ private void RenormalizeDocumentEditedFlags(IReadOnlyCollection propertyTyp } //lookup all matching rows in umbracoDocumentCultureVariation - var docCultureVariationsToUpdate = editedLanguageVersions.InGroupsOf(2000) + var docCultureVariationsToUpdate = editedLanguageVersions.InGroupsOf(Constants.Sql.MaxParameterCount) .SelectMany(_ => Database.Fetch( Sql().Select().From() .WhereIn(x => x.LanguageId, editedLanguageVersions.Keys.Select(x => x.langId).ToList()) diff --git a/src/Umbraco.Core/Persistence/Repositories/Implement/DictionaryRepository.cs b/src/Umbraco.Core/Persistence/Repositories/Implement/DictionaryRepository.cs index ac1f7c3f2a94..7895b7aa8fc2 100644 --- a/src/Umbraco.Core/Persistence/Repositories/Implement/DictionaryRepository.cs +++ b/src/Umbraco.Core/Persistence/Repositories/Implement/DictionaryRepository.cs @@ -260,8 +260,7 @@ public IEnumerable GetDictionaryItemDescendants(Guid? parentId) Func>> getItemsFromParents = guids => { - //needs to be in groups of 2000 because we are doing an IN clause and there's a max parameter count that can be used. - return guids.InGroupsOf(2000) + return guids.InGroupsOf(Constants.Sql.MaxParameterCount) .Select(@group => { var sqlClause = GetBaseQuery(false) diff --git a/src/Umbraco.Core/Persistence/Repositories/Implement/DocumentRepository.cs b/src/Umbraco.Core/Persistence/Repositories/Implement/DocumentRepository.cs index 5716fbe129c4..753630d186d0 100644 --- a/src/Umbraco.Core/Persistence/Repositories/Implement/DocumentRepository.cs +++ b/src/Umbraco.Core/Persistence/Repositories/Implement/DocumentRepository.cs @@ -1342,7 +1342,7 @@ private IDictionary GetContentSchedule(params in { var result = new Dictionary(); - var scheduleDtos = Database.FetchByGroups(contentIds, 2000, batch => Sql() + var scheduleDtos = Database.FetchByGroups(contentIds, Constants.Sql.MaxParameterCount, batch => Sql() .Select() .From() .WhereIn(x => x.NodeId, batch)); @@ -1391,7 +1391,7 @@ private IDictionary> GetContentVariations(List>(); - var dtos = Database.FetchByGroups(versions, 2000, batch + var dtos = Database.FetchByGroups(versions, Constants.Sql.MaxParameterCount, batch => Sql() .Select() .From() @@ -1420,7 +1420,7 @@ private IDictionary> GetDocumentVariations(List< { var ids = temps.Select(x => x.Id); - var dtos = Database.FetchByGroups(ids, 2000, batch => + var dtos = Database.FetchByGroups(ids, Constants.Sql.MaxParameterCount, batch => Sql() .Select() .From() diff --git a/src/Umbraco.Core/Persistence/Repositories/Implement/EntityContainerRepository.cs b/src/Umbraco.Core/Persistence/Repositories/Implement/EntityContainerRepository.cs index 505cbfc816ea..07b82190f5d4 100644 --- a/src/Umbraco.Core/Persistence/Repositories/Implement/EntityContainerRepository.cs +++ b/src/Umbraco.Core/Persistence/Repositories/Implement/EntityContainerRepository.cs @@ -60,7 +60,7 @@ protected override IEnumerable PerformGetAll(params int[] ids) { if (ids.Any()) { - return Database.FetchByGroups(ids, 2000, batch => + return Database.FetchByGroups(ids, Constants.Sql.MaxParameterCount, batch => GetBaseQuery(false) .Where(x => x.NodeObjectType == NodeObjectTypeId) .WhereIn(x => x.NodeId, batch)) diff --git a/src/Umbraco.Core/Persistence/Repositories/Implement/EntityRepository.cs b/src/Umbraco.Core/Persistence/Repositories/Implement/EntityRepository.cs index a7502a338af8..7bcc5f6b2db4 100644 --- a/src/Umbraco.Core/Persistence/Repositories/Implement/EntityRepository.cs +++ b/src/Umbraco.Core/Persistence/Repositories/Implement/EntityRepository.cs @@ -281,7 +281,7 @@ private IEnumerable BuildVariants(IEnumerable(v.Select(x => x.Id), 2000, GetVariantInfos); + var dtos = Database.FetchByGroups(v.Select(x => x.Id), Constants.Sql.MaxParameterCount, GetVariantInfos); // group by node id (each group contains all languages) var xdtos = dtos.GroupBy(x => x.NodeId).ToDictionary(x => x.Key, x => x); diff --git a/src/Umbraco.Core/Persistence/Repositories/Implement/PermissionRepository.cs b/src/Umbraco.Core/Persistence/Repositories/Implement/PermissionRepository.cs index 259f0b89c0ab..ce324df6856b 100644 --- a/src/Umbraco.Core/Persistence/Repositories/Implement/PermissionRepository.cs +++ b/src/Umbraco.Core/Persistence/Repositories/Implement/PermissionRepository.cs @@ -44,7 +44,7 @@ public EntityPermissionCollection GetPermissionsForEntities(int[] groupIds, para { var result = new EntityPermissionCollection(); - foreach (var groupOfGroupIds in groupIds.InGroupsOf(2000)) + foreach (var groupOfGroupIds in groupIds.InGroupsOf(Constants.Sql.MaxParameterCount)) { //copy local var localIds = groupOfGroupIds.ToArray(); @@ -64,7 +64,7 @@ public EntityPermissionCollection GetPermissionsForEntities(int[] groupIds, para else { //iterate in groups of 2000 since we don't want to exceed the max SQL param count - foreach (var groupOfEntityIds in entityIds.InGroupsOf(2000)) + foreach (var groupOfEntityIds in entityIds.InGroupsOf(Constants.Sql.MaxParameterCount)) { var ids = groupOfEntityIds; var sql = Sql() @@ -133,11 +133,10 @@ public void ReplacePermissions(int groupId, IEnumerable permissions, param var db = AmbientScope.Database; - //we need to batch these in groups of 2000 so we don't exceed the max 2100 limit var sql = "DELETE FROM umbracoUserGroup2NodePermission WHERE userGroupId = @groupId AND nodeId in (@nodeIds)"; - foreach (var idGroup in entityIds.InGroupsOf(2000)) + foreach (var group in entityIds.InGroupsOf(Constants.Sql.MaxParameterCount)) { - db.Execute(sql, new { groupId, nodeIds = idGroup }); + db.Execute(sql, new { groupId, nodeIds = group }); } var toInsert = new List(); diff --git a/src/Umbraco.Core/Persistence/Repositories/Implement/RedirectUrlRepository.cs b/src/Umbraco.Core/Persistence/Repositories/Implement/RedirectUrlRepository.cs index 24c1e31c2015..099d49fbf8ac 100644 --- a/src/Umbraco.Core/Persistence/Repositories/Implement/RedirectUrlRepository.cs +++ b/src/Umbraco.Core/Persistence/Repositories/Implement/RedirectUrlRepository.cs @@ -37,8 +37,9 @@ protected override IRedirectUrl PerformGet(Guid id) protected override IEnumerable PerformGetAll(params Guid[] ids) { - if (ids.Length > 2000) - throw new NotSupportedException("This repository does not support more than 2000 ids."); + if (ids.Length > Constants.Sql.MaxParameterCount) + throw new NotSupportedException($"This repository does not support more than {Constants.Sql.MaxParameterCount} ids."); + var sql = GetBaseQuery(false).WhereIn(x => x.Id, ids); var dtos = Database.Fetch(sql); return dtos.WhereNotNull().Select(Map); diff --git a/src/Umbraco.Core/Persistence/Repositories/Implement/RepositoryBaseOfTIdTEntity.cs b/src/Umbraco.Core/Persistence/Repositories/Implement/RepositoryBaseOfTIdTEntity.cs index 69e4db5940a2..c2aec05fa7e1 100644 --- a/src/Umbraco.Core/Persistence/Repositories/Implement/RepositoryBaseOfTIdTEntity.cs +++ b/src/Umbraco.Core/Persistence/Repositories/Implement/RepositoryBaseOfTIdTEntity.cs @@ -186,14 +186,13 @@ public IEnumerable GetMany(params TId[] ids) // can't query more than 2000 ids at a time... but if someone is really querying 2000+ entities, // the additional overhead of fetching them in groups is minimal compared to the lookup time of each group - const int maxParams = 2000; - if (ids.Length <= maxParams) + if (ids.Length <= Constants.Sql.MaxParameterCount) { return CachePolicy.GetAll(ids, PerformGetAll); } var entities = new List(); - foreach (var groupOfIds in ids.InGroupsOf(maxParams)) + foreach (var groupOfIds in ids.InGroupsOf(Constants.Sql.MaxParameterCount)) { entities.AddRange(CachePolicy.GetAll(groupOfIds.ToArray(), PerformGetAll)); } diff --git a/src/Umbraco.Core/Persistence/Repositories/Implement/TagRepository.cs b/src/Umbraco.Core/Persistence/Repositories/Implement/TagRepository.cs index 279e03b19e37..83170d9dbcb4 100644 --- a/src/Umbraco.Core/Persistence/Repositories/Implement/TagRepository.cs +++ b/src/Umbraco.Core/Persistence/Repositories/Implement/TagRepository.cs @@ -39,7 +39,7 @@ protected override IEnumerable PerformGetAll(params int[] ids) { var dtos = ids.Length == 0 ? Database.Fetch(Sql().Select().From()) - : Database.FetchByGroups(ids, 2000, batch => Sql().Select().From().WhereIn(x => x.Id, batch)); + : Database.FetchByGroups(ids, Constants.Sql.MaxParameterCount, batch => Sql().Select().From().WhereIn(x => x.Id, batch)); return dtos.Select(TagFactory.BuildEntity).ToList(); } diff --git a/src/Umbraco.Web/Models/Mapping/UserMapDefinition.cs b/src/Umbraco.Web/Models/Mapping/UserMapDefinition.cs index 619863089847..f66a1ee934d9 100644 --- a/src/Umbraco.Web/Models/Mapping/UserMapDefinition.cs +++ b/src/Umbraco.Web/Models/Mapping/UserMapDefinition.cs @@ -240,7 +240,7 @@ private void Map(IUserGroup source, UserGroupDisplay target, MapperContext conte // the entity service due to too many Sql parameters. var list = new List(); - foreach (var idGroup in allContentPermissions.Keys.InGroupsOf(2000)) + foreach (var idGroup in allContentPermissions.Keys.InGroupsOf(Constants.Sql.MaxParameterCount)) list.AddRange(_entityService.GetAll(UmbracoObjectTypes.Document, idGroup.ToArray())); contentEntities = list.ToArray(); } From 88a20cb13cbde845829cbe00efa581f9737713e4 Mon Sep 17 00:00:00 2001 From: Ronald Barendse Date: Wed, 13 Oct 2021 13:46:51 +0200 Subject: [PATCH 03/52] Minor query cleanup --- .../Repositories/Implement/DictionaryRepository.cs | 4 ++-- .../Repositories/Implement/MemberRepository.cs | 9 +++------ .../Repositories/Implement/RepositoryBaseOfTIdTEntity.cs | 6 ++++-- 3 files changed, 9 insertions(+), 10 deletions(-) diff --git a/src/Umbraco.Core/Persistence/Repositories/Implement/DictionaryRepository.cs b/src/Umbraco.Core/Persistence/Repositories/Implement/DictionaryRepository.cs index 7895b7aa8fc2..da957a728858 100644 --- a/src/Umbraco.Core/Persistence/Repositories/Implement/DictionaryRepository.cs +++ b/src/Umbraco.Core/Persistence/Repositories/Implement/DictionaryRepository.cs @@ -261,11 +261,11 @@ public IEnumerable GetDictionaryItemDescendants(Guid? parentId) Func>> getItemsFromParents = guids => { return guids.InGroupsOf(Constants.Sql.MaxParameterCount) - .Select(@group => + .Select(group => { var sqlClause = GetBaseQuery(false) .Where(x => x.Parent != null) - .Where($"{SqlSyntax.GetQuotedColumnName("parent")} IN (@parentIds)", new { parentIds = @group }); + .WhereIn(x => x.Parent, group); var translator = new SqlTranslator(sqlClause, Query()); var sql = translator.Translate(); diff --git a/src/Umbraco.Core/Persistence/Repositories/Implement/MemberRepository.cs b/src/Umbraco.Core/Persistence/Repositories/Implement/MemberRepository.cs index 62f41aa72759..1982d6ebf921 100644 --- a/src/Umbraco.Core/Persistence/Repositories/Implement/MemberRepository.cs +++ b/src/Umbraco.Core/Persistence/Repositories/Implement/MemberRepository.cs @@ -431,16 +431,13 @@ public IEnumerable FindMembersInRole(string roleName, string usernameTo var matchedMembers = Get(query).ToArray(); var membersInGroup = new List(); + //then we need to filter the matched members that are in the role - //since the max sql params are 2100 on sql server, we'll reduce that to be safe for potentially other servers and run the queries in batches - var inGroups = matchedMembers.InGroupsOf(1000); - foreach (var batch in inGroups) + foreach (var group in matchedMembers.Select(x => x.Id).InGroupsOf(Constants.Sql.MaxParameterCount)) { - var memberIdBatch = batch.Select(x => x.Id); - var sql = Sql().SelectAll().From() .Where(dto => dto.MemberGroup == memberGroup.Id) - .WhereIn(dto => dto.Member, memberIdBatch); + .WhereIn(dto => dto.Member, group); var memberIdsInGroup = Database.Fetch(sql) .Select(x => x.Member).ToArray(); diff --git a/src/Umbraco.Core/Persistence/Repositories/Implement/RepositoryBaseOfTIdTEntity.cs b/src/Umbraco.Core/Persistence/Repositories/Implement/RepositoryBaseOfTIdTEntity.cs index c2aec05fa7e1..5892f2bf4993 100644 --- a/src/Umbraco.Core/Persistence/Repositories/Implement/RepositoryBaseOfTIdTEntity.cs +++ b/src/Umbraco.Core/Persistence/Repositories/Implement/RepositoryBaseOfTIdTEntity.cs @@ -188,14 +188,16 @@ public IEnumerable GetMany(params TId[] ids) // the additional overhead of fetching them in groups is minimal compared to the lookup time of each group if (ids.Length <= Constants.Sql.MaxParameterCount) { + // the additional overhead of fetching them in groups is minimal compared to the lookup time of each group return CachePolicy.GetAll(ids, PerformGetAll); } var entities = new List(); - foreach (var groupOfIds in ids.InGroupsOf(Constants.Sql.MaxParameterCount)) + foreach (var group in ids.InGroupsOf(Constants.Sql.MaxParameterCount)) { - entities.AddRange(CachePolicy.GetAll(groupOfIds.ToArray(), PerformGetAll)); + entities.AddRange(CachePolicy.GetAll(group.ToArray(), PerformGetAll)); } + return entities; } From 1bc3290497626ebe720806c4af1b62820d12a665 Mon Sep 17 00:00:00 2001 From: Ronald Barendse Date: Wed, 13 Oct 2021 14:10:24 +0200 Subject: [PATCH 04/52] Fix bugs in fetching more than 2000 items (permissions and culture variations) --- .../Implement/ContentTypeRepositoryBase.cs | 22 +++++++---- .../Implement/PermissionRepository.cs | 37 +++++++++---------- 2 files changed, 31 insertions(+), 28 deletions(-) diff --git a/src/Umbraco.Core/Persistence/Repositories/Implement/ContentTypeRepositoryBase.cs b/src/Umbraco.Core/Persistence/Repositories/Implement/ContentTypeRepositoryBase.cs index 8835f8c647a4..3a74b9209b61 100644 --- a/src/Umbraco.Core/Persistence/Repositories/Implement/ContentTypeRepositoryBase.cs +++ b/src/Umbraco.Core/Persistence/Repositories/Implement/ContentTypeRepositoryBase.cs @@ -1094,14 +1094,20 @@ private void RenormalizeDocumentEditedFlags(IReadOnlyCollection propertyTyp } } - //lookup all matching rows in umbracoDocumentCultureVariation - var docCultureVariationsToUpdate = editedLanguageVersions.InGroupsOf(Constants.Sql.MaxParameterCount) - .SelectMany(_ => Database.Fetch( - Sql().Select().From() - .WhereIn(x => x.LanguageId, editedLanguageVersions.Keys.Select(x => x.langId).ToList()) - .WhereIn(x => x.NodeId, editedLanguageVersions.Keys.Select(x => x.nodeId)))) - //convert to dictionary with the same key type - .ToDictionary(x => (x.NodeId, (int?)x.LanguageId), x => x); + // lookup all matching rows in umbracoDocumentCultureVariation + // fetch in batches to account for maximum parameter count (distinct languages can't exceed 2000) + var languageIds = editedLanguageVersions.Keys.Select(x => x.langId).Distinct().ToArray(); + var nodeIds = editedLanguageVersions.Keys.Select(x => x.nodeId).Distinct(); + var docCultureVariationsToUpdate = nodeIds.InGroupsOf(Constants.Sql.MaxParameterCount - languageIds.Length) + .SelectMany(group => + { + var sql = Sql().Select().From() + .WhereIn(x => x.LanguageId, languageIds) + .WhereIn(x => x.NodeId, group); + + return Database.Fetch(sql); + }) + .ToDictionary(x => (x.NodeId, (int?)x.LanguageId), x => x); //convert to dictionary with the same key type var toUpdate = new List(); foreach (var ev in editedLanguageVersions) diff --git a/src/Umbraco.Core/Persistence/Repositories/Implement/PermissionRepository.cs b/src/Umbraco.Core/Persistence/Repositories/Implement/PermissionRepository.cs index ce324df6856b..735496a0d187 100644 --- a/src/Umbraco.Core/Persistence/Repositories/Implement/PermissionRepository.cs +++ b/src/Umbraco.Core/Persistence/Repositories/Implement/PermissionRepository.cs @@ -38,44 +38,41 @@ public PermissionRepository(IScopeAccessor scopeAccessor, AppCaches cache, ILogg /// /// /// - /// This method will not support passing in more than 2000 group Ids + /// This method will not support passing in more than 2000 group IDs when also passing in entity IDs. /// public EntityPermissionCollection GetPermissionsForEntities(int[] groupIds, params int[] entityIds) { var result = new EntityPermissionCollection(); - foreach (var groupOfGroupIds in groupIds.InGroupsOf(Constants.Sql.MaxParameterCount)) + if (entityIds.Length == 0) { - //copy local - var localIds = groupOfGroupIds.ToArray(); - - if (entityIds.Length == 0) + foreach (var group in groupIds.InGroupsOf(Constants.Sql.MaxParameterCount)) { var sql = Sql() .SelectAll() .From() - .Where(dto => localIds.Contains(dto.UserGroupId)); + .Where(dto => group.Contains(dto.UserGroupId)); + var permissions = AmbientScope.Database.Fetch(sql); foreach (var permission in ConvertToPermissionList(permissions)) { result.Add(permission); } } - else + } + else + { + foreach (var group in entityIds.InGroupsOf(Constants.Sql.MaxParameterCount - groupIds.Length)) { - //iterate in groups of 2000 since we don't want to exceed the max SQL param count - foreach (var groupOfEntityIds in entityIds.InGroupsOf(Constants.Sql.MaxParameterCount)) + var sql = Sql() + .SelectAll() + .From() + .Where(dto => groupIds.Contains(dto.UserGroupId) && group.Contains(dto.NodeId)); + + var permissions = AmbientScope.Database.Fetch(sql); + foreach (var permission in ConvertToPermissionList(permissions)) { - var ids = groupOfEntityIds; - var sql = Sql() - .SelectAll() - .From() - .Where(dto => localIds.Contains(dto.UserGroupId) && ids.Contains(dto.NodeId)); - var permissions = AmbientScope.Database.Fetch(sql); - foreach (var permission in ConvertToPermissionList(permissions)) - { - result.Add(permission); - } + result.Add(permission); } } } From 60be71d1a0037ffb5556511342065f85afce2825 Mon Sep 17 00:00:00 2001 From: Ronald Barendse Date: Wed, 13 Oct 2021 23:34:50 +0200 Subject: [PATCH 05/52] Remove duplicated comment --- .../Repositories/Implement/RepositoryBaseOfTIdTEntity.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Umbraco.Core/Persistence/Repositories/Implement/RepositoryBaseOfTIdTEntity.cs b/src/Umbraco.Core/Persistence/Repositories/Implement/RepositoryBaseOfTIdTEntity.cs index 5892f2bf4993..a7704272a85f 100644 --- a/src/Umbraco.Core/Persistence/Repositories/Implement/RepositoryBaseOfTIdTEntity.cs +++ b/src/Umbraco.Core/Persistence/Repositories/Implement/RepositoryBaseOfTIdTEntity.cs @@ -188,7 +188,6 @@ public IEnumerable GetMany(params TId[] ids) // the additional overhead of fetching them in groups is minimal compared to the lookup time of each group if (ids.Length <= Constants.Sql.MaxParameterCount) { - // the additional overhead of fetching them in groups is minimal compared to the lookup time of each group return CachePolicy.GetAll(ids, PerformGetAll); } From b13f2603412dc62536d759ab67ae4ed7e4f7feb2 Mon Sep 17 00:00:00 2001 From: Patrick de Mooij Date: Mon, 11 Oct 2021 21:15:25 +0200 Subject: [PATCH 06/52] 11343: Remove blocklist block on cancel --- .../blocklist/umbBlockListPropertyEditor.component.js | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/blocklist/umbBlockListPropertyEditor.component.js b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/blocklist/umbBlockListPropertyEditor.component.js index 7334fbeadf5e..11ef37029c54 100644 --- a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/blocklist/umbBlockListPropertyEditor.component.js +++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/blocklist/umbBlockListPropertyEditor.component.js @@ -65,6 +65,9 @@ vm.layout = []; // The layout object specific to this Block Editor, will be a direct reference from Property Model. vm.availableBlockTypes = []; // Available block entries of this property editor. vm.labels = {}; + vm.options = { + createFlow: false + }; localizationService.localizeMany(["grid_addElement", "content_createEmpty"]).then(function (data) { vm.labels.grid_addElement = data[0]; @@ -380,7 +383,7 @@ function editBlock(blockObject, openSettings, blockIndex, parentForm, options) { - options = options || {}; + options = options || vm.options; // this must be set if (blockIndex === undefined) { @@ -560,7 +563,9 @@ if (inlineEditing === true) { blockObject.activate(); } else if (inlineEditing === false && blockObject.hideContentInOverlay !== true) { + vm.options.createFlow = true; blockObject.edit(); + vm.options.createFlow = false; } } } From 809671b9caa4355d086afb8abeaec041287640f4 Mon Sep 17 00:00:00 2001 From: patrickdemooij9 Date: Thu, 21 Oct 2021 02:09:08 +0200 Subject: [PATCH 07/52] Align template picking more towards the other pickers (#11363) * Align template picking more towards the other pickers * style/cleanup - remove unused args, updated openItemPicker function name to openTemplatePicker since that's what we're opening Co-authored-by: Nathan Woulfe --- .../components/umbgridselector.directive.js | 49 ++++++++++--------- .../src/common/services/editor.service.js | 25 +++++++++- .../treepicker/treepicker.controller.js | 3 ++ .../views/templates/templates.controller.js | 26 +++++++++- .../views/templates/templates.html | 3 +- .../src/views/templates/edit.controller.js | 26 +++++----- src/Umbraco.Web/Editors/EntityController.cs | 18 +++++++ 7 files changed, 110 insertions(+), 40 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/components/umbgridselector.directive.js b/src/Umbraco.Web.UI.Client/src/common/directives/components/umbgridselector.directive.js index bf03749faa7c..4c628391cb97 100644 --- a/src/Umbraco.Web.UI.Client/src/common/directives/components/umbgridselector.directive.js +++ b/src/Umbraco.Web.UI.Client/src/common/directives/components/umbgridselector.directive.js @@ -1,9 +1,9 @@ (function () { 'use strict'; - function GridSelector($location, overlayService, editorService) { + function GridSelector(overlayService, editorService) { - function link(scope, el, attr, ctrl) { + function link(scope) { var eventBindings = []; scope.dialogModel = {}; @@ -33,26 +33,30 @@ }; scope.openItemPicker = function ($event) { - var dialogModel = { - view: "itempicker", - title: "Choose " + scope.itemLabel, - availableItems: scope.availableItems, - selectedItems: scope.selectedItems, - position: "target", - event: $event, - submit: function (model) { - scope.selectedItems.push(model.selectedItem); - // if no default item - set item as default - if (scope.defaultItem === null) { - scope.setAsDefaultItem(model.selectedItem); + if (scope.itemPicker) { + scope.itemPicker(); + } else { + var dialogModel = { + view: "itempicker", + title: "Choose " + scope.itemLabel, + availableItems: scope.availableItems, + selectedItems: scope.selectedItems, + position: "target", + event: $event, + submit: function (model) { + scope.selectedItems.push(model.selectedItem); + // if no default item - set item as default + if (scope.defaultItem === null) { + scope.setAsDefaultItem(model.selectedItem); + } + overlayService.close(); + }, + close: function () { + overlayService.close(); } - overlayService.close(); - }, - close: function() { - overlayService.close(); - } - }; - overlayService.open(dialogModel); + }; + overlayService.open(dialogModel); + } }; scope.openTemplate = function (selectedItem) { @@ -156,7 +160,8 @@ availableItems: "=", defaultItem: "=", itemName: "@", - updatePlaceholder: "=" + updatePlaceholder: "=", + itemPicker: "=" }, link: link }; diff --git a/src/Umbraco.Web.UI.Client/src/common/services/editor.service.js b/src/Umbraco.Web.UI.Client/src/common/services/editor.service.js index b917d6fa4f33..a68f68fbb35f 100644 --- a/src/Umbraco.Web.UI.Client/src/common/services/editor.service.js +++ b/src/Umbraco.Web.UI.Client/src/common/services/editor.service.js @@ -179,7 +179,7 @@ When building a custom infinite editor view you can use the same components as a } else { focus(); } - }); + }); /** * @ngdoc method @@ -928,6 +928,28 @@ When building a custom infinite editor view you can use the same components as a open(editor); } + /** + * @ngdoc method + * @name umbraco.services.editorService#templatePicker + * @methodOf umbraco.services.editorService + * + * @description + * Opens a template picker in infinite editing, the submit callback returns an array of selected items. + * + * @param {object} editor rendering options. + * @param {boolean} editor.multiPicker Pick one or multiple items. + * @param {function} editor.submit Callback function when the submit button is clicked. Returns the editor model object. + * @param {function} editor.close Callback function when the close button is clicked. + * @returns {object} editor object. + */ + function templatePicker(editor) { + editor.view = "views/common/infiniteeditors/treepicker/treepicker.html"; + if (!editor.size) editor.size = "small"; + editor.section = "settings"; + editor.treeAlias = "templates"; + open(editor); + } + /** * @ngdoc method * @name umbraco.services.editorService#macroPicker @@ -1088,6 +1110,7 @@ When building a custom infinite editor view you can use the same components as a templateSections: templateSections, userPicker: userPicker, itemPicker: itemPicker, + templatePicker: templatePicker, macroPicker: macroPicker, memberGroupPicker: memberGroupPicker, memberPicker: memberPicker, diff --git a/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/treepicker/treepicker.controller.js b/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/treepicker/treepicker.controller.js index ed5c4096bcca..72eb504c600d 100644 --- a/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/treepicker/treepicker.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/treepicker/treepicker.controller.js @@ -141,6 +141,9 @@ angular.module("umbraco").controller("Umbraco.Editors.TreePickerController", }); } } + else if (vm.treeAlias === "templates") { + vm.entityType = "Template"; + } // TODO: Seems odd this logic is here, i don't think it needs to be and should just exist on the property editor using this if ($scope.model.minNumber) { diff --git a/src/Umbraco.Web.UI.Client/src/views/documenttypes/views/templates/templates.controller.js b/src/Umbraco.Web.UI.Client/src/views/documenttypes/views/templates/templates.controller.js index e2a964c29365..46e856410d94 100644 --- a/src/Umbraco.Web.UI.Client/src/views/documenttypes/views/templates/templates.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/documenttypes/views/templates/templates.controller.js @@ -9,7 +9,7 @@ (function () { 'use strict'; - function TemplatesController($scope, entityResource, contentTypeHelper, templateResource, contentTypeResource, $routeParams) { + function TemplatesController($scope, entityResource, contentTypeHelper, contentTypeResource, editorService, $routeParams) { /* ----------- SCOPE VARIABLES ----------- */ @@ -22,6 +22,7 @@ vm.isElement = $scope.model.isElement; vm.createTemplate = createTemplate; + vm.openTemplatePicker = openTemplatePicker; /* ---------- INIT ---------- */ @@ -81,6 +82,29 @@ vm.canCreateTemplate = existingTemplate ? false : true; } + function openTemplatePicker() { + const editor = { + title: "Choose template", + filterCssClass: 'not-allowed', + multiPicker: true, + filter: item => { + return !vm.availableTemplates.some(template => template.id == item.id) || + $scope.model.allowedTemplates.some(template => template.id == item.id); + }, + submit: model => { + model.selection.forEach(item => { + $scope.model.allowedTemplates.push(item); + }); + editorService.close(); + }, + close: function() { + editorService.close(); + } + } + + editorService.templatePicker(editor); + } + var unbindWatcher = $scope.$watch("model.isElement", function(newValue, oldValue) { vm.isElement = newValue; diff --git a/src/Umbraco.Web.UI.Client/src/views/documenttypes/views/templates/templates.html b/src/Umbraco.Web.UI.Client/src/views/documenttypes/views/templates/templates.html index 279ffb73c0e4..04fd61be3cd7 100644 --- a/src/Umbraco.Web.UI.Client/src/views/documenttypes/views/templates/templates.html +++ b/src/Umbraco.Web.UI.Client/src/views/documenttypes/views/templates/templates.html @@ -17,7 +17,8 @@
item-name="template" name="model.name" alias="model.alias" - update-placeholder="vm.updateTemplatePlaceholder"> + update-placeholder="vm.updateTemplatePlaceholder" + item-picker="vm.openTemplatePicker"> { + const editor = { + title, + filterCssClass: 'not-allowed', + filter: item => !availableMasterTemplates.some(template => template.id == item.id), + submit: model => { + var template = model.selection[0]; if (template && template.alias) { vm.template.masterTemplateAlias = template.alias; setLayout(template.alias + ".cshtml"); @@ -575,14 +575,10 @@ } editorService.close(); }, - close: function (oldModel) { - // close dialog - editorService.close(); - // focus editor - vm.editor.focus(); - } - }; - editorService.itemPicker(masterTemplate); + close: () => editorService.close(), + } + + editorService.templatePicker(editor); }); } diff --git a/src/Umbraco.Web/Editors/EntityController.cs b/src/Umbraco.Web/Editors/EntityController.cs index 0b6273e79da8..573246e1f063 100644 --- a/src/Umbraco.Web/Editors/EntityController.cs +++ b/src/Umbraco.Web/Editors/EntityController.cs @@ -997,6 +997,15 @@ private EntityBasic GetResultForKey(Guid key, UmbracoEntityTypes entityType) case UmbracoEntityTypes.Macro: + case UmbracoEntityTypes.Template: + var template = Services.FileService.GetTemplate(key); + if (template is null) + { + throw new HttpResponseException(HttpStatusCode.NotFound); + } + + return Mapper.Map(template); + default: throw new NotSupportedException("The " + typeof(EntityController) + " does not currently support data for the type " + entityType); } @@ -1029,6 +1038,15 @@ private EntityBasic GetResultForId(int id, UmbracoEntityTypes entityType) case UmbracoEntityTypes.Macro: + case UmbracoEntityTypes.Template: + var template = Services.FileService.GetTemplate(id); + if (template is null) + { + throw new HttpResponseException(HttpStatusCode.NotFound); + } + + return Mapper.Map(template); + default: throw new NotSupportedException("The " + typeof(EntityController) + " does not currently support data for the type " + entityType); } From aa6c5d48a2ec61bc19dc7d00d67e004c926dcc94 Mon Sep 17 00:00:00 2001 From: BatJan <1932158+BatJan@users.noreply.github.com> Date: Wed, 20 Oct 2021 22:30:31 +0200 Subject: [PATCH 08/52] Add fallback text --- .../views/propertyeditors/grid/overlays/rowdeleteconfirm.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/grid/overlays/rowdeleteconfirm.html b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/grid/overlays/rowdeleteconfirm.html index 2ba56a5b8832..ded2e5b9408f 100644 --- a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/grid/overlays/rowdeleteconfirm.html +++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/grid/overlays/rowdeleteconfirm.html @@ -11,6 +11,6 @@

- ? + Are you sure you want to delete? From 00d7422d2fe894810c50a242b3cf07e020a4f678 Mon Sep 17 00:00:00 2001 From: Paul Seal Date: Fri, 22 Oct 2021 02:47:35 +0100 Subject: [PATCH 09/52] V8/feature/app header localized titles (#11429) * Added a link to 404 documentation I think it will be useful to include a link to the documentation on how to create a custom 404 * added localized titles to the search and help buttons in the app header (top right of Umbraco) --- .../src/views/components/application/umb-app-header.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/views/components/application/umb-app-header.html b/src/Umbraco.Web.UI.Client/src/views/components/application/umb-app-header.html index 3ad4ebc18815..e0fb4aeb7793 100644 --- a/src/Umbraco.Web.UI.Client/src/views/components/application/umb-app-header.html +++ b/src/Umbraco.Web.UI.Client/src/views/components/application/umb-app-header.html @@ -10,7 +10,7 @@
  • -
  • -
@@ -313,7 +313,7 @@

Create user

- + Create new users to give them access to Umbraco. When a new user is created a password will be generated that you can share with the user.

@@ -437,7 +437,7 @@

-

+

The new user has successfully been created. To log in to Umbraco use the password below.

@@ -520,7 +520,7 @@

-

+

An invitation has been sent to the new user with details about how to log in to Umbraco.

From 123bceef085caa48817f7d3c18042f4d418a9471 Mon Sep 17 00:00:00 2001 From: Erik-Jan Westendorp Date: Tue, 12 Oct 2021 03:50:17 +0200 Subject: [PATCH 13/52] Localization add tab text dutch (#11346) * Update nl.xml add addTab key * tab to tablad * Add translation to shortcuts sections (cherry picked from commit d22297270beacc9364b6eec39dd04f102215f010) --- src/Umbraco.Web.UI/Umbraco/config/lang/nl.xml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/Umbraco.Web.UI/Umbraco/config/lang/nl.xml b/src/Umbraco.Web.UI/Umbraco/config/lang/nl.xml index c8f39cf02081..1f27ef5fc7b8 100644 --- a/src/Umbraco.Web.UI/Umbraco/config/lang/nl.xml +++ b/src/Umbraco.Web.UI/Umbraco/config/lang/nl.xml @@ -791,6 +791,7 @@ Blauw + Tabblad toevoegen Groep toevoegen Eigenschap toevoegen Editor toevoegen @@ -1530,6 +1531,7 @@ Echter, Runway biedt een gemakkelijke basis om je snel op weg te helpen. Als je Een documenttype kan niet worden gewijzigd in een elementtype nadat het is gebruikt om een of meer contentitems te maken. Dit is niet van toepassing op een elementtype Je hebt wijzigingen aangebracht aan deze eigenschap. Ben je zeker dat je ze wil weggooien? + Tabblad toevoegen Taal toevoegen From f9ed371cb779a13f49d15d6bf5170054f5c50bed Mon Sep 17 00:00:00 2001 From: BatJan <1932158+BatJan@users.noreply.github.com> Date: Sat, 23 Oct 2021 15:16:20 +0200 Subject: [PATCH 14/52] Add missing fallback texts --- .../views/propertyeditors/contentpicker/contentpicker.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/contentpicker/contentpicker.html b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/contentpicker/contentpicker.html index e93637c67142..fa148ecfc725 100644 --- a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/contentpicker/contentpicker.html +++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/contentpicker/contentpicker.html @@ -1,7 +1,7 @@
-

-

+

You have picked a content item currently deleted or in the recycle bin

+

You have picked content items currently deleted or in the recycle bin

From 52f56628e97e9da2db38e236c0b3ab1061ebb406 Mon Sep 17 00:00:00 2001 From: BatJan <1932158+BatJan@users.noreply.github.com> Date: Sat, 23 Oct 2021 15:44:36 +0200 Subject: [PATCH 15/52] Add missing fallback texts --- src/Umbraco.Web.UI.Client/src/views/datatypes/delete.html | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/views/datatypes/delete.html b/src/Umbraco.Web.UI.Client/src/views/datatypes/delete.html index 825633be6109..773724f25d28 100644 --- a/src/Umbraco.Web.UI.Client/src/views/datatypes/delete.html +++ b/src/Umbraco.Web.UI.Client/src/views/datatypes/delete.html @@ -38,7 +38,7 @@
- + Document Types
@@ -72,7 +72,7 @@
- + Media Types
@@ -106,7 +106,7 @@
- + Member Types
From bed34b99165b9d3827e26b5f5f31363bb8fa8413 Mon Sep 17 00:00:00 2001 From: BatJan <1932158+BatJan@users.noreply.github.com> Date: Sat, 23 Oct 2021 15:49:21 +0200 Subject: [PATCH 16/52] Map missing values --- .../src/views/datatypes/views/datatype.info.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/views/datatypes/views/datatype.info.html b/src/Umbraco.Web.UI.Client/src/views/datatypes/views/datatype.info.html index 7bf985ca5618..2b59a8c4e75f 100644 --- a/src/Umbraco.Web.UI.Client/src/views/datatypes/views/datatype.info.html +++ b/src/Umbraco.Web.UI.Client/src/views/datatypes/views/datatype.info.html @@ -24,7 +24,7 @@
- + Used in Document Types
@@ -85,7 +85,7 @@
- + Used in Member Types
From 8b4398c0063ae8bec40b302cb86aa10911d500d3 Mon Sep 17 00:00:00 2001 From: BatJan <1932158+BatJan@users.noreply.github.com> Date: Sat, 23 Oct 2021 15:49:30 +0200 Subject: [PATCH 17/52] Remove space --- src/Umbraco.Web.UI/Umbraco/config/lang/en_us.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Umbraco.Web.UI/Umbraco/config/lang/en_us.xml b/src/Umbraco.Web.UI/Umbraco/config/lang/en_us.xml index fa8cfad670e9..8efa19335d95 100644 --- a/src/Umbraco.Web.UI/Umbraco/config/lang/en_us.xml +++ b/src/Umbraco.Web.UI/Umbraco/config/lang/en_us.xml @@ -2355,7 +2355,7 @@ To manage your website, simply open the Umbraco backoffice and start adding cont No references to Document Types. Used in Media Types No references to Media Types. - Used in Member Types + Used in Member Types No references to Member Types. Used by Used in Documents From 1ce05d44e590e70b59a8523e027c3b8b7f36201f Mon Sep 17 00:00:00 2001 From: BatJan <1932158+BatJan@users.noreply.github.com> Date: Sat, 23 Oct 2021 15:53:20 +0200 Subject: [PATCH 18/52] Map missing text values --- .../src/views/content/overlays/sendtopublish.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) 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 8217da5752f0..d366c9aa9a11 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 @@ -1,7 +1,7 @@
-

+

What languages would you like to send for approval?

@@ -32,7 +32,7 @@ - - + Mandatory {{publishVariantSelectorForm.publishVariantSelector.errorMsg}} From ad172070727a0f7e6c1874c51f8073e3f9b2af75 Mon Sep 17 00:00:00 2001 From: BatJan <1932158+BatJan@users.noreply.github.com> Date: Sat, 23 Oct 2021 15:23:16 +0200 Subject: [PATCH 19/52] Fix localizations --- .../src/views/prevalueeditors/mediafolderpicker.html | 12 +++++++++--- src/Umbraco.Web.UI/Umbraco/config/lang/en.xml | 1 + src/Umbraco.Web.UI/Umbraco/config/lang/en_us.xml | 1 + 3 files changed, 11 insertions(+), 3 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/views/prevalueeditors/mediafolderpicker.html b/src/Umbraco.Web.UI.Client/src/views/prevalueeditors/mediafolderpicker.html index e3449f07b9fa..f72846ea9888 100644 --- a/src/Umbraco.Web.UI.Client/src/views/prevalueeditors/mediafolderpicker.html +++ b/src/Umbraco.Web.UI.Client/src/views/prevalueeditors/mediafolderpicker.html @@ -5,7 +5,7 @@
  • - + Trashed

    @@ -18,15 +18,21 @@
    -
  • -
  • diff --git a/src/Umbraco.Web.UI/Umbraco/config/lang/en.xml b/src/Umbraco.Web.UI/Umbraco/config/lang/en.xml index 35e55f0c80dd..908ff9e82486 100644 --- a/src/Umbraco.Web.UI/Umbraco/config/lang/en.xml +++ b/src/Umbraco.Web.UI/Umbraco/config/lang/en.xml @@ -1349,6 +1349,7 @@ To manage your website, simply open the Umbraco backoffice and start adding cont Remove all medias? Clipboard Not allowed + Open media picker enter external link diff --git a/src/Umbraco.Web.UI/Umbraco/config/lang/en_us.xml b/src/Umbraco.Web.UI/Umbraco/config/lang/en_us.xml index 8efa19335d95..1cf449ca5686 100644 --- a/src/Umbraco.Web.UI/Umbraco/config/lang/en_us.xml +++ b/src/Umbraco.Web.UI/Umbraco/config/lang/en_us.xml @@ -1361,6 +1361,7 @@ To manage your website, simply open the Umbraco backoffice and start adding cont Remove all medias? Clipboard Not allowed + Open media picker enter external link From 034e43d3b8691bb5f7d3a6879eeb4fa7613367c9 Mon Sep 17 00:00:00 2001 From: BatJan <1932158+BatJan@users.noreply.github.com> Date: Sat, 23 Oct 2021 15:58:22 +0200 Subject: [PATCH 20/52] Add missing text fallback values --- .../src/views/content/overlays/schedule.html | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/views/content/overlays/schedule.html b/src/Umbraco.Web.UI.Client/src/views/content/overlays/schedule.html index c168c7cf90c9..f383fb200a44 100644 --- a/src/Umbraco.Web.UI.Client/src/views/content/overlays/schedule.html +++ b/src/Umbraco.Web.UI.Client/src/views/content/overlays/schedule.html @@ -4,13 +4,13 @@
    -

    +

    Select the date and time to publish and/or unpublish the content item.

    @@ -44,7 +44,7 @@
    @@ -80,7 +80,7 @@
    -

    +

    What languages would you like to schedule?

    @@ -107,7 +107,7 @@ - - + - Mandatory From 1bffd97be9919be84dc3c663bcba977fd23a8fe8 Mon Sep 17 00:00:00 2001 From: Bjarne Fyrstenborg Date: Sun, 24 Oct 2021 15:30:35 +0200 Subject: [PATCH 21/52] Update noUiSlider to v15.5.0 --- src/Umbraco.Web.UI.Client/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Umbraco.Web.UI.Client/package.json b/src/Umbraco.Web.UI.Client/package.json index 35f2d6589087..69dae230efc2 100644 --- a/src/Umbraco.Web.UI.Client/package.json +++ b/src/Umbraco.Web.UI.Client/package.json @@ -41,7 +41,7 @@ "lazyload-js": "1.0.0", "moment": "2.22.2", "ng-file-upload": "12.2.13", - "nouislider": "15.4.0", + "nouislider": "15.5.0", "npm": "^6.14.7", "signalr": "2.4.0", "spectrum-colorpicker2": "2.0.8", From 85c9d55b7a0e500c9ef38203b9d228185268eb35 Mon Sep 17 00:00:00 2001 From: BatJan <1932158+BatJan@users.noreply.github.com> Date: Sat, 23 Oct 2021 16:02:17 +0200 Subject: [PATCH 22/52] Add missing translations --- .../src/views/content/overlays/save.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) 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 36e01991dfa6..df6332e5bee1 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 @@ -7,7 +7,7 @@

    - + Choose which variants to be saved.

    @@ -39,7 +39,7 @@ - - + Mandatory {{saveVariantSelectorForm.saveVariantSelector.errorMsg}} From 20941016ff537a13a8c99b91a68c3d0e3a9bc29b Mon Sep 17 00:00:00 2001 From: BatJan <1932158+BatJan@users.noreply.github.com> Date: Sat, 23 Oct 2021 16:25:35 +0200 Subject: [PATCH 23/52] Map missing translations --- .../listview/overlays/listviewunpublish.html | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/listview/overlays/listviewunpublish.html b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/listview/overlays/listviewunpublish.html index 5806bb8f0265..9a6af50f3e6c 100644 --- a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/listview/overlays/listviewunpublish.html +++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/listview/overlays/listviewunpublish.html @@ -2,7 +2,7 @@
    -

    +

    Unpublishing will remove the selected items and all their descendants from the site.

    @@ -13,13 +13,13 @@
    -

    +

    Select the languages to unpublish. Unpublishing a mandatory language will unpublish all languages.

    - + Languages
    @@ -35,7 +35,7 @@
    - + Mandatory language
    From 57634d5b4e8b267818c48768f57bc8d0d0f5ed2c Mon Sep 17 00:00:00 2001 From: BatJan <1932158+BatJan@users.noreply.github.com> Date: Sat, 23 Oct 2021 16:29:57 +0200 Subject: [PATCH 24/52] Add missing fallback values --- .../listview/overlays/listviewpublish.html | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/listview/overlays/listviewpublish.html b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/listview/overlays/listviewpublish.html index c6f7c85c0b3c..b6933dffc06e 100644 --- a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/listview/overlays/listviewpublish.html +++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/listview/overlays/listviewpublish.html @@ -2,7 +2,7 @@
    -

    +

    Publishing will make the selected items visible on the site.

    @@ -13,13 +13,13 @@
    -

    +

    What languages would you like to publish?

    - + Languages
    @@ -34,7 +34,7 @@
    - + Mandatory language
    From 965ce917bf82790566f74291b155377ad5cbfdd7 Mon Sep 17 00:00:00 2001 From: BatJan <1932158+BatJan@users.noreply.github.com> Date: Sat, 23 Oct 2021 16:36:10 +0200 Subject: [PATCH 25/52] Map missing fallback texts --- .../umb-content-type-property.html | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/views/components/contenttype/umb-content-type-property.html b/src/Umbraco.Web.UI.Client/src/views/components/contenttype/umb-content-type-property.html index 8751a4723fe5..14f647e761f4 100644 --- a/src/Umbraco.Web.UI.Client/src/views/components/contenttype/umb-content-type-property.html +++ b/src/Umbraco.Web.UI.Client/src/views/components/contenttype/umb-content-type-property.html @@ -28,7 +28,7 @@
    {{propertyTypeForm.groupName.errorMsg}}
    -
    +
    Required label
    @@ -61,37 +61,37 @@ {{vm.property.dataTypeName}} - + Preview
    * - + Mandatory
    - + Show on member profile
    - + Member can edit
    - + Is sensitive data
    - + Vary by culture
    - + Vary by segments
    @@ -100,13 +100,13 @@
    - + Inherited from {{vm.property.contentTypeName}}
    - + Locked
    From f1998ca5ab3878dbfd9c9848c5e21cff8e62c493 Mon Sep 17 00:00:00 2001 From: BatJan <1932158+BatJan@users.noreply.github.com> Date: Tue, 26 Oct 2021 15:40:14 +0200 Subject: [PATCH 26/52] Add missing fallback texts --- .../src/views/content/create.html | 20 ++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/views/content/create.html b/src/Umbraco.Web.UI.Client/src/views/content/create.html index 98767b8b9579..e2e3fb9453b7 100644 --- a/src/Umbraco.Web.UI.Client/src/views/content/create.html +++ b/src/Umbraco.Web.UI.Client/src/views/content/create.html @@ -9,27 +9,33 @@
    Select a blueprint
    -

    +

    + The selected page in the content tree doesn't allow for any pages to be created below it. +

    - + There are no allowed Document Types available for creating content here. You must enable these in Document + Types within the Settings section, by editing the Allowed child node + types under Permissions.

    - + There are no allowed Document Types available for creating content here. You must enable these in Document + Types within the Settings section, by changing the Allow as root option under Permissions.

    - + There are no Document Types available for creating content here. You must create these in Document + Types within the Settings section.

    @@ -58,7 +64,7 @@
    Select - +
    • From 072374913d43a20d98fea0bd9bb8fca434a701fd Mon Sep 17 00:00:00 2001 From: BatJan <1932158+BatJan@users.noreply.github.com> Date: Tue, 26 Oct 2021 15:44:51 +0200 Subject: [PATCH 27/52] Add missing fallback texts --- .../contenttype/umb-content-type-tab.html | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/views/components/contenttype/umb-content-type-tab.html b/src/Umbraco.Web.UI.Client/src/views/components/contenttype/umb-content-type-tab.html index 59476f7e26c6..b62e3f17d914 100644 --- a/src/Umbraco.Web.UI.Client/src/views/components/contenttype/umb-content-type-tab.html +++ b/src/Umbraco.Web.UI.Client/src/views/components/contenttype/umb-content-type-tab.html @@ -1,6 +1,6 @@ -
      - : {{ vm.tab.inheritedFromName }} + Inherited from: {{ vm.tab.inheritedFromName }} , @@ -50,7 +50,7 @@
      {{tabNameForm.tabName.errorMsg}}
      -
      +
      Required
      @@ -61,9 +61,9 @@ -
      +
      Required
      -
      +
      Required
      From 87a8ea755e8b63cb311801cd80798ca871e9156d Mon Sep 17 00:00:00 2001 From: BatJan <1932158+BatJan@users.noreply.github.com> Date: Tue, 26 Oct 2021 15:48:38 +0200 Subject: [PATCH 28/52] Add missing fallback texts --- .../components/contenttype/umb-content-type-group.html | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/views/components/contenttype/umb-content-type-group.html b/src/Umbraco.Web.UI.Client/src/views/components/contenttype/umb-content-type-group.html index 35b3eb73534f..a8e32821a19f 100644 --- a/src/Umbraco.Web.UI.Client/src/views/components/contenttype/umb-content-type-group.html +++ b/src/Umbraco.Web.UI.Client/src/views/components/contenttype/umb-content-type-group.html @@ -26,7 +26,7 @@
      {{groupNameForm.groupName.errorMsg}}
      -
      +
      Required
      @@ -34,7 +34,7 @@
      - : {{ vm.group.inheritedFromName }} + Inherited from: {{ vm.group.inheritedFromName }} , @@ -46,9 +46,9 @@ -
      +
      Required
      -
      +
      Required
      From 0d73d903d1a14d6ae8df4ba2b32e8765013c1924 Mon Sep 17 00:00:00 2001 From: BatJan <1932158+BatJan@users.noreply.github.com> Date: Tue, 26 Oct 2021 15:54:51 +0200 Subject: [PATCH 29/52] Add missing fallback texts --- .../src/views/content/assigndomain.html | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/views/content/assigndomain.html b/src/Umbraco.Web.UI.Client/src/views/content/assigndomain.html index 3bf10d610e99..1625552955a9 100644 --- a/src/Umbraco.Web.UI.Client/src/views/content/assigndomain.html +++ b/src/Umbraco.Web.UI.Client/src/views/content/assigndomain.html @@ -8,7 +8,7 @@
      Culture
      - + @@ -25,18 +25,19 @@
      CultureDomains
      - + Valid domain names are: "example.com", "www.example.com", "example.com:8080", or "https://www.example.com/". + Furthermore also one-level paths in domains are supported, eg. "example.com/en" or "/en".
    @@ -49,9 +50,9 @@
    Domains - + Value cannot be empty - ({{domain.other}}) + Domain has already been assigned.({{domain.other}})
    - + Domain * - + Language * @@ -138,7 +140,7 @@
    -
    +
    Appearance
    -
    +
    Allow vary by culture
    @@ -162,7 +164,7 @@
    -
    +
    Allow segmentation
    -
    +
    Options
    Date: Tue, 26 Oct 2021 16:20:51 +0200 Subject: [PATCH 32/52] Add missing fallback texts --- .../templatesections/templatesections.html | 48 ++++++++++--------- 1 file changed, 26 insertions(+), 22 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/templatesections/templatesections.html b/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/templatesections/templatesections.html index 1fdfdfb14579..5e656bc26098 100644 --- a/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/templatesections/templatesections.html +++ b/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/templatesections/templatesections.html @@ -20,33 +20,35 @@
    - -
    - + +
    Render child template
    +
    - + Renders the contents of a child template, by inserting a @RenderBody() placeholder.
    - +
    - +
    -
    +
    Render a named section
    - + Renders a named area of a child template, by inserting a @RenderSection(name) placeholder. + This renders an area of a child template which is wrapped in a corresponding @section [name]{ ... } definition. +
    - +
    - + - + Required
    - +
    - + If mandatory, the child template must contain a @section definition, otherwise an error is shown.
    - +
    - +
    - +
    -
    +
    Define a named section
    - + Defines a part of your template as a named section by wrapping it in @section { ... }. + This can be rendered in a specific area of the parent of this template, by using @RenderSection. +
    - +
    - + - + Required
    - +
    From 97775196ae001f1404e64736d6c4306cbbe92251 Mon Sep 17 00:00:00 2001 From: BatJan <1932158+BatJan@users.noreply.github.com> Date: Tue, 26 Oct 2021 16:29:59 +0200 Subject: [PATCH 33/52] Add missing fallback texts --- .../infiniteeditors/compositions/overlays/confirmremove.html | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/compositions/overlays/confirmremove.html b/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/compositions/overlays/confirmremove.html index 6fc3bd826d48..33f48b8c1ea8 100644 --- a/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/compositions/overlays/confirmremove.html +++ b/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/compositions/overlays/confirmremove.html @@ -1,9 +1,10 @@
    - + Removing a composition will delete all the associated property data. Once you save the Document Type there's no way + back.
    - + Are you sure?
    From 090fe7e9ae5eef5bdc5f7c8df022257f6e6f692e Mon Sep 17 00:00:00 2001 From: BatJan <1932158+BatJan@users.noreply.github.com> Date: Tue, 26 Oct 2021 16:25:58 +0200 Subject: [PATCH 34/52] Add missing fallback texts --- .../mediapicker/overlays/mediacropdetails.html | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/mediapicker/overlays/mediacropdetails.html b/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/mediapicker/overlays/mediacropdetails.html index 99f4fc04e7a2..9a01d3329da1 100644 --- a/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/mediapicker/overlays/mediacropdetails.html +++ b/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/mediapicker/overlays/mediacropdetails.html @@ -12,21 +12,21 @@
    - + URL
    - + Alternative text (optional)
    - + Caption (optional)
    From 713f204ea5062e542f050bd66f3bfddeb33c94e4 Mon Sep 17 00:00:00 2001 From: BatJan <1932158+BatJan@users.noreply.github.com> Date: Tue, 26 Oct 2021 16:43:00 +0200 Subject: [PATCH 35/52] Add missing fallback texts --- .../src/views/content/overlays/unpublish.html | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/views/content/overlays/unpublish.html b/src/Umbraco.Web.UI.Client/src/views/content/overlays/unpublish.html index dc3862879a51..a994fe38ed72 100644 --- a/src/Umbraco.Web.UI.Client/src/views/content/overlays/unpublish.html +++ b/src/Umbraco.Web.UI.Client/src/views/content/overlays/unpublish.html @@ -2,13 +2,13 @@
    -

    +

    Unpublishing will remove this page and all its descendants from the site.

    -

    +

    Select the languages to unpublish. Unpublishing a mandatory language will unpublish all languages.

    @@ -36,7 +36,7 @@ - - + Mandatory {{publishVariantSelectorForm.publishVariantSelector.errorMsg}} From d1005c5976f86250f70e73fad709a79943029518 Mon Sep 17 00:00:00 2001 From: BatJan <1932158+BatJan@users.noreply.github.com> Date: Tue, 26 Oct 2021 16:34:38 +0200 Subject: [PATCH 36/52] Add missing fallback texts --- .../infiniteeditors/compositions/compositions.html | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/compositions/compositions.html b/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/compositions/compositions.html index 7ec69018b64c..9ebb9d4e45d8 100644 --- a/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/compositions/compositions.html +++ b/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/compositions/compositions.html @@ -30,21 +30,22 @@
    - + Inherit tabs and properties from an existing Document Type. New tabs will be added to the current Document Type or + merged if a tab with an identical name exists.
    - + There are no Content Types available to use as a composition. - + This Content Type is used in a composition, and therefore cannot be composed itself.
    -
    -

    +
    Where is this composition used?
    +

    This composition is currently used in the composition of the following Content Types: