Browse Source

New Scripting methods and S3 improvements.

pull/978/head
Sebastian 3 years ago
parent
commit
3634d29f2e
  1. 2
      backend/src/Squidex.Domain.Apps.Core.Operations/Scripting/IScriptDescriptor.cs
  2. 2
      backend/src/Squidex.Domain.Apps.Core.Operations/Scripting/Internal/JintObjectConverter.cs
  3. 8
      backend/src/Squidex.Domain.Apps.Core.Operations/Scripting/ScriptingCompleter.cs
  4. 6
      backend/src/Squidex.Domain.Apps.Core.Operations/Scripting/ScriptingValue.cs
  5. 2
      backend/src/Squidex.Domain.Apps.Core.Operations/Squidex.Domain.Apps.Core.Operations.csproj
  6. 75
      backend/src/Squidex.Domain.Apps.Entities/Assets/AssetsJintExtension.cs
  7. 66
      backend/src/Squidex.Domain.Apps.Entities/Contents/ReferencesJintExtension.cs
  8. 281
      backend/src/Squidex.Domain.Apps.Entities/Properties/Resources.Designer.cs
  9. 12
      backend/src/Squidex.Domain.Apps.Entities/Properties/Resources.resx
  10. 2
      backend/src/Squidex.Domain.Apps.Entities/Squidex.Domain.Apps.Entities.csproj
  11. 12
      backend/src/Squidex.Infrastructure/Squidex.Infrastructure.csproj
  12. 24
      backend/src/Squidex/Squidex.csproj
  13. 5
      backend/src/Squidex/appsettings.json
  14. 21
      backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/AssetsJintExtensionTests.cs
  15. 21
      backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/ReferencesJintExtensionTests.cs
  16. 4
      frontend/src/app/features/rules/shared/actions/formattable-input.component.ts
  17. 4
      frontend/src/app/features/rules/shared/actions/generic-action.component.ts
  18. 4
      frontend/src/app/features/rules/shared/triggers/completions-cache.ts
  19. 4
      frontend/src/app/features/rules/shared/triggers/content-changed-schema.component.ts
  20. 4
      frontend/src/app/features/schemas/pages/schema/preview/schema-preview-urls-form.component.ts
  21. 4
      frontend/src/app/features/schemas/pages/schema/rules/schema-field-rules-form.component.ts
  22. 4
      frontend/src/app/features/schemas/pages/schema/scripts/schema-scripts-form.component.ts
  23. 4
      frontend/src/app/features/settings/pages/asset-scripts/asset-scripts-page.component.ts
  24. 10
      frontend/src/app/framework/angular/forms/editors/code-editor.component.ts
  25. 1
      frontend/src/app/framework/internal.ts
  26. 25
      frontend/src/app/framework/utils/completion.ts
  27. 4
      frontend/src/app/shared/services/assets.service.spec.ts
  28. 17
      frontend/src/app/shared/services/assets.service.ts
  29. 5
      frontend/src/app/shared/services/rules.service.spec.ts
  30. 17
      frontend/src/app/shared/services/rules.service.ts
  31. 11
      frontend/src/app/shared/services/schemas.service.spec.ts
  32. 32
      frontend/src/app/shared/services/schemas.service.ts

2
backend/src/Squidex.Domain.Apps.Core.Operations/Scripting/IScriptDescriptor.cs

