Skip to content

Commit eba4a8d

Browse files
Rich text bugfixes. (#1267)
* Rich text bugfixes. * Fix tests * Fix test containers.
1 parent 1677aa4 commit eba4a8d

File tree

59 files changed

+2778
-2431
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

59 files changed

+2778
-2431
lines changed

.github/workflows/dev.yml

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,10 +37,20 @@ jobs:
3737
uses: actions/[email protected]
3838

3939
- name: Prepare - Setup dotnet
40+
id: dotnet
4041
uses: actions/[email protected]
4142
with:
4243
dotnet-version: 8.0.x
4344

45+
# Note: Unless a concrete version is specified in the `global.json` file,
46+
# the latest .NET version installed on the runner (including preinstalled
47+
# versions) will be used by default. To control this behavior, you may want
48+
# to use temporary `global.json` files.
49+
# https://github.com/actions/setup-dotnet/blob/main/README.md#matrix-testing
50+
- name: Create `global.json`
51+
run: |
52+
echo '{"sdk":{"version": "${{ steps.dotnet.outputs.dotnet-version }}"}}' > ./global.json
53+
4454
- name: Test - TestContainers
4555
run: dotnet test backend/Squidex.sln --filter Category=TestContainer
4656

.github/workflows/release.yml

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,10 +32,23 @@ jobs:
3232
uses: actions/[email protected]
3333

3434
- name: Prepare - Setup dotnet
35+
id: dotnet
3536
uses: actions/[email protected]
3637
with:
3738
dotnet-version: 8.0.x
3839

40+
# Note: Unless a concrete version is specified in the `global.json` file,
41+
# the latest .NET version installed on the runner (including preinstalled
42+
# versions) will be used by default. To control this behavior, you may want
43+
# to use temporary `global.json` files.
44+
# https://github.com/actions/setup-dotnet/blob/main/README.md#matrix-testing
45+
- name: Create `global.json`
46+
run: |
47+
echo '{"sdk":{"version": "${{ steps.dotnet.outputs.dotnet-version }}"}}' > ./global.json
48+
49+
- name: Test - TestContainers
50+
run: dotnet test backend/Squidex.sln --filter Category=TestContainer
51+
3952
- name: Test - TestContainers
4053
run: dotnet test backend/Squidex.sln --filter Category=TestContainer
4154

backend/extensions/Squidex.Extensions/Text/ElasticSearch/ElasticSearchClient.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ namespace Squidex.Extensions.Text.ElasticSearch;
1111

1212
public sealed class ElasticSearchClient : IElasticSearchClient
1313
{
14-
private readonly IElasticLowLevelClient elasticSearch;
14+
private readonly ElasticLowLevelClient elasticSearch;
1515

1616
public ElasticSearchClient(string configurationString)
1717
{

backend/src/Squidex.Data.EntityFramework/Squidex.Data.EntityFramework.csproj

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -40,13 +40,13 @@
4040
<PackageReference Include="Pomelo.EntityFrameworkCore.MySql.Json.Microsoft" Version="8.0.3" />
4141
<PackageReference Include="Pomelo.EntityFrameworkCore.MySql.NetTopologySuite" Version="8.0.3" />
4242
<PackageReference Include="RefactoringEssentials" Version="5.6.0" PrivateAssets="all" />
43-
<PackageReference Include="Squidex.AI.EntityFramework" Version="7.30.0" />
44-
<PackageReference Include="Squidex.Assets.EntityFramework" Version="7.30.0" />
45-
<PackageReference Include="Squidex.Assets.TusAdapter" Version="7.30.0" />
46-
<PackageReference Include="Squidex.Events.EntityFramework" Version="7.30.0" />
47-
<PackageReference Include="Squidex.Flows.EntityFramework" Version="7.30.0" />
48-
<PackageReference Include="Squidex.Hosting" Version="7.30.0" />
49-
<PackageReference Include="Squidex.Messaging.EntityFramework" Version="7.30.0" />
43+
<PackageReference Include="Squidex.AI.EntityFramework" Version="7.33.0" />
44+
<PackageReference Include="Squidex.Assets.EntityFramework" Version="7.33.0" />
45+
<PackageReference Include="Squidex.Assets.TusAdapter" Version="7.33.0" />
46+
<PackageReference Include="Squidex.Events.EntityFramework" Version="7.33.0" />
47+
<PackageReference Include="Squidex.Flows.EntityFramework" Version="7.33.0" />
48+
<PackageReference Include="Squidex.Hosting" Version="7.33.0" />
49+
<PackageReference Include="Squidex.Messaging.EntityFramework" Version="7.33.0" />
5050
<PackageReference Include="Squidex.OpenIdDict.EntityFramework" Version="5.8.4" />
5151
<PackageReference Include="StyleCop.Analyzers" Version="1.1.118" PrivateAssets="all" />
5252
<PackageReference Include="System.ValueTuple" Version="4.5.0" />

backend/src/Squidex.Data.MongoDb/Infrastructure/MongoRepositoryBase.cs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -95,8 +95,7 @@ public async Task InitializeAsync(
9595
{
9696
var databaseName = Database.DatabaseNamespace.DatabaseName;
9797

98-
var error = new ConfigurationError($"MongoDb connection failed to connect to database {databaseName}.");
99-
98+
var error = new ConfigurationError($"MongoDb connection failed to connect to database {databaseName}: {ex.Message}.");
10099
throw new ConfigurationException(error, ex);
101100
}
102101
}

backend/src/Squidex.Data.MongoDb/Squidex.Data.MongoDb.csproj

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -25,12 +25,12 @@
2525
<PackageReference Include="MongoDB.Driver.GridFS" Version="2.30.0" />
2626
<PackageReference Include="NodaTime.Serialization.SystemTextJson" Version="1.3.0" />
2727
<PackageReference Include="RefactoringEssentials" Version="5.6.0" PrivateAssets="all" />
28-
<PackageReference Include="Squidex.AI.Mongo" Version="7.30.0" />
29-
<PackageReference Include="Squidex.Assets.Mongo" Version="7.30.0" />
30-
<PackageReference Include="Squidex.Events.Mongo" Version="7.30.0" />
31-
<PackageReference Include="Squidex.Flows.Mongo" Version="7.30.0" />
32-
<PackageReference Include="Squidex.Hosting" Version="7.30.0" />
33-
<PackageReference Include="Squidex.Messaging.Mongo" Version="7.30.0" />
28+
<PackageReference Include="Squidex.AI.Mongo" Version="7.33.0" />
29+
<PackageReference Include="Squidex.Assets.Mongo" Version="7.33.0" />
30+
<PackageReference Include="Squidex.Events.Mongo" Version="7.33.0" />
31+
<PackageReference Include="Squidex.Flows.Mongo" Version="7.33.0" />
32+
<PackageReference Include="Squidex.Hosting" Version="7.33.0" />
33+
<PackageReference Include="Squidex.Messaging.Mongo" Version="7.33.0" />
3434
<PackageReference Include="Squidex.OpenIddict.MongoDb" Version="5.8.4" />
3535
<PackageReference Include="StyleCop.Analyzers" Version="1.1.118" PrivateAssets="all" />
3636
<PackageReference Include="System.ValueTuple" Version="4.5.0" />

backend/src/Squidex.Domain.Apps.Core.Model/Contents/RichTextExtensions.cs

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -11,13 +11,6 @@ namespace Squidex.Domain.Apps.Core.Contents;
1111

1212
public static class RichTextExtensions
1313
{
14-
public static bool TryGetEnum<T>(this JsonValue value, out T enumValue) where T : struct
15-
{
16-
enumValue = default;
17-
18-
return value.Value is string text && Enum.TryParse(text, true, out enumValue);
19-
}
20-
2114
public static int GetIntAttr(this JsonObject? attrs, string name, int defaultValue = 0)
2215
{
2316
if (attrs?.TryGetValue(name, out var value) == true && value.Value is double attr)

backend/src/Squidex.Domain.Apps.Core.Model/Contents/RichTextMark.cs

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -14,12 +14,10 @@ internal sealed class RichTextMark : IMark
1414
{
1515
private JsonObject? attrs;
1616

17-
public MarkType Type { get; private set; }
17+
public string Type { get; private set; } = string.Empty;
1818

19-
public bool TryUse(JsonValue source)
19+
public bool TryUse(JsonValue source, RichTextOptions options)
2020
{
21-
Type = MarkType.Undefined;
22-
2321
attrs = null;
2422

2523
if (source.Value is not JsonObject obj)
@@ -32,7 +30,7 @@ public bool TryUse(JsonValue source)
3230
{
3331
switch (key)
3432
{
35-
case "type" when value.TryGetEnum<MarkType>(out var type):
33+
case "type" when value.Value is string type && options.IsSupportedMarkType(type):
3634
Type = type;
3735
break;
3836
case "attrs" when value.Value is JsonObject attrs:
@@ -41,8 +39,7 @@ public bool TryUse(JsonValue source)
4139
}
4240
}
4341

44-
isValid &= Type != MarkType.Undefined;
45-
42+
isValid &= !string.IsNullOrWhiteSpace(Type);
4643
return isValid;
4744
}
4845

backend/src/Squidex.Domain.Apps.Core.Model/Contents/RichTextNode.cs

Lines changed: 16 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -20,15 +20,15 @@ public sealed class RichTextNode : INode
2020
internal struct State
2121
{
2222
public JsonObject? Root;
23-
public NodeType Type;
23+
public string Type;
2424
public JsonArray? Marks;
2525
public JsonObject? Attrs;
2626
public JsonArray? Content;
2727
public string? Text;
2828
public int MarkIndex;
2929
}
3030

31-
public NodeType Type
31+
public string Type
3232
{
3333
get => currentState.Type;
3434
}
@@ -43,11 +43,11 @@ public string? Text
4343
get => currentState.Text;
4444
}
4545

46-
public static bool TryCreate(JsonValue source, out RichTextNode node)
46+
public static bool TryCreate(JsonValue source, RichTextOptions options, out RichTextNode node)
4747
{
4848
var candidate = new RichTextNode();
4949

50-
if (candidate.TryUse(source, true))
50+
if (candidate.TryUse(source, true, options))
5151
{
5252
node = candidate;
5353
return true;
@@ -57,17 +57,17 @@ public static bool TryCreate(JsonValue source, out RichTextNode node)
5757
return false;
5858
}
5959

60-
public static RichTextNode Create(JsonValue source)
60+
public static RichTextNode Create(JsonValue source, RichTextOptions options)
6161
{
6262
var node = new RichTextNode();
6363

6464
// We assume that we have made the validation before.
65-
node.TryUse(source, false);
65+
node.TryUse(source, false, options);
6666

6767
return node;
6868
}
6969

70-
public bool TryUse(JsonValue source, bool recursive = false)
70+
public bool TryUse(JsonValue source, bool recursive, RichTextOptions options)
7171
{
7272
State state = default;
7373

@@ -84,7 +84,7 @@ public bool TryUse(JsonValue source, bool recursive = false)
8484
{
8585
switch (key)
8686
{
87-
case "type" when value.TryGetEnum<NodeType>(out var type):
87+
case "type" when value.Value is string type && options.IsSupportedNodeType(type):
8888
state.Type = type;
8989
break;
9090
case "attrs" when value.Value is JsonObject attrs:
@@ -103,17 +103,16 @@ public bool TryUse(JsonValue source, bool recursive = false)
103103
}
104104

105105
currentState = state;
106-
107-
isValid &= Type != NodeType.Undefined;
106+
isValid &= !string.IsNullOrWhiteSpace(Type);
108107

109108
if (isValid && recursive)
110109
{
111110
if (state.Content != null)
112111
{
113-
foreach (var content in state.Content)
112+
foreach (var contentObj in state.Content)
114113
{
115114
// We have already validated this before.
116-
isValid &= TryUse((JsonObject)content.Value!, recursive);
115+
isValid &= TryUse((JsonObject)contentObj.Value!, recursive, options);
117116
}
118117
}
119118

@@ -122,13 +121,12 @@ public bool TryUse(JsonValue source, bool recursive = false)
122121
foreach (var markObj in state.Marks)
123122
{
124123
// We have already validated this before.
125-
isValid &= mark.TryUse((JsonObject)markObj.Value!);
124+
isValid &= mark.TryUse((JsonObject)markObj.Value!, options);
126125
}
127126
}
128127
}
129128

130129
currentState = state;
131-
132130
return isValid;
133131
}
134132

@@ -142,19 +140,19 @@ public string GetStringAttr(string name, string defaultValue = "")
142140
return currentState.Attrs.GetStringAttr(name, defaultValue);
143141
}
144142

145-
public IMark? GetNextMark()
143+
public IMark? GetNextMark(RichTextOptions options)
146144
{
147145
if (currentState.Marks == null || currentState.MarkIndex >= currentState.Marks.Count)
148146
{
149147
return null;
150148
}
151149

152150
// We have already validated this before.
153-
mark.TryUse((JsonObject)currentState.Marks[currentState.MarkIndex++].Value!);
151+
mark.TryUse((JsonObject)currentState.Marks[currentState.MarkIndex++].Value!, options);
154152
return mark;
155153
}
156154

157-
public void IterateContent<T>(T state, Action<INode, T, bool, bool> action)
155+
public void IterateContent<T>(T state, RichTextOptions options, Action<INode, T, bool, bool> action)
158156
{
159157
var prevState = currentState;
160158

@@ -170,7 +168,7 @@ public void IterateContent<T>(T state, Action<INode, T, bool, bool> action)
170168
var isLast = i == prevState.Content.Count - 1;
171169

172170
// We have already validated this before.
173-
TryUse((JsonObject)item.Value!, false);
171+
TryUse((JsonObject)item.Value!, false, options);
174172
action(this, state, isFirst, isLast);
175173
i++;
176174
}
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
// ==========================================================================
2+
// Squidex Headless CMS
3+
// ==========================================================================
4+
// Copyright (c) Squidex UG (haftungsbeschraenkt)
5+
// All rights reserved. Licensed under the MIT license.
6+
// ==========================================================================
7+
8+
using Squidex.Text.RichText.Model;
9+
10+
namespace Squidex.Domain.Apps.Core.Contents;
11+
12+
public static class SquidexRichText
13+
{
14+
public static class NodeTypes
15+
{
16+
public const string ContentLink = "contentLink";
17+
}
18+
19+
private class ExtendedOptions : RichTextOptions
20+
{
21+
public override bool IsSupportedMarkType(string type)
22+
{
23+
return base.IsSupportedMarkType(type) || IsExtension(type);
24+
}
25+
26+
public override bool IsSupportedNodeType(string type)
27+
{
28+
return base.IsSupportedNodeType(type) || IsExtension(type);
29+
}
30+
31+
private static bool IsExtension(string type)
32+
{
33+
return type.StartsWith("x-", StringComparison.OrdinalIgnoreCase);
34+
}
35+
}
36+
37+
public static readonly RichTextOptions Options = new ExtendedOptions
38+
{
39+
NodeTypes =
40+
[
41+
..RichTextOptions.Default.NodeTypes,
42+
NodeTypes.ContentLink,
43+
],
44+
MarkTypes = RichTextOptions.Default.MarkTypes,
45+
};
46+
}

0 commit comments

Comments
 (0)