diff --git a/src/OrchardCore.Modules/OrchardCore.ContentFields/GraphQL/Fields/ContentFieldsProvider.cs b/src/OrchardCore.Modules/OrchardCore.ContentFields/GraphQL/Fields/ContentFieldsProvider.cs index 33a8e130729..53a00dfb719 100644 --- a/src/OrchardCore.Modules/OrchardCore.ContentFields/GraphQL/Fields/ContentFieldsProvider.cs +++ b/src/OrchardCore.Modules/OrchardCore.ContentFields/GraphQL/Fields/ContentFieldsProvider.cs @@ -86,7 +86,7 @@ public class ContentFieldsProvider : IContentFieldProvider } }; - public FieldType GetField(ContentPartFieldDefinition field) + public FieldType GetField(ContentPartFieldDefinition field, string namedPartTechnicalName, string customFieldName) { if (!_contentFieldTypeMappings.TryGetValue(field.FieldDefinition.Name, out var value)) { @@ -96,7 +96,7 @@ public FieldType GetField(ContentPartFieldDefinition field) var fieldDescriptor = value; return new FieldType { - Name = field.Name, + Name = customFieldName ?? field.Name, Description = fieldDescriptor.Description, Type = fieldDescriptor.FieldType, Resolver = new FuncFieldResolver(context => @@ -116,6 +116,8 @@ public FieldType GetField(ContentPartFieldDefinition field) }; } + public bool HasField(ContentPartFieldDefinition field) => _contentFieldTypeMappings.ContainsKey(field.FieldDefinition.Name); + private sealed class FieldTypeDescriptor { public string Description { get; set; } diff --git a/src/OrchardCore.Modules/OrchardCore.ContentFields/GraphQL/Fields/ObjectGraphTypeFieldProvider.cs b/src/OrchardCore.Modules/OrchardCore.ContentFields/GraphQL/Fields/ObjectGraphTypeFieldProvider.cs index 678d36551fc..c88e173dce8 100644 --- a/src/OrchardCore.Modules/OrchardCore.ContentFields/GraphQL/Fields/ObjectGraphTypeFieldProvider.cs +++ b/src/OrchardCore.Modules/OrchardCore.ContentFields/GraphQL/Fields/ObjectGraphTypeFieldProvider.cs @@ -21,19 +21,15 @@ public ObjectGraphTypeFieldProvider(IHttpContextAccessor httpContextAccessor) _httpContextAccessor = httpContextAccessor; } - public FieldType GetField(ContentPartFieldDefinition field) + public FieldType GetField(ContentPartFieldDefinition field, string namedPartTechnicalName, string customFieldName) { - var serviceProvider = _httpContextAccessor.HttpContext.RequestServices; - var queryGraphType = _partObjectGraphTypes.GetOrAdd(field.FieldDefinition.Name, - partName => serviceProvider.GetService>()? - .FirstOrDefault(x => x.GetType().BaseType.GetGenericArguments().First().Name == partName) - ); + var queryGraphType = GetObjectGraphType(field); if (queryGraphType != null) { return new FieldType { - Name = field.Name, + Name = customFieldName ?? field.Name, Description = field.FieldDefinition.Name, Type = queryGraphType.GetType(), Resolver = new FuncFieldResolver(context => @@ -54,5 +50,17 @@ public FieldType GetField(ContentPartFieldDefinition field) return null; } + + private IObjectGraphType GetObjectGraphType(ContentPartFieldDefinition field) + { + var serviceProvider = _httpContextAccessor.HttpContext.RequestServices; + + return _partObjectGraphTypes.GetOrAdd(field.FieldDefinition.Name, + partName => serviceProvider.GetService>()? + .FirstOrDefault(x => x.GetType().BaseType.GetGenericArguments().First().Name == partName) + ); + } + + public bool HasField(ContentPartFieldDefinition field) => GetObjectGraphType(field) != null; } } diff --git a/src/OrchardCore.Modules/OrchardCore.ContentTypes/GraphQL/Drivers/GraphQLContentTypePartSettingsDriver.cs b/src/OrchardCore.Modules/OrchardCore.ContentTypes/GraphQL/Drivers/GraphQLContentTypePartSettingsDriver.cs index 1ce66d2c6ce..a818fc77bbf 100644 --- a/src/OrchardCore.Modules/OrchardCore.ContentTypes/GraphQL/Drivers/GraphQLContentTypePartSettingsDriver.cs +++ b/src/OrchardCore.Modules/OrchardCore.ContentTypes/GraphQL/Drivers/GraphQLContentTypePartSettingsDriver.cs @@ -5,6 +5,7 @@ using OrchardCore.ContentManagement.Metadata.Models; using OrchardCore.ContentTypes.Editors; using OrchardCore.ContentTypes.GraphQL.ViewModels; +using OrchardCore.DisplayManagement.ModelBinding; using OrchardCore.DisplayManagement.Views; namespace OrchardCore.ContentTypes.GraphQL.Drivers @@ -18,18 +19,23 @@ public GraphQLContentTypePartSettingsDriver(IOptions opti _contentOptions = optionsAccessor.Value; } - public override IDisplayResult Edit(ContentTypePartDefinition contentTypePartDefinition) + public override IDisplayResult Edit(ContentTypePartDefinition contentTypePartDefinition, IUpdateModel updater) { if (contentTypePartDefinition.ContentTypeDefinition.Name == contentTypePartDefinition.PartDefinition.Name) { return null; } - return Initialize("GraphQLContentTypePartSettings_Edit", model => + return Initialize("GraphQLContentTypePartSettings_Edit", async model => { model.Definition = contentTypePartDefinition; model.Options = _contentOptions; model.Settings = contentTypePartDefinition.GetSettings(); + + if (!updater.ModelState.IsValid) + { + await updater.TryUpdateModelAsync(model, Prefix, x => x.Settings); + } }).Location("Content"); } @@ -42,11 +48,11 @@ public override async Task UpdateAsync(ContentTypePartDefinition var model = new GraphQLContentTypePartSettingsViewModel(); - await context.Updater.TryUpdateModelAsync(model, Prefix); + await context.Updater.TryUpdateModelAsync(model, Prefix, m => m.Settings); context.Builder.WithSettings(model.Settings); - return Edit(contentTypePartDefinition); + return Edit(contentTypePartDefinition, context.Updater); } } } diff --git a/src/OrchardCore.Modules/OrchardCore.ContentTypes/Views/GraphQLContentTypePartSettings.Edit.cshtml b/src/OrchardCore.Modules/OrchardCore.ContentTypes/Views/GraphQLContentTypePartSettings.Edit.cshtml index f5a8108f61e..f5f0082856d 100644 --- a/src/OrchardCore.Modules/OrchardCore.ContentTypes/Views/GraphQLContentTypePartSettings.Edit.cshtml +++ b/src/OrchardCore.Modules/OrchardCore.ContentTypes/Views/GraphQLContentTypePartSettings.Edit.cshtml @@ -11,29 +11,52 @@ var hidden = hiddenByDefault ? true : settings.Hidden; } -
-
- - - @if (collapsedByDefault) - { - @T["NB. Setting is collapsed by default, and cannot be overwritten."] - } - else - { - @T["Check to collapse fields in the GraphQL schema."] - } -
-
- - - @if (hiddenByDefault) - { - @T["Setting is hidden by default, and cannot be overwritten."] - } - else - { - @T["Check to hide part from the GraphQL schema."] - } -
+ +
+ + + @if (collapsedByDefault) + { + @T["NB. Setting is collapsed by default, and cannot be overwritten."] + } + else + { + @T["Check to collapse fields in the GraphQL schema."] + } +
+ +
+ + + @T["Check to prevent fields' names collisions in the GraphQL schema when they are collapsed."] +
+ +
+ + + @if (hiddenByDefault) + { + @T["Setting is hidden by default, and cannot be overwritten."] + } + else + { + @T["Check to hide part from the GraphQL schema."] + }
+ + diff --git a/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Options/GraphQLContentOptions.cs b/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Options/GraphQLContentOptions.cs index f890610d32e..ac2da4221c3 100644 --- a/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Options/GraphQLContentOptions.cs +++ b/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Options/GraphQLContentOptions.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Linq; +using GraphQL; using GraphQL.Types; using OrchardCore.ContentManagement.GraphQL.Settings; using OrchardCore.ContentManagement.Metadata.Models; @@ -221,5 +222,17 @@ public bool IsHiddenByDefault(ContentTypePartDefinition definition) return false; } + + internal static string GetFieldName(ContentTypePartDefinition definition, string partName, string fieldName) + { + var settings = definition.GetSettings(); + + if (settings.PreventFieldNameCollision) + { + return partName.ToFieldName() + fieldName.ToPascalCase(); + } + + return fieldName; + } } } diff --git a/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/Types/DynamicContentTypeBuilder.cs b/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/Types/DynamicContentTypeBuilder.cs index 279cfab714c..b699530f66c 100644 --- a/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/Types/DynamicContentTypeBuilder.cs +++ b/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/Types/DynamicContentTypeBuilder.cs @@ -53,7 +53,7 @@ public void Build(FieldType contentQuery, ContentTypeDefinition contentTypeDefin continue; } - if (!(part.PartDefinition.Fields.Any(field => contentFieldProviders.Any(fieldProvider => fieldProvider.GetField(field) != null)))) + if (!(part.PartDefinition.Fields.Any(field => contentFieldProviders.Any(fieldProvider => fieldProvider.HasField(field))))) { continue; } @@ -64,7 +64,9 @@ public void Build(FieldType contentQuery, ContentTypeDefinition contentTypeDefin { foreach (var fieldProvider in contentFieldProviders) { - var fieldType = fieldProvider.GetField(field); + var customFieldName = GraphQLContentOptions.GetFieldName(part, part.Name, field.Name); + + var fieldType = fieldProvider.GetField(field, part.Name, customFieldName); if (fieldType != null) { @@ -90,7 +92,7 @@ public void Build(FieldType contentQuery, ContentTypeDefinition contentTypeDefin { foreach (var fieldProvider in contentFieldProviders) { - var contentFieldType = fieldProvider.GetField(field); + var contentFieldType = fieldProvider.GetField(field, part.Name); if (contentFieldType != null && !contentItemType.HasField(contentFieldType.Name)) { diff --git a/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/Types/DynamicPartGraphType.cs b/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/Types/DynamicPartGraphType.cs index fe23f63dfad..6d99b1cb789 100644 --- a/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/Types/DynamicPartGraphType.cs +++ b/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/Types/DynamicPartGraphType.cs @@ -19,7 +19,7 @@ public DynamicPartGraphType(IHttpContextAccessor httpContextAccessor, ContentTyp { foreach (var fieldProvider in contentFieldProviders) { - var fieldType = fieldProvider.GetField(field); + var fieldType = fieldProvider.GetField(field, part.Name); if (fieldType != null) { AddField(fieldType); diff --git a/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/Types/IContentFieldProvider.cs b/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/Types/IContentFieldProvider.cs index 38e25d5812d..addbb2a00b7 100644 --- a/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/Types/IContentFieldProvider.cs +++ b/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/Types/IContentFieldProvider.cs @@ -5,6 +5,8 @@ namespace OrchardCore.ContentManagement.GraphQL.Queries.Types { public interface IContentFieldProvider { - FieldType GetField(ContentPartFieldDefinition field); + FieldType GetField(ContentPartFieldDefinition field, string namedPartTechnicalName, string customFieldName = null); + + bool HasField(ContentPartFieldDefinition field); } } diff --git a/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Settings/GraphQLContentTypePartSettings.cs b/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Settings/GraphQLContentTypePartSettings.cs index c7227d9e9f9..f27034452ee 100644 --- a/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Settings/GraphQLContentTypePartSettings.cs +++ b/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Settings/GraphQLContentTypePartSettings.cs @@ -5,5 +5,7 @@ public class GraphQLContentTypePartSettings public bool Collapse { get; set; } public bool Hidden { get; set; } + + public bool PreventFieldNameCollision { get; set; } } }