@ -9,7 +9,7 @@
namespace Squidex.Domain.Apps.Core.Scripting;
public delegate void AddDescription(JsonType type, string name, string description, string[]? allowedValues = null);
public delegate void AddDescription(JsonType type, string name, string description, string[]? allowedValues = null, string? deprecationReason = null);
public interface IScriptDescriptor
{

2
backend/src/Squidex.Domain.Apps.Core.Operations/Scripting/Internal/JintObjectConverter.cs

@ -51,7 +51,7 @@ public sealed class JintObjectConverter : IObjectConverter
result = guid.ToString();
return true;
case Instant instant:
result = JsValue.FromObject(engine, instant.ToDateTimeUtc());
result = new JsDate(engine, instant.ToDateTimeUtc());
return true;
case Status status:
result = status.ToString();

8
backend/src/Squidex.Domain.Apps.Core.Operations/Scripting/ScriptingCompleter.cs

@ -474,7 +474,7 @@ public sealed class ScriptingCompleter
Add(JsonType.String, name, description);
}
private void Add(JsonType type, string? name, string? description, string[]? allowedValues = null)
private void Add(JsonType type, string? name, string? description, string[]? allowedValues = null, string? decprecationReason = null)
{
var parts = name?.Split('.') ?? Array.Empty<string>();
@ -490,9 +490,11 @@ public sealed class ScriptingCompleter
var path = string.Concat(prefixes.Reverse());
result[path] = new ScriptingValue(path, type, description)
result[path] = new ScriptingValue(path, type)
{
AllowedValues = allowedValues
AllowedValues = allowedValues,
Description = description,
DeprecationReason = decprecationReason
};
for (int i = 0; i < parts.Length; i++)

6
backend/src/Squidex.Domain.Apps.Core.Operations/Scripting/ScriptingValue.cs

@ -9,7 +9,11 @@
namespace Squidex.Domain.Apps.Core.Scripting;
public sealed record ScriptingValue(string Path, JsonType Type, string? Description)
public sealed record ScriptingValue(string Path, JsonType Type)
{
public string? Description { get; init; }
public string? DeprecationReason { get; init; }
public string[]? AllowedValues { get; init; }
}

2
backend/src/Squidex.Domain.Apps.Core.Operations/Squidex.Domain.Apps.Core.Operations.csproj

@ -28,7 +28,7 @@
<PackageReference Include="Microsoft.Extensions.Http" Version="7.0.0" />
<PackageReference Include="NJsonSchema" Version="10.8.0" />
<PackageReference Include="RefactoringEssentials" Version="5.6.0" PrivateAssets="all" />
<PackageReference Include="Squidex.Messaging.Subscriptions" Version="5.3.0" />
<PackageReference Include="Squidex.Messaging.Subscriptions" Version="5.4.0" />
<PackageReference Include="StyleCop.Analyzers" Version="1.1.118" PrivateAssets="all" />
<PackageReference Include="System.Collections.Immutable" Version="7.0.0" />
<PackageReference Include="System.Linq.Async" Version="6.0.1" />

75
backend/src/Squidex.Domain.Apps.Entities/Assets/AssetsJintExtension.cs

@ -24,6 +24,8 @@ namespace Squidex.Domain.Apps.Entities.Assets;
public sealed class AssetsJintExtension : IJintExtension, IScriptDescriptor
{
private static readonly JsString ErrorNoAsset = new JsString(nameof(ErrorNoAsset));
private static readonly JsString ErrorTooBig = new JsString(nameof(ErrorTooBig));
private delegate void GetAssetsDelegate(JsValue references, Action<JsValue> callback);
private delegate void GetAssetTextDelegate(JsValue asset, Action<JsValue> callback, JsValue? encoding);
private delegate void GetBlurHashDelegate(JsValue asset, Action<JsValue> callback, JsValue? componentX, JsValue? componentY);
@ -48,12 +50,16 @@ public sealed class AssetsJintExtension : IJintExtension, IScriptDescriptor
return;
}
describe(JsonType.Function, "getAsset(ids, callback)",
Resources.ScriptingGetAsset,
deprecationReason: Resources.ScriptingGetAssetDeprecated);
describe(JsonType.Function, "getAssetV2(ids, callback)",
Resources.ScriptingGetAssetV2);
describe(JsonType.Function, "getAssets(ids, callback)",
Resources.ScriptingGetAssets);
describe(JsonType.Function, "getAsset(ids, callback)",
Resources.ScriptingGetAsset);
describe(JsonType.Function, "getAssetText(asset, callback, encoding?)",
Resources.ScriptingGetAssetText);
@ -78,7 +84,13 @@ public sealed class AssetsJintExtension : IJintExtension, IScriptDescriptor
GetAssets(context, appId, user, references, callback);
});
var getAsset = new GetAssetsDelegate((references, callback) =>
{
GetAsset(context, appId, user, references, callback);
});
context.Engine.SetValue("getAsset", getAssets);
context.Engine.SetValue("getAssetV2", getAsset);
context.Engine.SetValue("getAssets", getAssets);
}
@ -110,7 +122,7 @@ public sealed class AssetsJintExtension : IJintExtension, IScriptDescriptor
{
if (input is not ObjectWrapper objectWrapper)
{
scheduler.Run(callback, JsValue.FromObject(context.Engine, "ErrorNoAsset"));
scheduler.Run(callback, ErrorNoAsset);
return;
}
@ -118,7 +130,7 @@ public sealed class AssetsJintExtension : IJintExtension, IScriptDescriptor
{
if (asset.FileSize > 256_000)
{
scheduler.Run(callback, JsValue.FromObject(context.Engine, "ErrorTooBig"));
scheduler.Run(callback, ErrorTooBig);
return;
}
@ -127,7 +139,7 @@ public sealed class AssetsJintExtension : IJintExtension, IScriptDescriptor
{
var text = await asset.GetTextAsync(encoding?.ToString(), assetFileStore, ct);
scheduler.Run(callback, JsValue.FromObject(context.Engine, text));
scheduler.Run(callback, text);
}
catch
{
@ -146,7 +158,7 @@ public sealed class AssetsJintExtension : IJintExtension, IScriptDescriptor
break;
default:
scheduler.Run(callback, JsValue.FromObject(context.Engine, "ErrorNoAsset"));
scheduler.Run(callback, ErrorNoAsset);
break;
}
});
@ -160,7 +172,7 @@ public sealed class AssetsJintExtension : IJintExtension, IScriptDescriptor
{
if (input is not ObjectWrapper objectWrapper)
{
scheduler.Run(callback, JsValue.FromObject(context.Engine, "ErrorNoAsset"));
scheduler.Run(callback, ErrorNoAsset);
return;
}
@ -190,7 +202,7 @@ public sealed class AssetsJintExtension : IJintExtension, IScriptDescriptor
{
var hash = await asset.GetBlurHashAsync(options, assetFileStore, assetGenerator, ct);
scheduler.Run(callback, JsValue.FromObject(context.Engine, hash));
scheduler.Run(callback, hash);
}
catch
{
@ -209,7 +221,7 @@ public sealed class AssetsJintExtension : IJintExtension, IScriptDescriptor
break;
default:
scheduler.Run(callback, JsValue.FromObject(context.Engine, "ErrorNoAsset"));
scheduler.Run(callback,ErrorNoAsset);
break;
}
});
@ -225,9 +237,7 @@ public sealed class AssetsJintExtension : IJintExtension, IScriptDescriptor
if (ids.Count == 0)
{
var emptyAssets = Array.Empty<IEnrichedAssetEntity>();
scheduler.Run(callback, JsValue.FromObject(context.Engine, emptyAssets));
scheduler.Run(callback, new JsArray(context.Engine));
return;
}
@ -235,9 +245,7 @@ public sealed class AssetsJintExtension : IJintExtension, IScriptDescriptor
if (app == null)
{
var emptyAssets = Array.Empty<IEnrichedAssetEntity>();
scheduler.Run(callback, JsValue.FromObject(context.Engine, emptyAssets));
scheduler.Run(callback, new JsArray(context.Engine));
return;
}
@ -254,6 +262,41 @@ public sealed class AssetsJintExtension : IJintExtension, IScriptDescriptor
});
}
private void GetAsset(ScriptExecutionContext context, DomainId appId, ClaimsPrincipal user, JsValue references, Action<JsValue> callback)
{
Guard.NotNull(callback);
context.Schedule(async (scheduler, ct) =>
{
var ids = references.ToIds();
if (ids.Count == 0)
{
scheduler.Run(callback, JsValue.Null);
return;
}
var app = await GetAppAsync(appId, ct);
if (app == null)
{
scheduler.Run(callback, JsValue.Null);
return;
}
var assetQuery = serviceProvider.GetRequiredService<IAssetQueryService>();
var requestContext =
new Context(user, app).Clone(b => b
.WithoutTotal());
var assets = await assetQuery.QueryAsync(requestContext, null, Q.Empty.WithIds(ids), ct);
scheduler.Run(callback, JsValue.FromObject(context.Engine, assets.FirstOrDefault()));
return;
});
}
private async Task<IAppEntity> GetAppAsync(DomainId appId,
CancellationToken ct)
{

66
backend/src/Squidex.Domain.Apps.Entities/Contents/ReferencesJintExtension.cs

@ -39,13 +39,19 @@ public sealed class ReferencesJintExtension : IJintExtension, IScriptDescriptor
return;
}
var action = new GetReferencesDelegate((references, callback) =>
var getReference = new GetReferencesDelegate((references, callback) =>
{
GetReference(context, appId, user, references, callback);
});
var getReferences = new GetReferencesDelegate((references, callback) =>
{
GetReferences(context, appId, user, references, callback);
});
context.Engine.SetValue("getReference", action);
context.Engine.SetValue("getReferences", action);
context.Engine.SetValue("getReference", getReferences);
context.Engine.SetValue("getReferenceV2", getReference);
context.Engine.SetValue("getReferences", getReferences);
}
public void Describe(AddDescription describe, ScriptScope scope)
@ -55,11 +61,15 @@ public sealed class ReferencesJintExtension : IJintExtension, IScriptDescriptor
return;
}
describe(JsonType.Function, "getReference(id, callback)",
Resources.ScriptingGetReference,
deprecationReason: Resources.ScriptingGetReferenceDeprecated);
describe(JsonType.Function, "getReferenceV2(id, callback)",
Resources.ScriptingGetReferenceV2);
describe(JsonType.Function, "getReferences(ids, callback)",
Resources.ScriptingGetReferences);
describe(JsonType.Function, "getReference(ids, callback)",
Resources.ScriptingGetReference);
}
private void GetReferences(ScriptExecutionContext context, DomainId appId, ClaimsPrincipal user, JsValue references, Action<JsValue> callback)
@ -72,9 +82,7 @@ public sealed class ReferencesJintExtension : IJintExtension, IScriptDescriptor
if (ids.Count == 0)
{
var emptyContents = Array.Empty<IEnrichedContentEntity>();
scheduler.Run(callback, JsValue.FromObject(context.Engine, emptyContents));
scheduler.Run(callback, new JsArray(context.Engine));
return;
}
@ -82,9 +90,7 @@ public sealed class ReferencesJintExtension : IJintExtension, IScriptDescriptor
if (app == null)
{
var emptyContents = Array.Empty<IEnrichedContentEntity>();
scheduler.Run(callback, JsValue.FromObject(context.Engine, emptyContents));
scheduler.Run(callback, new JsArray(context.Engine));
return;
}
@ -102,6 +108,42 @@ public sealed class ReferencesJintExtension : IJintExtension, IScriptDescriptor
});
}
private void GetReference(ScriptExecutionContext context, DomainId appId, ClaimsPrincipal user, JsValue references, Action<JsValue> callback)
{
Guard.NotNull(callback);
context.Schedule(async (scheduler, ct) =>
{
var ids = references.ToIds();
if (ids.Count == 0)
{
scheduler.Run(callback, JsValue.Null);
return;
}
var app = await GetAppAsync(appId);
if (app == null)
{
scheduler.Run(callback, JsValue.Null);
return;
}
var contentQuery = serviceProvider.GetRequiredService<IContentQueryService>();
var requestContext =
new Context(user, app).Clone(b => b
.WithoutContentEnrichment()
.WithUnpublished()
.WithoutTotal());
var contents = await contentQuery.QueryAsync(requestContext, Q.Empty.WithIds(ids), ct);
scheduler.Run(callback, JsValue.FromObject(context.Engine, contents.FirstOrDefault()));
});
}
private async Task<IAppEntity> GetAppAsync(DomainId appId)
{
var appProvider = serviceProvider.GetRequiredService<IAppProvider>();

281
backend/src/Squidex.Domain.Apps.Entities/Properties/Resources.Designer.cs

@ -8,145 +8,182 @@
// </auto-generated>
//------------------------------------------------------------------------------
namespace Squidex.Domain.Apps.Entities.Properties;
using System;
/// <summary>
/// A strongly-typed resource class, for looking up localized strings, etc.
/// </summary>
// This class was auto-generated by the StronglyTypedResourceBuilder
// class via a tool like ResGen or Visual Studio.
// To add or remove a member, edit your .ResX file then rerun ResGen
// with the /str option, or rebuild your VS project.
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
internal class Resources {
private static global::System.Resources.ResourceManager resourceMan;
namespace Squidex.Domain.Apps.Entities.Properties {
using System;
private static global::System.Globalization.CultureInfo resourceCulture;
[global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
internal Resources() {
}
/// <summary>
/// Returns the cached ResourceManager instance used by this class.
/// A strongly-typed resource class, for looking up localized strings, etc.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Resources.ResourceManager ResourceManager {
get {
if (object.ReferenceEquals(resourceMan, null)) {
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Squidex.Domain.Apps.Entities.Properties.Resources", typeof(Resources).Assembly);
resourceMan = temp;
// This class was auto-generated by the StronglyTypedResourceBuilder
// class via a tool like ResGen or Visual Studio.
// To add or remove a member, edit your .ResX file then rerun ResGen
// with the /str option, or rebuild your VS project.
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
internal class Resources {
private static global::System.Resources.ResourceManager resourceMan;
private static global::System.Globalization.CultureInfo resourceCulture;
[global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
internal Resources() {
}
/// <summary>
/// Returns the cached ResourceManager instance used by this class.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Resources.ResourceManager ResourceManager {
get {
if (object.ReferenceEquals(resourceMan, null)) {
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Squidex.Domain.Apps.Entities.Properties.Resources", typeof(Resources).Assembly);
resourceMan = temp;
}
return resourceMan;
}
return resourceMan;
}
}
/// <summary>
/// Overrides the current thread's CurrentUICulture property for all
/// resource lookups using this strongly typed resource class.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Globalization.CultureInfo Culture {
get {
return resourceCulture;
/// <summary>
/// Overrides the current thread's CurrentUICulture property for all
/// resource lookups using this strongly typed resource class.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Globalization.CultureInfo Culture {
get {
return resourceCulture;
}
set {
resourceCulture = value;
}
}
set {
resourceCulture = value;
/// <summary>
/// Looks up a localized string similar to Queries the asset with the specified ID and invokes the callback with an array of assets..
/// </summary>
internal static string ScriptingGetAsset {
get {
return ResourceManager.GetString("ScriptingGetAsset", resourceCulture);
}
}
}
/// <summary>
/// Looks up a localized string similar to Queries the asset with the specified ID and invokes the callback with an array of assets..
/// </summary>
internal static string ScriptingGetAsset {
get {
return ResourceManager.GetString("ScriptingGetAsset", resourceCulture);
/// <summary>
/// Looks up a localized string similar to Please use getAssetV2, which returns a single asset and not an array..
/// </summary>
internal static string ScriptingGetAssetDeprecated {
get {
return ResourceManager.GetString("ScriptingGetAssetDeprecated", resourceCulture);
}
}
}
/// <summary>
/// Looks up a localized string similar to Queries the assets with the specified IDs and invokes the callback with an array of assets..
/// </summary>
internal static string ScriptingGetAssets {
get {
return ResourceManager.GetString("ScriptingGetAssets", resourceCulture);
/// <summary>
/// Looks up a localized string similar to Queries the assets with the specified IDs and invokes the callback with an array of assets..
/// </summary>
internal static string ScriptingGetAssets {
get {
return ResourceManager.GetString("ScriptingGetAssets", resourceCulture);
}
}
}
/// <summary>
/// Looks up a localized string similar to Get the text of an asset. Encodings: base64,ascii,unicode,utf8.
/// </summary>
internal static string ScriptingGetAssetText {
get {
return ResourceManager.GetString("ScriptingGetAssetText", resourceCulture);
/// <summary>
/// Looks up a localized string similar to Get the text of an asset. Encodings: base64,ascii,unicode,utf8.
/// </summary>
internal static string ScriptingGetAssetText {
get {
return ResourceManager.GetString("ScriptingGetAssetText", resourceCulture);
}
}
}
/// <summary>
/// Looks up a localized string similar to Gets the blur hash of an asset if it is an image or null otherwise..
/// </summary>
internal static string ScriptingGetBlurHash {
get {
return ResourceManager.GetString("ScriptingGetBlurHash", resourceCulture);
/// <summary>
/// Looks up a localized string similar to Queries the asset with the specified ID and invokes the callback with the found asset or null otherwise..
/// </summary>
internal static string ScriptingGetAssetV2 {
get {
return ResourceManager.GetString("ScriptingGetAssetV2", resourceCulture);
}
}
}
/// <summary>
/// Looks up a localized string similar to Queries the content item with the specified ID and invokes the callback with an array of contents..
/// </summary>
internal static string ScriptingGetReference {
get {
return ResourceManager.GetString("ScriptingGetReference", resourceCulture);
/// <summary>
/// Looks up a localized string similar to Gets the blur hash of an asset if it is an image or null otherwise..
/// </summary>
internal static string ScriptingGetBlurHash {
get {
return ResourceManager.GetString("ScriptingGetBlurHash", resourceCulture);
}
}
}
/// <summary>
/// Looks up a localized string similar to Queries the content items with the specified IDs and invokes the callback with an array of contents..
/// </summary>
internal static string ScriptingGetReferences {
get {
return ResourceManager.GetString("ScriptingGetReferences", resourceCulture);
/// <summary>
/// Looks up a localized string similar to Queries the content item with the specified ID and invokes the callback with an array of contents..
/// </summary>
internal static string ScriptingGetReference {
get {
return ResourceManager.GetString("ScriptingGetReference", resourceCulture);
}
}
}
/// <summary>
/// Looks up a localized string similar to Increments the counter with the given name and returns the value (OBSOLETE)..
/// </summary>
internal static string ScriptingIncrementCounter {
get {
return ResourceManager.GetString("ScriptingIncrementCounter", resourceCulture);
/// <summary>
/// Looks up a localized string similar to Please use getReferenceV2, which returns a single content item and not an array..
/// </summary>
internal static string ScriptingGetReferenceDeprecated {
get {
return ResourceManager.GetString("ScriptingGetReferenceDeprecated", resourceCulture);
}
}
}
/// <summary>
/// Looks up a localized string similar to Increments the counter with the given name and returns the value..
/// </summary>
internal static string ScriptingIncrementCounterV2 {
get {
return ResourceManager.GetString("ScriptingIncrementCounterV2", resourceCulture);
/// <summary>
/// Looks up a localized string similar to Queries the content items with the specified IDs and invokes the callback with an array of contents..
/// </summary>
internal static string ScriptingGetReferences {
get {
return ResourceManager.GetString("ScriptingGetReferences", resourceCulture);
}
}
}
/// <summary>
/// Looks up a localized string similar to Resets the counter with the given name to zero (OBSOLETE)..
/// </summary>
internal static string ScriptingResetCounter {
get {
return ResourceManager.GetString("ScriptingResetCounter", resourceCulture);
/// <summary>
/// Looks up a localized string similar to Queries the content item with the specified ID and invokes the callback with the found content item or null otherwise..
/// </summary>
internal static string ScriptingGetReferenceV2 {
get {
return ResourceManager.GetString("ScriptingGetReferenceV2", resourceCulture);
}
}
}
/// <summary>
/// Looks up a localized string similar to Resets the counter with the given name to zero..
/// </summary>
internal static string ScriptingResetCounterV2 {
get {
return ResourceManager.GetString("ScriptingResetCounterV2", resourceCulture);
/// <summary>
/// Looks up a localized string similar to Increments the counter with the given name and returns the value (OBSOLETE)..
/// </summary>
internal static string ScriptingIncrementCounter {
get {
return ResourceManager.GetString("ScriptingIncrementCounter", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Increments the counter with the given name and returns the value..
/// </summary>
internal static string ScriptingIncrementCounterV2 {
get {
return ResourceManager.GetString("ScriptingIncrementCounterV2", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Resets the counter with the given name to zero (OBSOLETE)..
/// </summary>
internal static string ScriptingResetCounter {
get {
return ResourceManager.GetString("ScriptingResetCounter", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Resets the counter with the given name to zero..
/// </summary>
internal static string ScriptingResetCounterV2 {
get {
return ResourceManager.GetString("ScriptingResetCounterV2", resourceCulture);
}
}
}
}

12
backend/src/Squidex.Domain.Apps.Entities/Properties/Resources.resx

@ -120,21 +120,33 @@
<data name="ScriptingGetAsset" xml:space="preserve">
<value>Queries the asset with the specified ID and invokes the callback with an array of assets.</value>
</data>
<data name="ScriptingGetAssetDeprecated" xml:space="preserve">
<value>Please use getAssetV2, which returns a single asset and not an array.</value>
</data>
<data name="ScriptingGetAssets" xml:space="preserve">
<value>Queries the assets with the specified IDs and invokes the callback with an array of assets.</value>
</data>
<data name="ScriptingGetAssetText" xml:space="preserve">
<value>Get the text of an asset. Encodings: base64,ascii,unicode,utf8</value>
</data>
<data name="ScriptingGetAssetV2" xml:space="preserve">
<value>Queries the asset with the specified ID and invokes the callback with the found asset or null otherwise.</value>
</data>
<data name="ScriptingGetBlurHash" xml:space="preserve">
<value>Gets the blur hash of an asset if it is an image or null otherwise.</value>
</data>
<data name="ScriptingGetReference" xml:space="preserve">
<value>Queries the content item with the specified ID and invokes the callback with an array of contents.</value>
</data>
<data name="ScriptingGetReferenceDeprecated" xml:space="preserve">
<value>Please use getReferenceV2, which returns a single content item and not an array.</value>
</data>
<data name="ScriptingGetReferences" xml:space="preserve">
<value>Queries the content items with the specified IDs and invokes the callback with an array of contents.</value>
</data>
<data name="ScriptingGetReferenceV2" xml:space="preserve">
<value>Queries the content item with the specified ID and invokes the callback with the found content item or null otherwise.</value>
</data>
<data name="ScriptingIncrementCounter" xml:space="preserve">
<value>Increments the counter with the given name and returns the value (OBSOLETE).</value>
</data>

2
backend/src/Squidex.Domain.Apps.Entities/Squidex.Domain.Apps.Entities.csproj

@ -29,7 +29,7 @@
<PackageReference Include="Microsoft.Extensions.Caching.Memory" Version="7.0.0" />
<PackageReference Include="Notifo.SDK" Version="1.5.1" />
<PackageReference Include="RefactoringEssentials" Version="5.6.0" PrivateAssets="all" />
<PackageReference Include="Squidex.CLI.Core" Version="9.2.0" />
<PackageReference Include="Squidex.CLI.Core" Version="9.5.0" />
<PackageReference Include="StyleCop.Analyzers" Version="1.1.118" PrivateAssets="all" />
<PackageReference Include="System.Collections.Immutable" Version="7.0.0" />
<PackageReference Include="System.ValueTuple" Version="4.5.0" />

12
backend/src/Squidex.Infrastructure/Squidex.Infrastructure.csproj

@ -24,12 +24,12 @@
<PackageReference Include="NodaTime" Version="3.1.6" />
<PackageReference Include="OpenTelemetry.Api" Version="1.3.1" />
<PackageReference Include="RefactoringEssentials" Version="5.6.0" PrivateAssets="all" />
<PackageReference Include="Squidex.Assets" Version="5.3.0" />
<PackageReference Include="Squidex.Caching" Version="5.3.0" />
<PackageReference Include="Squidex.Hosting.Abstractions" Version="5.3.0" />
<PackageReference Include="Squidex.Log" Version="5.3.0" />
<PackageReference Include="Squidex.Messaging" Version="5.3.0" />
<PackageReference Include="Squidex.Text" Version="5.3.0" />
<PackageReference Include="Squidex.Assets" Version="5.4.0" />
<PackageReference Include="Squidex.Caching" Version="5.4.0" />
<PackageReference Include="Squidex.Hosting.Abstractions" Version="5.4.0" />
<PackageReference Include="Squidex.Log" Version="5.4.0" />
<PackageReference Include="Squidex.Messaging" Version="5.4.0" />
<PackageReference Include="Squidex.Text" Version="5.4.0" />
<PackageReference Include="StyleCop.Analyzers" Version="1.1.118" PrivateAssets="all" />
<PackageReference Include="System.Collections.Immutable" Version="7.0.0" />
<PackageReference Include="System.ComponentModel.Annotations" Version="5.0.0" />

24
backend/src/Squidex/Squidex.csproj

@ -63,18 +63,18 @@
<PackageReference Include="OpenTelemetry.Instrumentation.Http" Version="1.0.0-rc7" />
<PackageReference Include="RefactoringEssentials" Version="5.6.0" PrivateAssets="all" />
<PackageReference Include="ReportGenerator" Version="5.1.12" PrivateAssets="all" />
<PackageReference Include="Squidex.Assets.Azure" Version="5.3.0" />
<PackageReference Include="Squidex.Assets.GoogleCloud" Version="5.3.0" />
<PackageReference Include="Squidex.Assets.FTP" Version="5.3.0" />
<PackageReference Include="Squidex.Assets.ImageMagick" Version="5.3.0" />
<PackageReference Include="Squidex.Assets.ImageSharp" Version="5.3.0" />
<PackageReference Include="Squidex.Assets.Mongo" Version="5.3.0" />
<PackageReference Include="Squidex.Assets.S3" Version="5.3.0" />
<PackageReference Include="Squidex.Assets.TusAdapter" Version="5.3.0" />
<PackageReference Include="Squidex.ClientLibrary" Version="12.6.0" />
<PackageReference Include="Squidex.Hosting" Version="5.3.0" />
<PackageReference Include="Squidex.Messaging.All" Version="5.3.0" />
<PackageReference Include="Squidex.Messaging.Subscriptions" Version="5.3.0" />
<PackageReference Include="Squidex.Assets.Azure" Version="5.4.0" />
<PackageReference Include="Squidex.Assets.GoogleCloud" Version="5.4.0" />
<PackageReference Include="Squidex.Assets.FTP" Version="5.4.0" />
<PackageReference Include="Squidex.Assets.ImageMagick" Version="5.4.0" />
<PackageReference Include="Squidex.Assets.ImageSharp" Version="5.4.0" />
<PackageReference Include="Squidex.Assets.Mongo" Version="5.4.0" />
<PackageReference Include="Squidex.Assets.S3" Version="5.4.0" />
<PackageReference Include="Squidex.Assets.TusAdapter" Version="5.4.0" />
<PackageReference Include="Squidex.ClientLibrary" Version="14.1.0" />
<PackageReference Include="Squidex.Hosting" Version="5.4.0" />
<PackageReference Include="Squidex.Messaging.All" Version="5.4.0" />
<PackageReference Include="Squidex.Messaging.Subscriptions" Version="5.4.0" />
<PackageReference Include="Squidex.OpenIddict.MongoDb" Version="4.0.1-dev" />
<PackageReference Include="StyleCop.Analyzers" Version="1.1.118" PrivateAssets="all" />
</ItemGroup>

5
backend/src/Squidex/appsettings.json

@ -439,6 +439,11 @@
// Read More: https://supsystic.com/documentation/id-secret-access-key-amazon-s3/
"secretKey": "<MY_SECRET>",
// True, to disable the SigV4 payload signing.
//
// This might be needed for some S3-compatible storage solutions, for example Cloudflare R2.
"disablePayloadSigning": false,
// Force path style property for AmazonS3Config
"forcePathStyle": false
},

21
backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/AssetsJintExtensionTests.cs

@ -97,6 +97,27 @@ public class AssetsJintExtensionTests : GivenContext, IClassFixture<Translations
Assert.Equal(Cleanup(expected), Cleanup(actual));
}
[Fact]
public async Task Should_resolve_asset_v2()
{
var (vars, assets) = SetupAssetsVars(1);
var expected = $@"
Text: {assets[0].FileName} {assets[0].Id}
";
var script = @"
getAssetV2(data.assets.iv[0], function (asset) {
var actual1 = `Text: ${asset.fileName} ${asset.id}`;
complete(`${actual1}`);
});";
var actual = (await sut.ExecuteAsync(vars, script, ct: CancellationToken)).ToString();
Assert.Equal(Cleanup(expected), Cleanup(actual));
}
[Fact]
public async Task Should_resolve_assets()
{

21
backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/ReferencesJintExtensionTests.cs

@ -66,6 +66,27 @@ public class ReferencesJintExtensionTests : GivenContext, IClassFixture<Translat
Assert.Equal(Cleanup(expected), Cleanup(actual));
}
[Fact]
public async Task Should_resolve_reference_v2()
{
var (vars, _) = SetupReferenceVars(1);
var expected = @"
Text: Hello 1 World 1
";
var script = @"
getReferenceV2(data.references.iv[0], function (reference) {
var actual1 = `Text: ${reference.data.field1.iv} ${reference.data.field2.iv}`;
complete(`${actual1}`);
})";
var actual = (await sut.ExecuteAsync(vars, script, ct: CancellationToken)).ToString();
Assert.Equal(Cleanup(expected), Cleanup(actual));
}
[Fact]
public async Task Should_resolve_references()
{

4
frontend/src/app/features/rules/shared/actions/formattable-input.component.ts

@ -7,7 +7,7 @@
import { AfterViewInit, ChangeDetectionStrategy, Component, forwardRef, Input, ViewChild } from '@angular/core';
import { ControlValueAccessor, DefaultValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';
import { CodeEditorComponent, Types } from '@app/framework';
import { CodeEditorComponent, ScriptCompletions, Types } from '@app/framework';
export const SQX_FORMATTABLE_INPUT_CONTROL_VALUE_ACCESSOR: any = {
provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => FormattableInputComponent), multi: true,
@ -35,7 +35,7 @@ export class FormattableInputComponent implements ControlValueAccessor, AfterVie
public type: 'Text' | 'Code' = 'Text';
@Input()
public completion: ReadonlyArray<{ path: string; description: string; type: string }> | undefined | null;
public completion: ScriptCompletions | undefined | null;
@ViewChild(DefaultValueAccessor)
public inputEditor!: DefaultValueAccessor;

4
frontend/src/app/features/rules/shared/actions/generic-action.component.ts

@ -7,7 +7,7 @@
import { ChangeDetectionStrategy, Component, Input } from '@angular/core';
import { EMPTY, Observable, shareReplay } from 'rxjs';
import { ActionForm, RuleCompletions, RulesService, TypedSimpleChanges } from '@app/shared';
import { ActionForm, RulesService, ScriptCompletions, TypedSimpleChanges } from '@app/shared';
@Component({
selector: 'sqx-generic-action[actionForm][appName][trigger][triggerType]',
@ -28,7 +28,7 @@ export class GenericActionComponent {
@Input()
public triggerType: string | undefined | null;
public ruleCompletions: Observable<RuleCompletions> = EMPTY;
public ruleCompletions: Observable<ScriptCompletions> = EMPTY;
constructor(
private readonly rulesService: RulesService,

4
frontend/src/app/features/rules/shared/triggers/completions-cache.ts

@ -7,11 +7,11 @@
import { Injectable } from '@angular/core';
import { EMPTY, map, Observable, shareReplay } from 'rxjs';
import { SchemaCompletions, SchemasService, SchemasState } from '@app/shared';
import { SchemasService, SchemasState, ScriptCompletions } from '@app/shared';
@Injectable()
export class CompletionsCache {
private readonly cache: { [schema: string]: Observable<SchemaCompletions> } = {};
private readonly cache: { [schema: string]: Observable<ScriptCompletions> } = {};
constructor(
private readonly schemasService: SchemasService,

4
frontend/src/app/features/rules/shared/triggers/content-changed-schema.component.ts

@ -8,7 +8,7 @@
import { Component, EventEmitter, Input, Output } from '@angular/core';
import { FormGroup } from '@angular/forms';
import { EMPTY, Observable, switchMap } from 'rxjs';
import { SchemaCompletions, SchemaDto, TypedSimpleChanges, value$ } from '@app/shared';
import { SchemaDto, ScriptCompletions, TypedSimpleChanges, value$ } from '@app/shared';
import { CompletionsCache } from './completions-cache';
@Component({
@ -26,7 +26,7 @@ export class ContentChangedSchemaComponent {
@Output()
public remove = new EventEmitter<any>();
public completions: Observable<SchemaCompletions> = EMPTY;
public completions: Observable<ScriptCompletions> = EMPTY;
constructor(
private readonly completionsCache: CompletionsCache,

4
frontend/src/app/features/schemas/pages/schema/preview/schema-preview-urls-form.component.ts

@ -7,7 +7,7 @@
import { Component, Input, OnInit } from '@angular/core';
import { EMPTY, Observable, shareReplay } from 'rxjs';
import { ConfigurePreviewUrlsForm, SchemaCompletions, SchemaDto, SchemasService, SchemasState } from '@app/shared';
import { ConfigurePreviewUrlsForm, SchemaDto, SchemasService, SchemasState, ScriptCompletions } from '@app/shared';
@Component({
selector: 'sqx-schema-preview-urls-form',
@ -20,7 +20,7 @@ export class SchemaPreviewUrlsFormComponent implements OnInit {
public editForm = new ConfigurePreviewUrlsForm();
public fieldCompletions: Observable<SchemaCompletions> = EMPTY;
public fieldCompletions: Observable<ScriptCompletions> = EMPTY;
public isEditable = false;

4
frontend/src/app/features/schemas/pages/schema/rules/schema-field-rules-form.component.ts

@ -7,7 +7,7 @@
import { Component, Input, OnInit } from '@angular/core';
import { EMPTY, Observable, shareReplay } from 'rxjs';
import { ConfigureFieldRulesForm, FIELD_RULE_ACTIONS, SchemaCompletions, SchemaDto, SchemasService, SchemasState } from '@app/shared';
import { ConfigureFieldRulesForm, FIELD_RULE_ACTIONS, SchemaDto, SchemasService, SchemasState, ScriptCompletions } from '@app/shared';
@Component({
selector: 'sqx-schema-field-rules-form',
@ -22,7 +22,7 @@ export class SchemaFieldRulesFormComponent implements OnInit {
public fieldNames!: ReadonlyArray<string>;
public fieldActions = FIELD_RULE_ACTIONS;
public fieldCompletions: Observable<SchemaCompletions> = EMPTY;
public fieldCompletions: Observable<ScriptCompletions> = EMPTY;
public isEditable = false;

4
frontend/src/app/features/schemas/pages/schema/scripts/schema-scripts-form.component.ts

@ -7,7 +7,7 @@
import { Component, Input } from '@angular/core';
import { EMPTY, Observable, shareReplay } from 'rxjs';
import { AppsState, EditSchemaScriptsForm, SchemaCompletions, SchemaDto, SchemasService, SchemasState } from '@app/shared';
import { AppsState, EditSchemaScriptsForm, ScriptCompletions, SchemaDto, SchemasService, SchemasState } from '@app/shared';
@Component({
selector: 'sqx-schema-scripts-form',
@ -19,7 +19,7 @@ export class SchemaScriptsFormComponent {
public schema!: SchemaDto;
public schemaScript = 'query';
public schemaCompletions: Observable<SchemaCompletions> = EMPTY;
public schemaCompletions: Observable<ScriptCompletions> = EMPTY;
public editForm = new EditSchemaScriptsForm();

4
frontend/src/app/features/settings/pages/asset-scripts/asset-scripts-page.component.ts

@ -7,7 +7,7 @@
import { Component, OnInit } from '@angular/core';
import { EMPTY, Observable, shareReplay } from 'rxjs';
import { AppsState, AssetCompletions, AssetScriptsState, AssetsService, EditAssetScriptsForm, ResourceOwner } from '@app/shared';
import { AppsState, AssetScriptsState, AssetsService, EditAssetScriptsForm, ResourceOwner, ScriptCompletions } from '@app/shared';
@Component({
selector: 'sqx-asset-scripts-page',
@ -16,7 +16,7 @@ import { AppsState, AssetCompletions, AssetScriptsState, AssetsService, EditAsse
})
export class AssetScriptsPageComponent extends ResourceOwner implements OnInit {
public assetScript = 'query';
public assetCompletions: Observable<AssetCompletions> = EMPTY;
public assetCompletions: Observable<ScriptCompletions> = EMPTY;
public editForm = new EditAssetScriptsForm();

10
frontend/src/app/framework/angular/forms/editors/code-editor.component.ts

@ -8,7 +8,7 @@
import { AfterViewInit, ChangeDetectionStrategy, ChangeDetectorRef, Component, ElementRef, forwardRef, Input, ViewChild } from '@angular/core';
import { NG_VALUE_ACCESSOR } from '@angular/forms';
import { debounceTime, Subject } from 'rxjs';
import { ResourceLoaderService, StatefulControlComponent, Types } from '@app/framework/internal';
import { ResourceLoaderService, ScriptCompletions, StatefulControlComponent, Types } from '@app/framework/internal';
import { TypedSimpleChanges } from './../../helpers';
import { FocusComponent } from './../forms-helper';
@ -68,9 +68,9 @@ export class CodeEditorComponent extends StatefulControlComponent<{}, string> im
}
@Input()
public set completion(value: ReadonlyArray<{ path: string; description: string; type: string; allowedValues?: string[] }> | undefined | null) {
public set completion(value: ScriptCompletions | undefined | null) {
if (value) {
this.completions = value.map(({ path, description, type, allowedValues }) => ({ value: path, name: path, description, meta: type?.toLowerCase(), path, allowedValues }));
this.completions = value.map(({ path, description, type, ...other }) => ({ value: path, name: path, description, meta: type?.toLowerCase(), path, ...other }));
} else {
this.completions = [];
}
@ -178,6 +178,10 @@ export class CodeEditorComponent extends StatefulControlComponent<{}, string> im
item.docHTML += '</ul></div>';
}
if (item.deprecationReason) {
item.docHTML += `<div class="mt-2 mb-2"><strong>Deprecated</strong>: ${item.deprecationReason}</div>`;
}
}
},
// eslint-disable-next-line no-useless-escape

1
frontend/src/app/framework/internal.ts

@ -25,6 +25,7 @@ export * from './services/title.service';
export * from './services/toolbar.service';
export * from './utils/array-helper';
export * from './utils/cookies';
export * from './utils/completion';
export * from './utils/date-helper';
export * from './utils/date-time';
export * from './utils/duration';

25
frontend/src/app/framework/utils/completion.ts

@ -0,0 +1,25 @@
/*
* Squidex Headless CMS
*
* @license
* Copyright (c) Squidex UG (haftungsbeschränkt). All rights reserved.
*/
export type ScriptCompletion = {
// The autocompletion path.
path: string;
// The description of the autocompletion field.
description: string;
// The type of the autocompletion field.
type: 'Any' | 'Array' | 'Boolean' | 'Function' | 'Object' | 'String';
// The allowed values if the property is a string enum.
allowedValues?: string[];
// If the property is deprecated, a description is given.
deprecationReason?: string;
};
export type ScriptCompletions = ReadonlyArray<ScriptCompletion>;

4
frontend/src/app/shared/services/assets.service.spec.ts

@ -7,7 +7,7 @@
import { HttpClientTestingModule, HttpTestingController } from '@angular/common/http/testing';
import { inject, TestBed } from '@angular/core/testing';
import { ApiUrlConfig, AssetCompletions, AssetDto, AssetFolderDto, AssetFoldersDto, AssetsDto, AssetsService, DateTime, ErrorDto, MathHelper, Resource, ResourceLinks, sanitize, Version } from '@app/shared/internal';
import { ApiUrlConfig, AssetDto, AssetFolderDto, AssetFoldersDto, AssetsDto, AssetsService, DateTime, ErrorDto, MathHelper, Resource, ResourceLinks, sanitize, ScriptCompletions, Version } from '@app/shared/internal';
describe('AssetsService', () => {
const version = new Version('1');
@ -472,7 +472,7 @@ describe('AssetsService', () => {
it('should make get request to get completions',
inject([AssetsService, HttpTestingController], (assetsService: AssetsService, httpMock: HttpTestingController) => {
let completions: AssetCompletions;
let completions: ScriptCompletions;
assetsService.getCompletions('my-app').subscribe(result => {
completions = result;

17
frontend/src/app/shared/services/assets.service.ts

@ -9,7 +9,7 @@ import { HttpClient, HttpErrorResponse, HttpEventType, HttpResponse } from '@ang
import { Injectable } from '@angular/core';
import { Observable, throwError } from 'rxjs';
import { catchError, filter, map } from 'rxjs/operators';
import { ApiUrlConfig, DateTime, ErrorDto, getLinkUrl, hasAnyLink, HTTP, Metadata, pretifyError, Resource, ResourceLinks, StringHelper, Types, Version, Versioned } from '@app/framework';
import { ApiUrlConfig, DateTime, ErrorDto, getLinkUrl, hasAnyLink, HTTP, Metadata, pretifyError, Resource, ResourceLinks, ScriptCompletions, StringHelper, Types, Version, Versioned } from '@app/framework';
import { AuthService } from './auth.service';
import { Query, sanitize } from './query';
@ -141,17 +141,6 @@ export type AssetFoldersDto = Readonly<{
canCreate?: boolean;
}>;
export type AssetCompletions = ReadonlyArray<{
// The autocompletion path.
path: string;
// The description of the autocompletion field.
description: string;
// The type of the autocompletion field.
type: string;
}>;
export type AnnotateAssetDto = Readonly<{
// The optional file name.
fileName?: string;
@ -407,10 +396,10 @@ export class AssetsService {
pretifyError('i18n:assets.deleteFailed'));
}
public getCompletions(appName: string): Observable<AssetCompletions> {
public getCompletions(appName: string): Observable<ScriptCompletions> {
const url = this.apiUrl.buildUrl(`api/apps/${appName}/assets/completion`);
return this.http.get<AssetCompletions>(url);
return this.http.get<ScriptCompletions>(url);
}
}

5
frontend/src/app/shared/services/rules.service.spec.ts

@ -7,8 +7,7 @@
import { HttpClientTestingModule, HttpTestingController } from '@angular/common/http/testing';
import { inject, TestBed } from '@angular/core/testing';
import { ApiUrlConfig, DateTime, Resource, ResourceLinks, RuleDto, RuleElementDto, RuleElementPropertyDto, RuleEventDto, RuleEventsDto, RulesDto, RulesService, Version } from '@app/shared/internal';
import { RuleCompletions } from './..';
import { ApiUrlConfig, DateTime, Resource, ResourceLinks, RuleDto, RuleElementDto, RuleElementPropertyDto, RuleEventDto, RuleEventsDto, RulesDto, RulesService, ScriptCompletions, Version } from '@app/shared/internal';
import { SimulatedRuleEventDto, SimulatedRuleEventsDto } from './rules.service';
describe('RulesService', () => {
@ -408,7 +407,7 @@ describe('RulesService', () => {
it('should make get request to get completions',
inject([RulesService, HttpTestingController], (rulesService: RulesService, httpMock: HttpTestingController) => {
let completions: RuleCompletions;
let completions: ScriptCompletions;
rulesService.getCompletions('my-app', 'TriggerType').subscribe(result => {
completions = result;

17
frontend/src/app/shared/services/rules.service.ts

@ -9,7 +9,7 @@ import { HttpClient } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { Observable } from 'rxjs';
import { map } from 'rxjs/operators';
import { ApiUrlConfig, DateTime, hasAnyLink, HTTP, Model, pretifyError, Resource, ResourceLinks, Version } from '@app/framework';
import { ApiUrlConfig, DateTime, hasAnyLink, HTTP, Model, pretifyError, Resource, ResourceLinks, ScriptCompletions, Version } from '@app/framework';
export type RuleElementMetadataDto = Readonly<{
description: string;
@ -186,17 +186,6 @@ export class SimulatedRuleEventDto {
}
}
export type RuleCompletions = ReadonlyArray<Readonly<{
// The autocompletion path.
path: string;
// The description of the autocompletion field.
description: string;
// The type of the autocompletion field.
type: string;
}>>;
export type RulesDto = Readonly<{
// The list of rules.
items: ReadonlyArray<RuleDto>;
@ -409,10 +398,10 @@ export class RulesService {
pretifyError('i18n:rules.ruleEvents.cancelFailed'));
}
public getCompletions(appName: string, actionType: string): Observable<RuleCompletions> {
public getCompletions(appName: string, actionType: string): Observable<ScriptCompletions> {
const url = this.apiUrl.buildUrl(`api/apps/${appName}/rules/completion/${actionType}`);
return this.http.get<RuleCompletions>(url);
return this.http.get<ScriptCompletions>(url);
}
}

11
frontend/src/app/shared/services/schemas.service.spec.ts

@ -7,8 +7,7 @@
import { HttpClientTestingModule, HttpTestingController } from '@angular/common/http/testing';
import { inject, TestBed } from '@angular/core/testing';
import { ApiUrlConfig, createProperties, DateTime, FieldRule, NestedFieldDto, Resource, ResourceLinks, RootFieldDto, SchemaDto, SchemaPropertiesDto, SchemasDto, SchemasService, Version } from '@app/shared/internal';
import { SchemaCompletions } from './..';
import { ApiUrlConfig, createProperties, DateTime, FieldRule, NestedFieldDto, Resource, ResourceLinks, RootFieldDto, SchemaDto, SchemaPropertiesDto, SchemasDto, SchemasService, ScriptCompletions, Version } from '@app/shared/internal';
describe('SchemasService', () => {
const version = new Version('1');
@ -577,7 +576,7 @@ describe('SchemasService', () => {
it('should make get request to get content scripts completions',
inject([SchemasService, HttpTestingController], (schemasService: SchemasService, httpMock: HttpTestingController) => {
let completions: SchemaCompletions;
let completions: ScriptCompletions;
schemasService.getContentScriptsCompletion('my-app', 'my-schema').subscribe(result => {
completions = result;
@ -595,7 +594,7 @@ describe('SchemasService', () => {
it('should make get request to get content trigger completions',
inject([SchemasService, HttpTestingController], (schemasService: SchemasService, httpMock: HttpTestingController) => {
let completions: SchemaCompletions;
let completions: ScriptCompletions;
schemasService.getContentTriggerCompletion('my-app', 'my-schema').subscribe(result => {
completions = result;
@ -613,7 +612,7 @@ describe('SchemasService', () => {
it('should make get request to get field rules completions',
inject([SchemasService, HttpTestingController], (schemasService: SchemasService, httpMock: HttpTestingController) => {
let completions: SchemaCompletions;
let completions: ScriptCompletions;
schemasService.getFieldRulesCompletion('my-app', 'my-schema').subscribe(result => {
completions = result;
@ -631,7 +630,7 @@ describe('SchemasService', () => {
it('should make get request to get preview urls completions',
inject([SchemasService, HttpTestingController], (schemasService: SchemasService, httpMock: HttpTestingController) => {
let completions: SchemaCompletions;
let completions: ScriptCompletions;
schemasService.getPreviewUrlsCompletion('my-app', 'my-schema').subscribe(result => {
completions = result;

32
frontend/src/app/shared/services/schemas.service.ts

@ -9,7 +9,7 @@ import { HttpClient } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { Observable } from 'rxjs';
import { map } from 'rxjs/operators';
import { ApiUrlConfig, DateTime, hasAnyLink, HTTP, pretifyError, Resource, ResourceLinks, StringHelper, Types, Version, Versioned } from '@app/framework';
import { ApiUrlConfig, DateTime, hasAnyLink, HTTP, pretifyError, Resource, ResourceLinks, ScriptCompletions, StringHelper, Types, Version, Versioned } from '@app/framework';
import { QueryModel } from './query';
import { createProperties, FieldPropertiesDto } from './schemas.types';
@ -378,20 +378,6 @@ export type FieldRule = Readonly<{
condition: string;
}>;
export type SchemaCompletions = ReadonlyArray<{
// The autocompletion path.
path: string;
// The description of the autocompletion field.
description: string;
// The type of the autocompletion field.
type: 'Any' | 'Array' | 'Boolean' | 'Function' | 'Object' | 'String';
// The allowed values if the property is a string enum.
allowedValues?: string[];
}>;
export type SchemasDto = Readonly<{
// The list of schemas.
items: ReadonlyArray<SchemaDto>;
@ -746,28 +732,28 @@ export class SchemasService {
pretifyError('i18n:schemas.deleteFailed'));
}
public getContentScriptsCompletion(appName: string, schemaName: string): Observable<SchemaCompletions> {
public getContentScriptsCompletion(appName: string, schemaName: string): Observable<ScriptCompletions> {
const url = this.apiUrl.buildUrl(`api/apps/${appName}/schemas/${schemaName}/completion/content-scripts`);
return this.http.get<SchemaCompletions>(url);
return this.http.get<ScriptCompletions>(url);
}
public getContentTriggerCompletion(appName: string, schemaName: string): Observable<SchemaCompletions> {
public getContentTriggerCompletion(appName: string, schemaName: string): Observable<ScriptCompletions> {
const url = this.apiUrl.buildUrl(`api/apps/${appName}/schemas/${schemaName}/completion/content-triggers`);
return this.http.get<SchemaCompletions>(url);
return this.http.get<ScriptCompletions>(url);
}
public getFieldRulesCompletion(appName: string, schemaName: string): Observable<SchemaCompletions> {
public getFieldRulesCompletion(appName: string, schemaName: string): Observable<ScriptCompletions> {
const url = this.apiUrl.buildUrl(`api/apps/${appName}/schemas/${schemaName}/completion/field-rules`);
return this.http.get<SchemaCompletions>(url);
return this.http.get<ScriptCompletions>(url);
}
public getPreviewUrlsCompletion(appName: string, schemaName: string): Observable<SchemaCompletions> {
public getPreviewUrlsCompletion(appName: string, schemaName: string): Observable<ScriptCompletions> {
const url = this.apiUrl.buildUrl(`api/apps/${appName}/schemas/${schemaName}/completion/preview-urls`);
return this.http.get<SchemaCompletions>(url);
return this.http.get<ScriptCompletions>(url);
}
public getFilters(appName: string, schemaName: string): Observable<QueryModel> {

Loading…
Cancel
Save