diff --git a/.github/workflows/check-updates.yml b/.github/workflows/check-updates.yml
index e5bd1c6aba..6aba3f9d14 100644
--- a/.github/workflows/check-updates.yml
+++ b/.github/workflows/check-updates.yml
@@ -12,7 +12,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- - uses: actions/checkout@v4.0.0
+ - uses: actions/checkout@v4.1.0
with:
token: ${{ secrets.WORKFLOW_SECRET }}
diff --git a/.github/workflows/dev.yml b/.github/workflows/dev.yml
index adc1859f26..121e2b4b00 100644
--- a/.github/workflows/dev.yml
+++ b/.github/workflows/dev.yml
@@ -16,7 +16,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Prepare - Checkout
- uses: actions/checkout@v4.0.0
+ uses: actions/checkout@v4.1.0
- name: Prepare - Inject short Variables
uses: rlespinasse/github-slug-action@v4.4.1
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index bd84b42e8b..3ad43915bb 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -11,7 +11,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Prepare - Checkout
- uses: actions/checkout@v4.0.0
+ uses: actions/checkout@v4.1.0
- name: Prepare - Inject short Variables
uses: rlespinasse/github-slug-action@v4.4.1
diff --git a/backend/src/Squidex.Domain.Apps.Core.Model/FieldDescriptions.Designer.cs b/backend/src/Squidex.Domain.Apps.Core.Model/FieldDescriptions.Designer.cs
index abb9aa2f38..7f4b90c450 100644
--- a/backend/src/Squidex.Domain.Apps.Core.Model/FieldDescriptions.Designer.cs
+++ b/backend/src/Squidex.Domain.Apps.Core.Model/FieldDescriptions.Designer.cs
@@ -762,6 +762,15 @@ public static string EventType {
}
}
+ ///
+ /// Looks up a localized string similar to The graphql request..
+ ///
+ public static string GraphqlRequest {
+ get {
+ return ResourceManager.GetString("GraphqlRequest", resourceCulture);
+ }
+ }
+
///
/// Looks up a localized string similar to The current item, if the field is part of an array..
///
diff --git a/backend/src/Squidex.Domain.Apps.Core.Model/FieldDescriptions.resx b/backend/src/Squidex.Domain.Apps.Core.Model/FieldDescriptions.resx
index fb2bdafa37..ed8b9d3032 100644
--- a/backend/src/Squidex.Domain.Apps.Core.Model/FieldDescriptions.resx
+++ b/backend/src/Squidex.Domain.Apps.Core.Model/FieldDescriptions.resx
@@ -351,6 +351,9 @@
The type of the event.
+
+ The graphql request.
+
The current item, if the field is part of an array.
diff --git a/backend/src/Squidex.Domain.Apps.Entities/Contents/ContentHeaders.cs b/backend/src/Squidex.Domain.Apps.Entities/Contents/ContentHeaders.cs
index bae1f0394d..8330ca44ff 100644
--- a/backend/src/Squidex.Domain.Apps.Entities/Contents/ContentHeaders.cs
+++ b/backend/src/Squidex.Domain.Apps.Entities/Contents/ContentHeaders.cs
@@ -23,6 +23,7 @@ public static class ContentHeaders
public const string KeyNoResolveLanguages = "X-NoResolveLanguages";
public const string KeyResolveFlow = "X-ResolveFlow";
public const string KeyResolveUrls = "X-ResolveUrls";
+ public const string KeyResolveSchemaNames = "X-ResolveSchemaName";
public const string KeyUnpublished = "X-Unpublished";
public static void AddCacheHeaders(this Context context, IRequestCache cache)
@@ -98,6 +99,16 @@ public static ICloneBuilder WithResolveFlow(this ICloneBuilder builder, bool val
return builder.WithBoolean(KeyResolveFlow, value);
}
+ public static bool ResolveSchemaNames(this Context context)
+ {
+ return context.AsBoolean(KeyResolveSchemaNames);
+ }
+
+ public static ICloneBuilder WithResolveSchemaNames(this ICloneBuilder builder, bool value = true)
+ {
+ return builder.WithBoolean(KeyResolveSchemaNames, value);
+ }
+
public static bool NoResolveLanguages(this Context context)
{
return context.AsBoolean(KeyNoResolveLanguages);
diff --git a/backend/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/GraphQLExecutionContext.cs b/backend/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/GraphQLExecutionContext.cs
index faf3609b24..3edc45f98d 100644
--- a/backend/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/GraphQLExecutionContext.cs
+++ b/backend/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/GraphQLExecutionContext.cs
@@ -41,6 +41,7 @@ public GraphQLExecutionContext(
this.dataLoaders = dataLoaders;
Context = context.Clone(b => b
+ .WithResolveSchemaNames()
.WithNoCleanup()
.WithNoEnrichment()
.WithNoAssetEnrichment());
diff --git a/backend/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/ApplicationQueries.cs b/backend/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/ApplicationQueries.cs
index 190cb3dacb..200b1a6c2c 100644
--- a/backend/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/ApplicationQueries.cs
+++ b/backend/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/ApplicationQueries.cs
@@ -6,7 +6,9 @@
// ==========================================================================
using GraphQL.Types;
+using Squidex.Domain.Apps.Core.Schemas;
using Squidex.Domain.Apps.Entities.Contents.GraphQL.Types.Contents;
+using static Squidex.Domain.Apps.Entities.Contents.GraphQL.Types.Contents.ContentActions;
namespace Squidex.Domain.Apps.Entities.Contents.GraphQL.Types;
@@ -28,34 +30,62 @@ public ApplicationQueries(Builder builder, IEnumerable schemaInfos)
continue;
}
- AddContentFind(schemaInfo, contentType);
- AddContentQueries(builder, schemaInfo, contentType);
+ if (schemaInfo.Schema.SchemaDef.Type == SchemaType.Singleton)
+ {
+ // Mark the normal queries as deprecated to motivate using the new endpoint.
+ var deprecation = $"Use 'find{schemaInfo.TypeName}Singleton' instead.";
+
+ AddContentFind(schemaInfo, contentType, deprecation);
+ AddContentFindSingleton(schemaInfo, contentType);
+ AddContentQueries(builder, schemaInfo, contentType, deprecation);
+ }
+ else
+ {
+ AddContentFind(schemaInfo, contentType, null);
+ AddContentQueries(builder, schemaInfo, contentType, null);
+ }
}
Description = "The app queries.";
}
- private void AddContentFind(SchemaInfo schemaInfo, IGraphType contentType)
+ private void AddContentFind(SchemaInfo schemaInfo, IGraphType contentType, string? deprecatedReason)
{
AddField(new FieldTypeWithSchemaId
{
Name = $"find{schemaInfo.TypeName}Content",
- Arguments = ContentActions.Find.Arguments,
+ Arguments = Find.Arguments,
ResolvedType = contentType,
- Resolver = ContentActions.Find.Resolver,
+ Resolver = Find.Resolver,
+ DeprecationReason = deprecatedReason,
Description = $"Find an {schemaInfo.DisplayName} content by id.",
SchemaId = schemaInfo.Schema.Id
});
}
- private void AddContentQueries(Builder builder, SchemaInfo schemaInfo, IGraphType contentType)
+ private void AddContentFindSingleton(SchemaInfo schemaInfo, IGraphType contentType)
+ {
+ AddField(new FieldTypeWithSchemaId
+ {
+ Name = $"find{schemaInfo.TypeName}Singleton",
+ Arguments = FindSingleton.Arguments,
+ ResolvedType = contentType,
+ Resolver = FindSingleton.Resolver,
+ DeprecationReason = null,
+ Description = $"Find an {schemaInfo.DisplayName} singleton.",
+ SchemaId = schemaInfo.Schema.Id
+ });
+ }
+
+ private void AddContentQueries(Builder builder, SchemaInfo schemaInfo, IGraphType contentType, string? deprecatedReason)
{
AddField(new FieldTypeWithSchemaId
{
Name = $"query{schemaInfo.TypeName}Contents",
- Arguments = ContentActions.QueryOrReferencing.Arguments,
+ Arguments = QueryOrReferencing.Arguments,
ResolvedType = new ListGraphType(new NonNullGraphType(contentType)),
- Resolver = ContentActions.QueryOrReferencing.Query,
+ Resolver = QueryOrReferencing.Query,
+ DeprecationReason = deprecatedReason,
Description = $"Query {schemaInfo.DisplayName} content items.",
SchemaId = schemaInfo.Schema.Id
});
@@ -70,9 +100,10 @@ private void AddContentQueries(Builder builder, SchemaInfo schemaInfo, IGraphTyp
AddField(new FieldTypeWithSchemaId
{
Name = $"query{schemaInfo.TypeName}ContentsWithTotal",
- Arguments = ContentActions.QueryOrReferencing.Arguments,
+ Arguments = QueryOrReferencing.Arguments,
ResolvedType = contentResultTyp,
- Resolver = ContentActions.QueryOrReferencing.QueryWithTotal,
+ Resolver = QueryOrReferencing.QueryWithTotal,
+ DeprecationReason = deprecatedReason,
Description = $"Query {schemaInfo.DisplayName} content items with total count.",
SchemaId = schemaInfo.Schema.Id
});
@@ -90,9 +121,9 @@ private void AddContentQuery(Builder builder)
AddField(new FieldType
{
Name = "queryContentsByIds",
- Arguments = ContentActions.QueryByIds.Arguments,
+ Arguments = QueryByIds.Arguments,
ResolvedType = new NonNullGraphType(new ListGraphType(new NonNullGraphType(unionType))),
- Resolver = ContentActions.QueryByIds.Resolver,
+ Resolver = QueryByIds.Resolver,
Description = "Query content items by IDs across schemeas."
});
}
diff --git a/backend/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/Contents/ContentActions.cs b/backend/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/Contents/ContentActions.cs
index bda4e47f03..949aacf554 100644
--- a/backend/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/Contents/ContentActions.cs
+++ b/backend/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/Contents/ContentActions.cs
@@ -96,6 +96,36 @@ public static class Find
});
}
+ public static class FindSingleton
+ {
+ public static readonly QueryArguments Arguments = new QueryArguments
+ {
+ new QueryArgument(Scalars.Int)
+ {
+ Name = "version",
+ Description = FieldDescriptions.QueryVersion,
+ DefaultValue = null
+ }
+ };
+
+ public static readonly IFieldResolver Resolver = Resolvers.Sync