Skip to content
Snippets Groups Projects
Commit 05a288ab authored by Alexander Philipp Nowosad's avatar Alexander Philipp Nowosad
Browse files

Add select elements in bm process

parent 1e36a542
No related branches found
No related tags found
No related merge requests found
Pipeline #
Showing
with 409 additions and 123 deletions
import { PouchdbModel } from '../database/pouchdb-model';
import { SituationalFactor } from './situational-factor';
import { DevelopmentMethod } from './development-method';
import { Decision } from './decision';
import { Decision, GroupSelection } from './decision';
import { Stakeholder } from './stakeholder';
import { Artifact } from './artifact';
export class BmProcess extends PouchdbModel {
......@@ -75,19 +77,10 @@ export class BmProcess extends PouchdbModel {
addDecision(id: string, method: DevelopmentMethod) {
this.decisions[id] = new Decision({
method,
stakeholders: {
selectedGroup: null,
elements: null,
},
inputArtifacts: {
selectedGroup: null,
elements: null,
},
outputArtifacts: {
selectedGroup: null,
elements: null,
},
tools: Array(method.tools.length).fill(null),
stakeholders: new GroupSelection<Stakeholder>({}, null),
inputArtifacts: new GroupSelection<Artifact>({}, null),
outputArtifacts: new GroupSelection<Artifact>({}, null),
tools: null,
});
}
......
......@@ -2,23 +2,52 @@ import { DevelopmentMethod } from './development-method';
import { Artifact } from './artifact';
import { Stakeholder } from './stakeholder';
import { Tool } from './tool';
import { MethodElement } from './method-element';
export class GroupSelection<T extends MethodElement> {
selectedGroup: number = null;
elements: T[][] = null;
constructor(groupSelection: Partial<GroupSelection<T>>, createElement: (element: Partial<T>) => T) {
this.update(groupSelection, createElement);
}
update(groupSelection: Partial<GroupSelection<T>>, createElement: (element: Partial<T>) => T) {
Object.assign(this, groupSelection);
this.elements = this.elements
? this.elements.map((element) =>
element
? element.map((e) =>
e ? createElement(e) : null
)
: null
)
: null;
}
toPouchDb(): any {
return {
selectedGroup: this.selectedGroup,
elements: this.elements
? this.elements.map((element) =>
element
? element.map((e) =>
e ? e.toPouchDb() : null
)
: null
)
: null,
};
}
}
export class Decision {
method: DevelopmentMethod;
inputArtifacts: {
selectedGroup: number;
elements: Artifact[];
};
outputArtifacts: {
selectedGroup: number;
elements: Artifact[];
};
stakeholders: {
selectedGroup: number;
elements: Stakeholder[];
};
tools: Tool[] = [];
inputArtifacts: GroupSelection<Artifact>;
outputArtifacts: GroupSelection<Artifact>;
stakeholders: GroupSelection<Stakeholder>;
tools: Tool[][] = null;
constructor(decision: Partial<Decision>) {
this.update(decision);
......@@ -27,49 +56,19 @@ export class Decision {
update(decision: Partial<Decision>) {
Object.assign(this, decision);
this.method = new DevelopmentMethod(this.method);
this.inputArtifacts = {
selectedGroup: this.inputArtifacts.selectedGroup,
elements: this.inputArtifacts.elements
? this.inputArtifacts.elements.map((artifact) => artifact ? new Artifact(artifact) : null)
: null,
};
this.outputArtifacts = {
selectedGroup: this.outputArtifacts.selectedGroup,
elements: this.outputArtifacts.elements
? this.outputArtifacts.elements.map((artifact) => artifact ? new Artifact(artifact) : null)
: null,
};
this.stakeholders = {
selectedGroup: this.stakeholders.selectedGroup,
elements: this.stakeholders.elements
? this.stakeholders.elements.map((stakeholder) => stakeholder ? new Stakeholder(stakeholder) : null)
: null,
};
this.tools = this.tools.map((tool) => tool ? new Tool(tool) : null);
this.inputArtifacts = new GroupSelection<Artifact>(this.inputArtifacts, (artifact) => new Artifact(artifact));
this.outputArtifacts = new GroupSelection<Artifact>(this.outputArtifacts, (artifact) => new Artifact(artifact));
this.stakeholders = new GroupSelection<Stakeholder>(this.stakeholders, (stakeholder) => new Stakeholder(stakeholder));
this.tools = this.tools ? this.tools.map((tool) => tool ? tool.map((t) => t ? new Tool(t) : null) : null) : null;
}
toPouchDb(): any {
return {
method: this.method.toPouchDb(),
inputArtifacts: {
selectedGroup: this.inputArtifacts.selectedGroup,
elements: this.inputArtifacts.elements
? this.inputArtifacts.elements.map((artifact) => artifact ? artifact.toPouchDb() : null)
: null,
},
outputArtifacts: {
selectedGroup: this.outputArtifacts.selectedGroup,
elements: this.outputArtifacts.elements
? this.outputArtifacts.elements.map((artifact) => artifact ? artifact.toPouchDb() : null)
: null,
},
stakeholders: {
selectedGroup: this.stakeholders.selectedGroup,
elements: this.stakeholders.elements
? this.stakeholders.elements.map((stakeholder) => stakeholder ? stakeholder.toPouchDb() : null)
: null,
},
tools: this.tools.map((tool) => tool ? tool.toPouchDb() : null),
inputArtifacts: this.inputArtifacts.toPouchDb(),
outputArtifacts: this.outputArtifacts.toPouchDb(),
stakeholders: this.stakeholders.toPouchDb(),
tools: this.tools ? this.tools.map((tool) => tool ? tool.map((t) => t ? t.toPouchDb() : null) : null) : null,
};
}
......
<app-method-element-group-info [groups]="groups" [selection]="selection" [methodElements]="methodElements"
methodElementName="Artifact"
(submitGroupsForm)="submitGroupsForm.emit($event)"></app-method-element-group-info>
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { ArtifactsGroupInfoComponent } from './artifacts-group-info.component';
describe('ArtifactsGroupInfoComponent', () => {
let component: ArtifactsGroupInfoComponent;
let fixture: ComponentFixture<ArtifactsGroupInfoComponent>;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ ArtifactsGroupInfoComponent ]
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(ArtifactsGroupInfoComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});
import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core';
import { Artifact } from '../../development-process-registry/artifact';
import { ArtifactService } from '../../development-process-registry/artifact.service';
import { FormGroup } from '@angular/forms';
import { GroupSelection } from '../../development-process-registry/decision';
@Component({
selector: 'app-artifacts-group-info',
templateUrl: './artifacts-group-info.component.html',
styleUrls: ['./artifacts-group-info.component.css']
})
export class ArtifactsGroupInfoComponent implements OnInit {
@Input() groups: { list: string, element: Artifact }[][];
@Input() selection: GroupSelection<Artifact>;
@Output() submitGroupsForm = new EventEmitter<FormGroup>();
methodElements: Artifact[] = [];
constructor(
private artifactService: ArtifactService,
) {
}
ngOnInit() {
this.loadMethodElements();
}
private loadMethodElements() {
this.artifactService.getAll().then((artifacts) => this.methodElements = artifacts.docs);
}
}
......@@ -122,7 +122,8 @@
</button>
</div>
<div class="modal-body">
<app-method-info [developmentMethod]="modalDevelopmentMethod"></app-method-info>
<app-method-info [developmentMethod]="modalDevelopmentMethod" [decision]="bmProcess.decisions[modalElement.id]"
(updateDecisions)="updateDecisions($event)"></app-method-info>
</div>
</ng-template>
......
......@@ -281,6 +281,11 @@ export class BmProcessDiagramComponent implements DiagramComponentInterface, OnI
});
}
updateDecisions(value: any) {
this.bmProcess.decisions[this.modalElement.id].update(value);
this.saveDiagram(this.bmProcess.decisions);
}
saveDiagram(decisions = null): Promise<void> {
return this.modeler.saveXML().then(result => {
if (decisions !== null) {
......
......@@ -36,6 +36,11 @@ import { StakeholdersSelectionFormComponent } from './stakeholders-selection-for
import { ToolsSelectionFormComponent } from './tools-selection-form/tools-selection-form.component';
import { ExamplesFormComponent } from './examples-form/examples-form.component';
import { MethodInfoComponent } from './method-info/method-info.component';
import { MethodElementGroupInfoComponent } from './method-element-group-info/method-element-group-info.component';
import { MethodElementInfoComponent } from './method-element-info/method-element-info.component';
import { ArtifactsGroupInfoComponent } from './artifacts-group-info/artifacts-group-info.component';
import { StakeholdersGroupInfoComponent } from './stakeholders-group-info/stakeholders-group-info.component';
import { ToolsInfoComponent } from './tools-info/tools-info.component';
@NgModule({
......@@ -73,6 +78,11 @@ import { MethodInfoComponent } from './method-info/method-info.component';
ToolsSelectionFormComponent,
ExamplesFormComponent,
MethodInfoComponent,
MethodElementGroupInfoComponent,
MethodElementInfoComponent,
ArtifactsGroupInfoComponent,
StakeholdersGroupInfoComponent,
ToolsInfoComponent,
],
entryComponents: [ConfirmLeaveModalComponent],
imports: [
......
<form [formGroup]="form" (ngSubmit)="submitForm()">
<ul class="form-group list-group" ngbRadioGroup formControlName="selectedGroup">
<li *ngFor="let group of groups; let index = index" class="list-group-item">
<ul class="list-group shadow-sm">
<li [class.list-group-item-secondary]="selectedGroup !== index"
[class.list-group-item-primary]="selectedGroup === index"
class="list-group-item d-flex align-items-baseline">
<h5 class="mb-0">Group</h5>
<div class="ml-auto btn-group btn-group-toggle">
<label ngbButtonLabel class="btn-primary">
<input ngbButton type="radio" [value]="index"> Select
</label>
</div>
</li>
<ng-container *ngIf="selectedGroup !== index">
<li *ngFor="let element of group" class="list-group-item">
<app-method-element-info
[listName]="element.list"
[methodElement]="element.element"
[methodElementName]="methodElementName"></app-method-element-info>
</li>
</ng-container>
<ng-container *ngIf="selectedGroup === index">
<li *ngFor="let element of group; let elementIndex = index" class="list-group-item" formArrayName="elements">
<app-method-element-info
[formArrayName]="elementIndex.toString()"
[listName]="element.list"
[methodElement]="element.element"
[methodElements]="methodElements"
[methodElementName]="methodElementName"></app-method-element-info>
</li>
</ng-container>
</ul>
</li>
</ul>
<div *ngIf="groups.length > 0" class="form-group row mt-3">
<div class="col-sm-12">
<button type="submit" class="btn btn-sm btn-dark btn-block" [disabled]="!form.valid">
<ng-container>Update</ng-container>
</button>
</div>
</div>
</form>
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { MethodElementGroupInfoComponent } from './method-element-group-info.component';
describe('MethodElementGroupInfoComponent', () => {
let component: MethodElementGroupInfoComponent;
let fixture: ComponentFixture<MethodElementGroupInfoComponent>;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ MethodElementGroupInfoComponent ]
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(MethodElementGroupInfoComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});
import { Component, EventEmitter, Input, OnChanges, OnDestroy, OnInit, Output, SimpleChanges } from '@angular/core';
import { MethodElement } from '../../development-process-registry/method-element';
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
import { Subscription } from 'rxjs';
import { GroupSelection } from '../../development-process-registry/decision';
@Component({
selector: 'app-method-element-group-info',
templateUrl: './method-element-group-info.component.html',
styleUrls: ['./method-element-group-info.component.css']
})
export class MethodElementGroupInfoComponent implements OnInit, OnChanges, OnDestroy {
@Input() methodElementName: string;
@Input() groups: { list: string, element: MethodElement }[][];
@Input() selection: GroupSelection<MethodElement>;
@Input() methodElements: MethodElement[] = [];
@Output() submitGroupsForm = new EventEmitter<FormGroup>();
form: FormGroup = this.fb.group({
selectedGroup: [null, Validators.required],
elements: this.fb.array([]),
});
private selectedIndexSubscription: Subscription;
constructor(
private fb: FormBuilder,
) {
}
ngOnInit() {
this.selectedIndexSubscription = this.selectedGroupControl.valueChanges.subscribe((value) => this.generateControls(value));
}
ngOnChanges(changes: SimpleChanges) {
if (changes.selection || changes.groups) {
this.loadForm();
}
}
ngOnDestroy() {
if (this.selectedIndexSubscription) {
this.selectedIndexSubscription.unsubscribe();
}
}
submitForm() {
this.submitGroupsForm.emit(this.form);
}
private loadForm() {
this.selectedGroupControl.setValue(this.selection.selectedGroup, {emitEvent: false});
this.generateControls(this.selection.selectedGroup);
if (this.selection.elements) {
this.elementsFormArray.patchValue(this.selection.elements);
}
}
private generateControls(selectedGroup: number) {
if (selectedGroup !== null) {
const elements = this.groups[selectedGroup].map(() => this.fb.array([this.fb.control(null)]));
this.form.setControl('elements', this.fb.array(elements));
} else {
this.form.setControl('elements', this.fb.control(null));
}
}
get selectedGroupControl() {
return this.form.get('selectedGroup');
}
get selectedGroup() {
return this.selectedGroupControl.value;
}
get elementsFormArray() {
return this.form.get('elements');
}
}
<div class="form-row">
<div class="form-group col">
<label for="listInput">List</label>
<input
readonly
type="text"
[value]="listName"
class="form-control-plaintext"
id="listInput">
</div>
<div class="form-group col" *ngIf="!methodElement">
<label for="elementInput">{{methodElementName}}</label>
<input *ngIf="formArray"
type="text"
[formControl]="$any(formArray.controls[0])"
class="form-control"
id="elementInput"
[ngbTypeahead]="searchElements"
[editable]="false"
[resultFormatter]="formatter"
[inputFormatter]="formatter"
(click)="openElementInput.next($any($event.target).value)"
(focus)="openElementInput.next($any($event.target).value)">
</div>
<div class="form-group col" *ngIf="methodElement">
<label for="elementInputStatic">{{methodElementName}}</label>
<input
readonly
type="text"
[value]="methodElement.name"
class="form-control-plaintext"
id="elementInputStatic">
</div>
</div>
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { MethodElementInfoComponent } from './method-element-info.component';
describe('MethodElementInfoComponent', () => {
let component: MethodElementInfoComponent;
let fixture: ComponentFixture<MethodElementInfoComponent>;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ MethodElementInfoComponent ]
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(MethodElementInfoComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});
import { Component, Input, Optional } from '@angular/core';
import { MethodElement } from '../../development-process-registry/method-element';
import { merge, Observable, Subject } from 'rxjs';
import { FormArrayName } from '@angular/forms';
import { getTypeaheadInputPipe } from '../../shared/utils';
import { map } from 'rxjs/operators';
@Component({
selector: 'app-method-element-info',
templateUrl: './method-element-info.component.html',
styleUrls: ['./method-element-info.component.css']
})
export class MethodElementInfoComponent {
@Input() methodElementName: string;
@Input() listName: string;
@Input() methodElement: MethodElement = null;
@Input() multiple = false;
@Input() methodElements: MethodElement[] = [];
openElementInput = new Subject<string>();
constructor(
@Optional() private formArrayName: FormArrayName,
) {
}
searchElements = (input: Observable<string>) => {
return merge(getTypeaheadInputPipe(input), this.openElementInput).pipe(
map(
(term) => this.methodElements.filter((methodElement) =>
methodElement.list.toLowerCase() === this.listName.toLowerCase() &&
methodElement.name.toLowerCase().includes(term.toLowerCase())
).slice(0, 7)
),
);
}
formatter(x: { name: string }) {
return x.name;
}
get formArray() {
return this.formArrayName ? this.formArrayName.control : null;
}
}
......@@ -21,77 +21,29 @@
<tr>
<th scope="row">Input Artifacts</th>
<td>
<ul class="list-group">
<li *ngFor="let group of developmentMethod.inputArtifacts" class="list-group-item">
<ul class="list-group shadow-sm">
<li *ngFor="let artifact of group" class="list-group-item">
<ng-container *ngIf="artifact.element">
<h5 class="mb-1"><<{{artifact.list}}>> {{artifact.element.name}}</h5>
<p class="mb-1 show-new-lines">{{artifact.element.description}}</p>
</ng-container>
<ng-container *ngIf="!artifact.element">
<h5 class="mb-1"><<{{artifact.list}}>></h5>
</ng-container>
</li>
</ul>
</li>
</ul>
<app-artifacts-group-info [selection]="decision.inputArtifacts" [groups]="developmentMethod.inputArtifacts"
(submitGroupsForm)="updateDecisions.emit({inputArtifacts: $event.value})"></app-artifacts-group-info>
</td>
</tr>
<tr>
<th scope="row">Output Artifacts</th>
<td>
<ul class="list-group">
<li *ngFor="let group of developmentMethod.outputArtifacts" class="list-group-item">
<ul class="list-group shadow-sm">
<li *ngFor="let artifact of group" class="list-group-item">
<ng-container *ngIf="artifact.element">
<h5 class="mb-1"><<{{artifact.list}}>> {{artifact.element.name}}</h5>
<p class="mb-1 show-new-lines">{{artifact.element.description}}</p>
</ng-container>
<ng-container *ngIf="!artifact.element">
<h5 class="mb-1"><<{{artifact.list}}>></h5>
</ng-container>
</li>
</ul>
</li>
</ul>
<app-artifacts-group-info [selection]="decision.outputArtifacts" [groups]="developmentMethod.outputArtifacts"
(submitGroupsForm)="updateDecisions.emit({outputArtifacts: $event.value})"></app-artifacts-group-info>
</td>
</tr>
<tr>
<th scope="row">Involved Stakeholders</th>
<td>
<ul class="list-group">
<li *ngFor="let group of developmentMethod.stakeholders" class="list-group-item">
<ul class="list-group shadow-sm">
<li *ngFor="let stakeholder of group" class="list-group-item">
<ng-container *ngIf="stakeholder.element">
<h5 class="mb-1"><<{{stakeholder.list}}>> {{stakeholder.element.name}}</h5>
<p class="mb-1 show-new-lines">{{stakeholder.element.description}}</p>
</ng-container>
<ng-container *ngIf="!stakeholder.element">
<h5 class="mb-1"><<{{stakeholder.list}}>></h5>
</ng-container>
</li>
</ul>
</li>
</ul>
<app-stakeholders-group-info [selection]="decision.stakeholders" [groups]="developmentMethod.stakeholders"
(submitGroupsForm)="updateDecisions.emit({stakeholders: $event.value})"></app-stakeholders-group-info>
</td>
</tr>
<tr>
<th scope="row">Tools</th>
<td>
<ul class="list-group">
<li *ngFor="let tool of developmentMethod.tools" class="list-group-item">
<ng-container *ngIf="tool.element">
<h5 class="mb-1"><<{{tool.list}}>> {{tool.element.name}}</h5>
<p class="mb-1 show-new-lines">{{tool.element.description}}</p>
</ng-container>
<ng-container *ngIf="!tool.element">
<h5 class="mb-1"><<{{tool.list}}>></h5>
</ng-container>
</li>
</ul>
<app-tools-info [selection]="decision.tools" [elements]="developmentMethod.tools"
(submitToolForm)="updateDecisions.emit({tools: $event.value})"></app-tools-info>
</td>
</tr>
</tbody>
......
import { Component, Input, OnInit } from '@angular/core';
import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core';
import { DevelopmentMethod } from '../../development-process-registry/development-method';
import { Decision } from '../../development-process-registry/decision';
@Component({
selector: 'app-method-info',
......@@ -9,6 +10,9 @@ import { DevelopmentMethod } from '../../development-process-registry/developmen
export class MethodInfoComponent implements OnInit {
@Input() developmentMethod: DevelopmentMethod;
@Input() decision: Decision;
@Output() updateDecisions = new EventEmitter<any>();
constructor() {
}
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment