From 6574f2ac5f60cefcb99419057fa8cbcebd1f4ab0 Mon Sep 17 00:00:00 2001 From: Sebastian Stehle Date: Tue, 31 Oct 2017 21:21:22 +0100 Subject: [PATCH] Rule UI updated. --- .../Schemas/FieldRegistry.cs | 1 - .../SquidexCoreModel.cs | 14 ++++ .../SquidexEvents.cs | 14 ++++ .../Rules/MongoRuleRepository.cs | 2 +- .../SquidexInfrastructure.cs | 14 ++++ .../TypeNameRegistry.cs | 36 +++++----- src/Squidex/Config/Domain/Serializers.cs | 10 +-- .../pages/rules/rules-page.component.html | 72 ++++++++++++++++--- .../pages/rules/rules-page.component.scss | 24 +++++-- .../rules/pages/rules/rules-page.component.ts | 44 +++++++++++- .../framework/angular/toggle.component.scss | 4 +- .../app/framework/angular/toggle.component.ts | 2 +- .../app/shared/services/rules.service.ts | 6 +- tests/Benchmarks/Tests/HandleEvents.cs | 2 +- .../Tests/HandleEventsWithManyWriters.cs | 2 +- .../Actors/ActorRemoteTests.cs | 2 +- .../CQRS/Events/EventDataFormatterTests.cs | 4 +- .../TypeNameRegistryTests.cs | 22 +++--- 18 files changed, 215 insertions(+), 60 deletions(-) create mode 100644 src/Squidex.Domain.Apps.Core.Model/SquidexCoreModel.cs create mode 100644 src/Squidex.Domain.Apps.Events/SquidexEvents.cs create mode 100644 src/Squidex.Infrastructure/SquidexInfrastructure.cs diff --git a/src/Squidex.Domain.Apps.Core.Model/Schemas/FieldRegistry.cs b/src/Squidex.Domain.Apps.Core.Model/Schemas/FieldRegistry.cs index bf94a3a13..710581ef1 100644 --- a/src/Squidex.Domain.Apps.Core.Model/Schemas/FieldRegistry.cs +++ b/src/Squidex.Domain.Apps.Core.Model/Schemas/FieldRegistry.cs @@ -84,7 +84,6 @@ namespace Squidex.Domain.Apps.Core.Schemas new TagsField(id, name, partitioning, (TagsFieldProperties)properties)); typeNameRegistry.MapObsolete(typeof(ReferencesFieldProperties), "DateTime"); - typeNameRegistry.MapObsolete(typeof(DateTimeFieldProperties), "References"); } diff --git a/src/Squidex.Domain.Apps.Core.Model/SquidexCoreModel.cs b/src/Squidex.Domain.Apps.Core.Model/SquidexCoreModel.cs new file mode 100644 index 000000000..5ed5bdea6 --- /dev/null +++ b/src/Squidex.Domain.Apps.Core.Model/SquidexCoreModel.cs @@ -0,0 +1,14 @@ +// ========================================================================== +// SquidexCoreModel.cs +// Squidex Headless CMS +// ========================================================================== +// Copyright (c) Squidex Group +// All rights reserved. +// ========================================================================== + +namespace Squidex.Domain.Apps.Core +{ + public static class SquidexCoreModel + { + } +} diff --git a/src/Squidex.Domain.Apps.Events/SquidexEvents.cs b/src/Squidex.Domain.Apps.Events/SquidexEvents.cs new file mode 100644 index 000000000..ab5d1ec98 --- /dev/null +++ b/src/Squidex.Domain.Apps.Events/SquidexEvents.cs @@ -0,0 +1,14 @@ +// ========================================================================== +// SquidexEvents.cs +// Squidex Headless CMS +// ========================================================================== +// Copyright (c) Squidex Group +// All rights reserved. +// ========================================================================== + +namespace Squidex.Domain.Apps.Events +{ + public static class SquidexEvents + { + } +} diff --git a/src/Squidex.Domain.Apps.Read.MongoDb/Rules/MongoRuleRepository.cs b/src/Squidex.Domain.Apps.Read.MongoDb/Rules/MongoRuleRepository.cs index 378b512f9..ab9ff0204 100644 --- a/src/Squidex.Domain.Apps.Read.MongoDb/Rules/MongoRuleRepository.cs +++ b/src/Squidex.Domain.Apps.Read.MongoDb/Rules/MongoRuleRepository.cs @@ -55,7 +55,7 @@ namespace Squidex.Domain.Apps.Read.MongoDb.Rules { await EnsureRulesLoadedAsync(); - return inMemoryRules.GetOrDefault(appId) ?? EmptyRules; + return inMemoryRules.GetOrDefault(appId)?.ToList() ?? EmptyRules; } private async Task EnsureRulesLoadedAsync() diff --git a/src/Squidex.Infrastructure/SquidexInfrastructure.cs b/src/Squidex.Infrastructure/SquidexInfrastructure.cs new file mode 100644 index 000000000..c0a3692f3 --- /dev/null +++ b/src/Squidex.Infrastructure/SquidexInfrastructure.cs @@ -0,0 +1,14 @@ +// ========================================================================== +// SquidexInfrastructure.cs +// Squidex Headless CMS +// ========================================================================== +// Copyright (c) Squidex Group +// All rights reserved. +// ========================================================================== + +namespace Squidex.Infrastructure +{ + public static class SquidexInfrastructure + { + } +} diff --git a/src/Squidex.Infrastructure/TypeNameRegistry.cs b/src/Squidex.Infrastructure/TypeNameRegistry.cs index f1aef2a1f..61135259c 100644 --- a/src/Squidex.Infrastructure/TypeNameRegistry.cs +++ b/src/Squidex.Infrastructure/TypeNameRegistry.cs @@ -17,20 +17,6 @@ namespace Squidex.Infrastructure private readonly Dictionary namesByType = new Dictionary(); private readonly Dictionary typesByName = new Dictionary(StringComparer.OrdinalIgnoreCase); - public TypeNameRegistry Map(Type type) - { - Guard.NotNull(type, nameof(type)); - - var typeNameAttribute = type.GetTypeInfo().GetCustomAttribute(); - - if (typeNameAttribute != null) - { - Map(type, typeNameAttribute.TypeName); - } - - return this; - } - public TypeNameRegistry MapObsolete(Type type, string name) { Guard.NotNull(type, nameof(type)); @@ -56,6 +42,20 @@ namespace Squidex.Infrastructure return this; } + public TypeNameRegistry Map(Type type) + { + Guard.NotNull(type, nameof(type)); + + var typeNameAttribute = type.GetTypeInfo().GetCustomAttribute(); + + if (!string.IsNullOrWhiteSpace(typeNameAttribute?.TypeName)) + { + Map(type, typeNameAttribute.TypeName); + } + + return this; + } + public TypeNameRegistry Map(Type type, string name) { Guard.NotNull(type, nameof(type)); @@ -95,15 +95,13 @@ namespace Squidex.Infrastructure return this; } - public TypeNameRegistry Map(Assembly assembly) + public TypeNameRegistry MapUnmapped(Assembly assembly) { foreach (var type in assembly.GetTypes()) { - var typeNameAttribute = type.GetTypeInfo().GetCustomAttribute(); - - if (!string.IsNullOrWhiteSpace(typeNameAttribute?.TypeName)) + if (!namesByType.ContainsKey(type)) { - Map(type, typeNameAttribute.TypeName); + Map(type); } } diff --git a/src/Squidex/Config/Domain/Serializers.cs b/src/Squidex/Config/Domain/Serializers.cs index 400333d51..97c3d3139 100644 --- a/src/Squidex/Config/Domain/Serializers.cs +++ b/src/Squidex/Config/Domain/Serializers.cs @@ -6,18 +6,18 @@ // All rights reserved. // ========================================================================== -using System.Reflection; using Microsoft.Extensions.DependencyInjection; using Newtonsoft.Json; using Newtonsoft.Json.Converters; using NodaTime; using NodaTime.Serialization.JsonNet; +using Squidex.Domain.Apps.Core; using Squidex.Domain.Apps.Core.Apps.Json; +using Squidex.Domain.Apps.Core.Rules.Json; using Squidex.Domain.Apps.Core.Schemas; using Squidex.Domain.Apps.Core.Schemas.Json; using Squidex.Domain.Apps.Events; using Squidex.Infrastructure; -using Squidex.Infrastructure.CQRS.Events; using Squidex.Infrastructure.Json; using Squidex.Infrastructure.MongoDb; @@ -45,6 +45,7 @@ namespace Squidex.Config.Domain new NamedStringIdConverter(), new PropertiesBagConverter(), new RefTokenConverter(), + new RuleConverter(), new SchemaConverter(FieldRegistry), new StringEnumConverter()); @@ -62,8 +63,9 @@ namespace Squidex.Config.Domain static Serializers() { - TypeNameRegistry.Map(typeof(SquidexEvent).GetTypeInfo().Assembly); - TypeNameRegistry.Map(typeof(NoopEvent).GetTypeInfo().Assembly); + TypeNameRegistry.MapUnmapped(typeof(SquidexCoreModel).Assembly); + TypeNameRegistry.MapUnmapped(typeof(SquidexEvents).Assembly); + TypeNameRegistry.MapUnmapped(typeof(SquidexInfrastructure).Assembly); ConfigureJson(SerializerSettings, TypeNameHandling.Auto); diff --git a/src/Squidex/app/features/rules/pages/rules/rules-page.component.html b/src/Squidex/app/features/rules/pages/rules/rules-page.component.html index 57dc83714..abc28c165 100644 --- a/src/Squidex/app/features/rules/pages/rules/rules-page.component.html +++ b/src/Squidex/app/features/rules/pages/rules/rules-page.component.html @@ -1,6 +1,6 @@ - +
@@ -29,14 +29,69 @@
No Rule created yet.
+ + + + + + + + + + + + + + + + + + + + + + + + +
+

