From afe55e35497b3443e7d1005dc4dc88dc7f648fd9 Mon Sep 17 00:00:00 2001 From: Sebastian Stehle Date: Sun, 17 Dec 2017 16:04:41 +0100 Subject: [PATCH] App UI integrated. --- .../Apps/AppPattern.cs | 4 +- .../Apps/Json/JsonAppPattern.cs | 3 - .../Apps/AppCommandMiddleware.cs | 6 +- .../Migrations/MongoMigrationStatus.cs | 2 +- .../Controllers/Apps/AppPatternsController.cs | 2 +- .../Config/Domain/SerializationServices.cs | 1 + .../types/string-validation.component.ts | 2 + .../app/features/settings/declarations.ts | 2 + src/Squidex/app/features/settings/module.ts | 24 +++++ .../pages/patterns/pattern.component.html | 45 +++++++++ .../pages/patterns/pattern.component.scss | 13 +++ .../pages/patterns/pattern.component.ts | 95 +++++++++++++++++++ .../patterns/patterns-page.component.html | 41 ++++++++ .../patterns/patterns-page.component.scss | 2 + .../pages/patterns/patterns-page.component.ts | 87 +++++++++++++++++ .../settings/settings-area.component.html | 6 ++ .../services/app-patterns.service.spec.ts | 18 ++-- .../shared/services/app-patterns.service.ts | 11 ++- tools/Migrate_01/Migration01.cs | 41 +------- 19 files changed, 344 insertions(+), 61 deletions(-) create mode 100644 src/Squidex/app/features/settings/pages/patterns/pattern.component.html create mode 100644 src/Squidex/app/features/settings/pages/patterns/pattern.component.scss create mode 100644 src/Squidex/app/features/settings/pages/patterns/pattern.component.ts create mode 100644 src/Squidex/app/features/settings/pages/patterns/patterns-page.component.html create mode 100644 src/Squidex/app/features/settings/pages/patterns/patterns-page.component.scss create mode 100644 src/Squidex/app/features/settings/pages/patterns/patterns-page.component.ts diff --git a/src/Squidex.Domain.Apps.Core.Model/Apps/AppPattern.cs b/src/Squidex.Domain.Apps.Core.Model/Apps/AppPattern.cs index 62fec4af0..ee64fc208 100644 --- a/src/Squidex.Domain.Apps.Core.Model/Apps/AppPattern.cs +++ b/src/Squidex.Domain.Apps.Core.Model/Apps/AppPattern.cs @@ -43,9 +43,9 @@ namespace Squidex.Domain.Apps.Core.Apps } [Pure] - public AppPattern Update(string name, string pattern, string defaultMessage) + public AppPattern Update(string name, string pattern, string message) { - return new AppPattern(name, pattern, defaultMessage); + return new AppPattern(name, pattern, message); } } } diff --git a/src/Squidex.Domain.Apps.Core.Model/Apps/Json/JsonAppPattern.cs b/src/Squidex.Domain.Apps.Core.Model/Apps/Json/JsonAppPattern.cs index 9c52a8198..57364a197 100644 --- a/src/Squidex.Domain.Apps.Core.Model/Apps/Json/JsonAppPattern.cs +++ b/src/Squidex.Domain.Apps.Core.Model/Apps/Json/JsonAppPattern.cs @@ -13,9 +13,6 @@ namespace Squidex.Domain.Apps.Core.Apps.Json { public class JsonAppPattern { - [JsonProperty] - public Guid Id { get; set; } - [JsonProperty] public string Name { get; set; } diff --git a/src/Squidex.Domain.Apps.Entities/Apps/AppCommandMiddleware.cs b/src/Squidex.Domain.Apps.Entities/Apps/AppCommandMiddleware.cs index ccdf24331..72d86aba2 100644 --- a/src/Squidex.Domain.Apps.Entities/Apps/AppCommandMiddleware.cs +++ b/src/Squidex.Domain.Apps.Entities/Apps/AppCommandMiddleware.cs @@ -140,7 +140,7 @@ namespace Squidex.Domain.Apps.Entities.Apps protected Task On(AddPattern command, CommandContext context) { - return handler.UpdateAsync(context, a => + return handler.UpdateSyncedAsync(context, a => { GuardAppPattern.CanAdd(a.State.Patterns, command); @@ -150,7 +150,7 @@ namespace Squidex.Domain.Apps.Entities.Apps protected Task On(DeletePattern command, CommandContext context) { - return handler.UpdateAsync(context, a => + return handler.UpdateSyncedAsync(context, a => { GuardAppPattern.CanDelete(a.State.Patterns, command); @@ -160,7 +160,7 @@ namespace Squidex.Domain.Apps.Entities.Apps protected async Task On(UpdatePattern command, CommandContext context) { - await handler.UpdateAsync(context, a => + await handler.UpdateSyncedAsync(context, a => { GuardAppPattern.CanUpdate(a.State.Patterns, command); diff --git a/src/Squidex.Infrastructure.MongoDb/Migrations/MongoMigrationStatus.cs b/src/Squidex.Infrastructure.MongoDb/Migrations/MongoMigrationStatus.cs index eb0ab586a..f70bf2e71 100644 --- a/src/Squidex.Infrastructure.MongoDb/Migrations/MongoMigrationStatus.cs +++ b/src/Squidex.Infrastructure.MongoDb/Migrations/MongoMigrationStatus.cs @@ -40,7 +40,7 @@ namespace Squidex.Infrastructure.Migrations await Collection.FindOneAndUpdateAsync(x => x.Id == DefaultId, Update .Set(x => x.IsLocked, true) - .Set(x => x.Version, 0), + .SetOnInsert(x => x.Version, 0), UpsertFind); return entity == null || entity.IsLocked == false; diff --git a/src/Squidex/Areas/Api/Controllers/Apps/AppPatternsController.cs b/src/Squidex/Areas/Api/Controllers/Apps/AppPatternsController.cs index 0dfb36706..846353eaf 100644 --- a/src/Squidex/Areas/Api/Controllers/Apps/AppPatternsController.cs +++ b/src/Squidex/Areas/Api/Controllers/Apps/AppPatternsController.cs @@ -93,7 +93,7 @@ namespace Squidex.Areas.Api.Controllers.Apps /// 404 => App not found or pattern not found. /// [HttpPut] - [Route("apps/{app}/patterns/{name}")] + [Route("apps/{app}/patterns/{id}/")] [ProducesResponseType(typeof(AppPatternDto), 201)] [ApiCosts(1)] public async Task UpdatePattern(string app, Guid id, [FromBody] UpdatePatternDto request) diff --git a/src/Squidex/Config/Domain/SerializationServices.cs b/src/Squidex/Config/Domain/SerializationServices.cs index bbbd00046..90ab4167c 100644 --- a/src/Squidex/Config/Domain/SerializationServices.cs +++ b/src/Squidex/Config/Domain/SerializationServices.cs @@ -43,6 +43,7 @@ namespace Squidex.Config.Domain settings.ContractResolver = new ConverterContractResolver( new AppClientsConverter(), new AppContributorsConverter(), + new AppPatternsConverter(), new ClaimsPrincipalConverter(), new InstantConverter(), new LanguageConverter(), diff --git a/src/Squidex/app/features/schemas/pages/schema/types/string-validation.component.ts b/src/Squidex/app/features/schemas/pages/schema/types/string-validation.component.ts index bf00e09dd..4c0b8750a 100644 --- a/src/Squidex/app/features/schemas/pages/schema/types/string-validation.component.ts +++ b/src/Squidex/app/features/schemas/pages/schema/types/string-validation.component.ts @@ -80,6 +80,8 @@ export class StringValidationComponent implements OnDestroy, OnInit { } this.setPatternName(); }); + + this.setPatternName(); } public setPattern(pattern: AppPatternDto) { diff --git a/src/Squidex/app/features/settings/declarations.ts b/src/Squidex/app/features/settings/declarations.ts index ee83aef2c..4bbde478f 100644 --- a/src/Squidex/app/features/settings/declarations.ts +++ b/src/Squidex/app/features/settings/declarations.ts @@ -10,6 +10,8 @@ export * from './pages/clients/clients-page.component'; export * from './pages/contributors/contributors-page.component'; export * from './pages/languages/language.component'; export * from './pages/languages/languages-page.component'; +export * from './pages/patterns/pattern.component'; +export * from './pages/patterns/patterns-page.component'; export * from './pages/plans/plans-page.component'; export * from './settings-area.component'; \ No newline at end of file diff --git a/src/Squidex/app/features/settings/module.ts b/src/Squidex/app/features/settings/module.ts index e2be986c4..281a4489f 100644 --- a/src/Squidex/app/features/settings/module.ts +++ b/src/Squidex/app/features/settings/module.ts @@ -22,6 +22,8 @@ import { ContributorsPageComponent, LanguageComponent, LanguagesPageComponent, + PatternComponent, + PatternsPageComponent, PlansPageComponent, SettingsAreaComponent } from './declarations'; @@ -97,6 +99,26 @@ const routes: Routes = [ } } ] + }, + { + path: 'patterns', + component: PatternsPageComponent, + children: [ + { + path: 'history', + component: HistoryComponent, + data: { + channel: 'settings.patterns' + } + }, + { + path: 'help', + component: HelpComponent, + data: { + helpPage: '05-integrated/patterns' + } + } + ] } ] } @@ -115,6 +137,8 @@ const routes: Routes = [ ContributorsPageComponent, LanguageComponent, LanguagesPageComponent, + PatternComponent, + PatternsPageComponent, PlansPageComponent, SettingsAreaComponent ] diff --git a/src/Squidex/app/features/settings/pages/patterns/pattern.component.html b/src/Squidex/app/features/settings/pages/patterns/pattern.component.html new file mode 100644 index 000000000..51913da2b --- /dev/null +++ b/src/Squidex/app/features/settings/pages/patterns/pattern.component.html @@ -0,0 +1,45 @@ +
+
+
+ + + + +
+ +
+ + + +
+ +
+ + + +
+ +
+ + + +
+ +
+ + + +
+
+
\ No newline at end of file diff --git a/src/Squidex/app/features/settings/pages/patterns/pattern.component.scss b/src/Squidex/app/features/settings/pages/patterns/pattern.component.scss new file mode 100644 index 000000000..d5c22dda1 --- /dev/null +++ b/src/Squidex/app/features/settings/pages/patterns/pattern.component.scss @@ -0,0 +1,13 @@ +@import '_vars'; +@import '_mixins'; + +.col-options { + min-width: 7.5rem; + max-width: 7.5rem; +} + +.col-name, +.col-message { + min-width: 10rem; + max-width: 10rem; +} \ No newline at end of file diff --git a/src/Squidex/app/features/settings/pages/patterns/pattern.component.ts b/src/Squidex/app/features/settings/pages/patterns/pattern.component.ts new file mode 100644 index 000000000..41d612573 --- /dev/null +++ b/src/Squidex/app/features/settings/pages/patterns/pattern.component.ts @@ -0,0 +1,95 @@ +/* + * Squidex Headless CMS + * + * @license + * Copyright (c) Sebastian Stehle. All rights reserved + */ + +import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core'; +import { FormBuilder, Validators } from '@angular/forms'; + +import { + AppPatternDto, + fadeAnimation, + ValidatorsEx, + UpdatePatternDto +} from 'shared'; + +@Component({ + selector: 'sqx-pattern', + styleUrls: ['./pattern.component.scss'], + templateUrl: './pattern.component.html', + animations: [ + fadeAnimation + ] +}) +export class PatternComponent implements OnInit { + @Input() + public isNew = false; + + @Input() + public pattern: AppPatternDto; + + @Output() + public removing = new EventEmitter(); + + @Output() + public updating = new EventEmitter(); + + public editFormSubmitted = false; + public editForm = + this.formBuilder.group({ + name: [ + '', + [ + Validators.required, + Validators.maxLength(100), + ValidatorsEx.pattern('[A-z0-9]+[A-z0-9\- ]*[A-z0-9]', 'Name can only contain letters, numbers, dashes and spaces.') + ] + ], + pattern: [ + '', + [ + Validators.required + ] + ], + message: [ + '', + [ + Validators.maxLength(1000) + ] + ] + }); + + constructor( + private readonly formBuilder: FormBuilder + ) { + } + + public ngOnInit() { + const pattern = this.pattern; + + if (pattern) { + this.editForm.setValue({ name: pattern.name, pattern: pattern.pattern, message: pattern.message || '' }); + } + } + + public cancel() { + this.editFormSubmitted = false; + this.editForm.reset(); + } + + public save() { + this.editFormSubmitted = true; + + if (this.editForm.valid) { + const requestDto = new UpdatePatternDto( + this.editForm.controls['name'].value, + this.editForm.controls['pattern'].value, + this.editForm.controls['message'].value); + + this.updating.emit(requestDto); + } + } +} + diff --git a/src/Squidex/app/features/settings/pages/patterns/patterns-page.component.html b/src/Squidex/app/features/settings/pages/patterns/patterns-page.component.html new file mode 100644 index 000000000..433c42aa8 --- /dev/null +++ b/src/Squidex/app/features/settings/pages/patterns/patterns-page.component.html @@ -0,0 +1,41 @@ + + + +
+
+

Patterns

+
+ + + + +
+ +
+
+
+
+ + +
+ + +
+
+ + + +
+
+ + \ No newline at end of file diff --git a/src/Squidex/app/features/settings/pages/patterns/patterns-page.component.scss b/src/Squidex/app/features/settings/pages/patterns/patterns-page.component.scss new file mode 100644 index 000000000..fbb752506 --- /dev/null +++ b/src/Squidex/app/features/settings/pages/patterns/patterns-page.component.scss @@ -0,0 +1,2 @@ +@import '_vars'; +@import '_mixins'; \ No newline at end of file diff --git a/src/Squidex/app/features/settings/pages/patterns/patterns-page.component.ts b/src/Squidex/app/features/settings/pages/patterns/patterns-page.component.ts new file mode 100644 index 000000000..d7e9868c2 --- /dev/null +++ b/src/Squidex/app/features/settings/pages/patterns/patterns-page.component.ts @@ -0,0 +1,87 @@ +/* + * Squidex Headless CMS + * + * @license + * Copyright (c) Sebastian Stehle. All rights reserved + */ + +import { Component, OnInit } from '@angular/core'; + +import { + AppContext, + AppPatternDto, + AppPatternsDto, + AppPatternsService, + HistoryChannelUpdated, + UpdatePatternDto +} from 'shared'; + +@Component({ + selector: 'sqx-patterns-page', + styleUrls: ['./patterns-page.component.scss'], + templateUrl: './patterns-page.component.html', + providers: [ + AppContext + ] +}) +export class PatternsPageComponent implements OnInit { + public appPatterns: AppPatternsDto; + + constructor(public readonly ctx: AppContext, + private readonly appPatternsService: AppPatternsService + ) { + } + + public ngOnInit() { + this.load(); + } + + public load() { + this.appPatternsService.getPatterns(this.ctx.appName).retry(2) + .subscribe(dtos => { + this.updatePatterns(dtos); + }, error => { + this.ctx.notifyError(error); + }); + } + + public addPattern(pattern: AppPatternDto) { + const requestDto = new UpdatePatternDto(pattern.name, pattern.pattern, pattern.message); + + this.appPatternsService.postPattern(this.ctx.appName, requestDto, this.appPatterns.version) + .subscribe(dto => { + this.updatePatterns(this.appPatterns.addPattern(dto.payload, dto.version)); + }, error => { + this.ctx.notifyError(error); + }); + } + + public updatePattern(pattern: AppPatternDto, update: UpdatePatternDto) { + this.appPatternsService.putPattern(this.ctx.appName, pattern.patternId, update, this.appPatterns.version) + .subscribe(dto => { + this.updatePatterns(this.appPatterns.updatePattern(pattern.update(update), dto.version)); + }, error => { + this.ctx.notifyError(error); + }); + } + + public removePattern(pattern: AppPatternDto) { + this.appPatternsService.deletePattern(this.ctx.appName, pattern.patternId, this.appPatterns.version) + .subscribe(dto => { + this.updatePatterns(this.appPatterns.deletePattern(pattern, dto.version)); + }, error => { + this.ctx.notifyError(error); + }); + } + + private updatePatterns(patterns: AppPatternsDto) { + this.appPatterns = + new AppPatternsDto( + patterns.patterns.sort((a, b) => { + return a.name.localeCompare(b.name); + }), + patterns.version); + + this.ctx.bus.emit(new HistoryChannelUpdated()); + } +} \ No newline at end of file diff --git a/src/Squidex/app/features/settings/settings-area.component.html b/src/Squidex/app/features/settings/settings-area.component.html index 7dd011dad..65954946d 100644 --- a/src/Squidex/app/features/settings/settings-area.component.html +++ b/src/Squidex/app/features/settings/settings-area.component.html @@ -32,6 +32,12 @@ +