Browse Source

6.8 bugfixes (#897)

* Several bugfixes.

* Fix scheduler and release semaphore.

* Disable delete button if the user does not have permissions.

* Fix concurrency issues with cache grains.

* Map translate code.

* Just some formatting.
pull/904/head
Sebastian Stehle 3 years ago
committed by GitHub
parent
commit
e337e41de7
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 1
      backend/i18n/source/backend_en.json
  2. 4
      backend/src/Squidex.Domain.Apps.Entities/Apps/Indexes/AppsCacheGrain.cs
  3. 1
      backend/src/Squidex.Domain.Apps.Entities/Contents/DomainObject/ContentDomainObject.cs
  4. 8
      backend/src/Squidex.Domain.Apps.Entities/Contents/DomainObject/Guards/SingletonExtensions.cs
  5. 31
      backend/src/Squidex.Domain.Apps.Entities/Rules/Indexes/RulesCacheGrain.cs
  6. 45
      backend/src/Squidex.Domain.Apps.Entities/Schemas/Indexes/SchemasCacheGrain.cs
  7. 2
      backend/src/Squidex.Infrastructure/Tasks/Scheduler.cs
  8. 4
      backend/src/Squidex/Areas/Api/Controllers/Schemas/Models/SchemaDto.cs
  9. 2
      backend/src/Squidex/Areas/Api/Controllers/Translations/Models/TranslationDto.cs
  10. 3
      backend/src/Squidex/Config/Domain/BackupsServices.cs
  11. 22
      backend/tests/Squidex.Domain.Apps.Entities.Tests/Apps/Indexes/AppsCacheGrainTests.cs
  12. 12
      backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/DomainObject/Guards/GuardContentTests.cs
  13. 46
      backend/tests/Squidex.Domain.Apps.Entities.Tests/Rules/Indexes/RulesCacheGrainTests.cs
  14. 48
      backend/tests/Squidex.Domain.Apps.Entities.Tests/Schemas/Indexes/SchemasCacheGrainTests.cs
  15. 25
      backend/tests/Squidex.Infrastructure.Tests/Tasks/SchedulerTests.cs
  16. 2
      frontend/src/app/features/content/shared/list/content.component.html
  17. 2
      frontend/src/app/features/content/shared/references/content-creator.component.ts
  18. 2
      frontend/src/app/features/schemas/pages/schema/fields/types/references-validation.component.html
  19. 2
      frontend/src/app/features/schemas/pages/schema/fields/types/string-ui.component.html
  20. 4
      frontend/src/app/features/settings/pages/workflows/workflow.component.html
  21. 2
      frontend/src/app/shared/components/references/content-selector.component.ts
  22. 11
      frontend/src/app/shared/state/schema-tag-source.ts

1
backend/i18n/source/backend_en.json

@ -142,6 +142,7 @@
"contents.singletonNotChangeable": "Singleton content cannot be updated.", "contents.singletonNotChangeable": "Singleton content cannot be updated.",
"contents.singletonNotCreatable": "Singleton content cannot be created.", "contents.singletonNotCreatable": "Singleton content cannot be created.",
"contents.singletonNotDeletable": "Singleton content cannot be deleted.", "contents.singletonNotDeletable": "Singleton content cannot be deleted.",
"contents.componentNotCreatable": "Component content cannot be created.",
"contents.statusNotValid": "Status is not defined in the workflow.", "contents.statusNotValid": "Status is not defined in the workflow.",
"contents.statusTransitionNotAllowed": "Cannot change status from {oldStatus} to {newStatus}.", "contents.statusTransitionNotAllowed": "Cannot change status from {oldStatus} to {newStatus}.",
"contents.validation.aspectRatio": "Must have aspect ratio {width}:{height}.", "contents.validation.aspectRatio": "Must have aspect ratio {width}:{height}.",

4
backend/src/Squidex.Domain.Apps.Entities/Apps/Indexes/AppsCacheGrain.cs

@ -76,6 +76,10 @@ namespace Squidex.Domain.Apps.Entities.Apps.Indexes
result.Add(id); result.Add(id);
} }
else if (appIds.TryGetValue(name, out var cachedId) && cachedId != DomainId.Empty)
{
result.Add(cachedId);
}
else else
{ {
appIds[name] = default; appIds[name] = default;

1
backend/src/Squidex.Domain.Apps.Entities/Contents/DomainObject/ContentDomainObject.cs

@ -229,6 +229,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.DomainObject
private async Task CreateCore(CreateContent c, ContentOperation operation) private async Task CreateCore(CreateContent c, ContentOperation operation)
{ {
operation.MustNotCreateComponent();
operation.MustNotCreateSingleton(); operation.MustNotCreateSingleton();
operation.MustNotCreateForUnpublishedSchema(); operation.MustNotCreateForUnpublishedSchema();
operation.MustHaveData(c.Data); operation.MustHaveData(c.Data);

8
backend/src/Squidex.Domain.Apps.Entities/Contents/DomainObject/Guards/SingletonExtensions.cs

@ -22,6 +22,14 @@ namespace Squidex.Domain.Apps.Entities.Contents.DomainObject.Guards
} }
} }
public static void MustNotCreateComponent(this ContentOperation operation)
{
if (operation.SchemaDef.Type == SchemaType.Component)
{
throw new DomainException(T.Get("contents.componentNotCreatable"));
}
}
public static void MustNotCreateSingleton(this ContentOperation operation) public static void MustNotCreateSingleton(this ContentOperation operation)
{ {
if (operation.SchemaDef.Type == SchemaType.Singleton && operation.CommandId != operation.Schema.Id) if (operation.SchemaDef.Type == SchemaType.Singleton && operation.CommandId != operation.Schema.Id)

31
backend/src/Squidex.Domain.Apps.Entities/Rules/Indexes/RulesCacheGrain.cs

@ -17,7 +17,8 @@ namespace Squidex.Domain.Apps.Entities.Rules.Indexes
public sealed class RulesCacheGrain : GrainBase, IRulesCacheGrain public sealed class RulesCacheGrain : GrainBase, IRulesCacheGrain
{ {
private readonly IRuleRepository ruleRepository; private readonly IRuleRepository ruleRepository;
private List<DomainId>? ruleIds; private readonly HashSet<DomainId> ruleIds = new HashSet<DomainId>();
private bool isLoaded;
public RulesCacheGrain(IGrainIdentity grainIdentity, IRuleRepository ruleRepository) public RulesCacheGrain(IGrainIdentity grainIdentity, IRuleRepository ruleRepository)
: base(grainIdentity) : base(grainIdentity)
@ -25,32 +26,40 @@ namespace Squidex.Domain.Apps.Entities.Rules.Indexes
this.ruleRepository = ruleRepository; this.ruleRepository = ruleRepository;
} }
public async Task<IReadOnlyCollection<DomainId>> GetRuleIdsAsync() public override Task OnActivateAsync()
{ {
var ids = ruleIds; return GetRuleIdsAsync();
}
if (ids == null) public async Task<IReadOnlyCollection<DomainId>> GetRuleIdsAsync()
{
if (!isLoaded)
{ {
ids = await ruleRepository.QueryIdsAsync(Key); var loaded = await ruleRepository.QueryIdsAsync(Key);
foreach (var id in loaded)
{
ruleIds.Add(id);
}
ruleIds = ids; isLoaded = true;
} }
return ids; return ruleIds;
} }
public Task AddAsync(DomainId id) public Task AddAsync(DomainId id)
{ {
ruleIds?.Add(id); ruleIds.Add(id);
return Task.CompletedTask; return Task.CompletedTask;
} }
public Task RemoveAsync(DomainId id) public async Task RemoveAsync(DomainId id)
{ {
ruleIds?.Remove(id); await GetRuleIdsAsync();
return Task.CompletedTask; ruleIds.Remove(id);
} }
} }
} }

