Browse Source

A lot of settings migrated.

pull/363/head
Sebastian 7 years ago
parent
commit
48beff2420
  1. 41
      src/Squidex/Areas/Api/Controllers/Apps/AppPatternsController.cs
  2. 15
      src/Squidex/Areas/Api/Controllers/Apps/Models/AppPatternDto.cs
  3. 38
      src/Squidex/Areas/Api/Controllers/Apps/Models/AppPatternsDto.cs
  4. 4
      src/Squidex/Areas/Api/Controllers/Apps/Models/ContributorsDto.cs
  5. 2
      src/Squidex/app/framework/utils/version.ts
  6. 11
      src/Squidex/app/shared/services/clients.service.spec.ts
  7. 2
      src/Squidex/app/shared/services/clients.service.ts
  8. 2
      src/Squidex/app/shared/services/contributors.service.spec.ts
  9. 2
      src/Squidex/app/shared/services/contributors.service.ts
  10. 118
      src/Squidex/app/shared/services/patterns.service.spec.ts
  11. 75
      src/Squidex/app/shared/services/patterns.service.ts
  12. 115
      src/Squidex/app/shared/services/roles.service.spec.ts
  13. 72
      src/Squidex/app/shared/services/roles.service.ts
  14. 31
      src/Squidex/app/shared/state/clients.state.spec.ts
  15. 2
      src/Squidex/app/shared/state/clients.state.ts
  16. 19
      src/Squidex/app/shared/state/contributors.state.spec.ts
  17. 2
      src/Squidex/app/shared/state/contributors.state.ts
  18. 8
      src/Squidex/app/shared/state/languages.state.spec.ts
  19. 2
      src/Squidex/app/shared/state/languages.state.ts
  20. 57
      src/Squidex/app/shared/state/patterns.state.spec.ts
  21. 60
      src/Squidex/app/shared/state/patterns.state.ts
  22. 2
      src/Squidex/app/shared/state/plans.state.ts
  23. 59
      src/Squidex/app/shared/state/roles.state.spec.ts
  24. 61
      src/Squidex/app/shared/state/roles.state.ts

41
src/Squidex/Areas/Api/Controllers/Apps/AppPatternsController.cs

@ -6,11 +6,11 @@
// ==========================================================================
using System;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Net.Http.Headers;
using Squidex.Areas.Api.Controllers.Apps.Models;
using Squidex.Domain.Apps.Entities.Apps;
using Squidex.Domain.Apps.Entities.Apps.Commands;
using Squidex.Infrastructure.Commands;
using Squidex.Shared;
@ -42,12 +42,12 @@ namespace Squidex.Areas.Api.Controllers.Apps
/// </remarks>
[HttpGet]
[Route("apps/{app}/patterns/")]
[ProducesResponseType(typeof(AppPatternDto[]), 200)]
[ProducesResponseType(typeof(AppPatternsDto), 200)]
[ApiPermission(Permissions.AppCommon)]
[ApiCosts(0)]
public IActionResult GetPatterns(string app)
{
var response = App.Patterns.Select(AppPatternDto.FromKvp).OrderBy(x => x.Name).ToArray();
var response = AppPatternsDto.FromApp(App, this);
Response.Headers[HeaderNames.ETag] = App.Version.ToString();
@ -66,16 +66,15 @@ namespace Squidex.Areas.Api.Controllers.Apps
/// </returns>
[HttpPost]
[Route("apps/{app}/patterns/")]
[ProducesResponseType(typeof(AppPatternDto), 201)]
[ProducesResponseType(typeof(AppPatternsDto), 200)]
[ProducesResponseType(typeof(ErrorDto), 400)]
[ApiPermission(Permissions.AppPatternsCreate)]
[ApiCosts(1)]
public async Task<IActionResult> PostPattern(string app, [FromBody] UpdatePatternDto request)
{
var command = request.ToAddCommand();
await CommandBus.PublishAsync(command);
var response = AppPatternDto.FromCommand(command);
var response = await InvokeCommandAsync(command);
return CreatedAtAction(nameof(GetPatterns), new { app }, response);
}
@ -93,14 +92,17 @@ namespace Squidex.Areas.Api.Controllers.Apps
/// </returns>
[HttpPut]
[Route("apps/{app}/patterns/{id}/")]
[ProducesResponseType(typeof(AppPatternDto), 201)]
[ProducesResponseType(typeof(AppPatternsDto), 200)]
[ProducesResponseType(typeof(ErrorDto), 400)]
[ApiPermission(Permissions.AppPatternsUpdate)]
[ApiCosts(1)]
public async Task<IActionResult> UpdatePattern(string app, Guid id, [FromBody] UpdatePatternDto request)
{
await CommandBus.PublishAsync(request.ToUpdateCommand(id));
var command = request.ToUpdateCommand(id);
var response = await InvokeCommandAsync(command);
return NoContent();
return Ok(response);
}
/// <summary>
@ -109,7 +111,7 @@ namespace Squidex.Areas.Api.Controllers.Apps
/// <param name="app">The name of the app.</param>
/// <param name="id">The id of the pattern to be deleted.</param>
/// <returns>
/// 204 => Pattern removed.
/// 200 => Pattern removed.
/// 404 => Pattern or app not found.
/// </returns>
/// <remarks>
@ -117,13 +119,26 @@ namespace Squidex.Areas.Api.Controllers.Apps
/// </remarks>
[HttpDelete]
[Route("apps/{app}/patterns/{id}/")]
[ProducesResponseType(typeof(AppPatternsDto), 200)]
[ApiPermission(Permissions.AppPatternsDelete)]
[ApiCosts(1)]
public async Task<IActionResult> DeletePattern(string app, Guid id)
{
await CommandBus.PublishAsync(new DeletePattern { PatternId = id });
var command = new DeletePattern { PatternId = id };
var response = await InvokeCommandAsync(command);
return Ok(response);
}
private async Task<AppPatternsDto> InvokeCommandAsync(ICommand command)
{
var context = await CommandBus.PublishAsync(command);
var result = context.Result<IAppEntity>();
var response = AppPatternsDto.FromApp(result, this);
return NoContent();
return response;
}
}
}

15
src/Squidex/Areas/Api/Controllers/Apps/Models/AppPatternDto.cs

