Skip to content

Commit 160301d

Browse files
Ticket #5 : Add UI to launch CMMN instance
1 parent 149e384 commit 160301d

14 files changed

Lines changed: 246 additions & 82 deletions

File tree

src/CaseManagement.CMMN.Host/Cmmns/firstDiagram.cmmn

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
<cmmn:standardEvent>complete</cmmn:standardEvent>
1212
</cmmn:planItemOnPart>
1313
</cmmn:sentry>
14-
<cmmn:processTask id="ProcessTask_03n8qmv" name="Send email" case:assemblyQualifiedName="CaseManagement.CMMN.Acceptance.Tests.Delegates.SendEmailTaskDelegate, CaseManagement.CMMN.Acceptance.Tests, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
14+
<cmmn:processTask id="ProcessTask_03n8qmv" name="Send email" case:assemblyQualifiedName="CaseManagement.CMMN.Host.Delegates.SendEmailTaskDelegate, CaseManagement.CMMN.Host, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
1515
<cmmn:humanTask id="HumanTask_07z2osx" name="Create meeting" case:formRef="createMeetingForm" />
1616
</cmmn:casePlanModel>
1717
</cmmn:case>
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
using System.Threading.Tasks;
2+
using CaseManagement.Workflow.Engine;
3+
using CaseManagement.Workflow.Infrastructure;
4+
5+
namespace CaseManagement.CMMN.Host.Delegates
6+
{
7+
public class SendEmailTaskDelegate : WorkflowTaskDelegate
8+
{
9+
public override Task Handle(ProcessFlowInstanceExecutionContext context)
10+
{
11+
return Task.FromResult(0);
12+
}
13+
}
14+
}

src/CaseManagement.CMMN/Apis/CaseDefinitionsController.cs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,8 +106,24 @@ private static JObject ToDto(tDefinitions def)
106106
{ "id", def.id },
107107
{ "name", def.name },
108108
{ "create_datetime", def.creationDate },
109+
{ "cases", ToDto(def.@case) },
109110
{ "xml", new CMMNParser().Serialize(def) }
110111
};
111112
}
113+
114+
private static JArray ToDto(tCase[] tCases)
115+
{
116+
var result = new JArray();
117+
foreach(var tCase in tCases)
118+
{
119+
result.Add(new JObject
120+
{
121+
{ "id", tCase.id },
122+
{ "name", tCase.casePlanModel.name }
123+
});
124+
}
125+
126+
return result;
127+
}
112128
}
113129
}

src/CaseManagement.CMMN/Apis/CaseInstancesController.cs

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -47,10 +47,7 @@ public async Task<IActionResult> Create([FromBody] CreateCaseInstanceCommand cre
4747
return new ContentResult
4848
{
4949
StatusCode = (int)HttpStatusCode.Created,
50-
Content = new JObject
51-
{
52-
{ "id", result }
53-
}.ToString()
50+
Content = ToDto(result).ToString()
5451
};
5552
}
5653

src/CaseManagement.CMMN/CaseInstance/CommandHandlers/CreateCaseInstanceCommandHandler.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ public CreateCaseInstanceCommandHandler(ICMMNDefinitionsQueryRepository cmmnDefi
2323
_cmmnDefinitionsQueryRepository = cmmnDefinitionsQueryRepository;
2424
}
2525