If

+
+ + + + + + {{ruleTriggers[rule.triggerType]}} + + + +

then

+
+ + + + + + {{ruleActions[rule.actionType]}} + + + + + + +
-
- -
- - - +
+ + + +
@@ -44,7 +99,8 @@ + (cancelled)="addRuleDialog.hide()" + (created)="onRuleCreated($event)">
diff --git a/src/Squidex/app/features/rules/pages/rules/rules-page.component.scss b/src/Squidex/app/features/rules/pages/rules/rules-page.component.scss index f78f04a07..c7674827d 100644 --- a/src/Squidex/app/features/rules/pages/rules/rules-page.component.scss +++ b/src/Squidex/app/features/rules/pages/rules/rules-page.component.scss @@ -1,10 +1,26 @@ @import '_vars'; @import '_mixins'; -.failed { - color: $color-theme-error; +sqx-toggle { + display: inline-block; } -.success { - color: $color-theme-green; +.table-items { + tbody { + td { + padding-bottom: .5rem; + } + } +} + +.step-if { + padding-left: 1.25rem; + padding-right: 0; + text-align: left; +} + +.step-then { + padding-left: 0; + padding-right: 0; + text-align: center; } \ No newline at end of file diff --git a/src/Squidex/app/features/rules/pages/rules/rules-page.component.ts b/src/Squidex/app/features/rules/pages/rules/rules-page.component.ts index 212be1d14..619c9c492 100644 --- a/src/Squidex/app/features/rules/pages/rules/rules-page.component.ts +++ b/src/Squidex/app/features/rules/pages/rules/rules-page.component.ts @@ -11,10 +11,13 @@ import { AppComponentBase, AppsStoreService, AuthService, + DateTime, DialogService, fadeAnimation, ImmutableArray, ModalView, + ruleActions, + ruleTriggers, RuleDto, RulesService, SchemaDto, @@ -30,7 +33,10 @@ import { ] }) export class RulesPageComponent extends AppComponentBase implements OnInit { - public addRuleDialog = new ModalView(true, false); + public ruleActions = ruleActions; + public ruleTriggers = ruleTriggers; + + public addRuleDialog = new ModalView(); public rules: ImmutableArray; public schemas: SchemaDto[]; @@ -63,4 +69,40 @@ export class RulesPageComponent extends AppComponentBase implements OnInit { this.notifyError(error); }); } + + public onRuleCreated(rule: RuleDto) { + this.rules = this.rules.push(rule); + + this.addRuleDialog.hide(); + } + + public toggleRule(rule: RuleDto) { + if (rule.isEnabled) { + this.appNameOnce() + .switchMap(app => this.rulesService.disableRule(app, rule.id, rule.version)) + .subscribe(dto => { + this.rules = this.rules.replace(rule, rule.disable(this.authService.user.id, dto.version, DateTime.now())); + }, error => { + this.notifyError(error); + }); + } else { + this.appNameOnce() + .switchMap(app => this.rulesService.enableRule(app, rule.id, rule.version)) + .subscribe(dto => { + this.rules = this.rules.replace(rule, rule.enable(this.authService.user.id, dto.version, DateTime.now())); + }, error => { + this.notifyError(error); + }); + } + } + + public deleteRule(rule: RuleDto) { + this.appNameOnce() + .switchMap(app => this.rulesService.deleteRule(app, rule.id, rule.version)) + .subscribe(dto => { + this.rules = this.rules.remove(rule); + }, error => { + this.notifyError(error); + }); + } } diff --git a/src/Squidex/app/framework/angular/toggle.component.scss b/src/Squidex/app/framework/angular/toggle.component.scss index b0a2f4323..d3c6432b6 100644 --- a/src/Squidex/app/framework/angular/toggle.component.scss +++ b/src/Squidex/app/framework/angular/toggle.component.scss @@ -1,8 +1,8 @@ @import '_mixins'; @import '_vars'; -$toggle-width: 3.2rem; -$toggle-height: 2rem; +$toggle-width: 2.2rem; +$toggle-height: 1.4rem; $toggle-button-size: $toggle-height - .3rem; .toggle { diff --git a/src/Squidex/app/framework/angular/toggle.component.ts b/src/Squidex/app/framework/angular/toggle.component.ts index bac7739ba..5fa5aaa23 100644 --- a/src/Squidex/app/framework/angular/toggle.component.ts +++ b/src/Squidex/app/framework/angular/toggle.component.ts @@ -28,7 +28,7 @@ export class ToggleComponent implements ControlValueAccessor { public isDisabled = false; public writeValue(value: boolean | null | undefined) { - this.isChecked = Types.isBoolean(value) ? value || null : null; + this.isChecked = Types.isBoolean(value) ? value : null; } public setDisabledState(isDisabled: boolean): void { diff --git a/src/Squidex/app/shared/services/rules.service.ts b/src/Squidex/app/shared/services/rules.service.ts index 8981dfbcd..8d64943c1 100644 --- a/src/Squidex/app/shared/services/rules.service.ts +++ b/src/Squidex/app/shared/services/rules.service.ts @@ -25,7 +25,7 @@ export const ruleTriggers: any = { }; export const ruleActions: any = { - 'Webhook': 'Send Webhooks' + 'Webhook': 'Send Webhook' }; export class RuleDto { @@ -52,9 +52,9 @@ export class RuleDto { version, this.isEnabled, update.trigger, - update.trigger['triggerType'], + update.trigger.triggerType, update.action, - update.action['actionType']); + update.action.actionType); } public enable(user: string, version: Version, now?: DateTime): RuleDto { diff --git a/tests/Benchmarks/Tests/HandleEvents.cs b/tests/Benchmarks/Tests/HandleEvents.cs index 75c552af2..f4f77fcc8 100644 --- a/tests/Benchmarks/Tests/HandleEvents.cs +++ b/tests/Benchmarks/Tests/HandleEvents.cs @@ -21,7 +21,7 @@ namespace Benchmarks.Tests public sealed class HandleEvents : IBenchmark { private const int NumEvents = 5000; - private readonly TypeNameRegistry typeNameRegistry = new TypeNameRegistry().Map(typeof(MyEvent)); + private readonly TypeNameRegistry typeNameRegistry = new TypeNameRegistry().MapUnmapped(typeof(MyEvent)); private readonly EventDataFormatter formatter; private readonly JsonSerializerSettings serializerSettings = new JsonSerializerSettings(); private IMongoClient mongoClient; diff --git a/tests/Benchmarks/Tests/HandleEventsWithManyWriters.cs b/tests/Benchmarks/Tests/HandleEventsWithManyWriters.cs index 548cb8d2c..b5ac6ae76 100644 --- a/tests/Benchmarks/Tests/HandleEventsWithManyWriters.cs +++ b/tests/Benchmarks/Tests/HandleEventsWithManyWriters.cs @@ -23,7 +23,7 @@ namespace Benchmarks.Tests { private const int NumCommits = 200; private const int NumStreams = 10; - private readonly TypeNameRegistry typeNameRegistry = new TypeNameRegistry().Map(typeof(MyEvent)); + private readonly TypeNameRegistry typeNameRegistry = new TypeNameRegistry().MapUnmapped(typeof(MyEvent)); private readonly EventDataFormatter formatter; private readonly JsonSerializerSettings serializerSettings = new JsonSerializerSettings(); private IMongoClient mongoClient; diff --git a/tests/Squidex.Infrastructure.Tests/Actors/ActorRemoteTests.cs b/tests/Squidex.Infrastructure.Tests/Actors/ActorRemoteTests.cs index e53df6eac..ae6c6516a 100644 --- a/tests/Squidex.Infrastructure.Tests/Actors/ActorRemoteTests.cs +++ b/tests/Squidex.Infrastructure.Tests/Actors/ActorRemoteTests.cs @@ -49,7 +49,7 @@ namespace Squidex.Infrastructure.Actors public ActorRemoteTests() { - registry.Map(typeof(SuccessMessage)); + registry.MapUnmapped(typeof(SuccessMessage)); actors = new RemoteActors(new DefaultRemoteActorChannel(new InMemoryPubSub(), registry)); actors.Connect("my", actor); diff --git a/tests/Squidex.Infrastructure.Tests/CQRS/Events/EventDataFormatterTests.cs b/tests/Squidex.Infrastructure.Tests/CQRS/Events/EventDataFormatterTests.cs index 7e07d5dd4..a57896f2b 100644 --- a/tests/Squidex.Infrastructure.Tests/CQRS/Events/EventDataFormatterTests.cs +++ b/tests/Squidex.Infrastructure.Tests/CQRS/Events/EventDataFormatterTests.cs @@ -40,8 +40,8 @@ namespace Squidex.Infrastructure.CQRS.Events { serializerSettings.Converters.Add(new PropertiesBagConverter()); - typeNameRegistry.Map(typeof(MyEvent), "Event"); - typeNameRegistry.Map(typeof(MyOldEvent), "OldEvent"); + typeNameRegistry.MapUnmapped(typeof(MyEvent), "Event"); + typeNameRegistry.MapUnmapped(typeof(MyOldEvent), "OldEvent"); sut = new EventDataFormatter(typeNameRegistry, serializerSettings); } diff --git a/tests/Squidex.Infrastructure.Tests/TypeNameRegistryTests.cs b/tests/Squidex.Infrastructure.Tests/TypeNameRegistryTests.cs index f34a342f9..9dffaa860 100644 --- a/tests/Squidex.Infrastructure.Tests/TypeNameRegistryTests.cs +++ b/tests/Squidex.Infrastructure.Tests/TypeNameRegistryTests.cs @@ -30,7 +30,7 @@ namespace Squidex.Infrastructure [Fact] public void Should_register_and_retrieve_types() { - sut.Map(typeof(int), "NumberField"); + sut.MapUnmapped(typeof(int), "NumberField"); Assert.Equal("NumberField", sut.GetName()); Assert.Equal("NumberField", sut.GetName(typeof(int))); @@ -42,7 +42,7 @@ namespace Squidex.Infrastructure [Fact] public void Should_register_from_attribute() { - sut.Map(typeof(MyType)); + sut.MapUnmapped(typeof(MyType)); Assert.Equal("my", sut.GetName()); Assert.Equal("my", sut.GetName(typeof(MyType))); @@ -54,7 +54,7 @@ namespace Squidex.Infrastructure [Fact] public void Should_register_from_assembly() { - sut.Map(typeof(TypeNameRegistryTests).GetTypeInfo().Assembly); + sut.MapUnmapped(typeof(TypeNameRegistryTests).GetTypeInfo().Assembly); Assert.Equal("my", sut.GetName()); Assert.Equal("my", sut.GetName(typeof(MyType))); @@ -66,7 +66,7 @@ namespace Squidex.Infrastructure [Fact] public void Should_register_event_type_from_assembly() { - sut.Map(typeof(TypeNameRegistryTests).GetTypeInfo().Assembly); + sut.MapUnmapped(typeof(TypeNameRegistryTests).GetTypeInfo().Assembly); Assert.Equal("MyAddedEventV2", sut.GetName()); Assert.Equal("MyAddedEventV2", sut.GetName(typeof(MyAdded))); @@ -78,7 +78,7 @@ namespace Squidex.Infrastructure [Fact] public void Should_register_fallback_name() { - sut.Map(typeof(MyType)); + sut.MapUnmapped(typeof(MyType)); sut.MapObsolete(typeof(MyType), "my-old"); Assert.Equal(typeof(MyType), sut.GetType("my")); @@ -88,24 +88,24 @@ namespace Squidex.Infrastructure [Fact] public void Should_not_throw_exception_if_type_is_already_registered_with_same_name() { - sut.Map(typeof(long), "long"); - sut.Map(typeof(long), "long"); + sut.MapUnmapped(typeof(long), "long"); + sut.MapUnmapped(typeof(long), "long"); } [Fact] public void Should_throw_exception_if_type_is_already_registered() { - sut.Map(typeof(long), "long"); + sut.MapUnmapped(typeof(long), "long"); - Assert.Throws(() => sut.Map(typeof(long), "longer")); + Assert.Throws(() => sut.MapUnmapped(typeof(long), "longer")); } [Fact] public void Should_throw_exception_if_name_is_already_registered() { - sut.Map(typeof(short), "short"); + sut.MapUnmapped(typeof(short), "short"); - Assert.Throws(() => sut.Map(typeof(byte), "short")); + Assert.Throws(() => sut.MapUnmapped(typeof(byte), "short")); } [Fact]