Browse Source

Workflow service ui changes (#379)

* Work on Workflow Service and Tests.

* Reworked tests to utilise WorkflowPayload.

* Services finalized.
pull/380/head
Sebastian Stehle 7 years ago
committed by GitHub
parent
commit
70ff3b3dc2
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 38
      src/Squidex/app/shared/services/users.service.ts
  2. 152
      src/Squidex/app/shared/services/workflows.service.spec.ts
  3. 73
      src/Squidex/app/shared/services/workflows.service.ts

38
src/Squidex/app/shared/services/users.service.ts

@ -44,38 +44,38 @@ export class UsersService {
const url = this.apiUrl.buildUrl(`api/users?query=${query || ''}`);
return this.http.get<any[]>(url).pipe(
map(body => {
const users = body.map(item =>
new UserDto(
item.id,
item.displayName));
map(body => {
const users = body.map(item =>
new UserDto(
item.id,
item.displayName));
return users;
}),
pretifyError('Failed to load users. Please reload.'));
return users;
}),
pretifyError('Failed to load users. Please reload.'));
}
public getUser(id: string): Observable<UserDto> {
const url = this.apiUrl.buildUrl(`api/users/${id}`);
return this.http.get<any>(url).pipe(
map(body => {
const user = new UserDto(
body.id,
body.displayName);
map(body => {
const user = new UserDto(
body.id,
body.displayName);
return user;
}),
pretifyError('Failed to load user. Please reload.'));
return user;
}),
pretifyError('Failed to load user. Please reload.'));
}
public getResources(): Observable<ResourcesDto> {
const url = this.apiUrl.buildUrl(`api`);
return this.http.get<{ _links: {} }>(url).pipe(
map(({ _links }) => {
return new ResourcesDto(_links);
}),
pretifyError('Failed to load user. Please reload.'));
map(({ _links }) => {
return new ResourcesDto(_links);
}),
pretifyError('Failed to load user. Please reload.'));
}
}

152
src/Squidex/app/shared/services/workflows.service.spec.ts

@ -5,7 +5,138 @@
* Copyright (c) Squidex UG (haftungsbeschränkt). All rights reserved.
*/
import { WorkflowDto, WorkflowPayload } from '@app/shared/internal';
import { HttpClientTestingModule, HttpTestingController } from '@angular/common/http/testing';
import { inject, TestBed } from '@angular/core/testing';
import {
AnalyticsService,
ApiUrlConfig,
Version,
Versioned,
WorkflowDto,
WorkflowPayload,
WorkflowsService
} from '@app/shared/internal';
describe('WorkflowsService', () => {
const version = new Version('1');
beforeEach(() => {
TestBed.configureTestingModule({
imports: [
HttpClientTestingModule
],
providers: [
WorkflowsService,
{ provide: ApiUrlConfig, useValue: new ApiUrlConfig('http://service/p/') },
{ provide: AnalyticsService, useValue: new AnalyticsService() }
]
});
});
afterEach(inject([HttpTestingController], (httpMock: HttpTestingController) => {
httpMock.verify();
}));
it('should make a get request to get app workflows',
inject([WorkflowsService, HttpTestingController], (workflowsService: WorkflowsService, httpMock: HttpTestingController) => {
let workflow: Versioned<WorkflowPayload>;
workflowsService.getWorkflow('my-app').subscribe(result => {
workflow = result;
});
const req = httpMock.expectOne('http://service/p/api/apps/my-app/workflows');
expect(req.request.method).toEqual('GET');
expect(req.request.headers.get('If-Match')).toBeNull();
req.flush(workflowsResponse('Draft'),
{
headers: {
etag: '2'
}
});
expect(workflow!).toEqual({ payload: createWorkflow('Draft'), version: new Version('2') });
}));
it('should make a put request to assign a workflow',
inject([WorkflowsService, HttpTestingController], (workflowsService: WorkflowsService, httpMock: HttpTestingController) => {
const dto = createWorkflow('Draft');
let workflow: Versioned<WorkflowPayload>;
workflowsService.putWorkflow('my-app', dto, dto.workflow.serialize(), version).subscribe(result => {
workflow = result;
});
const req = httpMock.expectOne('http://service/p/api/apps/my-app/workflows');
expect(req.request.method).toEqual('PUT');
expect(req.request.headers.get('If-Match')).toEqual(version.value);
req.flush(workflowsResponse('Draft'), {
headers: {
etag: '2'
}
});
expect(workflow!).toEqual({ payload: createWorkflow('Draft'), version: new Version('2') });
}));
function workflowsResponse(name: string) {
return {
workflow: {
steps: {
[`${name}1`]: {
transitions: {
[`${name}2`]: {
expression: 'Expression1', role: 'Role1'
}
},
color: `${name}1`, noUpdate: true
},
[`${name}2`]: {
transitions: {
[`${name}1`]: {
expression: 'Expression2', role: 'Role2'
}
},
color: `${name}2`, noUpdate: true
}
},
initial: `${name}1`,
_links: {
update: { method: 'PUT', href: '/api/workflows' }
}
},
_links: {},
canCreate: true
};
}
});
export function createWorkflow(name: string): WorkflowPayload {
return {
workflow: new WorkflowDto({
update: { method: 'PUT', href: '/api/workflows' }
},
`${name}1`,
[
{ name: `${name}1`, color: `${name}1`, noUpdate: true, isLocked: false },
{ name: `${name}2`, color: `${name}2`, noUpdate: true, isLocked: false }
],
[
{ from: `${name}1`, to: `${name}2`, expression: 'Expression1', role: 'Role1' },
{ from: `${name}2`, to: `${name}1`, expression: 'Expression2', role: 'Role2' }
]),
_links: {}
};
}
describe('Workflow', () => {
it('should create empty workflow', () => {
@ -296,22 +427,5 @@ describe('Workflow', () => {
initial: '2'
});
});
});
export function createWorkflow(name: string): WorkflowPayload {
return {
workflow: new WorkflowDto({
update: { method: 'PUT', href: '/api/workflows' }
},
`${name}1`,
[
{ name: `${name}1`, color: `${name}1`, noUpdate: true, isLocked: true },
{ name: `${name}2`, color: `${name}1`, noUpdate: true, isLocked: true }
],
[
{ from: `${name}1`, to: `${name}2`, expression: 'Expression1', role: 'Role1' },
{ from: `${name}2`, to: `${name}1`, expression: 'Expression2', role: 'Role2' }
]),
_links: {}
};
}
});