26-
public async Task<string> Handle(CreateCaseInstanceCommand createCaseInstanceCommand)
26+
public async Task<ProcessFlowInstance> Handle(CreateCaseInstanceCommand createCaseInstanceCommand)
2727
{
2828
var caseDefinition = await _cmmnDefinitionsQueryRepository.FindDefinitionById(createCaseInstanceCommand.CaseDefinitionId);
2929
if (caseDefinition == null)
@@ -41,7 +41,7 @@ public async Task<string> Handle(CreateCaseInstanceCommand createCaseInstanceCom
4141

4242
var processFlowInstance = BuildProcessFlowInstance(tCase, caseDefinition.id);
4343
await Commit(processFlowInstance, processFlowInstance.GetStreamName());
44-
return processFlowInstance.Id;
44+
return processFlowInstance;
4545
}
4646

4747
public static ProcessFlowInstance BuildProcessFlowInstance(tCase tCase, string id)
Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
using CaseManagement.CMMN.CaseInstance.Commands;
2+
using CaseManagement.Workflow.Domains;
23
using System.Threading.Tasks;
34

45
namespace CaseManagement.CMMN.CaseInstance.CommandHandlers
56
{
67
public interface ICreateCaseInstanceCommandHandler
78
{
8-
Task<string> Handle(CreateCaseInstanceCommand createCaseInstanceCommand);
9+
Task<ProcessFlowInstance> Handle(CreateCaseInstanceCommand createCaseInstanceCommand);
910
}
1011
}

src/CaseManagement.CMMN/Extensions/QueryCollectionExtensions.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ public static bool TryGet(this IQueryCollection queryCollection, string name, ou
8080
}
8181

8282
FindOrders result;
83-
if (Enum.TryParse(orderStr, out result))
83+
if (Enum.TryParse(orderStr.ToUpperInvariant(), out result))
8484
{
8585
order = result;
8686
return true;

src/CaseManagement.Website/angularApp/app/casedefinitions/case-def/case-def-effects.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,5 +40,5 @@ export class CaseDefEffects {
4040
);
4141
}
4242
)
43-
);
43+
);
4444
}

src/CaseManagement.Website/angularApp/app/casedefinitions/case-def/case-def.component.html

