From f2e8c010bc82627594775bbc03d738604373324d Mon Sep 17 00:00:00 2001 From: Sebastian Stehle Date: Wed, 28 Mar 2018 21:12:45 +0200 Subject: [PATCH] Take the guards back. --- .../features/administration/declarations.ts | 3 + .../administration/guards/unset-user.guard.ts | 24 +++++++ .../guards/user-must-exist.guard.ts | 38 ++++++++++ .../app/features/administration/module.ts | 16 +++-- .../pages/users/user-page.component.html | 65 +++++++++-------- .../pages/users/user-page.component.ts | 24 +++---- .../pages/users/users-page.component.html | 2 +- .../pages/users/users-page.component.ts | 5 +- .../administration/state/users.state.ts | 15 ++-- .../app/features/api/api-area.component.html | 4 +- .../app/features/api/api-area.component.ts | 9 +-- .../pages/graphql/graphql-page.component.html | 2 +- .../pages/graphql/graphql-page.component.ts | 10 ++- .../apps/pages/apps-page.component.html | 10 ++- .../apps/pages/apps-page.component.ts | 13 ++-- .../schemas/guards/schema-must-exist.guard.ts | 8 +-- src/Squidex/app/features/schemas/module.ts | 23 +------ .../app/features/schemas/pages/messages.ts | 2 +- .../pages/schema/field-wizard.component.html | 2 +- .../pages/schema/field-wizard.component.ts | 6 +- .../schemas/pages/schema/field.component.ts | 8 ++- .../pages/schema/schema-page.component.html | 22 +----- .../pages/schema/schema-page.component.scss | 2 +- .../pages/schema/schema-page.component.ts | 19 ++--- .../pages/schemas/schema-form.component.html | 2 +- .../pages/schemas/schema-form.component.ts | 7 +- .../pages/schemas/schemas-page.component.ts | 28 ++++++-- .../features/schemas/state/schemas.state.ts | 69 +++++++++++-------- .../framework/angular/root-view.component.ts | 2 +- .../app/shared/services/schemas.service.ts | 2 +- src/Squidex/app/shared/state/apps.state.ts | 4 ++ 31 files changed, 252 insertions(+), 194 deletions(-) create mode 100644 src/Squidex/app/features/administration/guards/unset-user.guard.ts create mode 100644 src/Squidex/app/features/administration/guards/user-must-exist.guard.ts diff --git a/src/Squidex/app/features/administration/declarations.ts b/src/Squidex/app/features/administration/declarations.ts index c09ac77a5..6be8c6e4f 100644 --- a/src/Squidex/app/features/administration/declarations.ts +++ b/src/Squidex/app/features/administration/declarations.ts @@ -7,6 +7,9 @@ export * from './administration-area.component'; +export * from './guards/user-must-exist.guard'; +export * from './guards/unset-user.guard'; + export * from './pages/event-consumers/event-consumers-page.component'; export * from './pages/users/user-page.component'; export * from './pages/users/users-page.component'; diff --git a/src/Squidex/app/features/administration/guards/unset-user.guard.ts b/src/Squidex/app/features/administration/guards/unset-user.guard.ts new file mode 100644 index 000000000..4acf14c0d --- /dev/null +++ b/src/Squidex/app/features/administration/guards/unset-user.guard.ts @@ -0,0 +1,24 @@ +/* + * Squidex Headless CMS + * + * @license + * Copyright (c) Squidex UG (haftungsbeschränkt). All rights reserved. + */ + +import { Injectable } from '@angular/core'; +import { ActivatedRouteSnapshot, CanActivate, RouterStateSnapshot } from '@angular/router'; +import { Observable } from 'rxjs'; + +import { UsersState } from './../state/users.state'; + +@Injectable() +export class UnsetUserGuard implements CanActivate { + constructor( + private readonly usersState: UsersState + ) { + } + + public canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable { + return this.usersState.selectUser(null).map(u => u === null); + } +} \ No newline at end of file diff --git a/src/Squidex/app/features/administration/guards/user-must-exist.guard.ts b/src/Squidex/app/features/administration/guards/user-must-exist.guard.ts new file mode 100644 index 000000000..97887dc24 --- /dev/null +++ b/src/Squidex/app/features/administration/guards/user-must-exist.guard.ts @@ -0,0 +1,38 @@ +/* + * Squidex Headless CMS + * + * @license + * Copyright (c) Squidex UG (haftungsbeschränkt). All rights reserved. + */ + +import { Injectable } from '@angular/core'; +import { ActivatedRouteSnapshot, CanActivate, Router, RouterStateSnapshot } from '@angular/router'; +import { Observable } from 'rxjs'; + +import { allParams } from 'framework'; + +import { UsersState } from './../state/users.state'; + +@Injectable() +export class UserMustExistGuard implements CanActivate { + constructor( + private readonly usersState: UsersState, + private readonly router: Router + ) { + } + + public canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable { + const userId = allParams(route)['userId']; + + const result = + this.usersState.selectUser(userId) + .do(dto => { + if (!dto) { + this.router.navigate(['/404']); + } + }) + .map(u => u !== null); + + return result; + } +} \ No newline at end of file diff --git a/src/Squidex/app/features/administration/module.ts b/src/Squidex/app/features/administration/module.ts index c2998f693..19b96d8f5 100644 --- a/src/Squidex/app/features/administration/module.ts +++ b/src/Squidex/app/features/administration/module.ts @@ -17,9 +17,12 @@ import { AdministrationAreaComponent, EventConsumersPageComponent, EventConsumersService, + UnsetUserGuard, + UserMustExistGuard, UserPageComponent, UsersPageComponent, - UsersService + UsersService, + UsersState } from './declarations'; const routes: Routes = [ @@ -40,11 +43,13 @@ const routes: Routes = [ children: [ { path: 'new', - component: UserPageComponent + component: UserPageComponent, + canActivate: [UnsetUserGuard] }, { path: ':userId', - component: UserPageComponent + component: UserPageComponent, + canActivate: [UserMustExistGuard] } ] } @@ -68,7 +73,10 @@ const routes: Routes = [ ], providers: [ EventConsumersService, - UsersService + UnsetUserGuard, + UserMustExistGuard, + UsersService, + UsersState ] }) export class SqxFeatureAdministrationModule { } \ No newline at end of file diff --git a/src/Squidex/app/features/administration/pages/users/user-page.component.html b/src/Squidex/app/features/administration/pages/users/user-page.component.html index 87ee15bc7..99f3a15f9 100644 --- a/src/Squidex/app/features/administration/pages/users/user-page.component.html +++ b/src/Squidex/app/features/administration/pages/users/user-page.component.html @@ -1,24 +1,27 @@
- +
-
+
- + -