45
backend/src/Squidex.Domain.Apps.Entities/Schemas/Indexes/SchemasCacheGrain.cs

@ -17,7 +17,8 @@ namespace Squidex.Domain.Apps.Entities.Schemas.Indexes
public sealed class SchemasCacheGrain : UniqueNameGrain<DomainId>, ISchemasCacheGrain public sealed class SchemasCacheGrain : UniqueNameGrain<DomainId>, ISchemasCacheGrain
{ {
private readonly ISchemaRepository schemaRepository; private readonly ISchemaRepository schemaRepository;
private Dictionary<string, DomainId>? schemaIds; private readonly Dictionary<string, DomainId> schemaIds = new Dictionary<string, DomainId>();
private bool isLoaded;
public SchemasCacheGrain(IGrainIdentity identity, ISchemaRepository schemaRepository) public SchemasCacheGrain(IGrainIdentity identity, ISchemaRepository schemaRepository)
: base(identity) : base(identity)
@ -25,6 +26,11 @@ namespace Squidex.Domain.Apps.Entities.Schemas.Indexes
this.schemaRepository = schemaRepository; this.schemaRepository = schemaRepository;
} }
public override Task OnActivateAsync()
{
return GetIdsAsync();
}
public override async Task<string?> ReserveAsync(DomainId id, string name) public override async Task<string?> ReserveAsync(DomainId id, string name)
{ {
var token = await base.ReserveAsync(id, name); var token = await base.ReserveAsync(id, name);
@ -61,41 +67,38 @@ namespace Squidex.Domain.Apps.Entities.Schemas.Indexes
private async Task<Dictionary<string, DomainId>> GetIdsAsync() private async Task<Dictionary<string, DomainId>> GetIdsAsync()
{ {
var ids = schemaIds; if (!isLoaded)
if (ids == null)
{ {
ids = await schemaRepository.QueryIdsAsync(Key); var loaded = await schemaRepository.QueryIdsAsync(Key);
schemaIds = ids; foreach (var (name, id) in loaded)
{
schemaIds[name] = id;
}
isLoaded = true;
} }
return ids; return schemaIds;
} }
public Task AddAsync(DomainId id, string name) public Task AddAsync(DomainId id, string name)
{ {
if (schemaIds != null) schemaIds[name] = id;
{
schemaIds[name] = id;
}
return Task.CompletedTask; return Task.CompletedTask;
} }
public Task RemoveAsync(DomainId id) public async Task RemoveAsync(DomainId id)
{ {
if (schemaIds != null) await GetIdsAsync();
{
var name = schemaIds.FirstOrDefault(x => x.Value == id).Key;
if (name != null) var name = schemaIds.FirstOrDefault(x => x.Value == id).Key;
{
schemaIds.Remove(name);
}
}
return Task.CompletedTask; if (name != null)
{
schemaIds.Remove(name);
}
} }
} }
} }