@ -6,15 +6,14 @@
// ==========================================================================
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using Squidex.Domain.Apps.Core.Apps;
using Squidex.Domain.Apps.Entities.Apps.Commands;
using Squidex.Infrastructure.Reflection;
using Squidex.Web;
namespace Squidex.Areas.Api.Controllers.Apps.Models
{
public sealed class AppPatternDto
public sealed class AppPatternDto : Resource
{
/// <summary>
/// Unique id of the pattern.
@ -38,14 +37,16 @@ namespace Squidex.Areas.Api.Controllers.Apps.Models
/// </summary>
public string Message { get; set; }
public static AppPatternDto FromKvp(KeyValuePair<Guid, AppPattern> kvp)
public static AppPatternDto FromPattern(Guid id, AppPattern pattern, ApiController controller, string app)
{
return SimpleMapper.Map(kvp.Value, new AppPatternDto { PatternId = kvp.Key });
var result = SimpleMapper.Map(pattern, new AppPatternDto { PatternId = id });
return result.CreateLinks(controller, app);
}
public static AppPatternDto FromCommand(AddPattern command)
private AppPatternDto CreateLinks(ApiController controller, string app)
{
return SimpleMapper.Map(command, new AppPatternDto());
return this;
}
}
}

38
src/Squidex/Areas/Api/Controllers/Apps/Models/AppPatternsDto.cs

@ -0,0 +1,38 @@
// ==========================================================================
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex UG (haftungsbeschraenkt)
// All rights reserved. Licensed under the MIT license.
// ==========================================================================
using System.ComponentModel.DataAnnotations;
using System.Linq;
using Squidex.Domain.Apps.Entities.Apps;
using Squidex.Web;
namespace Squidex.Areas.Api.Controllers.Apps.Models
{
public sealed class AppPatternsDto : Resource
{
/// <summary>
/// The patterns.
/// </summary>
[Required]
public AppPatternDto[] Items { get; set; }
public static AppPatternsDto FromApp(IAppEntity app, ApiController controller)
{
var result = new AppPatternsDto
{
Items = app.Patterns.Select(x => AppPatternDto.FromPattern(x.Key, x.Value, controller, app.Name)).ToArray()
};
return result.CreateLinks(controller, app.Name);
}
private AppPatternsDto CreateLinks(ApiController controller, string app)
{
return this;
}
}
}

4
src/Squidex/Areas/Api/Controllers/Apps/Models/ContributorsDto.cs

@ -21,7 +21,7 @@ namespace Squidex.Areas.Api.Controllers.Apps.Models
/// The contributors.
/// </summary>
[Required]
public ContributorDto[] Contributors { get; set; }
public ContributorDto[] Items { get; set; }
/// <summary>
/// The maximum number of allowed contributors.
@ -40,7 +40,7 @@ namespace Squidex.Areas.Api.Controllers.Apps.Models
var result = new ContributorsDto
{
Contributors = contributors,
Items = contributors,
};
if (isInvited)

2
src/Squidex/app/framework/utils/version.ts

