Browse Source

Fix for settings page. (#462)

* Fix for settings page.
pull/464/head
Sebastian Stehle 6 years ago
committed by GitHub
parent
commit
7e61a68aef
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 2
      backend/src/Squidex.Domain.Apps.Entities.MongoDb/Contents/MongoContentCollection.cs
  2. 30
      backend/src/Squidex/Areas/Api/Controllers/Apps/AppsController.cs
  3. 7
      frontend/app/features/settings/pages/more/more-page.component.ts
  4. 2
      frontend/app/framework/angular/modals/dialog-renderer.component.scss
  5. 19
      frontend/app/shared/services/apps.service.spec.ts
  6. 12
      frontend/app/shared/services/apps.service.ts
  7. 40
      frontend/app/shared/state/apps.state.spec.ts
  8. 38
      frontend/app/shared/state/apps.state.ts
  9. 2
      frontend/app/shared/state/schemas.state.spec.ts
  10. 1
      frontend/app/theme/_vars.scss

2
backend/src/Squidex.Domain.Apps.Entities.MongoDb/Contents/MongoContentCollection.cs

@ -133,7 +133,7 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.Contents
foreach (var entity in contentItems)
{
var schema = schemas.FirstOrDefault(x => x.Id == entity.IndexedSchemaId);
var schema = schemas.FirstOrDefault(x => x?.Id == entity.IndexedSchemaId);
if (schema != null)
{

30
backend/src/Squidex/Areas/Api/Controllers/Apps/AppsController.cs

@ -81,6 +81,8 @@ namespace Squidex.Areas.Api.Controllers.Apps
var response = Deferred.Response(() =>
{
var userPermissions = HttpContext.Permissions();
return apps.OrderBy(x => x.Name).Select(a => AppDto.FromApp(a, userOrClientId, userPermissions, appPlansProvider, this)).ToArray();
});
@ -89,6 +91,34 @@ namespace Squidex.Areas.Api.Controllers.Apps
return Ok(response);
}
/// <summary>
/// Get an app by name.
/// </summary>
/// <param name="app">The name of the app.</param>
/// <returns>
/// 200 => Apps returned.
/// 404 => App not found.
/// </returns>
[HttpGet]
[Route("apps/{app}")]
[ProducesResponseType(typeof(AppDto), 200)]
[ApiPermission]
[ApiCosts(0)]
public IActionResult GetApp(string app)
{
var response = Deferred.Response(() =>
{
var userOrClientId = HttpContext.User.UserOrClientId()!;
var userPermissions = HttpContext.Permissions();
return AppDto.FromApp(App, userOrClientId, userPermissions, appPlansProvider, this);
});
Response.Headers[HeaderNames.ETag] = App.ToEtag();
return Ok(response);
}
/// <summary>
/// Create a new app.
/// </summary>

7
frontend/app/features/settings/pages/more/more-page.component.ts

@ -8,6 +8,7 @@
import { Component, OnInit } from '@angular/core';
import { FormBuilder } from '@angular/forms';
import { Router } from '@angular/router';
import { map } from 'rxjs/operators';
import {
AppDto,
@ -44,7 +45,7 @@ export class MorePageComponent extends ResourceOwner implements OnInit {
public ngOnInit() {
this.own(
this.appsState.selectedApp
this.appsState.reloadSelected().pipe(map(x => x!))
.subscribe(app => {
this.app = app;
@ -66,8 +67,8 @@ export class MorePageComponent extends ResourceOwner implements OnInit {
if (value) {
this.appsState.update(this.app, value)
.subscribe(user => {
this.updateForm.submitCompleted({ newValue: user });
.subscribe(app => {
this.updateForm.submitCompleted({ newValue: app });
}, error => {
this.updateForm.submitFailed(error);
});

2
frontend/app/framework/angular/modals/dialog-renderer.component.scss

@ -46,7 +46,7 @@
.overlay {
@include absolute(0, auto, 0, 0);
animation: width 10s 1 linear;
background: $color-white;
background: $color-black;
border: 0;
opacity: .1;
overflow: hidden;

19
frontend/app/shared/services/apps.service.spec.ts

@ -62,6 +62,25 @@ describe('AppsService', () => {
expect(apps!).toEqual([createApp(12), createApp(13)]);
}));
it('should make get request to get app',
inject([AppsService, HttpTestingController], (appsService: AppsService, httpMock: HttpTestingController) => {
let app: AppDto;
appsService.getApp('my-app').subscribe(result => {
app = result;
});
const req = httpMock.expectOne('http://service/p/api/apps/my-app');
expect(req.request.method).toEqual('GET');
expect(req.request.headers.get('If-Match')).toBeNull();
req.flush(appResponse(12));
expect(app!).toEqual(createApp(12));
}));
it('should make post request to create app',
inject([AppsService, HttpTestingController], (appsService: AppsService, httpMock: HttpTestingController) => {

12
frontend/app/shared/services/apps.service.ts

@ -119,6 +119,18 @@ export class AppsService {
pretifyError('Failed to load apps. Please reload.'));
}
public getApp(name: string): Observable<AppDto> {
const url = this.apiUrl.buildUrl(`/api/apps/${name}`);
return this.http.get<any>(url).pipe(
map(body => {
const app = parseApp(body);
return app;
}),
pretifyError('Failed to load app. Please reload.'));
}
public postApp(dto: CreateAppDto): Observable<AppDto> {
const url = this.apiUrl.buildUrl('api/apps');

40
frontend/app/shared/state/apps.state.spec.ts

@ -5,7 +5,7 @@
* Copyright (c) Squidex UG (haftungsbeschränkt). All rights reserved.
*/
import { of } from 'rxjs';
import { of, throwError } from 'rxjs';
import { IMock, Mock } from 'typemoq';
import {
@ -56,7 +56,7 @@ describe('AppsState', () => {
expect(appsState.snapshot.selectedApp).toBe(app1);
});
it('should return null on select when unselecting user', () => {
it('should return null on select when unselecting app', () => {
let selectedApp: AppDto;
appsState.select(null).subscribe(x => {
@ -67,9 +67,40 @@ describe('AppsState', () => {
expect(appsState.snapshot.selectedApp).toBeNull();
});
it('should return null on select when apps is not found', () => {
it('should return new app when loaded', () => {
const newApp = createApp(1, '_new');
appsService.setup(x => x.getApp(app1.name))
.returns(() => of(newApp));
let selectedApp: AppDto;
appsState.loadApp(app1.name).subscribe(x => {
selectedApp = x!;
});
expect(selectedApp!).toEqual(newApp);
expect(appsState.snapshot.selectedApp).toBeNull();
});
it('should return new app when reloaded', () => {
const newApp = createApp(1, '_new');
appsService.setup(x => x.getApp(app1.name))
.returns(() => of(newApp));
appsState.select(app1.name).subscribe();
appsState.reloadSelected();
expect(appsState.snapshot.selectedApp).toEqual(newApp);
});
it('should return null on select when app is not found', () => {
let selectedApp: AppDto;
appsService.setup(x => x.getApp('unknown'))
.returns(() => throwError(new Error('404')));
appsState.select('unknown').subscribe(x => {
selectedApp = x!;
});
@ -152,6 +183,9 @@ describe('AppsState', () => {
appsService.setup(x => x.deleteApp(app1))
.returns(() => of({})).verifiable();
appsService.setup(x => x.getApp(app1.name))
.returns(() => of(app1));
appsState.select(app1.name).subscribe();
appsState.delete(app1).subscribe();

38
frontend/app/shared/state/apps.state.ts

@ -7,7 +7,7 @@
import { Injectable } from '@angular/core';
import { Observable, of } from 'rxjs';
import { tap } from 'rxjs/operators';
import { catchError, tap } from 'rxjs/operators';
import {
defined,
@ -58,18 +58,40 @@ export class AppsState extends State<Snapshot> {
super({ apps: [], selectedApp: null });
}
public select(name: string | null): Observable<AppDto | null> {
const observable =
!name ?
of(null) :
of(this.snapshot.apps.find(x => x.name === name) || null);
public reloadSelected() {
return this.loadApp(this.appName).pipe(
shareSubscribed(this.dialogs));
}
return observable.pipe(
public select(name: string | null): Observable<AppDto | null> {
return this.loadApp(name, true).pipe(
tap(selectedApp => {
this.next(s => ({ ...s, selectedApp }));
this.next(s => {
return { ...s, selectedApp };
});
}));
}
public loadApp(name: string | null, cached = false) {
if (!name) {
return of(null);
}
if (cached) {
const found = this.snapshot.apps.find(x => x.name === name);
if (found) {
return of(found);
}
}
return this.appsService.getApp(name).pipe(
tap(app => {
this.replaceApp(app, app);
}),
catchError(() => of(null)));
}
public load(): Observable<any> {
return this.appsService.getApps().pipe(
tap(apps => {

2
frontend/app/shared/state/schemas.state.spec.ts

@ -236,7 +236,7 @@ describe('SchemasState', () => {
expect().nothing();
});
it('should return null on select when loading failed', () => {
it('should return null on select when loading failed', () => {
schemasService.setup(x => x.getSchema(app, 'failed'))
.returns(() => throwError({})).verifiable();

1
frontend/app/theme/_vars.scss

@ -35,6 +35,7 @@ $color-theme-orange-dark: #a65b00;
$color-theme-error: #eb3142;
$color-theme-error-dark: #c00;
$color-black: #000;
$color-white: #fff;
$color-theme-info: #5bc0de;

Loading…
Cancel
Save