2
backend/src/Squidex.Infrastructure/Tasks/Scheduler.cs

@ -113,6 +113,8 @@ namespace Squidex.Infrastructure.Tasks
} }
finally finally
{ {
semaphore.Release();
if (Interlocked.Decrement(ref pendingTasks) <= 1) if (Interlocked.Decrement(ref pendingTasks) <= 1)
{ {
tcs.TrySetResult(true); tcs.TrySetResult(true);

4
backend/src/Squidex/Areas/Api/Controllers/Schemas/Models/SchemaDto.cs

@ -154,12 +154,12 @@ namespace Squidex.Areas.Api.Controllers.Schemas.Models
AddSelfLink(resources.Url<SchemasController>(x => nameof(x.GetSchema), values)); AddSelfLink(resources.Url<SchemasController>(x => nameof(x.GetSchema), values));
if (resources.CanReadContent(Name)) if (resources.CanReadContent(Name) && Type == SchemaType.Default)
{ {
AddGetLink("contents", resources.Url<ContentsController>(x => nameof(x.GetContents), values)); AddGetLink("contents", resources.Url<ContentsController>(x => nameof(x.GetContents), values));
} }
if (resources.CanCreateContent(Name)) if (resources.CanCreateContent(Name) && Type == SchemaType.Default)
{ {
AddPostLink("contents/create", resources.Url<ContentsController>(x => nameof(x.PostContent), values)); AddPostLink("contents/create", resources.Url<ContentsController>(x => nameof(x.PostContent), values));
AddPostLink("contents/create/publish", resources.Url<ContentsController>(x => nameof(x.PostContent), values) + "?publish=true"); AddPostLink("contents/create/publish", resources.Url<ContentsController>(x => nameof(x.PostContent), values) + "?publish=true");

2
backend/src/Squidex/Areas/Api/Controllers/Translations/Models/TranslationDto.cs

@ -24,7 +24,7 @@ namespace Squidex.Areas.Api.Controllers.Translations.Models
public static TranslationDto FromDomain(TranslationResult translation) public static TranslationDto FromDomain(TranslationResult translation)
{ {
return SimpleMapper.Map(translation, new TranslationDto()); return SimpleMapper.Map(translation, new TranslationDto { Result = translation.Code });
} }
} }
} }

3
backend/src/Squidex/Config/Domain/BackupsServices.cs

@ -22,6 +22,9 @@ namespace Squidex.Config.Domain
services.AddSingletonAs<TempFolderBackupArchiveLocation>() services.AddSingletonAs<TempFolderBackupArchiveLocation>()
.As<IBackupArchiveLocation>(); .As<IBackupArchiveLocation>();
services.AddSingletonAs<DefaultBackupHandlerFactory>()
.As<IBackupHandlerFactory>();
services.AddSingletonAs<DefaultBackupArchiveStore>() services.AddSingletonAs<DefaultBackupArchiveStore>()
.As<IBackupArchiveStore>(); .As<IBackupArchiveStore>();

22
backend/tests/Squidex.Domain.Apps.Entities.Tests/Apps/Indexes/AppsCacheGrainTests.cs

@ -149,5 +149,27 @@ namespace Squidex.Domain.Apps.Entities.Apps.Indexes
A.CallTo(() => appRepository.QueryIdsAsync(A<IEnumerable<string>>.That.Is("name1", "name2"), default)) A.CallTo(() => appRepository.QueryIdsAsync(A<IEnumerable<string>>.That.Is("name1", "name2"), default))
.MustHaveHappenedOnceExactly(); .MustHaveHappenedOnceExactly();
} }
[Fact]
public async Task Should_merge_found_value_with_added_id()
{
var foundId = DomainId.NewGuid();
async Task<Dictionary<string, DomainId>> GetIds()
{
await sut.AddAsync(foundId, "name1");
return new Dictionary<string, DomainId>();
}
A.CallTo(() => appRepository.QueryIdsAsync(A<IEnumerable<string>>._, A<CancellationToken>._))
.ReturnsLazily(() => GetIds());
var result1 = await sut.GetAppIdsAsync(new[] { "name1" });
var result2 = await sut.GetAppIdsAsync(new[] { "name1" });
Assert.Equal(foundId, result1.Single());
Assert.Equal(foundId, result2.Single());
}
} }
} }