Lines changed: 110 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -8,56 +8,115 @@
88
</div>
99
</div>
1010
<div fxLayout="row">
11-
<div fxFlex="80%" fxFlexOffset="10%">
12-
<mat-card>
13-
<mat-card-header>
14-
<mat-card-title>{{ "CASE_DEFINITION" | translate }}</mat-card-title>
15-
</mat-card-header>
16-
<mat-card-content>
17-
<div id="canvas" style="height: 300px;"></div>
18-
</mat-card-content>
19-
</mat-card>
20-
</div>
21-
</div>
22-
<div fxLayout="row">
23-
<div fxFlex="80%" fxFlexOffset="10%">
24-
<mat-card>
25-
<mat-card-header>
26-
<mat-card-title>{{ "CASE_INSTANCES" | translate }}</mat-card-title>
27-
</mat-card-header>
28-
<mat-card-content>
29-
<div class="mat-elevation-z8 overflow-hidden">
30-
<table mat-table class="full-width" [dataSource]="caseInstances" matSort>
31-
<ng-container matColumnDef="Id">
32-
<th mat-header-cell *matHeaderCellDef mat-sort-header>{{ "CASE_INSTANCE_IDENTIFIER" | translate }}</th>
33-
<td mat-cell *matCellDef="let case"> {{case.Id}} </td>
34-
</ng-container>
35-
<ng-container matColumnDef="Name">
36-
<th mat-header-cell *matHeaderCellDef mat-sort-header>{{ "CASE_INSTANCE_NAME" | translate }}</th>
37-
<td mat-cell *matCellDef="let case"> {{case.Name}} </td>
38-
</ng-container>
39-
<ng-container matColumnDef="Status">
40-
<th mat-header-cell *matHeaderCellDef mat-sort-header>{{ "CASE_INSTANCE_STATUS" | translate }}</th>
41-
<td mat-cell *matCellDef="let case"> {{case.Status}} </td>
42-
</ng-container>
43-
<ng-container matColumnDef="CreateDateTime">
44-
<th mat-header-cell *matHeaderCellDef mat-sort-header>{{ "CASE_INSTANCE_CREATEDATETIME" | translate }}</th>
45-
<td mat-cell *matCellDef="let case"> {{case.CreateDateTime}} </td>
46-
</ng-container>
47-
<ng-container matColumnDef="Actions">
48-
<th mat-header-cell *matHeaderCellDef>{{ "CASE_INSTANCE_ACTIONS" | translate }}</th>
49-
<td mat-cell *matCellDef="let case">
50-
<button mat-icon-button [routerLink]="['/casedefinitions/' + case.Id ]">
51-
<mat-icon>visibility</mat-icon>
52-
</button>
53-
</td>
54-
</ng-container>
55-
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
56-
<tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr>
57-
</table>
58-
<mat-paginator [length]="length" [pageSize]="5" [pageSizeOptions]="[5, 10, 25, 100]"></mat-paginator>
59-
</div>
60-
</mat-card-content>
61-
</mat-card>
11+
<div fxFlexOffset="10%" fxFlex="80%">
12+
<div fxLayout="column" fxLayoutGap="5px">
13+
<mat-card>
14+
<mat-card-header>
15+
<mat-card-title>{{ "CASE_DEFINITION_INFORMATION" | translate }}</mat-card-title>
16+
</mat-card-header>
17+
<mat-card-content>
18+
<div *ngIf="isCaseDefinitionLoading" class="center-spinner">
19+
<mat-spinner></mat-spinner>
20+
</div>
21+
<div fxLayout="row" *ngIf="!isCaseDefinitionLoading && !isCaseDefinitionErrorLoadOccured">
22+
<div fxFlex="50%" fxLayout="column">
23+
<mat-form-field>
24+
<mat-label>{{ "CASE_DEFINITION_ID" | translate }}</mat-label>
25+
<input matInput [value]="caseDefinition.Id" disabled />
26+
</mat-form-field>
27+
<mat-form-field>
28+
<mat-label>{{ "CASE_DEFINITION_NAME" | translate }}</mat-label>
29+
<input matInput [value]="caseDefinition.Name" disabled />
30+
</mat-form-field>
31+
<mat-form-field>
32+
<mat-label>{{ "CASE_DEFINITION_CREATEDATETIME" | translate }}</mat-label>
33+
<input matInput [value]="caseDefinition.CreateDateTime" disabled />
34+
</mat-form-field>
35+
</div>
36+
<div fxFlex="50%">
37+
<form (submit)="createCaseInstance($event)">
38+
<div fxLayout="column">
39+
<mat-form-field>
40+
<mat-label>{{ "SELECT_CASE_PLAN_MODEL" | translate }}</mat-label>
41+
<mat-select [(value)]="selectedCasePlanModel">
42+
<mat-option *ngFor="let casePlanModel of caseDefinition.CasePlanModels" [value]="casePlanModel.Id">
43+
{{casePlanModel.Name}}
44+
</mat-option>
45+
</mat-select>
46+
</mat-form-field>
47+
<button mat-raised-button type="submit">{{ "CREATE_CASE_INSTANCE" | translate }}</button>
48+
</div>
49+
</form>
50+
</div>
51+
</div>
52+
<div *ngIf="isCaseDefinitionErrorLoadOccured" class="error">
53+
<p>{{ "ERROR_LOAD_CASE_DEFINITION" | translate }}</p>
54+
</div>
55+
</mat-card-content>
56+
</mat-card>
57+
<mat-card>
58+
<mat-card-header>
59+
<mat-card-title>{{ "CASE_DEFINITION_SCHEMA" | translate }}</mat-card-title>
60+
</mat-card-header>
61+
<mat-card-content>
62+
<div *ngIf="isCaseDefinitionLoading" class="center-spinner">
63+
<mat-spinner></mat-spinner>
64+
</div>
65+
<div *ngIf="isCaseDefinitionErrorLoadOccured" class="error">
66+
<p>{{ "ERROR_LOAD_CASE_DEFINITION" | translate }}</p>
67+
</div>
68+
<div id="canvas" style="height: 300px;"></div>
69+
</mat-card-content>
70+
</mat-card>
71+
<mat-card>
72+
<mat-card-header>
73+
<mat-card-title>{{ "CASE_INSTANCES" | translate }}</mat-card-title>
74+
</mat-card-header>
75+
<mat-card-content>
76+
<div class="mat-elevation-z8 overflow-hidden">
77+
<table mat-table class="full-width" [dataSource]="caseInstances" matSort>
78+
<ng-container matColumnDef="name">
79+
<th mat-header-cell *matHeaderCellDef mat-sort-header>{{ "CASE_INSTANCE_NAME" | translate }}</th>
80+
<td mat-cell *matCellDef="let case"> {{case.Name}} </td>
81+
</ng-container>
82+
<ng-container matColumnDef="status">
83+
<th mat-header-cell *matHeaderCellDef mat-sort-header>{{ "CASE_INSTANCE_STATUS" | translate }}</th>
84+
<td mat-cell *matCellDef="let case">
85+
<mat-chip-list>
86+
<mat-chip *ngIf="case.Status == 'none'" color="none">{{ "CREATED" | translate }}</mat-chip>
87+
<mat-chip *ngIf="case.Status == 'started'" color="accent">{{ "STARTED" | translate }}</mat-chip>
88+
<mat-chip *ngIf="case.Status == 'completed'" color="primary">{{ "COMPLETED" | translate }}</mat-chip>
89+
</mat-chip-list>
90+
</td>
91+
</ng-container>
92+
<ng-container matColumnDef="create_datetime">
93+
<th mat-header-cell *matHeaderCellDef mat-sort-header>{{ "CASE_INSTANCE_CREATEDATETIME" | translate }}</th>
94+
<td mat-cell *matCellDef="let case"> {{case.CreateDateTime | date:'medium'}} </td>
95+
</ng-container>
96+
<ng-container matColumnDef="Actions">
97+
<th mat-header-cell *matHeaderCellDef>{{ "CASE_INSTANCE_ACTIONS" | translate }}</th>
98+
<td mat-cell *matCellDef="let case">
99+
<button mat-icon-button (click)="launchInstance(case)">
100+
<mat-icon>play_arrow</mat-icon>
101+
</button>
102+
<button mat-icon-button [routerLink]="['/casedefinitions/' + case.Id ]">
103+
<mat-icon>visibility</mat-icon>
104+
</button>
105+
</td>
106+
</ng-container>
107+
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
108+
<tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr>
109+
</table>
110+
<div *ngIf="isCaseInstancesLoading" class="center-spinner">
111+
<mat-spinner></mat-spinner>
112+
</div>
113+
<div *ngIf="isCaseInstancesErrorLoadOccured" class="error">
114+
<p>{{ "ERROR_LOAD_CASE_INSTANCES" | translate }}</p>
115+
</div>
116+
<mat-paginator [length]="length" [pageSize]="5" [pageSizeOptions]="[5, 10, 25, 100]"></mat-paginator>
117+
</div>
118+
</mat-card-content>
119+
</mat-card>
120+
</div>
62121
</div>
63122
</div>