@ -6,6 +6,8 @@
*/
export class Version {
public static readonly EMPTY = new Version('');
constructor(
public readonly value: string
) {

11
src/Squidex/app/shared/services/clients.service.spec.ts

@ -172,7 +172,7 @@ describe('ClientsService', () => {
function clientsResponse(...ids: number[]) {
return {
contributors: ids.map(id => ({
items: ids.map(id => ({
id: `id${id}`,
name: `Client ${id}`,
role: `Role${id}`,
@ -181,12 +181,8 @@ describe('ClientsService', () => {
update: { method: 'PUT', href: `/clients/id${id}` }
}
})),
maxContributors: ids.length * 13,
_links: {
create: { method: 'POST', href: '/contributors' }
},
_meta: {
isInvited: 'true'
create: { method: 'POST', href: '/clients' }
}
};
}
@ -205,9 +201,6 @@ export function createClients(...ids: number[]): ClientsPayload {
)),
_links: {
create: { method: 'POST', href: '/clients' }
},
_meta: {
isInvited: 'true'
}
};
}

2
src/Squidex/app/shared/services/clients.service.ts

@ -139,7 +139,7 @@ export class ClientsService {
}
function parseClients(response: any): ClientsPayload {
const items: any[] = response;
const items: any[] = response.items;
const clients = items.map(item =>
withLinks(

2
src/Squidex/app/shared/services/contributors.service.spec.ts

@ -119,7 +119,7 @@ describe('ContributorsService', () => {
function contributorsResponse(...ids: number[]) {
return {
contributors: ids.map(id => ({
items: ids.map(id => ({
contributorId: `id${id}`, role: id % 2 === 0 ? 'Owner' : 'Developer',
_links: {
update: { method: 'PUT', href: `/contributors/id${id}` }

2
src/Squidex/app/shared/services/contributors.service.ts

@ -96,7 +96,7 @@ export class ContributorsService {
}
function parseContributors(response: any) {
const items: any[] = response.contributors;
const items: any[] = response.items;
const contributors = items.map(item =>
withLinks(

118
src/Squidex/app/shared/services/patterns.service.spec.ts

@ -13,8 +13,11 @@ import {
ApiUrlConfig,
PatternDto,
PatternsDto,
PatternsPayload,
PatternsService,
Version
Resource,
Version,
withLinks
} from '@app/shared/internal';
describe('PatternsService', () => {
@ -51,31 +54,13 @@ describe('PatternsService', () => {
expect(req.request.method).toEqual('GET');
expect(req.request.headers.get('If-Match')).toBeNull();
req.flush([
{
patternId: '1',
pattern: '[0-9]',
name: 'Number',
message: 'Message1'
}, {
patternId: '2',
pattern: '[0-9]*',
name: 'Numbers',
message: 'Message2'
}
], {
req.flush(patternsResponse(1, 2, 3), {
headers: {
etag: '2'
}
});
expect(patterns!).toEqual({
payload: [
new PatternDto('1', 'Number', '[0-9]', 'Message1'),
new PatternDto('2', 'Numbers', '[0-9]*', 'Message2')
],
version: new Version('2')
});
expect(patterns!).toEqual({payload: createPatterns(1, 2, 3), version: new Version('2') });
}));
it('should make post request to add pattern',
@ -83,10 +68,10 @@ describe('PatternsService', () => {
const dto = { name: 'Number', pattern: '[0-9]' };
let pattern: PatternDto;
let patterns: PatternsDto;
patternService.postPattern('my-app', dto, version).subscribe(result => {
pattern = result.payload;
patterns = result;
});
const req = httpMock.expectOne('http://service/p/api/apps/my-app/patterns');
@ -94,14 +79,13 @@ describe('PatternsService', () => {
expect(req.request.method).toEqual('POST');
expect(req.request.headers.get('If-Match')).toEqual(version.value);
req.flush({
name: 'Number',
patternId: '1',
pattern: '[0-9]',
message: 'Message1'
req.flush(patternsResponse(1, 2, 3), {
headers: {
etag: '2'
}
});
expect(pattern!).toEqual(new PatternDto('1', 'Number', '[0-9]', 'Message1'));
expect(patterns!).toEqual({payload: createPatterns(1, 2, 3), version: new Version('2') });
}));
it('should make put request to update pattern',
@ -109,26 +93,92 @@ describe('PatternsService', () => {
const dto = { name: 'Number', pattern: '[0-9]' };
patternService.putPattern('my-app', '1', dto, version).subscribe();
const resource: Resource = {
_links: {
update: { method: 'PUT', href: '/api/apps/my-app/patterns/1' }
}
};
let patterns: PatternsDto;
patternService.putPattern('my-app', resource, dto, version).subscribe(result => {
patterns = result;
});
const req = httpMock.expectOne('http://service/p/api/apps/my-app/patterns/1');
expect(req.request.method).toEqual('PUT');
expect(req.request.headers.get('If-Match')).toEqual(version.value);
req.flush({});
req.flush(patternsResponse(1, 2, 3), {
headers: {
etag: '2'
}
});
expect(patterns!).toEqual({payload: createPatterns(1, 2, 3), version: new Version('2') });
}));
it('should make delete request to remove pattern',
inject([PatternsService, HttpTestingController], (patternService: PatternsService, httpMock: HttpTestingController) => {
patternService.deletePattern('my-app', '1', version).subscribe();
const resource: Resource = {
_links: {
delete: { method: 'DELETE', href: '/api/apps/my-app/patterns/1' }
}
};
let patterns: PatternsDto;
patternService.deletePattern('my-app', resource, version).subscribe(result => {
patterns = result;
});
const req = httpMock.expectOne('http://service/p/api/apps/my-app/patterns/1');
expect(req.request.method).toEqual('DELETE');
expect(req.request.headers.get('If-Match')).toEqual(version.value);
req.flush({});
req.flush(patternsResponse(1, 2, 3), {
headers: {
etag: '2'
}
});
expect(patterns!).toEqual({payload: createPatterns(1, 2, 3), version: new Version('2') });
}));
});
function patternsResponse(...ids: number[]) {
return {
items: ids.map(id => ({
name: `Name${id}`,
patternId: `id${id}`,
pattern: `Pattern${id}`,
message: `Message${id}`,
_links: {
update: { method: 'PUT', href: `/patterns/id${id}` }
}
})),
_links: {
create: { method: 'POST', href: '/patterns' }
}
};
}
});
export function createPatterns(...ids: number[]): PatternsPayload {
return {
items: ids.map(id =>
withLinks(
new PatternDto(`id${id}`, `Name${id}`, `Pattern${id}`, `Message${id}`),
{
_links: {
update: { method: 'PUT', href: `/patterns/id${id}` }
}
}
)),
_links: {
create: { method: 'POST', href: '/patterns' }
}
};
}

75
src/Squidex/app/shared/services/patterns.service.ts

@ -15,22 +15,28 @@ import {
ApiUrlConfig,
HTTP,
mapVersioned,
Model,
pretifyError,
Resource,
ResourceLinks,
Version,
Versioned
Versioned,
withLinks
} from '@app/framework';
export type PatternsDto = Versioned<PatternDto[]>;
export type PatternsDto = Versioned<PatternsPayload>;
export type PatternsPayload = {
items: PatternDto[]
} & Resource;
export class PatternDto {
public readonly _links: ResourceLinks = {};
export class PatternDto extends Model<PatternDto> {
constructor(
public readonly id: string,
public readonly name: string,
public readonly pattern: string,
public readonly message?: string
) {
super();
}
}
@ -54,33 +60,17 @@ export class PatternsService {
return HTTP.getVersioned(this.http, url).pipe(
mapVersioned(({ body }) => {
const items: any[] = body;
const patterns =
items.map(item =>
new PatternDto(
item.patternId,
item.name,
item.pattern,
item.message));
return patterns;
return parsePatterns(body);
}),
pretifyError('Failed to add pattern. Please reload.'));
}
public postPattern(appName: string, dto: EditPatternDto, version: Version): Observable<Versioned<PatternDto>> {
public postPattern(appName: string, dto: EditPatternDto, version: Version): Observable<PatternsDto> {
const url = this.apiUrl.buildUrl(`api/apps/${appName}/patterns`);
return HTTP.postVersioned(this.http, url, dto, version).pipe(
mapVersioned(({ body }) => {
const pattern = new PatternDto(
body.patternId,
body.name,
body.pattern,
body.message);
return pattern;
return parsePatterns(body);
}),
tap(() => {
this.analytics.trackEvent('Patterns', 'Created', appName);
@ -88,23 +78,48 @@ export class PatternsService {
pretifyError('Failed to add pattern. Please reload.'));
}
public putPattern(appName: string, id: string, dto: EditPatternDto, version: Version): Observable<Versioned<any>> {
const url = this.apiUrl.buildUrl(`api/apps/${appName}/patterns/${id}`);
public putPattern(appName: string, resource: Resource, dto: EditPatternDto, version: Version): Observable<PatternsDto> {
const link = resource._links['update'];
return HTTP.putVersioned(this.http, url, dto, version).pipe(
const url = this.apiUrl.buildUrl(link.href);
return HTTP.requestVersioned(this.http, link.method, url, version, dto).pipe(
mapVersioned(({ body }) => {
return parsePatterns(body);
}),
tap(() => {
this.analytics.trackEvent('Patterns', 'Updated', appName);
}),
pretifyError('Failed to update pattern. Please reload.'));
}
public deletePattern(appName: string, id: string, version: Version): Observable<Versioned<any>> {
const url = this.apiUrl.buildUrl(`api/apps/${appName}/patterns/${id}`);
public deletePattern(appName: string, resource: Resource, version: Version): Observable<PatternsDto> {
const link = resource._links['delete'];
return HTTP.deleteVersioned(this.http, url, version).pipe(
const url = this.apiUrl.buildUrl(link.href);
return HTTP.requestVersioned(this.http, link.method, url, version).pipe(
mapVersioned(({ body }) => {
return parsePatterns(body);
}),
tap(() => {
this.analytics.trackEvent('Patterns', 'Configured', appName);
}),
pretifyError('Failed to remove pattern. Please reload.'));
}
}
function parsePatterns(response: any) {
const items: any[] = response.items;
const patterns = items.map(item =>
withLinks(
new PatternDto(
item.patternId,
item.name,
item.pattern,
item.message),
item));
return withLinks({ items: patterns, _links: {} }, response);
}

115
src/Squidex/app/shared/services/roles.service.spec.ts

@ -11,10 +11,13 @@ import { inject, TestBed } from '@angular/core/testing';
import {
AnalyticsService,
ApiUrlConfig,
Resource,
RoleDto,
RolesDto,
RolesPayload,
RolesService,
Version
Version,
withLinks
} from '@app/shared/internal';
describe('RolesService', () => {
@ -70,31 +73,13 @@ describe('RolesService', () => {
expect(req.request.method).toEqual('GET');
expect(req.request.headers.get('If-Match')).toBeNull();
req.flush({
roles: [{
name: 'Role1',
numClients: 3,
numContributors: 5,
permissions: ['P1']
}, {
name: 'Role2',
numClients: 7,
numContributors: 9,
permissions: ['P2']
}]
}, {
req.flush(rolesResponse(2, 4), {
headers: {
etag: '2'
}
});
expect(roles!).toEqual({
payload: [
new RoleDto('Role1', 3, 5, ['P1']),
new RoleDto('Role2', 7, 9, ['P2'])
],
version: new Version('2')
});
expect(roles!).toEqual({ payload: createRoles(2, 4), version: new Version('2') });
}));
it('should make post request to add role',
@ -102,10 +87,10 @@ describe('RolesService', () => {
const dto = { name: 'Role3' };
let role: RoleDto;
let roles: RolesDto;
roleService.postRole('my-app', dto, version).subscribe(result => {
role = result.payload;
roles = result;
});
const req = httpMock.expectOne('http://service/p/api/apps/my-app/roles');
@ -113,9 +98,13 @@ describe('RolesService', () => {
expect(req.request.method).toEqual('POST');
expect(req.request.headers.get('If-Match')).toEqual(version.value);
req.flush({});
req.flush(rolesResponse(2, 4), {
headers: {
etag: '2'
}
});
expect(role!).toEqual(new RoleDto('Role3', 0, 0, []));
expect(roles!).toEqual({ payload: createRoles(2, 4), version: new Version('2') });
}));
it('should make put request to update role',
@ -123,26 +112,92 @@ describe('RolesService', () => {
const dto = { permissions: ['P4', 'P5'] };
roleService.putRole('my-app', 'role1', dto, version).subscribe();
const resource: Resource = {
_links: {
update: { method: 'PUT', href: '/api/apps/my-app/roles/role1' }
}
};
let roles: RolesDto;
roleService.putRole('my-app', resource, dto, version).subscribe(result => {
roles = result;
});
const req = httpMock.expectOne('http://service/p/api/apps/my-app/roles/role1');
expect(req.request.method).toEqual('PUT');
expect(req.request.headers.get('If-Match')).toEqual(version.value);
req.flush({});
req.flush(rolesResponse(2, 4), {
headers: {
etag: '2'
}
});
expect(roles!).toEqual({ payload: createRoles(2, 4), version: new Version('2') });
}));
it('should make delete request to remove role',
inject([RolesService, HttpTestingController], (roleService: RolesService, httpMock: HttpTestingController) => {
roleService.deleteRole('my-app', 'role1', version).subscribe();
const resource: Resource = {
_links: {
delete: { method: 'DELETE', href: '/api/apps/my-app/roles/role1' }
}
};
let roles: RolesDto;
roleService.deleteRole('my-app', resource, version).subscribe(result => {
roles = result;
});
const req = httpMock.expectOne('http://service/p/api/apps/my-app/roles/role1');
expect(req.request.method).toEqual('DELETE');
expect(req.request.headers.get('If-Match')).toEqual(version.value);
req.flush({});
req.flush(rolesResponse(2, 4), {
headers: {
etag: '2'
}
});
expect(roles!).toEqual({ payload: createRoles(2, 4), version: new Version('2') });
}));
});
function rolesResponse(...ids: number[]) {
return {
items: ids.map(id => ({
name: `name${id}`,
numClients: id * 2,
numContributors: id * 3,
permissions: [`permission${id}`],
_links: {
update: { method: 'PUT', href: `/roles/id${id}` }
}
})),
_links: {
create: { method: 'POST', href: '/roles' }
}
};
}
});
export function createRoles(...ids: number[]): RolesPayload {
return {
items: ids.map(id =>
withLinks(
new RoleDto(`name${id}`, id * 2, id * 3, [`permission${id}`]),
{
_links: {
update: { method: 'PUT', href: `/roles/id${id}` }
}
}
)),
_links: {
create: { method: 'POST', href: '/roles' }
}
};
}

72
src/Squidex/app/shared/services/roles.service.ts

@ -15,22 +15,28 @@ import {
ApiUrlConfig,
HTTP,
mapVersioned,
Model,
pretifyError,
Resource,
ResourceLinks,
Version,
Versioned
Versioned,
withLinks
} from '@app/framework';
export type RolesDto = Versioned<RoleDto[]>;
export type RolesDto = Versioned<RolesPayload>;
export type RolesPayload = {
items: RoleDto[]
} & Resource;
export class RoleDto {
public readonly _links: ResourceLinks = {};
export class RoleDto extends Model<RoleDto> {
constructor(
public readonly name: string,
public readonly numClients: number,
public readonly numContributors: number,
public readonly permissions: string[]
) {
super();
}
}
@ -56,28 +62,17 @@ export class RolesService {
return HTTP.getVersioned(this.http, url).pipe(
mapVersioned(({ body }) => {
const items: any[] = body.roles;
const roles = items.map(item =>
new RoleDto(
item.name,
item.numClients,
item.numContributors,
item.permissions));
return roles;
return parseRoles(body);
}),
pretifyError('Failed to load roles. Please reload.'));
}
public postRole(appName: string, dto: CreateRoleDto, version: Version): Observable<Versioned<RoleDto>> {
public postRole(appName: string, dto: CreateRoleDto, version: Version): Observable<RolesDto> {
const url = this.apiUrl.buildUrl(`api/apps/${appName}/roles`);
return HTTP.postVersioned(this.http, url, dto, version).pipe(
mapVersioned(() => {
const role = new RoleDto(dto.name, 0, 0, []);
return role;
mapVersioned(({ body }) => {
return parseRoles(body);
}),
tap(() => {
this.analytics.trackEvent('Role', 'Created', appName);
@ -85,20 +80,30 @@ export class RolesService {
pretifyError('Failed to add role. Please reload.'));
}
public putRole(appName: string, name: string, dto: UpdateRoleDto, version: Version): Observable<Versioned<any>> {
const url = this.apiUrl.buildUrl(`api/apps/${appName}/roles/${name}`);
public putRole(appName: string, resource: Resource, dto: UpdateRoleDto, version: Version): Observable<RolesDto> {
const link = resource._links['update'];
const url = this.apiUrl.buildUrl(link.href);
return HTTP.putVersioned(this.http, url, dto, version).pipe(
return HTTP.requestVersioned(this.http, link.method, url, version, dto).pipe(
mapVersioned(({ body }) => {
return parseRoles(body);
}),
tap(() => {
this.analytics.trackEvent('Role', 'Updated', appName);
}),
pretifyError('Failed to revoke role. Please reload.'));
}
public deleteRole(appName: string, name: string, version: Version): Observable<Versioned<any>> {
const url = this.apiUrl.buildUrl(`api/apps/${appName}/roles/${name}`);
public deleteRole(appName: string, resource: Resource, version: Version): Observable<RolesDto> {
const link = resource._links['delete'];
return HTTP.deleteVersioned(this.http, url, version).pipe(
const url = this.apiUrl.buildUrl(link.href);
return HTTP.requestVersioned(this.http, link.method, url, version).pipe(
mapVersioned(({ body }) => {
return parseRoles(body);
}),
tap(() => {
this.analytics.trackEvent('Role', 'Deleted', appName);
}),
@ -111,4 +116,19 @@ export class RolesService {
return this.http.get<string[]>(url).pipe(
pretifyError('Failed to load permissions. Please reload.'));
}
}
export function parseRoles(response: any) {
const items: any[] = response.items;
const roles = items.map(item =>
withLinks(
new RoleDto(
item.name,
item.numClients,
item.numContributors,
item.permissions),
item));
return withLinks({ items: roles, _links: {} }, response);
}

31
src/Squidex/app/shared/state/clients.state.spec.ts

@ -9,6 +9,7 @@ import { of } from 'rxjs';
import { IMock, It, Mock, Times } from 'typemoq';
import {
ClientsPayload,
ClientsService,
ClientsState,
DialogService,
@ -88,8 +89,7 @@ describe('ClientsState', () => {
clientsState.attach(request).subscribe();
expect(clientsState.snapshot.clients.values).toEqual(updated.items);
expect(clientsState.snapshot.version).toEqual(newVersion);
expectNewClients(updated);
});
it('should update clients when role updated', () => {
@ -97,13 +97,12 @@ describe('ClientsState', () => {
const request = { role: 'Owner' };
clientsService.setup(x => x.putClient(app, oldClients[0].id, request, version))
.returns(() => of(versioned(newVersion))).verifiable();
clientsService.setup(x => x.putClient(app, oldClients.items[0], request, version))
.returns(() => of(versioned(newVersion, updated))).verifiable();
clientsState.update(oldClients[0], request).subscribe();
clientsState.update(oldClients.items[0], request).subscribe();
expect(clientsState.snapshot.clients.values).toEqual(updated.items);
expect(clientsState.snapshot.version).toEqual(newVersion);
expectNewClients(updated);
});
it('should update clients when name updated', () => {
@ -112,24 +111,28 @@ describe('ClientsState', () => {
const request = { name: 'NewName' };
clientsService.setup(x => x.putClient(app, oldClients.items[0], request, version))
.returns(() => of(versioned(newVersion))).verifiable();
.returns(() => of(versioned(newVersion, updated))).verifiable();
clientsState.update(oldClients[0], request).subscribe();
clientsState.update(oldClients.items[0], request).subscribe();
expect(clientsState.snapshot.clients.values).toEqual(updated.items);
expect(clientsState.snapshot.version).toEqual(newVersion);
expectNewClients(updated);
});
it('should update clients when client revoked', () => {
const updated = createClients(1, 2, 3);
clientsService.setup(x => x.deleteClient(app, oldClients.items[0], version))
.returns(() => of(versioned(newVersion))).verifiable();
.returns(() => of(versioned(newVersion, updated))).verifiable();
clientsState.revoke(oldClients[0]).subscribe();
clientsState.revoke(oldClients.items[0]).subscribe();
expectNewClients(updated);
});
function expectNewClients(updated: ClientsPayload) {
expect(clientsState.snapshot.clients.values).toEqual(updated.items);
expect(clientsState.snapshot.version).toEqual(newVersion);
});
}
});
});

2
src/Squidex/app/shared/state/clients.state.ts

@ -65,7 +65,7 @@ export class ClientsState extends State<Snapshot> {
private readonly appsState: AppsState,
private readonly dialogs: DialogService
) {
super({ clients: ImmutableArray.empty(), version: new Version(''), links: {} });
super({ clients: ImmutableArray.empty(), version: Version.EMPTY, links: {} });
}
public load(isReload = false): Observable<any> {

19
src/Squidex/app/shared/state/contributors.state.spec.ts

@ -9,6 +9,7 @@ import { of } from 'rxjs';
import { IMock, It, Mock, Times } from 'typemoq';
import {
ContributorsPayload,
ContributorsService,
ContributorsState,
DialogService,
@ -81,7 +82,7 @@ describe('ContributorsState', () => {
});
it('should update contributors when user assigned', () => {
const updated = createContributors(1, 2, 3);
const updated = createContributors(5, 6);
const request = { contributorId: 'mail2stehle@gmail.com', role: 'Developer' };
@ -90,22 +91,24 @@ describe('ContributorsState', () => {
contributorsState.assign(request).subscribe();
expect(contributorsState.snapshot.contributors.values).toEqual(oldContributors.items);
expect(contributorsState.snapshot.maxContributors).toBe(oldContributors.maxContributors);
expect(contributorsState.snapshot.version).toEqual(newVersion);
expectNewContributors(updated);
});
it('should update contributors when contribution revoked', () => {
const updated = createContributors(1, 2, 3);
const updated = createContributors(5, 6);
contributorsService.setup(x => x.deleteContributor(app, oldContributors.items[0], version))
.returns(() => of(versioned(newVersion, updated))).verifiable();
contributorsState.revoke(oldContributors.items[0]).subscribe();
expect(contributorsState.snapshot.contributors.values).toEqual(oldContributors.items);
expect(contributorsState.snapshot.maxContributors).toBe(oldContributors.maxContributors);
expect(contributorsState.snapshot.version).toEqual(newVersion);
expectNewContributors(updated);
});
function expectNewContributors(updated: ContributorsPayload) {
expect(contributorsState.snapshot.contributors.values).toEqual(updated.items);
expect(contributorsState.snapshot.maxContributors).toBe(updated.maxContributors);
expect(contributorsState.snapshot.version).toEqual(newVersion);
}
});
});

2
src/Squidex/app/shared/state/contributors.state.ts

@ -79,7 +79,7 @@ export class ContributorsState extends State<Snapshot> {
private readonly appsState: AppsState,
private readonly dialogs: DialogService
) {
super({ contributors: ImmutableArray.empty(), version: new Version(''), maxContributors: -1, links: {} });
super({ contributors: ImmutableArray.empty(), version: Version.EMPTY, maxContributors: -1, links: {} });
}
public load(isReload = false): Observable<any> {

8
src/Squidex/app/shared/state/languages.state.spec.ts

@ -109,7 +109,7 @@ describe('LanguagesState', () => {
languagesState.add(languageIT).subscribe();
expectUpdated(updated);
expectNewLanguages(updated);
});
it('should update languages when language updated', () => {
@ -122,7 +122,7 @@ describe('LanguagesState', () => {
languagesState.update(oldLanguages.items[1], request).subscribe();
expectUpdated(updated);
expectNewLanguages(updated);
});
it('should update languages when language deleted', () => {
@ -133,10 +133,10 @@ describe('LanguagesState', () => {
languagesState.remove(oldLanguages.items[1]).subscribe();
expectUpdated(updated);
expectNewLanguages(updated);
});
function expectUpdated(updated: AppLanguagesPayload) {
function expectNewLanguages(updated: AppLanguagesPayload) {
expect(languagesState.snapshot.languages.values).toEqual([
{
language: updated.items[0],

2
src/Squidex/app/shared/state/languages.state.ts

@ -96,7 +96,7 @@ export class LanguagesState extends State<Snapshot> {
allLanguages: ImmutableArray.empty(),
allLanguagesNew: ImmutableArray.empty(),
languages: ImmutableArray.empty(),
version: new Version(''),
version: Version.EMPTY,
links: {}
});
}

57
src/Squidex/app/shared/state/patterns.state.spec.ts

@ -10,12 +10,14 @@ import { IMock, It, Mock, Times } from 'typemoq';
import {
DialogService,
PatternDto,
PatternsPayload,
PatternsService,
PatternsState,
versioned
} from '@app/shared/internal';
import { createPatterns } from '../services/patterns.service.spec';
import { TestValues } from './_test-helpers';
describe('PatternsState', () => {
@ -26,10 +28,7 @@ describe('PatternsState', () => {
version
} = TestValues;
const oldPatterns = [
new PatternDto('id1', 'name1', 'pattern1', ''),
new PatternDto('id2', 'name2', 'pattern2', '')
];
const oldPatterns = createPatterns(1, 2, 3);
let dialogs: IMock<DialogService>;
let patternsService: IMock<PatternsService>;
@ -49,11 +48,11 @@ describe('PatternsState', () => {
describe('Loading', () => {
it('should load patterns', () => {
patternsService.setup(x => x.getPatterns(app))
.returns(() => of({ payload: oldPatterns, version })).verifiable();
.returns(() => of(versioned(version, oldPatterns))).verifiable();
patternsState.load().subscribe();
expect(patternsState.snapshot.patterns.values).toEqual(oldPatterns);
expect(patternsState.snapshot.patterns.values).toEqual(oldPatterns.items);
expect(patternsState.snapshot.version).toEqual(version);
dialogs.verify(x => x.notifyInfo(It.isAnyString()), Times.never());
@ -61,7 +60,7 @@ describe('PatternsState', () => {
it('should show notification on load when reload is true', () => {
patternsService.setup(x => x.getPatterns(app))
.returns(() => of({ payload: oldPatterns, version })).verifiable();
.returns(() => of(versioned(version, oldPatterns))).verifiable();
patternsState.load(true).subscribe();
@ -74,49 +73,51 @@ describe('PatternsState', () => {
describe('Updates', () => {
beforeEach(() => {
patternsService.setup(x => x.getPatterns(app))
.returns(() => of({ payload: oldPatterns, version })).verifiable();
.returns(() => of(versioned(version, oldPatterns))).verifiable();
patternsState.load().subscribe();
});
it('should add pattern to snapshot when created', () => {
const newPattern = new PatternDto('id3', 'name3', 'pattern3', '');
const updated = createPatterns(4, 5);
const request = { ...newPattern };
const request = { name: 'new', pattern: 'a-z' };
patternsService.setup(x => x.postPattern(app, request, version))
.returns(() => of(versioned(newVersion, newPattern))).verifiable();
.returns(() => of(versioned(newVersion, updated))).verifiable();
patternsState.create(request).subscribe();
expect(patternsState.snapshot.patterns.values).toEqual([...oldPatterns, newPattern]);
expect(patternsState.snapshot.version).toEqual(newVersion);
expectNewPatterns(updated);
});
it('should update properties when updated', () => {
const request = { name: 'name2_1', pattern: 'pattern2_1', message: 'message2_1' };
const updated = createPatterns(4, 5);
patternsService.setup(x => x.putPattern(app, oldPatterns[1].id, request, version))
.returns(() => of(versioned(newVersion))).verifiable();
const request = { name: 'name2_1', pattern: 'pattern2_1', message: 'message2_1' };
patternsState.update(oldPatterns[1], request).subscribe();
patternsService.setup(x => x.putPattern(app, oldPatterns.items[1], request, version))
.returns(() => of(versioned(newVersion, updated))).verifiable();
const pattern_1 = patternsState.snapshot.patterns.at(1);
patternsState.update(oldPatterns.items[1], request).subscribe();
expect(pattern_1.name).toBe(request.name);
expect(pattern_1.pattern).toBe(request.pattern);
expect(pattern_1.message).toBe(request.message);
expect(patternsState.snapshot.version).toEqual(newVersion);
expectNewPatterns(updated);
});
it('should remove pattern from snapshot when deleted', () => {
patternsService.setup(x => x.deletePattern(app, oldPatterns[0].id, version))
.returns(() => of(versioned(newVersion))).verifiable();
const updated = createPatterns(4, 5);
patternsState.delete(oldPatterns[0]).subscribe();
patternsService.setup(x => x.deletePattern(app, oldPatterns.items[0], version))
.returns(() => of(versioned(newVersion, updated))).verifiable();
expect(patternsState.snapshot.patterns.values).toEqual([oldPatterns[1]]);
expect(patternsState.snapshot.version).toEqual(newVersion);
patternsState.delete(oldPatterns.items[0]).subscribe();
expectNewPatterns(updated);
});
function expectNewPatterns(updated: PatternsPayload) {
expect(patternsState.snapshot.patterns.values).toEqual(updated.items);
expect(patternsState.snapshot.version).toEqual(newVersion);
}
});
});

60
src/Squidex/app/shared/state/patterns.state.ts

@ -12,7 +12,7 @@ import { distinctUntilChanged, map, tap } from 'rxjs/operators';
import {
DialogService,
ImmutableArray,
mapVersioned,
ResourceLinks,
shareMapSubscribed,
shareSubscribed,
State,
@ -24,6 +24,7 @@ import { AppsState } from './apps.state';
import {
EditPatternDto,
PatternDto,
PatternsPayload,
PatternsService
} from './../services/patterns.service';
@ -36,6 +37,9 @@ interface Snapshot {
// Indicates if the patterns are loaded.
isLoaded?: boolean;
// The links.
links: ResourceLinks;
}
type PatternsList = ImmutableArray<PatternDto>;
@ -55,7 +59,7 @@ export class PatternsState extends State<Snapshot> {
private readonly appsState: AppsState,
private readonly dialogs: DialogService
) {
super({ patterns: ImmutableArray.empty(), version: new Version('') });
super({ patterns: ImmutableArray.empty(), version: Version.EMPTY, links: {} });
}
public load(isReload = false): Observable<any> {
@ -69,52 +73,43 @@ export class PatternsState extends State<Snapshot> {
this.dialogs.notifyInfo('Patterns reloaded.');
}
this.next(s => {
const patterns = ImmutableArray.of(payload).sortByStringAsc(x => x.name);
return { ...s, patterns, isLoaded: true, version: version };
});
this.replacePatterns(payload, version);
}),
shareMapSubscribed(this.dialogs, x => x.payload));
}
public create(request: EditPatternDto): Observable<PatternDto> {
public create(request: EditPatternDto): Observable<any> {
return this.patternsService.postPattern(this.appName, request, this.version).pipe(
tap(({ version, payload }) => {
this.next(s => {
const patterns = s.patterns.push(payload).sortByStringAsc(x => x.name);
return { ...s, patterns, version: version };
});
this.replacePatterns(payload, version);
}),
shareMapSubscribed(this.dialogs, x => x.payload));
shareSubscribed(this.dialogs));
}
public update(pattern: PatternDto, request: EditPatternDto): Observable<PatternDto> {
return this.patternsService.putPattern(this.appName, pattern.id, request, this.version).pipe(
mapVersioned(() => update(pattern, request)),
public update(pattern: PatternDto, request: EditPatternDto): Observable<any> {
return this.patternsService.putPattern(this.appName, pattern, request, this.version).pipe(
tap(({ version, payload }) => {
this.next(s => {
const patterns = s.patterns.replaceBy('id', payload).sortByStringAsc(x => x.name);
return { ...s, patterns, version: version };
});
this.replacePatterns(payload, version);
}),
shareMapSubscribed(this.dialogs, x => x.payload));
shareSubscribed(this.dialogs));
}
public delete(pattern: PatternDto): Observable<any> {
return this.patternsService.deletePattern(this.appName, pattern.id, this.version).pipe(
tap(({ version }) => {
this.next(s => {
const patterns = s.patterns.filter(c => c.id !== pattern.id);
return { ...s, patterns, version: version };
});
return this.patternsService.deletePattern(this.appName, pattern, this.version).pipe(
tap(({ version, payload }) => {
this.replacePatterns(payload, version);
}),
shareSubscribed(this.dialogs));
}
private replacePatterns(payload: PatternsPayload, version: Version) {
const patterns = ImmutableArray.of(payload.items);
this.next(s => {
return { ...s, patterns, isLoaded: true, version, links: payload._links };
});
}
private get appName() {
return this.appsState.appName;
}
@ -122,7 +117,4 @@ export class PatternsState extends State<Snapshot> {
private get version() {
return this.snapshot.version;
}
}
const update = (pattern: PatternDto, request: EditPatternDto) =>
pattern.with(request);
}

2
src/Squidex/app/shared/state/plans.state.ts

@ -79,7 +79,7 @@ export class PlansState extends State<Snapshot> {
private readonly dialogs: DialogService,
private readonly plansService: PlansService
) {
super({ plans: ImmutableArray.empty(), version: new Version('') });
super({ plans: ImmutableArray.empty(), version: Version.EMPTY });
}
public load(isReload = false, overridePlanId?: string): Observable<any> {

59
src/Squidex/app/shared/state/roles.state.spec.ts

@ -10,12 +10,14 @@ import { IMock, It, Mock, Times } from 'typemoq';
import {
DialogService,
RoleDto,
RolesPayload,
RolesService,
RolesState,
versioned
} from '@app/shared/internal';
import { createRoles } from '../services/roles.service.spec';
import { TestValues } from './_test-helpers';
describe('RolesState', () => {
@ -26,10 +28,7 @@ describe('RolesState', () => {
version
} = TestValues;
const oldRoles = [
new RoleDto('Role1', 3, 5, ['P1']),
new RoleDto('Role2', 7, 9, ['P2'])
];
const oldRoles = createRoles(1, 2);
let dialogs: IMock<DialogService>;
let rolesService: IMock<RolesService>;
@ -45,11 +44,11 @@ describe('RolesState', () => {
describe('Loading', () => {
it('should load roles', () => {
rolesService.setup(x => x.getRoles(app))
.returns(() => of({ payload: oldRoles, version })).verifiable();
.returns(() => of(versioned(version, oldRoles))).verifiable();
rolesState.load().subscribe();
expect(rolesState.snapshot.roles.values).toEqual(oldRoles);
expect(rolesState.snapshot.roles.values).toEqual(oldRoles.items);
expect(rolesState.snapshot.isLoaded).toBeTruthy();
expect(rolesState.snapshot.version).toEqual(version);
@ -76,42 +75,46 @@ describe('RolesState', () => {
rolesState.load().subscribe();
});
it('should add role to snapshot when added', () => {
const newRole = new RoleDto('Role3', 0, 0, ['P3']);
it('should update roles when role added', () => {
const updated = createRoles(4, 5);
const request = { name: newRole.name };
const request = { name: 'newRole' };
rolesService.setup(x => x.postRole(app, request, version))
.returns(() => of(versioned(newVersion, newRole)));
.returns(() => of(versioned(newVersion, updated)));
rolesState.add(request).subscribe();
expect(rolesState.snapshot.roles.values).toEqual([oldRoles[0], oldRoles[1], newRole]);
expect(rolesState.snapshot.version).toEqual(newVersion);
expectNewRoles(updated);
});
it('should update permissions when updated', () => {
const request = { permissions: ['P4', 'P5'] };
it('should update roles when role updated', () => {
const updated = createRoles(4, 5);
rolesService.setup(x => x.putRole(app, oldRoles[1].name, request, version))
.returns(() => of(versioned(newVersion)));
const request = { permissions: ['P4', 'P5'] };
rolesState.update(oldRoles[1], request).subscribe();
rolesService.setup(x => x.putRole(app, oldRoles.items[1], request, version))
.returns(() => of(versioned(newVersion, updated)));
const role_1 = rolesState.snapshot.roles.at(1);
rolesState.update(oldRoles.items[1], request).subscribe();
expect(role_1.permissions).toEqual(request.permissions);
expect(rolesState.snapshot.version).toEqual(newVersion);
expectNewRoles(updated);
});
it('should remove role from snapshot when deleted', () => {
rolesService.setup(x => x.deleteRole(app, oldRoles[0].name, version))
.returns(() => of(versioned(newVersion)));
it('should update roles when role deleted', () => {
const updated = createRoles(4, 5);
rolesState.delete(oldRoles[0]).subscribe();
rolesService.setup(x => x.deleteRole(app, oldRoles.items[1], version))
.returns(() => of(versioned(newVersion, updated)));
expect(rolesState.snapshot.roles.values).toEqual([oldRoles[1]]);
expect(rolesState.snapshot.version).toEqual(newVersion);
rolesState.delete(oldRoles.items[1]).subscribe();
expectNewRoles(updated);
});
function expectNewRoles(updated: RolesPayload) {
expect(rolesState.snapshot.roles.values).toEqual(updated.items);
expect(rolesState.snapshot.version).toEqual(newVersion);
}
});
});
});

61
src/Squidex/app/shared/state/roles.state.ts

@ -12,8 +12,7 @@ import { distinctUntilChanged, map, tap } from 'rxjs/operators';
import {
DialogService,
ImmutableArray,
mapVersioned,
shareMapSubscribed,
ResourceLinks,
shareSubscribed,
State,
Version
@ -24,6 +23,7 @@ import { AppsState } from './apps.state';
import {
CreateRoleDto,
RoleDto,
RolesPayload,
RolesService,
UpdateRoleDto
} from './../services/roles.service';
@ -37,6 +37,9 @@ interface Snapshot {
// Indicates if the roles are loaded.
isLoaded?: boolean;
// The links.
links: ResourceLinks;
}
type RolesList = ImmutableArray<RoleDto>;
@ -56,7 +59,7 @@ export class RolesState extends State<Snapshot> {
private readonly appsState: AppsState,
private readonly dialogs: DialogService
) {
super({ roles: ImmutableArray.empty(), version: new Version('') });
super({ roles: ImmutableArray.empty(), version: Version.EMPTY, links: {} });
}
public load(isReload = false): Observable<any> {
@ -70,50 +73,41 @@ export class RolesState extends State<Snapshot> {
this.dialogs.notifyInfo('Roles reloaded.');
}
this.next(s => {
const roles = ImmutableArray.of(payload).sortByStringAsc(x => x.name);
return { ...s, roles, isLoaded: true, version };
});
this.replaceRoles(payload, version);
}),
shareSubscribed(this.dialogs));
}
public add(request: CreateRoleDto): Observable<RoleDto> {
public add(request: CreateRoleDto): Observable<any> {
return this.rolesService.postRole(this.appName, request, this.version).pipe(
tap(({ version, payload }) => {
this.next(s => {
const roles = s.roles.push(payload).sortByStringAsc(x => x.name);
this.replaceRoles(payload, version);
}),
shareSubscribed(this.dialogs));
}
return { ...s, roles, version };
});
public update(role: RoleDto, request: UpdateRoleDto): Observable<any> {
return this.rolesService.putRole(this.appName, role, request, this.version).pipe(
tap(({ version, payload }) => {
this.replaceRoles(payload, version);
}),
shareMapSubscribed(this.dialogs, x => x.payload));
shareSubscribed(this.dialogs));
}
public delete(role: RoleDto): Observable<any> {
return this.rolesService.deleteRole(this.appName, role.name, this.version).pipe(
tap(({ version }) => {
this.next(s => {
const roles = s.roles.removeBy('name', role);
return { ...s, roles, version };
});
return this.rolesService.deleteRole(this.appName, role, this.version).pipe(
tap(({ version, payload }) => {
this.replaceRoles(payload, version);
}),
shareSubscribed(this.dialogs));
}
public update(role: RoleDto, request: UpdateRoleDto): Observable<RoleDto> {
return this.rolesService.putRole(this.appName, role.name, request, this.version).pipe(
mapVersioned(() => update(role, request)),
tap(({ version, payload }) => {
this.next(s => {
const roles = s.roles.replaceBy('name', payload);
private replaceRoles(payload: RolesPayload, version: Version) {
const roles = ImmutableArray.of(payload.items);
return { ...s, roles, version };
});
}),
shareMapSubscribed(this.dialogs, x => x.payload));
this.next(s => {
return { ...s, roles, isLoaded: true, version, links: payload._links };
});
}
private get appName() {
@ -123,7 +117,4 @@ export class RolesState extends State<Snapshot> {
private get version() {
return this.snapshot.version;
}
}
const update = (role: RoleDto, request: UpdateRoleDto) =>
role.with({ permissions: request.permissions });
}
Loading…
Cancel
Save