12
backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/DomainObject/Guards/GuardContentTests.cs

@ -34,6 +34,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.DomainObject.Guards
private readonly ISchemaEntity normalUnpublishedSchema; private readonly ISchemaEntity normalUnpublishedSchema;
private readonly ISchemaEntity singletonSchema; private readonly ISchemaEntity singletonSchema;
private readonly ISchemaEntity singletonUnpublishedSchema; private readonly ISchemaEntity singletonUnpublishedSchema;
private readonly ISchemaEntity componentSchema;
private readonly RefToken actor = RefToken.User("123"); private readonly RefToken actor = RefToken.User("123");
public GuardContentTests() public GuardContentTests()
@ -49,6 +50,9 @@ namespace Squidex.Domain.Apps.Entities.Contents.DomainObject.Guards
singletonSchema = singletonSchema =
Mocks.Schema(appId, schemaId, new Schema(schemaId.Name, type: SchemaType.Singleton).Publish()); Mocks.Schema(appId, schemaId, new Schema(schemaId.Name, type: SchemaType.Singleton).Publish());
componentSchema =
Mocks.Schema(appId, schemaId, new Schema(schemaId.Name, type: SchemaType.Component).Publish());
} }
[Fact] [Fact]
@ -91,6 +95,14 @@ namespace Squidex.Domain.Apps.Entities.Contents.DomainObject.Guards
Assert.Throws<DomainException>(() => operation.MustNotCreateSingleton()); Assert.Throws<DomainException>(() => operation.MustNotCreateSingleton());
} }
[Fact]
public void Should_throw_exception_if_creating_component_content()
{
var operation = Operation(CreateContent(Status.Draft), componentSchema);
Assert.Throws<DomainException>(() => operation.MustNotCreateComponent());
}
[Fact] [Fact]
public void Should_not_throw_exception_if_creating_singleton_content_with_schema_id() public void Should_not_throw_exception_if_creating_singleton_content_with_schema_id()
{ {

46
backend/tests/Squidex.Domain.Apps.Entities.Tests/Rules/Indexes/RulesCacheGrainTests.cs

@ -99,5 +99,51 @@ namespace Squidex.Domain.Apps.Entities.Rules.Indexes
A.CallTo(() => ruleRepository.QueryIdsAsync(appId, default)) A.CallTo(() => ruleRepository.QueryIdsAsync(appId, default))
.MustHaveHappenedOnceExactly(); .MustHaveHappenedOnceExactly();
} }
[Fact]
public async Task Should_remove_id_from_not_loaded_result()
{
var ids = new List<DomainId>
{
DomainId.NewGuid(),
DomainId.NewGuid()
};
var newId = DomainId.NewGuid();
A.CallTo(() => ruleRepository.QueryIdsAsync(appId, default))
.Returns(ids);
await sut.RemoveAsync(ids.ElementAt(0));
var result = await sut.GetRuleIdsAsync();
Assert.Equal(ids.Skip(1), result);
A.CallTo(() => ruleRepository.QueryIdsAsync(appId, default))
.MustHaveHappenedOnceExactly();
}
[Fact]
public async Task Should_merge_found_value_with_added_id()
{
var foundId = DomainId.NewGuid();
async Task<List<DomainId>> GetIds()
{
await sut.AddAsync(foundId);
return new List<DomainId>();
}
A.CallTo(() => ruleRepository.QueryIdsAsync(appId, default))
.ReturnsLazily(() => GetIds());
var result1 = await sut.GetRuleIdsAsync();
var result2 = await sut.GetRuleIdsAsync();
Assert.Equal(foundId, result1.Single());
Assert.Equal(foundId, result2.Single());
}
} }
} }