src/CaseManagement.Website/angularApp/app/casedefinitions/case-def/case-def.component.ts

Lines changed: 42 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,12 @@ import { Component, OnDestroy, OnInit, ViewChild } from '@angular/core';
22
import { MatPaginator, MatSort } from '@angular/material';
33
import { ActivatedRoute } from '@angular/router';
44
import { select, Store } from '@ngrx/store';
5-
import { SearchCaseInstanceItem } from '../models/search-case-instances-result.model';
5+
import { merge } from 'rxjs';
6+
import { CaseDefinition } from '../models/case-def.model';
7+
import { CaseInstance } from '../models/search-case-instances-result.model';
68
import { ActionTypes } from './case-def-actions';
79
import * as fromListCaseDefState from './case-def-states';
8-
import { merge } from 'rxjs';
10+
import { CaseInstancesService } from '../services/caseinstances.service';
911
let CmmnViewer = require('cmmn-js');
1012

1113
@Component({
@@ -15,33 +17,44 @@ let CmmnViewer = require('cmmn-js');
1517
})
1618

1719
export class CaseDefComponent implements OnInit, OnDestroy {
18-
// isLoading: boolean;
19-
// isErrorLoadOccured: boolean;
20-
caseInstances: SearchCaseInstanceItem[] = [];
21-
displayedColumns: string[] = ['Id', 'Name', 'Status', 'CreateDateTime', 'Actions'];
20+
isCaseDefinitionLoading: boolean;
21+
isCaseDefinitionErrorLoadOccured: boolean;
22+
isCaseInstancesLoading: boolean;
23+
isCaseInstancesErrorLoadOccured: boolean;
24+
caseDefinition: CaseDefinition = new CaseDefinition();
25+
selectedCasePlanModel: string;
26+
caseInstances: CaseInstance[] = [];
27+
displayedColumns: string[] = ['name', 'status', 'create_datetime', 'Actions'];
2228
subscription: any;
2329
viewer: any;
2430
length: number;
2531
@ViewChild(MatPaginator) paginator: MatPaginator;
2632
@ViewChild(MatSort) sort: MatSort;
2733

28-
constructor(private store: Store<fromListCaseDefState.CaseDefState>, private route: ActivatedRoute) { }
34+
constructor(private store: Store<fromListCaseDefState.CaseDefState>, private route: ActivatedRoute, private caseInstanceService: CaseInstancesService) { }
2935

3036
ngOnInit() {
3137
let self = this;
32-
// this.isLoading = true;
33-
// this.isErrorLoadOccured = false;
34-
this.viewer = new CmmnViewer({
38+
self.isCaseDefinitionLoading = true;
39+
self.isCaseDefinitionErrorLoadOccured = false;
40+
self.viewer = new CmmnViewer({
3541
container: '#canvas'
3642
});
37-
this.subscription = this.store.pipe(select('caseDef')).subscribe((st: fromListCaseDefState.CaseDefState) => {
43+
self.store.pipe()
44+
self.subscription = self.store.pipe(select('caseDef')).subscribe((st: fromListCaseDefState.CaseDefState) => {
3845
if (!st) {
3946
return;
4047
}
4148

42-
// this.isLoading = st.;
43-
// this.isErrorLoadOccured = st.isErrorLoadOccured;
49+
self.isCaseDefinitionLoading = st.isCaseDefinitionLoading;
50+
self.isCaseDefinitionErrorLoadOccured = st.isCaseDefinitionErrorLoadOccured;
51+
self.isCaseInstancesLoading = st.isCaseInstancesLoading;
52+
self.isCaseInstancesErrorLoadOccured = st.isCaseInstancesErrorLoadOccured;
4453
if (st.caseDefinitionContent) {
54+
self.caseDefinition = st.caseDefinitionContent;
55+
if (self.caseDefinition.CasePlanModels) {
56+
self.selectedCasePlanModel = self.caseDefinition.CasePlanModels[0].Id;
57+
}
4558
self.viewer.importXML(st.caseDefinitionContent.Xml, function (err : any) {
4659
if (!err) {
4760
self.viewer.get('canvas').zoom('fit-viewport');
@@ -54,13 +67,28 @@ export class CaseDefComponent implements OnInit, OnDestroy {
5467
self.caseInstances = st.caseInstancesContent.Content;
5568
}
5669
});
57-
this.refresh();
70+
self.refresh();
5871
}
5972

6073
ngAfterViewInit() {
6174
merge(this.sort.sortChange, this.paginator.page).subscribe(() => this.refresh());
6275
}
6376

77+
createCaseInstance(e: any) {
78+
e.preventDefault();
79+
let self = this;
80+
self.caseInstanceService.create(this.caseDefinition.Id, this.selectedCasePlanModel).subscribe(() => {
81+
self.refresh();
82+
});
83+
}
84+
85+
launchInstance(caseInstance: CaseInstance) {
86+
let self = this;
87+
self.caseInstanceService.launch(caseInstance.Id).subscribe(() => {
88+
self.refresh();
89+
});
90+
}
91+
6492
refresh() {
6593
var id = this.route.snapshot.params['id'];
6694
let loadDefRequest: any = {

0 commit comments

Comments
 (0)