Browse Source

Bugfixes:

1) Ignore users with no email for comments
2) Fix loading handling on domain object.
3) Do not assign client as contributor when app is created.
pull/474/head
Sebastian 7 years ago
parent
commit
03d6ca45f5
  1. 6
      backend/src/Squidex.Domain.Apps.Entities/Apps/AppDomainObject.cs
  2. 2
      backend/src/Squidex.Infrastructure/Commands/DomainObject.cs
  3. 2
      backend/src/Squidex.Infrastructure/Commands/DomainObjectBase.cs
  4. 2
      backend/src/Squidex.Infrastructure/Commands/LogSnapshotDomainObject.cs
  5. 1
      backend/src/Squidex.Infrastructure/Commands/Rebuilder.cs
  6. 21
      backend/tests/Squidex.Domain.Apps.Entities.Tests/Apps/AppDomainObjectTests.cs
  7. 21
      backend/tests/Squidex.Domain.Apps.Entities.Tests/TestHelpers/HandlerTestBase.cs
  8. 112
      backend/tests/Squidex.Infrastructure.Tests/Commands/DomainObjectTests.cs
  9. 128
      backend/tests/Squidex.Infrastructure.Tests/Commands/LogSnapshotDomainObjectTests.cs
  10. 4
      frontend/app/shared/components/comments.component.ts

6
backend/src/Squidex.Domain.Apps.Entities/Apps/AppDomainObject.cs

@ -319,10 +319,14 @@ namespace Squidex.Domain.Apps.Entities.Apps
var events = new List<AppEvent>
{
CreateInitalEvent(command.Name),
CreateInitialOwner(command.Actor),
CreateInitialLanguage()
};
if (command.Actor.IsSubject)
{
events.Add(CreateInitialOwner(command.Actor));
}
foreach (var (key, value) in initialPatterns)
{
events.Add(CreateInitialPattern(key, value));

2
backend/src/Squidex.Infrastructure/Commands/DomainObject.cs

@ -83,6 +83,8 @@ namespace Squidex.Infrastructure.Commands
public async sealed override Task RebuildStateAsync()
{
await EnsureLoadedAsync();
if (persistence != null)
{
await persistence.WriteSnapshotAsync(Snapshot);

2
backend/src/Squidex.Infrastructure/Commands/DomainObjectBase.cs

@ -176,6 +176,8 @@ namespace Squidex.Infrastructure.Commands
}
}
isLoaded = true;
return result;
}
catch

2
backend/src/Squidex.Infrastructure/Commands/LogSnapshotDomainObject.cs

@ -97,6 +97,8 @@ namespace Squidex.Infrastructure.Commands
public async sealed override Task RebuildStateAsync()
{
await EnsureLoadedAsync();
if (persistence != null)
{
var persistedSnapshots = store.GetSnapshotStore<T>();

1
backend/src/Squidex.Infrastructure/Commands/Rebuilder.cs

@ -75,7 +75,6 @@ namespace Squidex.Infrastructure.Commands
domainObject.Setup(id);
await domainObject.EnsureLoadedAsync();
await domainObject.RebuildStateAsync();
}
catch (DomainObjectNotFoundException)

21
backend/tests/Squidex.Domain.Apps.Entities.Tests/Apps/AppDomainObjectTests.cs

@ -90,7 +90,7 @@ namespace Squidex.Domain.Apps.Entities.Apps
[Fact]
public async Task Create_should_create_events_and_update_state()
{
var command = new CreateApp { Name = AppName, Actor = Actor, AppId = AppId };
var command = new CreateApp { Name = AppName, AppId = AppId };
var result = await PublishAsync(command);
@ -107,6 +107,25 @@ namespace Squidex.Domain.Apps.Entities.Apps
);
}
[Fact]
public async Task Create_should_not_assign_client_as_contributor()
{
var command = new CreateApp { Name = AppName, Actor = ActorClient, AppId = AppId };
var result = await PublishAsync(command);
result.ShouldBeEquivalent2(sut.Snapshot);
Assert.Equal(AppName, sut.Snapshot.Name);
LastEvents
.ShouldHaveSameEvents(
CreateEvent(new AppCreated { Name = AppName }, true),
CreateEvent(new AppPatternAdded { PatternId = patternId1, Name = "Number", Pattern = "[0-9]" }, true),
CreateEvent(new AppPatternAdded { PatternId = patternId2, Name = "Numbers", Pattern = "[0-9]*" }, true)
);
}
[Fact]
public async Task Update_should_create_events_and_update_state()
{

21
backend/tests/Squidex.Domain.Apps.Entities.Tests/TestHelpers/HandlerTestBase.cs

@ -27,6 +27,8 @@ namespace Squidex.Domain.Apps.Entities.TestHelpers
protected RefToken Actor { get; } = new RefToken(RefTokenType.Subject, "me");
protected RefToken ActorClient { get; } = new RefToken(RefTokenType.Client, "client");
protected Guid AppId { get; } = Guid.NewGuid();
protected Guid SchemaId { get; } = Guid.NewGuid();
@ -85,7 +87,7 @@ namespace Squidex.Domain.Apps.Entities.TestHelpers
command.Actor = Actor;
}
if (command.User == null)
if (command.User == null && command.Actor.IsSubject)
{
command.User = User;
}
@ -108,30 +110,21 @@ namespace Squidex.Domain.Apps.Entities.TestHelpers
return command.AsJ();
}
protected TEvent CreateEvent<TEvent>(TEvent @event) where TEvent : SquidexEvent
protected TEvent CreateEvent<TEvent>(TEvent @event, bool fromClient = false) where TEvent : SquidexEvent
{
@event.Actor = Actor;
EnrichAppInfo(@event);
EnrichSchemaInfo(@event);
return @event;
}
@event.Actor = fromClient ? ActorClient : Actor;
private void EnrichAppInfo(IEvent @event)
{
if (@event is AppEvent appEvent)
{
appEvent.AppId = AppNamedId;
}
}
private void EnrichSchemaInfo(IEvent @event)
{
if (@event is SchemaEvent schemaEvent)
{
schemaEvent.SchemaId = SchemaNamedId;
}
return @event;
}
}
}