48
backend/tests/Squidex.Domain.Apps.Entities.Tests/Schemas/Indexes/SchemasCacheGrainTests.cs

@ -112,10 +112,56 @@ namespace Squidex.Domain.Apps.Entities.Schemas.Indexes
var result = await sut.GetSchemaIdsAsync(); var result = await sut.GetSchemaIdsAsync();
Assert.Equal(ids.Values.Take(1), result); Assert.Equal(ids.Values.Skip(1), result);
A.CallTo(() => schemaRepository.QueryIdsAsync(appId, default)) A.CallTo(() => schemaRepository.QueryIdsAsync(appId, default))
.MustHaveHappenedOnceExactly(); .MustHaveHappenedOnceExactly();
} }
[Fact]
public async Task Should_remove_id_from_not_loaded_result()
{
var ids = new Dictionary<string, DomainId>
{
["name1"] = DomainId.NewGuid(),
["name2"] = DomainId.NewGuid()
};
var newId = DomainId.NewGuid();
A.CallTo(() => schemaRepository.QueryIdsAsync(appId, default))
.Returns(ids);
await sut.RemoveAsync(ids.ElementAt(0).Value);
var result = await sut.GetSchemaIdsAsync();
Assert.Equal(ids.Values.Skip(1), result);
A.CallTo(() => schemaRepository.QueryIdsAsync(appId, default))
.MustHaveHappenedOnceExactly();
}
[Fact]
public async Task Should_merge_found_value_with_added_id()
{
var foundId = DomainId.NewGuid();
async Task<Dictionary<string, DomainId>> GetIds()
{
await sut.AddAsync(foundId, "name1");
return new Dictionary<string, DomainId>();
}
A.CallTo(() => schemaRepository.QueryIdsAsync(appId, default))
.ReturnsLazily(() => GetIds());
var result1 = await sut.GetSchemaIdsAsync();
var result2 = await sut.GetSchemaIdsAsync();
Assert.Equal(foundId, result1.Single());
Assert.Equal(foundId, result2.Single());
}
} }
} }