73
src/Squidex/app/shared/services/workflows.service.ts

@ -5,19 +5,26 @@
* Copyright (c) Squidex UG (haftungsbeschränkt). All rights reserved.
*/
import { HttpClient } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { Observable, of } from 'rxjs';
import { Observable } from 'rxjs';
import { tap } from 'rxjs/operators';
import {
AnalyticsService,
ApiUrlConfig,
compareStringsAsc,
hasAnyLink,
HTTP,
mapVersioned,
pretifyError,
Resource,
ResourceLinks,
Version,
Versioned,
versioned
Versioned
} from '@app/framework';
export type WorkflowsDto = Versioned<WorkflowPayload>;
export type WorkflowPayload = { workflow: WorkflowDto; } & Resource;
export class WorkflowDto {
@ -72,7 +79,7 @@ export class WorkflowDto {
return this;
}
values = { ...existing, ...values };
values = { ...existing, ...values };
}
const steps = [...this.steps.filter(s => s !== found), { name, ...values }];
@ -209,7 +216,6 @@ export class WorkflowDto {
}
return result;
}
}
@ -223,11 +229,64 @@ export type WorkflowTransitionView = { step: WorkflowStep } & WorkflowTransition
@Injectable()
export class WorkflowsService {
constructor(
private readonly http: HttpClient,
private readonly apiUrl: ApiUrlConfig,
private readonly analytics: AnalyticsService
) {
}
public getWorkflow(appName: string): Observable<Versioned<WorkflowPayload>> {
return of(versioned(new Version('1'), { workflow: WorkflowDto.DEFAULT, _links: {} }));
const url = this.apiUrl.buildUrl(`api/apps/${appName}/workflows`);
return HTTP.getVersioned(this.http, url).pipe(
mapVersioned(({ body }) => {
return parseWorkflowPayload(body);
}),
pretifyError('Failed to load workflows. Please reload.'));
}
public putWorkflow(appName: string, resource: Resource, dto: any, version: Version): Observable<Versioned<WorkflowPayload>> {
return of(versioned(new Version('1'), { workflow: WorkflowDto.DEFAULT, _links: {} }));
const url = this.apiUrl.buildUrl(`api/apps/${appName}/workflows`);
return HTTP.putVersioned(this.http, url, resource, version).pipe(
mapVersioned(({ body }) => {
return parseWorkflowPayload(body);
}),
tap(() => {
this.analytics.trackEvent('Workflow', 'Configured', appName);
}),
pretifyError('Failed to configure Workflow. Please reload.'));
}
}
function parseWorkflowPayload(response: any) {
const { workflow, _links } = response;
const result = parseWorkflow(workflow);
return { workflow: result, _links };
}
function parseWorkflow(workflow: any) {
const steps: WorkflowStep[] = [];
const transitions: WorkflowTransition[] = [];
for (let stepName in workflow.steps) {
if (workflow.steps.hasOwnProperty(stepName)) {
const step = workflow.steps[stepName];
steps.push({ name: stepName, color: step.color, noUpdate: step.noUpdate, isLocked: stepName === 'Published' });
for (let to in step.transitions) {
if (step.transitions.hasOwnProperty(to)) {
const transition = step.transitions[to];
transitions.push({ from: stepName, to, ...transition });
}
}
}
}
return new WorkflowDto(workflow._links, workflow.initial, steps, transitions);
}
Loading…
Cancel
Save