112
backend/tests/Squidex.Infrastructure.Tests/Commands/DomainObjectTests.cs

@ -71,9 +71,6 @@ namespace Squidex.Infrastructure.Commands
public DomainObjectTests()
{
A.CallTo(() => store.WithSnapshotsAndEventSourcing(typeof(MyDomainObject), id, A<HandleSnapshot<MyDomainState>>.Ignored, A<HandleEvent>.Ignored))
.Returns(persistence);
sut = new MyDomainObject(store);
}
@ -86,7 +83,7 @@ namespace Squidex.Infrastructure.Commands
[Fact]
public async Task Should_write_state_and_events_when_created()
{
await SetupEmptyAsync();
SetupEmpty();
var result = await sut.ExecuteAsync(new CreateAuto { Value = 4 });
@ -94,6 +91,8 @@ namespace Squidex.Infrastructure.Commands
.MustHaveHappened();
A.CallTo(() => persistence.WriteEventsAsync(A<IEnumerable<Envelope<IEvent>>>.That.Matches(x => x.Count() == 1)))
.MustHaveHappened();
A.CallTo(() => persistence.ReadAsync(A<long>.Ignored))
.MustNotHaveHappened();
Assert.True(result is EntityCreatedResult<Guid>);
@ -103,17 +102,43 @@ namespace Squidex.Infrastructure.Commands
Assert.Equal(0, sut.Snapshot.Version);
}
[Fact]
public async Task Should_write_state_and_events_when_updated_after_creation()
{
SetupEmpty();
await sut.ExecuteAsync(new CreateAuto { Value = 4 });
var result = await sut.ExecuteAsync(new UpdateAuto { Value = 8, ExpectedVersion = 0 });
A.CallTo(() => persistence.WriteSnapshotAsync(A<MyDomainState>.That.Matches(x => x.Value == 8)))
.MustHaveHappened();
A.CallTo(() => persistence.WriteEventsAsync(A<IEnumerable<Envelope<IEvent>>>.That.Matches(x => x.Count() == 1)))
.MustHaveHappened();
A.CallTo(() => persistence.ReadAsync(A<long>.Ignored))
.MustNotHaveHappened();
Assert.True(result is EntitySavedResult);
Assert.Empty(sut.GetUncomittedEvents());
Assert.Equal(8, sut.Snapshot.Value);
Assert.Equal(1, sut.Snapshot.Version);
}
[Fact]
public async Task Should_write_state_and_events_when_updated()
{
await SetupCreatedAsync();
SetupCreated(4);
var result = await sut.ExecuteAsync(new UpdateAuto { Value = 8 });
var result = await sut.ExecuteAsync(new UpdateAuto { Value = 8, ExpectedVersion = 0 });
A.CallTo(() => persistence.WriteSnapshotAsync(A<MyDomainState>.That.Matches(x => x.Value == 8)))
.MustHaveHappened();
A.CallTo(() => persistence.WriteEventsAsync(A<IEnumerable<Envelope<IEvent>>>.That.Matches(x => x.Count() == 1)))
.MustHaveHappened();
A.CallTo(() => persistence.ReadAsync(A<long>.Ignored))
.MustHaveHappenedOnceExactly();
Assert.True(result is EntitySavedResult);
@ -123,25 +148,38 @@ namespace Squidex.Infrastructure.Commands
Assert.Equal(1, sut.Snapshot.Version);
}
[Fact]
public async Task Should_only_load_once_on_update()
{
SetupCreated(4);
await sut.ExecuteAsync(new UpdateAuto { Value = 8, ExpectedVersion = 0 });
await sut.ExecuteAsync(new UpdateAuto { Value = 9, ExpectedVersion = 1 });
A.CallTo(() => persistence.ReadAsync(A<long>.Ignored))
.MustHaveHappenedOnceExactly();
Assert.Equal(9, sut.Snapshot.Value);
Assert.Equal(2, sut.Snapshot.Version);
}
[Fact]
public async Task Should_rebuild_state_async()
{
await SetupCreatedAsync();
SetupCreated(4);
await sut.RebuildStateAsync();
A.CallTo(() => persistence.WriteSnapshotAsync(A<MyDomainState>.That.Matches(x => x.Value == 4)))
.MustHaveHappened();
A.CallTo(() => persistence.WriteEventsAsync(A<IEnumerable<Envelope<IEvent>>>.Ignored))
.MustHaveHappenedOnceExactly();
.MustNotHaveHappened();
}
[Fact]
public async Task Should_not_update_when_snapshot_is_not_changed()
{
await SetupCreatedAsync();
var previousSnapshot = sut.Snapshot;
SetupCreated(4);
var result = await sut.ExecuteAsync(new UpdateAuto { Value = MyDomainState.Unchanged });
@ -151,14 +189,12 @@ namespace Squidex.Infrastructure.Commands
Assert.Equal(4, sut.Snapshot.Value);
Assert.Equal(0, sut.Snapshot.Version);
Assert.Same(previousSnapshot, sut.Snapshot);
}
[Fact]
public async Task Should_not_throw_exception_when_already_created()
{
await SetupCreatedAsync();
SetupCreated(4);
await sut.ExecuteAsync(new CreateAuto());
}
@ -166,7 +202,7 @@ namespace Squidex.Infrastructure.Commands
[Fact]
public async Task Should_throw_exception_when_not_created()
{
await SetupEmptyAsync();
SetupEmpty();
await Assert.ThrowsAsync<DomainObjectNotFoundException>(() => sut.ExecuteAsync(new UpdateAuto()));
}
@ -174,7 +210,7 @@ namespace Squidex.Infrastructure.Commands
[Fact]
public async Task Should_return_custom_result_on_create()
{
await SetupEmptyAsync();
SetupEmpty();
var result = await sut.ExecuteAsync(new CreateCustom());
@ -184,7 +220,7 @@ namespace Squidex.Infrastructure.Commands
[Fact]
public async Task Should_return_custom_result_on_update()
{
await SetupCreatedAsync();
SetupCreated(4);
var result = await sut.ExecuteAsync(new UpdateCustom());
@ -194,7 +230,7 @@ namespace Squidex.Infrastructure.Commands
[Fact]
public async Task Should_throw_exception_when_other_verison_expected()
{
await SetupCreatedAsync();
SetupCreated(4);
await Assert.ThrowsAsync<DomainObjectVersionException>(() => sut.ExecuteAsync(new UpdateCustom { ExpectedVersion = 3 }));
}
@ -202,7 +238,7 @@ namespace Squidex.Infrastructure.Commands
[Fact]
public async Task Should_reset_state_when_writing_snapshot_for_create_failed()
{
await SetupEmptyAsync();
SetupEmpty();
A.CallTo(() => persistence.WriteSnapshotAsync(A<MyDomainState>.Ignored))
.Throws(new InvalidOperationException());
@ -218,7 +254,7 @@ namespace Squidex.Infrastructure.Commands
[Fact]
public async Task Should_reset_state_when_writing_snapshot_for_update_failed()
{
await SetupCreatedAsync();
SetupCreated(4);
A.CallTo(() => persistence.WriteSnapshotAsync(A<MyDomainState>.Ignored))
.Throws(new InvalidOperationException());
@ -231,18 +267,42 @@ namespace Squidex.Infrastructure.Commands
Assert.Equal(0, sut.Snapshot.Version);
}
private async Task SetupCreatedAsync()
private void SetupCreated(int value)
{
sut.Setup(id);
HandleEvent handleEvent = x => { };
await sut.ExecuteAsync(new CreateAuto { Value = 4 });
var version = -1;
A.CallTo(() => persistence.ReadAsync(-2))
.Invokes(() =>
{
version = 0;
handleEvent(Envelope.Create(new ValueChanged { Value = value }));
});
A.CallTo(() => store.WithSnapshotsAndEventSourcing(typeof(MyDomainObject), id, A<HandleSnapshot<MyDomainState>>.Ignored, A<HandleEvent>.Ignored))
.Invokes(args =>
{
handleEvent = args.GetArgument<HandleEvent>(3);
})
.Returns(persistence);
A.CallTo(() => persistence.Version)
.ReturnsLazily(() => version);
sut.Setup(id);
}
private async Task SetupEmptyAsync()
private void SetupEmpty()
{
sut.Setup(id);
A.CallTo(() => store.WithSnapshotsAndEventSourcing(typeof(MyDomainObject), id, A<HandleSnapshot<MyDomainState>>.Ignored, A<HandleEvent>.Ignored))
.Returns(persistence);
A.CallTo(() => persistence.Version)
.Returns(-1);
await Task.Yield();
sut.Setup(id);
}
}
}

128
backend/tests/Squidex.Infrastructure.Tests/Commands/LogSnapshotDomainObjectTests.cs

@ -73,9 +73,6 @@ namespace Squidex.Infrastructure.Commands
public LogSnapshotDomainObjectTests()
{
A.CallTo(() => store.WithEventSourcing(typeof(MyLogDomainObject), id, A<HandleEvent>.Ignored))
.Returns(persistence);
A.CallTo(() => store.GetSnapshotStore<MyDomainState>())
.Returns(snapshotStore);
@ -85,7 +82,7 @@ namespace Squidex.Infrastructure.Commands
[Fact]
public async Task Should_get_latestet_version_when_requesting_state_with_any()
{
await SetupUpdatedAsync();
await SetupUpdatedAsync(4, 8);
var result = sut.GetSnapshot(EtagVersion.Any);
@ -95,7 +92,7 @@ namespace Squidex.Infrastructure.Commands
[Fact]
public async Task Should_get_latestet_version_when_requesting_state_with_auto()
{
await SetupUpdatedAsync();
await SetupUpdatedAsync(4, 8);
var result = sut.GetSnapshot(EtagVersion.Auto);
@ -105,7 +102,7 @@ namespace Squidex.Infrastructure.Commands
[Fact]
public async Task Should_get_empty_version_when_requesting_state_with_empty_version()
{
await SetupUpdatedAsync();
await SetupUpdatedAsync(4, 8);
var result = sut.GetSnapshot(EtagVersion.Empty);
@ -115,7 +112,7 @@ namespace Squidex.Infrastructure.Commands
[Fact]
public async Task Should_get_specific_version_when_requesting_state_with_specific_version()
{
await SetupUpdatedAsync();
await SetupUpdatedAsync(4, 8);
sut.GetSnapshot(0).Should().BeEquivalentTo(new MyDomainState { Value = 4, Version = 0 });
sut.GetSnapshot(1).Should().BeEquivalentTo(new MyDomainState { Value = 8, Version = 1 });
@ -124,7 +121,7 @@ namespace Squidex.Infrastructure.Commands
[Fact]
public async Task Should_get_null_state_when_requesting_state_with_invalid_version()
{
await SetupUpdatedAsync();
await SetupUpdatedAsync(4, 8);
Assert.Null(sut.GetSnapshot(-4));
Assert.Null(sut.GetSnapshot(2));
@ -139,7 +136,7 @@ namespace Squidex.Infrastructure.Commands
[Fact]
public async Task Should_write_state_and_events_when_created()
{
await SetupEmptyAsync();
SetupEmpty();
var result = await sut.ExecuteAsync(new CreateAuto { Value = 4 });
@ -147,6 +144,8 @@ namespace Squidex.Infrastructure.Commands
.MustHaveHappened();
A.CallTo(() => persistence.WriteEventsAsync(A<IEnumerable<Envelope<IEvent>>>.That.Matches(x => x.Count() == 1)))
.MustHaveHappened();
A.CallTo(() => persistence.ReadAsync(A<long>.Ignored))
.MustNotHaveHappened();
Assert.True(result is EntityCreatedResult<Guid>);
@ -156,17 +155,43 @@ namespace Squidex.Infrastructure.Commands
Assert.Equal(0, sut.Snapshot.Version);
}
[Fact]
public async Task Should_write_state_and_events_when_updated_after_creation()
{
SetupEmpty();
await sut.ExecuteAsync(new CreateAuto { Value = 4 });
var result = await sut.ExecuteAsync(new UpdateAuto { Value = 8, ExpectedVersion = 0 });
A.CallTo(() => snapshotStore.WriteAsync(id, A<MyDomainState>.That.Matches(x => x.Value == 8), 0, 1))
.MustHaveHappened();
A.CallTo(() => persistence.WriteEventsAsync(A<IEnumerable<Envelope<IEvent>>>.That.Matches(x => x.Count() == 1)))
.MustHaveHappened();
A.CallTo(() => persistence.ReadAsync(A<long>.Ignored))
.MustNotHaveHappened();
Assert.True(result is EntitySavedResult);
Assert.Empty(sut.GetUncomittedEvents());
Assert.Equal(8, sut.Snapshot.Value);
Assert.Equal(1, sut.Snapshot.Version);
}
[Fact]
public async Task Should_write_state_and_events_when_updated()
{
await SetupCreatedAsync();
SetupCreated(4);
var result = await sut.ExecuteAsync(new UpdateAuto { Value = 8 });
var result = await sut.ExecuteAsync(new UpdateAuto { Value = 8, ExpectedVersion = 0 });
A.CallTo(() => snapshotStore.WriteAsync(id, A<MyDomainState>.That.Matches(x => x.Value == 8), 0, 1))
.MustHaveHappened();
A.CallTo(() => persistence.WriteEventsAsync(A<IEnumerable<Envelope<IEvent>>>.That.Matches(x => x.Count() == 1)))
.MustHaveHappened();
A.CallTo(() => persistence.ReadAsync(A<long>.Ignored))
.MustHaveHappenedOnceExactly();
Assert.True(result is EntitySavedResult);
@ -176,25 +201,38 @@ namespace Squidex.Infrastructure.Commands
Assert.Equal(1, sut.Snapshot.Version);
}
[Fact]
public async Task Should_only_load_once_on_update()
{
SetupCreated(4);
await sut.ExecuteAsync(new UpdateAuto { Value = 8, ExpectedVersion = 0 });
await sut.ExecuteAsync(new UpdateAuto { Value = 9, ExpectedVersion = 1 });
A.CallTo(() => persistence.ReadAsync(A<long>.Ignored))
.MustHaveHappenedOnceExactly();
Assert.Equal(9, sut.Snapshot.Value);
Assert.Equal(2, sut.Snapshot.Version);
}
[Fact]
public async Task Should_rebuild_state_async()
{
await SetupCreatedAsync();
SetupCreated(4);
await sut.RebuildStateAsync();
A.CallTo(() => snapshotStore.WriteAsync(id, A<MyDomainState>.That.Matches(x => x.Value == 4), EtagVersion.Any, 0))
.MustHaveHappened();
A.CallTo(() => persistence.WriteEventsAsync(A<IEnumerable<Envelope<IEvent>>>.Ignored))
.MustHaveHappenedOnceExactly();
.MustNotHaveHappened();
}
[Fact]
public async Task Should_not_update_when_snapshot_is_not_changed()
{
await SetupCreatedAsync();
var previousSnapshot = sut.Snapshot;
SetupCreated(4);
var result = await sut.ExecuteAsync(new UpdateAuto { Value = MyDomainState.Unchanged });
@ -204,14 +242,12 @@ namespace Squidex.Infrastructure.Commands
Assert.Equal(4, sut.Snapshot.Value);
Assert.Equal(0, sut.Snapshot.Version);
Assert.Same(previousSnapshot, sut.Snapshot);
}
[Fact]
public async Task Should_not_throw_exception_when_already_created()
{
await SetupCreatedAsync();
SetupCreated(4);
await sut.ExecuteAsync(new CreateAuto());
}
@ -219,7 +255,7 @@ namespace Squidex.Infrastructure.Commands
[Fact]
public async Task Should_throw_exception_when_not_created()
{
await SetupEmptyAsync();
SetupEmpty();
await Assert.ThrowsAsync<DomainObjectNotFoundException>(() => sut.ExecuteAsync(new UpdateAuto()));
}
@ -227,7 +263,7 @@ namespace Squidex.Infrastructure.Commands
[Fact]
public async Task Should_return_custom_result_on_create()
{
await SetupEmptyAsync();
SetupEmpty();
var result = await sut.ExecuteAsync(new CreateCustom());
@ -237,7 +273,7 @@ namespace Squidex.Infrastructure.Commands
[Fact]
public async Task Should_return_custom_result_on_update()
{
await SetupCreatedAsync();
SetupCreated(4);
var result = await sut.ExecuteAsync(new UpdateCustom());
@ -247,7 +283,7 @@ namespace Squidex.Infrastructure.Commands
[Fact]
public async Task Should_throw_exception_when_other_verison_expected()
{
await SetupCreatedAsync();
SetupCreated(4);
await Assert.ThrowsAsync<DomainObjectVersionException>(() => sut.ExecuteAsync(new UpdateCustom { ExpectedVersion = 3 }));
}
@ -255,7 +291,7 @@ namespace Squidex.Infrastructure.Commands
[Fact]
public async Task Should_reset_state_when_writing_snapshot_for_create_failed()
{
await SetupEmptyAsync();
SetupEmpty();
A.CallTo(() => snapshotStore.WriteAsync(A<Guid>.Ignored, A<MyDomainState>.Ignored, -1, 0))
.Throws(new InvalidOperationException());
@ -271,7 +307,7 @@ namespace Squidex.Infrastructure.Commands
[Fact]
public async Task Should_reset_state_when_writing_snapshot_for_update_failed()
{
await SetupCreatedAsync();
SetupCreated(4);
A.CallTo(() => snapshotStore.WriteAsync(A<Guid>.Ignored, A<MyDomainState>.Ignored, 0, 1))
.Throws(new InvalidOperationException());
@ -284,25 +320,49 @@ namespace Squidex.Infrastructure.Commands
Assert.Equal(0, sut.Snapshot.Version);
}
private async Task SetupCreatedAsync()
private async Task SetupUpdatedAsync(int value, int updatedValue)
{
sut.Setup(id);
SetupCreated(value);
await sut.ExecuteAsync(new CreateAuto { Value = 4 });
await sut.ExecuteAsync(new UpdateAuto { Value = updatedValue });
}
private async Task SetupUpdatedAsync()
private void SetupCreated(int value)
{
await SetupCreatedAsync();
HandleEvent handleEvent = x => { };
var version = -1;
A.CallTo(() => persistence.ReadAsync(-2))
.Invokes(() =>
{
version = 0;
await sut.ExecuteAsync(new UpdateAuto { Value = 8 });
handleEvent(Envelope.Create(new ValueChanged { Value = value }));
});
A.CallTo(() => store.WithEventSourcing(typeof(MyLogDomainObject), id, A<HandleEvent>.Ignored))
.Invokes(args =>
{
handleEvent = args.GetArgument<HandleEvent>(2);
})
.Returns(persistence);
A.CallTo(() => persistence.Version)
.ReturnsLazily(() => version);
sut.Setup(id);
}
private async Task SetupEmptyAsync()
private void SetupEmpty()
{
sut.Setup(id);
A.CallTo(() => store.WithEventSourcing(typeof(MyLogDomainObject), id, A<HandleEvent>.Ignored))
.Returns(persistence);
A.CallTo(() => persistence.Version)
.Returns(-1);
await Task.Yield();
sut.Setup(id);
}
}
}

4
frontend/app/shared/components/comments.component.ts

@ -9,7 +9,7 @@ import { ChangeDetectorRef, Component, Input, OnInit } from '@angular/core';
import { FormBuilder } from '@angular/forms';
import { Router } from '@angular/router';
import { timer } from 'rxjs';
import { map, onErrorResumeNext, switchMap } from 'rxjs/operators';
import { filter, map, onErrorResumeNext, switchMap } from 'rxjs/operators';
import {
AppsState,
@ -36,7 +36,7 @@ export class CommentsComponent extends ResourceOwner implements OnInit {
public commentsState: CommentsState;
public commentForm = new UpsertCommentForm(this.formBuilder);
public mentionUsers = this.contributorsState.contributors.pipe(map(x => x.map(c => c.contributorEmail)));
public mentionUsers = this.contributorsState.contributors.pipe(map(x => x.map(c => c.contributorEmail), filter(x => !!x)));
public mentionConfig = { dropUp: true };
public userToken: string;

Loading…
Cancel
Save