25
backend/tests/Squidex.Infrastructure.Tests/Tasks/SchedulerTests.cs

@ -25,6 +25,21 @@ namespace Squidex.Infrastructure.Tasks
Assert.Equal(new[] { 1 }, results.ToArray()); Assert.Equal(new[] { 1 }, results.ToArray());
} }
[Fact]
public async Task Should_schedule_lot_of_tasks_with_limited_concurrency()
{
var limited = new Scheduler(1);
for (var i = 1; i <= 10; i++)
{
Schedule(i, limited);
}
await limited.CompleteAsync();
Assert.Equal(Enumerable.Range(1, 10).ToArray(), results.OrderBy(x => x).ToArray());
}
[Fact] [Fact]
public async Task Should_schedule_multiple_tasks() public async Task Should_schedule_multiple_tasks()
{ {
@ -83,5 +98,15 @@ namespace Squidex.Infrastructure.Tasks
results.Add(value); results.Add(value);
}); });
} }
private void Schedule(int value, Scheduler target)
{
target.Schedule(async _ =>
{
await Task.Delay(1);
results.Add(value);
});
}
} }
} }

2
frontend/src/app/features/content/shared/list/content.component.html

@ -43,7 +43,7 @@
<div class="dropdown-divider"></div> <div class="dropdown-divider"></div>
<a class="dropdown-item dropdown-item-delete" <a class="dropdown-item dropdown-item-delete" [class.disabled]="!content.canDelete"
(sqxConfirmClick)="delete.emit()" (sqxConfirmClick)="delete.emit()"
confirmTitle="i18n:contents.deleteConfirmTitle" confirmTitle="i18n:contents.deleteConfirmTitle"
confirmText="i18n:contents.deleteConfirmText" confirmText="i18n:contents.deleteConfirmText"

2
frontend/src/app/features/content/shared/references/content-creator.component.ts