- {{isNotFound || user ? 'Edit User' : 'New User'}} +

+ New User +

+

+ Edit User

- + @@ -28,46 +31,40 @@
-
- The user does not exist. +
+
-
-
-
-
+
+ -
- - - + - -
-
- + +
+
+ - + - -
+ +
-
-
- +
+
+ - + - -
+ +
-
- +
+ - + - -
+
diff --git a/src/Squidex/app/features/administration/pages/users/user-page.component.ts b/src/Squidex/app/features/administration/pages/users/user-page.component.ts index d0d9c2262..1fb3bef80 100644 --- a/src/Squidex/app/features/administration/pages/users/user-page.component.ts +++ b/src/Squidex/app/features/administration/pages/users/user-page.component.ts @@ -5,9 +5,10 @@ * Copyright (c) Squidex UG (haftungsbeschränkt). All rights reserved. */ -import { Component, OnInit } from '@angular/core'; +import { Component, OnDestroy, OnInit } from '@angular/core'; import { FormBuilder, Validators } from '@angular/forms'; import { ActivatedRoute, Router } from '@angular/router'; +import { Subscription } from 'rxjs'; import { AuthService, ValidatorsEx } from 'shared'; @@ -19,7 +20,9 @@ import { UsersState } from './../../state/users.state'; styleUrls: ['./user-page.component.scss'], templateUrl: './user-page.component.html' }) -export class UserPageComponent implements OnInit { +export class UserPageComponent implements OnDestroy, OnInit { + private selectedUserSubscription: Subscription; + public userFormSubmitted = false; public userFormError = ''; public userForm = @@ -48,7 +51,6 @@ export class UserPageComponent implements OnInit { public user: UserDto | null; public isCurrentUser = false; - public isNotFound = false; constructor( private readonly authService: AuthService, @@ -59,14 +61,13 @@ export class UserPageComponent implements OnInit { ) { } - public ngOnInit() { - this.route.params.map(p => p['userId']) - .switchMap(id => this.usersState.selectUser(id).map(u => { return { user: u, expected: !!id }; })) - .subscribe(result => { - this.isNotFound = !result.user && result.expected; + public ngOnDestroy() { + this.selectedUserSubscription.unsubscribe(); + } - this.setupAndPopulateForm(result.user); - }); + public ngOnInit() { + this.selectedUserSubscription = + this.usersState.selectedUser.subscribe(user => this.setupAndPopulateForm(user!)); } public save() { @@ -118,9 +119,8 @@ export class UserPageComponent implements OnInit { private resetFormState(message: string = '') { this.userFormSubmitted = false; this.userFormError = message; - this.userForm.enable(); this.userForm.controls['password'].reset(); this.userForm.controls['passwordConfirm'].reset(); + this.userForm.enable(); } } - diff --git a/src/Squidex/app/features/administration/pages/users/users-page.component.html b/src/Squidex/app/features/administration/pages/users/users-page.component.html index 56a1093a8..6c98f9f7b 100644 --- a/src/Squidex/app/features/administration/pages/users/users-page.component.html +++ b/src/Squidex/app/features/administration/pages/users/users-page.component.html @@ -76,7 +76,7 @@ - diff --git a/src/Squidex/app/features/administration/pages/users/users-page.component.ts b/src/Squidex/app/features/administration/pages/users/users-page.component.ts index 8fc39ff52..902068c7b 100644 --- a/src/Squidex/app/features/administration/pages/users/users-page.component.ts +++ b/src/Squidex/app/features/administration/pages/users/users-page.component.ts @@ -16,10 +16,7 @@ import { UsersState } from './../../state/users.state'; @Component({ selector: 'sqx-users-page', styleUrls: ['./users-page.component.scss'], - templateUrl: './users-page.component.html', - providers: [ - UsersState - ] + templateUrl: './users-page.component.html' }) export class UsersPageComponent implements OnInit { public usersFilter = new FormControl(); diff --git a/src/Squidex/app/features/administration/state/users.state.ts b/src/Squidex/app/features/administration/state/users.state.ts index 86e7b19a0..a70e68f98 100644 --- a/src/Squidex/app/features/administration/state/users.state.ts +++ b/src/Squidex/app/features/administration/state/users.state.ts @@ -37,8 +37,14 @@ export class UsersState { } public selectUser(id: string | null): Observable { - const observable = - !id ? + return this.loadUser(id) + .do(user => { + this.selectedUser.next(user); + }); + } + + private loadUser(id: string | null) { + return !id ? Observable.of(null) : Observable.of(this.users.value.find(x => x.id === id)) .switchMap(user => { @@ -48,11 +54,6 @@ export class UsersState { return Observable.of(user); } }); - - return observable - .do(user => { - this.selectedUser.next(user); - }); } public loadUsers(): Observable { diff --git a/src/Squidex/app/features/api/api-area.component.html b/src/Squidex/app/features/api/api-area.component.html index 59c48ccf6..1aa702dea 100644 --- a/src/Squidex/app/features/api/api-area.component.html +++ b/src/Squidex/app/features/api/api-area.component.html @@ -1,4 +1,4 @@ - +
@@ -21,7 +21,7 @@ diff --git a/src/Squidex/app/features/api/api-area.component.ts b/src/Squidex/app/features/api/api-area.component.ts index 093dee1c4..446dfdd57 100644 --- a/src/Squidex/app/features/api/api-area.component.ts +++ b/src/Squidex/app/features/api/api-area.component.ts @@ -7,19 +7,16 @@ import { Component } from '@angular/core'; -import { AppContext } from 'shared'; +import { AppsState } from 'shared'; @Component({ selector: 'sqx-api-area', styleUrls: ['./api-area.component.scss'], - templateUrl: './api-area.component.html', - providers: [ - AppContext - ] + templateUrl: './api-area.component.html' }) export class ApiAreaComponent { constructor( - public readonly ctx: AppContext + public readonly appsState: AppsState ) { } } \ No newline at end of file diff --git a/src/Squidex/app/features/api/pages/graphql/graphql-page.component.html b/src/Squidex/app/features/api/pages/graphql/graphql-page.component.html index ff2fc5573..579a1b0a3 100644 --- a/src/Squidex/app/features/api/pages/graphql/graphql-page.component.html +++ b/src/Squidex/app/features/api/pages/graphql/graphql-page.component.html @@ -1,4 +1,4 @@ - +
diff --git a/src/Squidex/app/features/api/pages/graphql/graphql-page.component.ts b/src/Squidex/app/features/api/pages/graphql/graphql-page.component.ts index c410caaeb..824d6acf0 100644 --- a/src/Squidex/app/features/api/pages/graphql/graphql-page.component.ts +++ b/src/Squidex/app/features/api/pages/graphql/graphql-page.component.ts @@ -16,7 +16,7 @@ const GraphiQL = require('graphiql'); /* tslint:disable:use-view-encapsulation */ import { - AppContext, + AppsState, GraphQlService, LocalStoreService } from 'shared'; @@ -25,16 +25,14 @@ import { selector: 'sqx-graphql-page', styleUrls: ['./graphql-page.component.scss'], templateUrl: './graphql-page.component.html', - providers: [ - AppContext - ], encapsulation: ViewEncapsulation.None }) export class GraphQLPageComponent implements OnInit { @ViewChild('graphiQLContainer') public graphiQLContainer: ElementRef; - constructor(public readonly ctx: AppContext, + constructor( + public readonly appsState: AppsState, private readonly graphQlService: GraphQlService, private readonly localStoreService: LocalStoreService ) { @@ -56,7 +54,7 @@ export class GraphQLPageComponent implements OnInit { } private request(params: any) { - return this.graphQlService.query(this.ctx.appName, params).catch(response => Observable.of(response.error)).toPromise(); + return this.graphQlService.query(this.appsState.appName, params).catch(response => Observable.of(response.error)).toPromise(); } } diff --git a/src/Squidex/app/features/apps/pages/apps-page.component.html b/src/Squidex/app/features/apps/pages/apps-page.component.html index f3e283566..4df3797e0 100644 --- a/src/Squidex/app/features/apps/pages/apps-page.component.html +++ b/src/Squidex/app/features/apps/pages/apps-page.component.html @@ -1,7 +1,7 @@ 
-

Hi {{ctx.user.displayName}}

+

Hi {{authState.user?.displayName}}

Welcome to Squidex. @@ -49,7 +49,9 @@
Start with our ready to use blog.
-
Sample Code: ASP.NET Core
+
+ Sample Code: C# +
@@ -64,7 +66,9 @@
Create your profile page.
-
Sample Code: ASP.NET Core
+
+ Sample Code: C# +
diff --git a/src/Squidex/app/features/apps/pages/apps-page.component.ts b/src/Squidex/app/features/apps/pages/apps-page.component.ts index b90153f27..146b4ebc3 100644 --- a/src/Squidex/app/features/apps/pages/apps-page.component.ts +++ b/src/Squidex/app/features/apps/pages/apps-page.component.ts @@ -9,9 +9,9 @@ import { Component, OnDestroy, OnInit } from '@angular/core'; import { Subscription } from 'rxjs'; import { - AppContext, AppDto, AppsState, + AuthService, fadeAnimation, ImmutableArray, ModalView, @@ -22,9 +22,6 @@ import { selector: 'sqx-apps-page', styleUrls: ['./apps-page.component.scss'], templateUrl: './apps-page.component.html', - providers: [ - AppContext - ], animations: [ fadeAnimation ] @@ -35,13 +32,13 @@ export class AppsPageComponent implements OnDestroy, OnInit { public addAppDialog = new ModalView(); public apps: ImmutableArray; - public apptemplate = ''; + public appTemplate = ''; public onboardingModal = new ModalView(); constructor( - public readonly ctx: AppContext, - private readonly appsState: AppsState, + public readonly appsState: AppsState, + public readonly authState: AuthService, private readonly onboardingService: OnboardingService ) { } @@ -64,7 +61,7 @@ export class AppsPageComponent implements OnDestroy, OnInit { } public createNewApp(template: string) { - this.apptemplate = template; + this.appTemplate = template; this.addAppDialog.show(); } diff --git a/src/Squidex/app/features/schemas/guards/schema-must-exist.guard.ts b/src/Squidex/app/features/schemas/guards/schema-must-exist.guard.ts index 17fb39753..4fd7e92c0 100644 --- a/src/Squidex/app/features/schemas/guards/schema-must-exist.guard.ts +++ b/src/Squidex/app/features/schemas/guards/schema-must-exist.guard.ts @@ -22,13 +22,7 @@ export class SchemaMustExistGuard implements CanActivate { } public canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable { - const params = allParams(route); - - const schemaName = params['schemaName']; - - if (!schemaName) { - throw 'Route must contain schema name.'; - } + const schemaName = allParams(route)['schemaName']; const result = this.schemasState.selectSchema(schemaName) diff --git a/src/Squidex/app/features/schemas/module.ts b/src/Squidex/app/features/schemas/module.ts index df20569fd..1cf021032 100644 --- a/src/Squidex/app/features/schemas/module.ts +++ b/src/Squidex/app/features/schemas/module.ts @@ -10,8 +10,6 @@ import { RouterModule, Routes } from '@angular/router'; import { DndModule } from 'ng2-dnd'; import { - HelpComponent, - HistoryComponent, SqxFrameworkModule, SqxSharedModule } from 'shared'; @@ -54,29 +52,10 @@ const routes: Routes = [ path: '', component: SchemasPageComponent, children: [ - { - path: '' - }, { path: ':schemaName', component: SchemaPageComponent, - canActivate: [SchemaMustExistGuard], - children: [ - { - path: 'history', - component: HistoryComponent, - data: { - channel: 'schemas.{schemaName}' - } - }, - { - path: 'help', - component: HelpComponent, - data: { - helpPage: '05-integrated/schemas' - } - } - ] + canActivate: [SchemaMustExistGuard] }] } ]; diff --git a/src/Squidex/app/features/schemas/pages/messages.ts b/src/Squidex/app/features/schemas/pages/messages.ts index f98ae6810..f0a5205ce 100644 --- a/src/Squidex/app/features/schemas/pages/messages.ts +++ b/src/Squidex/app/features/schemas/pages/messages.ts @@ -7,7 +7,7 @@ export class SchemaCloning { constructor( - public readonly importing: any + public readonly schema: any ) { } } \ No newline at end of file diff --git a/src/Squidex/app/features/schemas/pages/schema/field-wizard.component.html b/src/Squidex/app/features/schemas/pages/schema/field-wizard.component.html index 29d1b6b73..b036f7732 100644 --- a/src/Squidex/app/features/schemas/pages/schema/field-wizard.component.html +++ b/src/Squidex/app/features/schemas/pages/schema/field-wizard.component.html @@ -42,7 +42,7 @@
- +
diff --git a/src/Squidex/app/features/schemas/pages/schema/field-wizard.component.ts b/src/Squidex/app/features/schemas/pages/schema/field-wizard.component.ts index 79a2470fe..d9f742941 100644 --- a/src/Squidex/app/features/schemas/pages/schema/field-wizard.component.ts +++ b/src/Squidex/app/features/schemas/pages/schema/field-wizard.component.ts @@ -10,7 +10,6 @@ import { FormBuilder, Validators, FormGroup } from '@angular/forms'; import { AddFieldDto, - AppContext, createProperties, fadeAnimation, FieldDto, @@ -26,9 +25,6 @@ import { SchemasState } from './../../state/schemas.state'; selector: 'sqx-field-wizard', styleUrls: ['./field-wizard.component.scss'], templateUrl: './field-wizard.component.html', - providers: [ - AppContext - ], animations: [ fadeAnimation ] @@ -146,9 +142,9 @@ export class FieldWizardComponent { private resetFieldForm(error = '') { this.addFieldFormSubmitted = false; + this.addFieldError = error; this.addFieldForm.enable(); this.addFieldForm.reset({ type: 'String' }, { emitEvent: false }); - this.addFieldError = error; } } diff --git a/src/Squidex/app/features/schemas/pages/schema/field.component.ts b/src/Squidex/app/features/schemas/pages/schema/field.component.ts index 2cf881a6e..e583f0658 100644 --- a/src/Squidex/app/features/schemas/pages/schema/field.component.ts +++ b/src/Squidex/app/features/schemas/pages/schema/field.component.ts @@ -93,19 +93,21 @@ export class FieldComponent implements OnInit { if (this.editForm.valid) { const properties = createProperties(this.field.properties['fieldType'], this.editForm.value); - this.schemasState.updateField(this.schema, this.field, new UpdateFieldDto(properties)).subscribe(); + this.schemasState.updateField(this.schema, this.field, new UpdateFieldDto(properties)) + .subscribe(() => { + this.resetEditForm(); + }); } } private resetEditForm() { + this.isEditing = false; this.editFormSubmitted = false; this.editForm.reset(this.field.properties); if (this.field.isLocked) { this.editForm.disable(); } - - this.isEditing = false; } } diff --git a/src/Squidex/app/features/schemas/pages/schema/schema-page.component.html b/src/Squidex/app/features/schemas/pages/schema/schema-page.component.html index a2ec7bcbe..74d3f1b1d 100644 --- a/src/Squidex/app/features/schemas/pages/schema/schema-page.component.html +++ b/src/Squidex/app/features/schemas/pages/schema/schema-page.component.html @@ -1,4 +1,4 @@ - +
@@ -68,22 +68,6 @@
Add Field
-
- - - - - - - - - The sidebar navigation contains useful context specific links. Here you can view the history how this schema has changed over time. - - - - Click the help icon to show a context specific help page. Go to https://docs.squidex.io for the full documentation. - -
@@ -128,6 +112,4 @@
- - - \ No newline at end of file + \ No newline at end of file diff --git a/src/Squidex/app/features/schemas/pages/schema/schema-page.component.scss b/src/Squidex/app/features/schemas/pages/schema/schema-page.component.scss index 4fa6a89d5..2c51ef5e1 100644 --- a/src/Squidex/app/features/schemas/pages/schema/schema-page.component.scss +++ b/src/Squidex/app/features/schemas/pages/schema/schema-page.component.scss @@ -40,7 +40,7 @@ & { @include circle(5.25rem); @include box-shadow(0, 8px, 16px, .3); - @include absolute(auto, 6.5rem, 1rem, auto); + @include absolute(auto, 2rem, 1rem, auto); } &-icon { diff --git a/src/Squidex/app/features/schemas/pages/schema/schema-page.component.ts b/src/Squidex/app/features/schemas/pages/schema/schema-page.component.ts index 2e87c474e..3ea3797d1 100644 --- a/src/Squidex/app/features/schemas/pages/schema/schema-page.component.ts +++ b/src/Squidex/app/features/schemas/pages/schema/schema-page.component.ts @@ -6,14 +6,15 @@ */ import { Component, OnDestroy, OnInit } from '@angular/core'; -import { Router } from '@angular/router'; +import { ActivatedRoute, Router } from '@angular/router'; import { Subscription } from 'rxjs'; import { - AppContext, + AppsState, fadeAnimation, FieldDto, fieldTypes, + MessageBus, ModalView, SchemaDetailsDto } from 'shared'; @@ -28,9 +29,6 @@ import { SchemasState } from './../../state/schemas.state'; selector: 'sqx-schema-page', styleUrls: ['./schema-page.component.scss'], templateUrl: './schema-page.component.html', - providers: [ - AppContext - ], animations: [ fadeAnimation ] @@ -52,9 +50,12 @@ export class SchemaPageComponent implements OnDestroy, OnInit { public addFieldDialog = new ModalView(); - constructor(public readonly ctx: AppContext, + constructor( + public readonly appsState: AppsState, + public readonly schemasState: SchemasState, + private readonly route: ActivatedRoute, private readonly router: Router, - private readonly schemasState: SchemasState + private readonly messageBus: MessageBus ) { } @@ -92,7 +93,7 @@ export class SchemaPageComponent implements OnDestroy, OnInit { } public cloneSchema() { - this.ctx.bus.emit(new SchemaCloning(this.schemaExport)); + this.messageBus.emit(new SchemaCloning(this.schemaExport)); } private export() { @@ -127,7 +128,7 @@ export class SchemaPageComponent implements OnDestroy, OnInit { } private back() { - this.router.navigate(['../'], { relativeTo: this.ctx.route }); + this.router.navigate(['../'], { relativeTo: this.route }); } } diff --git a/src/Squidex/app/features/schemas/pages/schemas/schema-form.component.html b/src/Squidex/app/features/schemas/pages/schemas/schema-form.component.html index 92f1f1388..64e470a4f 100644 --- a/src/Squidex/app/features/schemas/pages/schemas/schema-form.component.html +++ b/src/Squidex/app/features/schemas/pages/schemas/schema-form.component.html @@ -23,7 +23,7 @@ - The schema name becomes part of the api url,
e.g {{apiUrl.buildUrl("api/content/")}}{{ctx.appName}}/{{schemaName | async}}/. + The schema name becomes part of the api url,
e.g {{apiUrl.buildUrl("api/content/")}}{{appsState.appName}}/{{schemaName | async}}/.
It must contain lower case letters (a-z), numbers and dashes only, and cannot be longer than 40 characters. The name cannot be changed later. diff --git a/src/Squidex/app/features/schemas/pages/schemas/schema-form.component.ts b/src/Squidex/app/features/schemas/pages/schemas/schema-form.component.ts index 19ed6a8f5..b5af05a25 100644 --- a/src/Squidex/app/features/schemas/pages/schemas/schema-form.component.ts +++ b/src/Squidex/app/features/schemas/pages/schemas/schema-form.component.ts @@ -8,7 +8,11 @@ import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core'; import { FormBuilder, Validators } from '@angular/forms'; -import { ApiUrlConfig, ValidatorsEx } from 'shared'; +import { + ApiUrlConfig, + AppsState, + ValidatorsEx +} from 'shared'; import { SchemasState } from './../../state/schemas.state'; @@ -47,6 +51,7 @@ export class SchemaFormComponent implements OnInit { constructor( public readonly apiUrl: ApiUrlConfig, + public readonly appsState: AppsState, private readonly schemasState: SchemasState, private readonly formBuilder: FormBuilder ) { diff --git a/src/Squidex/app/features/schemas/pages/schemas/schemas-page.component.ts b/src/Squidex/app/features/schemas/pages/schemas/schemas-page.component.ts index 0d80b8bd7..99ec3f3e3 100644 --- a/src/Squidex/app/features/schemas/pages/schemas/schemas-page.component.ts +++ b/src/Squidex/app/features/schemas/pages/schemas/schemas-page.component.ts @@ -5,16 +5,20 @@ * Copyright (c) Squidex UG (haftungsbeschränkt). All rights reserved. */ -import { Component, OnInit } from '@angular/core'; +import { Component, OnDestroy, OnInit } from '@angular/core'; import { FormControl } from '@angular/forms'; import { ActivatedRoute } from '@angular/router'; +import { Subscription } from 'rxjs'; import { AppsState, fadeAnimation, + MessageBus, ModalView } from 'shared'; +import { SchemaCloning } from './../messages'; + import { SchemasState } from './../../state/schemas.state'; @Component({ @@ -25,7 +29,9 @@ import { SchemasState } from './../../state/schemas.state'; fadeAnimation ] }) -export class SchemasPageComponent implements OnInit { +export class SchemasPageComponent implements OnDestroy, OnInit { + private schemaCloningSubscription: Subscription; + public addSchemaDialog = new ModalView(); public schemasFilter = new FormControl(); @@ -42,13 +48,27 @@ export class SchemasPageComponent implements OnInit { public import: any; - constructor(public readonly appsState: AppsState, + constructor( + public readonly appsState: AppsState, + private readonly schemasState: SchemasState, private readonly route: ActivatedRoute, - private readonly schemasState: SchemasState + private readonly messageBus: MessageBus ) { } + public ngOnDestroy() { + this.schemaCloningSubscription.unsubscribe(); + } + public ngOnInit() { + this.schemaCloningSubscription = + this.messageBus.of(SchemaCloning) + .subscribe(m => { + this.import = m.schema; + + this.addSchemaDialog.show(); + }); + this.route.params.map(q => q['showDialog']) .subscribe(showDialog => { if (showDialog) { diff --git a/src/Squidex/app/features/schemas/state/schemas.state.ts b/src/Squidex/app/features/schemas/state/schemas.state.ts index a3bd06a0f..943ce9d85 100644 --- a/src/Squidex/app/features/schemas/state/schemas.state.ts +++ b/src/Squidex/app/features/schemas/state/schemas.state.ts @@ -32,9 +32,10 @@ export class SchemasState { public schemasItems = new BehaviorSubject>(ImmutableArray.empty()); public selectedSchema = new BehaviorSubject(null); + public selectedReferencedSchema = new BehaviorSubject(null); - private get app() { - return this.appsState.selectedApp.value!.name; + private get appName() { + return this.appsState.appName; } private get user() { @@ -49,28 +50,35 @@ export class SchemasState { ) { } - public selectSchema(id: string | null): Observable { - const observable = - !id ? + public selectSchema(id: string | null): Observable { + return this.loadSchema(id) + .do(schema => { + this.selectedSchema.next(schema); + }); + } + + public selectReferencedSchema(id: string | null): Observable { + return this.loadSchema(id) + .do(schema => { + this.selectedReferencedSchema.next(schema); + }); + } + + private loadSchema(id: string | null) { + return !id ? Observable.of(null) : Observable.of(this.schemasItems.value.find(x => x.id === id && x instanceof SchemaDetailsDto)) .switchMap(schema => { if (!schema) { - return this.schemasService.getSchema(this.app, id).catch(() => Observable.of(null)); + return this.schemasService.getSchema(this.appName, id).catch(() => Observable.of(null)); } else { return Observable.of(schema); } }); - - return observable - .do(schema => { - this.selectedSchema.next(schema); - }) - .map(s => s !== null); } public load(): Observable { - return this.schemasService.getSchemas(this.app) + return this.schemasService.getSchemas(this.appName) .catch(error => this.dialogs.notifyError(error)) .do(dtos => { this.schemasItems.nextBy(v => ImmutableArray.of(dtos)); @@ -78,21 +86,21 @@ export class SchemasState { } public create(request: CreateSchemaDto) { - return this.schemasService.postSchema(this.app, request, this.user, DateTime.now()) + return this.schemasService.postSchema(this.appName, request, this.user, DateTime.now()) .do(dto => { this.schemasItems.nextBy(v => v.push(dto)); }); } public addField(schema: SchemaDetailsDto, request: AddFieldDto): Observable { - return this.schemasService.postField(this.app, schema.name, request, schema.version) + return this.schemasService.postField(this.appName, schema.name, request, schema.version) .do(dto => { this.replaceSchema(schema.addField(dto.payload, this.user, dto.version)); }).map(d => d.payload); } public publish(schema: SchemaDto): Observable { - return this.schemasService.publishSchema(this.app, schema.name, schema.version) + return this.schemasService.publishSchema(this.appName, schema.name, schema.version) .catch(error => this.dialogs.notifyError(error)) .do(dto => { this.replaceSchema(schema.publish(this.user, dto.version)); @@ -100,7 +108,7 @@ export class SchemasState { } public unpublish(schema: SchemaDto): Observable { - return this.schemasService.unpublishSchema(this.app, schema.name, schema.version) + return this.schemasService.unpublishSchema(this.appName, schema.name, schema.version) .catch(error => this.dialogs.notifyError(error)) .do(dto => { this.replaceSchema(schema.unpublish(this.user, dto.version)); @@ -108,7 +116,7 @@ export class SchemasState { } public enableField(schema: SchemaDetailsDto, field: FieldDto): Observable { - return this.schemasService.enableField(this.app, schema.name, field.fieldId, schema.version) + return this.schemasService.enableField(this.appName, schema.name, field.fieldId, schema.version) .catch(error => this.dialogs.notifyError(error)) .do(dto => { this.replaceSchema(schema.updateField(field.enable(), this.user, dto.version)); @@ -116,7 +124,7 @@ export class SchemasState { } public disableField(schema: SchemaDetailsDto, field: FieldDto): Observable { - return this.schemasService.disableField(this.app, schema.name, field.fieldId, schema.version) + return this.schemasService.disableField(this.appName, schema.name, field.fieldId, schema.version) .catch(error => this.dialogs.notifyError(error)) .do(dto => { this.replaceSchema(schema.updateField(field.disable(), this.user, dto.version)); @@ -124,7 +132,7 @@ export class SchemasState { } public lockField(schema: SchemaDetailsDto, field: FieldDto): Observable { - return this.schemasService.lockField(this.app, schema.name, field.fieldId, schema.version) + return this.schemasService.lockField(this.appName, schema.name, field.fieldId, schema.version) .catch(error => this.dialogs.notifyError(error)) .do(dto => { this.replaceSchema(schema.updateField(field.lock(), this.user, dto.version)); @@ -132,7 +140,7 @@ export class SchemasState { } public showField(schema: SchemaDetailsDto, field: FieldDto): Observable { - return this.schemasService.showField(this.app, schema.name, field.fieldId, schema.version) + return this.schemasService.showField(this.appName, schema.name, field.fieldId, schema.version) .catch(error => this.dialogs.notifyError(error)) .do(dto => { this.replaceSchema(schema.updateField(field.show(), this.user, dto.version)); @@ -140,7 +148,7 @@ export class SchemasState { } public hideField(schema: SchemaDetailsDto, field: FieldDto): Observable { - return this.schemasService.hideField(this.app, schema.name, field.fieldId, schema.version) + return this.schemasService.hideField(this.appName, schema.name, field.fieldId, schema.version) .catch(error => this.dialogs.notifyError(error)) .do(dto => { this.replaceSchema(schema.updateField(field.hide(), this.user, dto.version)); @@ -148,7 +156,7 @@ export class SchemasState { } public deleteField(schema: SchemaDetailsDto, field: FieldDto): Observable { - return this.schemasService.deleteField(this.app, schema.name, field.fieldId, schema.version) + return this.schemasService.deleteField(this.appName, schema.name, field.fieldId, schema.version) .catch(error => this.dialogs.notifyError(error)) .do(dto => { this.replaceSchema(schema.removeField(field, this.user, dto.version)); @@ -156,7 +164,7 @@ export class SchemasState { } public sortFields(schema: SchemaDetailsDto, fields: FieldDto[]): Observable { - return this.schemasService.putFieldOrdering(this.app, schema.name, fields.map(t => t.fieldId), schema.version) + return this.schemasService.putFieldOrdering(this.appName, schema.name, fields.map(t => t.fieldId), schema.version) .catch(error => this.dialogs.notifyError(error)) .do(dto => { this.replaceSchema(schema.replaceFields(fields, this.user, dto.version)); @@ -164,7 +172,7 @@ export class SchemasState { } public updateField(schema: SchemaDetailsDto, field: FieldDto, request: UpdateFieldDto): Observable { - return this.schemasService.putField(this.app, schema.name, field.fieldId, request, schema.version) + return this.schemasService.putField(this.appName, schema.name, field.fieldId, request, schema.version) .catch(error => this.dialogs.notifyError(error)) .do(dto => { this.replaceSchema(schema.updateField(field.update(request.properties), this.user, dto.version)); @@ -172,7 +180,7 @@ export class SchemasState { } public configureScripts(schema: SchemaDetailsDto, request: UpdateSchemaScriptsDto): Observable { - return this.schemasService.putSchemaScripts(this.app, schema.name, request, schema.version) + return this.schemasService.putSchemaScripts(this.appName, schema.name, request, schema.version) .catch(error => this.dialogs.notifyError(error)) .do(dto => { this.replaceSchema(schema.configureScripts(request, this.user, dto.version)); @@ -180,7 +188,7 @@ export class SchemasState { } public update(schema: SchemaDetailsDto, request: UpdateSchemaDto): Observable { - return this.schemasService.putSchema(this.app, schema.name, request, schema.version) + return this.schemasService.putSchema(this.appName, schema.name, request, schema.version) .catch(error => this.dialogs.notifyError(error)) .do(dto => { this.replaceSchema(schema.update(request, this.user, dto.version)); @@ -188,7 +196,7 @@ export class SchemasState { } public delete(schema: SchemaDto): Observable { - return this.schemasService.deleteSchema(this.app, schema.name, schema.version) + return this.schemasService.deleteSchema(this.appName, schema.name, schema.version) .catch(error => this.dialogs.notifyError(error)) .do(dto => { this.schemasItems.nextBy(v => v.filter(s => s.id !== schema.id)); @@ -198,7 +206,10 @@ export class SchemasState { private replaceSchema(schema: SchemaDto) { this.schemasItems.nextBy(v => v.replaceBy('id', schema)); - this.selectedSchema.nextBy(v => v !== null && v.id === schema.id ? schema : v); + if (schema instanceof SchemaDetailsDto) { + this.selectedSchema.nextBy(v => v !== null && v.id === schema.id ? schema : v); + this.selectedReferencedSchema.nextBy(v => v !== null && v.id === schema.id ? schema : v); + } } public trackBySchema(index: number, schema: SchemaDto): any { diff --git a/src/Squidex/app/framework/angular/root-view.component.ts b/src/Squidex/app/framework/angular/root-view.component.ts index a7585f234..12173faf9 100644 --- a/src/Squidex/app/framework/angular/root-view.component.ts +++ b/src/Squidex/app/framework/angular/root-view.component.ts @@ -16,6 +16,6 @@ import { Component, ViewChild, ViewContainerRef } from '@angular/core'; ` }) export class RootViewComponent { - @ViewChild('element') + @ViewChild('element', { read: ViewContainerRef }) public viewContainer: ViewContainerRef; } \ No newline at end of file diff --git a/src/Squidex/app/shared/services/schemas.service.ts b/src/Squidex/app/shared/services/schemas.service.ts index fbbfb5097..fb2889a5d 100644 --- a/src/Squidex/app/shared/services/schemas.service.ts +++ b/src/Squidex/app/shared/services/schemas.service.ts @@ -32,7 +32,7 @@ export const fieldTypes = [ description: 'Images, videos, documents.' }, { type: 'Boolean', - description: 'Yes or no, true or false, 1 or 0.' + description: 'Yes or no, true or false.' }, { type: 'DateTime', description: 'Events date, opening hours.' diff --git a/src/Squidex/app/shared/state/apps.state.ts b/src/Squidex/app/shared/state/apps.state.ts index 4c8cf3915..4af6f136f 100644 --- a/src/Squidex/app/shared/state/apps.state.ts +++ b/src/Squidex/app/shared/state/apps.state.ts @@ -25,6 +25,10 @@ export class AppsState { public selectedApp = new BehaviorSubject(null); + public get appName() { + return this.selectedApp.value!.name; + } + constructor( private readonly appsService: AppsService ) {