@ -56,7 +56,7 @@ export class ContentCreatorComponent extends ResourceOwner implements OnInit {
this.schemas = this.schemasState.snapshot.schemas.filter(x => x.canContentsCreate); this.schemas = this.schemasState.snapshot.schemas.filter(x => x.canContentsCreate);
if (this.schemaIds && this.schemaIds.length > 0) { if (this.schemaIds && this.schemaIds.length > 0) {
this.schemas = this.schemas.filter(x => this.schemaIds!.indexOf(x.id) >= 0); this.schemas = this.schemas.filter(x => x.type === 'Default' && this.schemaIds!.indexOf(x.id) >= 0);
} }
const selectedSchema = this.schemas.find(x => x.name === this.schemaName) || this.schemas[0]; const selectedSchema = this.schemas.find(x => x.name === this.schemaName) || this.schemas[0];

2
frontend/src/app/features/schemas/pages/schema/fields/types/references-validation.component.html

@ -4,7 +4,7 @@
<div class="col-9"> <div class="col-9">
<sqx-tag-editor placeholder="{{ 'common.tagAddSchema' | sqxTranslate }}" formControlName="schemaIds" <sqx-tag-editor placeholder="{{ 'common.tagAddSchema' | sqxTranslate }}" formControlName="schemaIds"
[converter]="(schemasSource.converter | async)!" [suggestions]="(schemasSource.converter | async)?.suggestions"> [converter]="(schemasSource.normalConverter | async)!" [suggestions]="(schemasSource.normalConverter | async)?.suggestions">
</sqx-tag-editor> </sqx-tag-editor>
</div> </div>
</div> </div>

2
frontend/src/app/features/schemas/pages/schema/fields/types/string-ui.component.html

@ -91,7 +91,7 @@
<div class="col-9"> <div class="col-9">
<sqx-tag-editor placeholder="{{ 'common.tagAddSchema' | sqxTranslate }}" formControlName="schemaIds" <sqx-tag-editor placeholder="{{ 'common.tagAddSchema' | sqxTranslate }}" formControlName="schemaIds"
[converter]="(schemasSource.converter | async)!" [suggestions]="(schemasSource.converter | async)?.suggestions"> [converter]="(schemasSource.normalConverter | async)!" [suggestions]="(schemasSource.normalConverter | async)?.suggestions">
</sqx-tag-editor> </sqx-tag-editor>
</div> </div>
</div> </div>

4
frontend/src/app/features/settings/pages/workflows/workflow.component.html

@ -4,7 +4,7 @@
<span class="workflow-name">{{workflow.displayName}}</span> <span class="workflow-name">{{workflow.displayName}}</span>
</div> </div>
<div class="col col-tags"> <div class="col col-tags">
<sqx-tag-editor [converter]="(schemasSource.converter | async)!" [ngModel]="workflow.schemaIds" <sqx-tag-editor [converter]="(schemasSource.normalConverter | async)!" [ngModel]="workflow.schemaIds"
[styleBlank]="true" [styleBlank]="true"
[singleLine]="true" [singleLine]="true"
[readonly]="true"> [readonly]="true">
@ -81,7 +81,7 @@
[disabled]="!isEditable" [disabled]="!isEditable"
[ngModel]="workflow.schemaIds" [ngModel]="workflow.schemaIds"
(ngModelChange)="changeSchemaIds($event)" (ngModelChange)="changeSchemaIds($event)"
[suggestions]="(schemasSource.converter | async)?.suggestions"> [suggestions]="(schemasSource.normalConverter | async)?.suggestions">
</sqx-tag-editor> </sqx-tag-editor>
<sqx-form-hint> <sqx-form-hint>

2
frontend/src/app/shared/components/references/content-selector.component.ts

@ -81,7 +81,7 @@ export class ContentSelectorComponent extends ResourceOwner implements OnInit {
this.schemas = this.schemasState.snapshot.schemas.filter(x => x.canReadContents); this.schemas = this.schemasState.snapshot.schemas.filter(x => x.canReadContents);
if (this.schemaIds && this.schemaIds.length > 0) { if (this.schemaIds && this.schemaIds.length > 0) {
this.schemas = this.schemas.filter(x => x.canReadContents && this.schemaIds!.includes(x.id)); this.schemas = this.schemas.filter(x => x.type === 'Default' && x.canReadContents && this.schemaIds!.includes(x.id));
} }
this.selectSchema(this.schemas[0]); this.selectSchema(this.schemas[0]);

11
frontend/src/app/shared/state/schema-tag-source.ts

@ -16,7 +16,12 @@ class SchemaConverter implements TagConverter {
constructor( constructor(
private readonly schemas: ReadonlyArray<SchemaDto>, private readonly schemas: ReadonlyArray<SchemaDto>,
normalOnly: boolean,
) { ) {
if (normalOnly) {
schemas = schemas.filter(x => x.type === 'Default');
}
this.suggestions = schemas.map(x => new TagValue(x.id, x.name, x.id)); this.suggestions = schemas.map(x => new TagValue(x.id, x.name, x.id));
} }
@ -45,7 +50,11 @@ class SchemaConverter implements TagConverter {
export class SchemaTagSource { export class SchemaTagSource {
public converter = public converter =
this.schemasState.schemas.pipe( this.schemasState.schemas.pipe(
map(x => new SchemaConverter(x))); map(x => new SchemaConverter(x, false)));
public normalConverter =
this.schemasState.schemas.pipe(
map(x => new SchemaConverter(x, true)));
constructor( constructor(
readonly schemasState: SchemasState, readonly schemasState: SchemasState,

Loading…
Cancel
Save