Commit 561655da authored by Alexander Philipp Nowosad's avatar Alexander Philipp Nowosad
Browse files

Add pattern component

parent 07b5b42b
<div class="modal-header">
<h4 class="modal-title" id="modal-basic-title">{{feature.name}}</h4>
<button type="button" class="close" aria-label="Close" (click)="closeModal.emit()">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body">
<ul class="list-group inner" style="margin:5px;">
<li class="list-group-item justify-content-between align-items-center"><i class="fas fa-plus-square"></i>
Add existing business model decisions:
<ul class="list-group inner" style="margin:5px;">
<li class="list-group-item justify-content-between align-items-center" *ngFor=" let f of unselectedFeatures">
<span>
{{f.name}}
<small class="text-muted" *ngIf="f.description">{{ f.description }}</small>
</span>
<button (click)="addBusinessModelDecision.emit(f.id)" type="button"
class="btn btn-warning btn-xs bottom-right">
Add
</button>
</li>
<li class="list-group-item justify-content-between align-items-center" *ngIf="unselectedFeatures.length == 0">
There are no existing business model decisions left to add.
</li>
</ul>
</li>
<li class="list-group-item justify-content-between align-items-center"><i class="fas fa-plus-square"></i>
Add new business model decision:
<ul class="list-group inner" style="margin:5px;">
<li class="list-group-item justify-content-between align-items-center">
<form [formGroup]="addFeatureForm" (ngSubmit)="submitAddFeatureForm()" class="form-inline">
<label class="sr-only" for="name">Decision Name</label>
<input type="text" formControlName="name" class="form-control mb-2 mr-sm-2" id="name">
<button type="submit" class="btn btn-warning btn-xs bottom-right">Add</button>
</form>
</li>
</ul>
</li>
</ul>
</div>
import { Component, EventEmitter, Input, Output } from '@angular/core';
import { FormBuilder, Validators } from '@angular/forms';
import { Instance } from '../../../canvas-meta-model/instance';
import { Feature } from '../../../canvas-meta-model/feature';
@Component({
selector: 'app-add-decision-modal',
templateUrl: './add-decision-modal.component.html',
styleUrls: ['./add-decision-modal.component.css']
})
export class AddDecisionModalComponent {
@Input() instance: Instance;
@Input() feature: Feature;
@Output() closeModal = new EventEmitter<void>();
@Output() addBusinessModelDecision = new EventEmitter<string>();
@Output() addFeature = new EventEmitter<Partial<Feature>>();
addFeatureForm = this.fb.group({name: ['', Validators.required]});
constructor(
private fb: FormBuilder,
) {
}
submitAddFeatureForm() {
this.addFeature.emit(this.addFeatureForm.value);
this.addFeatureForm.reset();
}
get unselectedFeatures(): Feature[] {
return Object.values(this.feature.subfeatures).filter((feature) => !this.instance.usedFeatures.includes(feature.id));
}
}
<div *ngIf="featureModel" class="container businesscanvas">
<div class="row">
<div class="col-2 buildingblock brectangle" [ngStyle]="getHeatmapStyle('key-partners')">
<app-canvas-building-block [doubleBlock]="false" [feature]="featureModel.features['key-partners']"
[instance]="instance"
[conformance]="conformance"
[showWarnings]="conformanceOptions.showWarnings"
[showStrengths]="conformanceOptions.showStrengths"
[showHints]="conformanceOptions.showHints"
[showPatternHints]="conformanceOptions.showPatternHints"
[compareInstance]="compareInstance"
[percentages]="percentages"
[patternInstance]="patternInstance"
[editable]="editable"
(addFeatureEmitter)="addFeatureModal.emit($event)"
(deleteFeatureEmitter)="deleteFeatureModal.emit($event)"></app-canvas-building-block>
</div>
<div class="col-3">
<div class="row">
<div class="col-md-12 buildingblock bsquare" [ngStyle]="getHeatmapStyle('key-activities')">
<app-canvas-building-block [doubleBlock]="false" [feature]="featureModel.features['key-activities']"
[instance]="instance"
[conformance]="conformance"
[showWarnings]="conformanceOptions.showWarnings"
[showStrengths]="conformanceOptions.showStrengths"
[showHints]="conformanceOptions.showHints"
[showPatternHints]="conformanceOptions.showPatternHints"
[compareInstance]="compareInstance"
[percentages]="percentages"
[patternInstance]="patternInstance"
[editable]="editable"
(addFeatureEmitter)="addFeatureModal.emit($event)"
(deleteFeatureEmitter)="deleteFeatureModal.emit($event)"></app-canvas-building-block>
</div>
<div class="col-md-12 buildingblock bsquare" [ngStyle]="getHeatmapStyle('key-resources')">
<app-canvas-building-block [doubleBlock]="false" [feature]="featureModel.features['key-resources']"
[instance]="instance"
[conformance]="conformance"
[showWarnings]="conformanceOptions.showWarnings"
[showStrengths]="conformanceOptions.showStrengths"
[showHints]="conformanceOptions.showHints"
[showPatternHints]="conformanceOptions.showPatternHints"
[compareInstance]="compareInstance"
[percentages]="percentages"
[patternInstance]="patternInstance"
[editable]="editable"
(addFeatureEmitter)="addFeatureModal.emit($event)"
(deleteFeatureEmitter)="deleteFeatureModal.emit($event)"></app-canvas-building-block>
</div>
</div>
</div>
<div class="col-2 buildingblock" [ngStyle]="getHeatmapStyle('value-propositions')">
<app-canvas-building-block [doubleBlock]="false" [feature]="featureModel.features['value-propositions']"
[instance]="instance"
[conformance]="conformance"
[showWarnings]="conformanceOptions.showWarnings"
[showStrengths]="conformanceOptions.showStrengths"
[showHints]="conformanceOptions.showHints"
[showPatternHints]="conformanceOptions.showPatternHints"
[compareInstance]="compareInstance"
[percentages]="percentages"
[patternInstance]="patternInstance"
[editable]="editable"
(addFeatureEmitter)="addFeatureModal.emit($event)"
(deleteFeatureEmitter)="deleteFeatureModal.emit($event)"></app-canvas-building-block>
</div>
<div class="col-3">
<div class="row">
<div class="col-md-12 buildingblock bsquare" [ngStyle]="getHeatmapStyle('customer-relationships')">
<app-canvas-building-block [doubleBlock]="false"
[feature]="featureModel.features['customer-relationships']"
[instance]="instance"
[conformance]="conformance"
[showWarnings]="conformanceOptions.showWarnings"
[showStrengths]="conformanceOptions.showStrengths"
[showHints]="conformanceOptions.showHints"
[showPatternHints]="conformanceOptions.showPatternHints"
[compareInstance]="compareInstance"
[percentages]="percentages"
[patternInstance]="patternInstance"
[editable]="editable"
(addFeatureEmitter)="addFeatureModal.emit($event)"
(deleteFeatureEmitter)="deleteFeatureModal.emit($event)"></app-canvas-building-block>
</div>
<div class="col-md-12 buildingblock bsquare" [ngStyle]="getHeatmapStyle('channels')">
<app-canvas-building-block [doubleBlock]="false" [feature]="featureModel.features['channels']"
[instance]="instance"
[conformance]="conformance"
[showWarnings]="conformanceOptions.showWarnings"
[showStrengths]="conformanceOptions.showStrengths"
[showHints]="conformanceOptions.showHints"
[showPatternHints]="conformanceOptions.showPatternHints"
[compareInstance]="compareInstance"
[percentages]="percentages"
[patternInstance]="patternInstance"
[editable]="editable"
(addFeatureEmitter)="addFeatureModal.emit($event)"
(deleteFeatureEmitter)="deleteFeatureModal.emit($event)"></app-canvas-building-block>
</div>
</div>
</div>
<div class="col-2 buildingblock brectangle" [ngStyle]="getHeatmapStyle('customer-segments')">
<app-canvas-building-block [doubleBlock]="false" [feature]="featureModel.features['customer-segments']"
[instance]="instance"
[conformance]="conformance"
[showWarnings]="conformanceOptions.showWarnings"
[showStrengths]="conformanceOptions.showStrengths"
[showHints]="conformanceOptions.showHints"
[showPatternHints]="conformanceOptions.showPatternHints"
[compareInstance]="compareInstance"
[percentages]="percentages"
[patternInstance]="patternInstance"
[editable]="editable"
(addFeatureEmitter)="addFeatureModal.emit($event)"
(deleteFeatureEmitter)="deleteFeatureModal.emit($event)"></app-canvas-building-block>
</div>
</div>
<div class="row">
<div class="col-6 buildingblock blongtangle" [ngStyle]="getHeatmapStyle('cost-structure')">
<app-canvas-building-block [doubleBlock]="false" [feature]="featureModel.features['cost-structure']"
[instance]="instance"
[conformance]="conformance"
[showWarnings]="conformanceOptions.showWarnings"
[showStrengths]="conformanceOptions.showStrengths"
[showHints]="conformanceOptions.showHints"
[showPatternHints]="conformanceOptions.showPatternHints"
[compareInstance]="compareInstance"
[percentages]="percentages"
[patternInstance]="patternInstance"
[editable]="editable"
(addFeatureEmitter)="addFeatureModal.emit($event)"
(deleteFeatureEmitter)="deleteFeatureModal.emit($event)"></app-canvas-building-block>
</div>
<div class="col-6 buildingblock blongtangle" [ngStyle]="getHeatmapStyle('revenue-streams')">
<app-canvas-building-block [doubleBlock]="false" [feature]="featureModel.features['revenue-streams']"
[instance]="instance"
[conformance]="conformance"
[showWarnings]="conformanceOptions.showWarnings"
[showStrengths]="conformanceOptions.showStrengths"
[showHints]="conformanceOptions.showHints"
[showPatternHints]="conformanceOptions.showPatternHints"
[compareInstance]="compareInstance"
[percentages]="percentages"
[patternInstance]="patternInstance"
[editable]="editable"
(addFeatureEmitter)="addFeatureModal.emit($event)"
(deleteFeatureEmitter)="deleteFeatureModal.emit($event)"></app-canvas-building-block>
</div>
</div>
</div>
import { Component, EventEmitter, Input, Output } from '@angular/core';
import { Instance } from '../../../canvas-meta-model/instance';
import { FeatureModel } from '../../../canvas-meta-model/feature-model';
import { ConformanceReport } from '../../conformance-report';
@Component({
selector: 'app-business-model-canvas',
templateUrl: './business-model-canvas.component.html',
styleUrls: ['./business-model-canvas.component.css']
})
export class BusinessModelCanvasComponent {
@Input() featureModel: FeatureModel;
@Input() instance: Instance;
@Input() conformance: ConformanceReport = new ConformanceReport();
@Input() conformanceOptions: {
showWarnings: boolean,
showStrengths: boolean,
showHints: boolean,
showPatternHints: boolean,
} = {
showHints: false,
showPatternHints: false,
showStrengths: false,
showWarnings: false,
};
@Input() compareInstance: Instance = null;
@Input() percentages: { [id: string]: number } = null;
@Input() patternInstance: Instance = null;
@Input() editable = true;
@Output() addFeatureModal = new EventEmitter<string>();
@Output() deleteFeatureModal = new EventEmitter<string>();
getHeatmapStyle(featureId: string) {
return this.percentages ? {'background-color': 'hsla(' + (this.percentages[featureId] / 100) * 120 + ', 100%, 66%, 0.3)'} : {};
}
}
<ul [class.no-list]="levelDepth === 1" class="list-group" style="margin-top: 5px; margin-left:5px;">
<li>
<ng-container *ngIf="instance.usedFeatures.includes(feature.id)">
<strong *ngIf="levelDepth === 1"
[class.text-success]="compareInstance && !compareInstance.usedFeatures.includes(feature.id) ||
showStrengths && conformance.strengthFeatureIds.includes(feature.id)"
[class.text-danger]="conformance.errorFeatureIds.includes(feature.id)"
[class.text-warning]="conformance.warningFeatureIds.includes(feature.id) && showWarnings">
{{feature.name}}
</strong>
<span *ngIf="levelDepth !== 1"
[class.text-success]="compareInstance && !compareInstance.usedFeatures.includes(feature.id) ||
showStrengths && conformance.strengthFeatureIds.includes(feature.id) ||
patternInstance && patternInstance.usedFeatures.includes(feature.id)"
[class.text-danger]="conformance.errorFeatureIds.includes(feature.id)"
[class.text-warning]="conformance.warningFeatureIds.includes(feature.id) && showWarnings">{{feature.name}}</span>
<i class="fas fa-plus-square ml-2" *ngIf="editable" (click)="addFeature(feature.id)"></i>
<i class="fas fa-minus-square ml-2" *ngIf="feature.parent !== null && editable"
(click)="deleteFeature(feature.id)"></i>
<small
*ngIf="percentages && asList(feature.subfeatures).length > 0 &&
compareInstance && compareInstance.usedFeatures.includes(feature.id) &&
instance.usedFeatures.includes(feature.id)"
class="text-muted ml-1">{{ percentages[feature.id] | number:".2-2" }}&nbsp;%</small>
</ng-container>
<em *ngIf="!instance.usedFeatures.includes(feature.id)"
[class.text-danger]="conformance.errorFeatureIds.includes(feature.id) || (compareInstance && compareInstance.usedFeatures.includes(feature.id)) || (patternInstance && patternInstance.usedFeatures.includes(feature.id))"
[class.text-success]="conformance.hintFeatureIds.includes(feature.id) && showHints"
[class.text-muted]="(conformance.patternHintFeatureIds.includes(feature.id) && showPatternHints)">{{feature.name}}</em>
<span *ngFor="let f of asList(feature.subfeatures)">
<app-canvas-building-block [doubleBlock]="doubleBlock" [feature]="f"
[instance]="instance"
*ngIf="
instance.usedFeatures.includes(f.id) ||
conformance.errorFeatureIds.includes(f.id) ||
(conformance.warningFeatureIds.includes(f.id) && showWarnings) ||
(conformance.strengthFeatureIds.includes(f.id) && showStrengths) ||
(conformance.hintFeatureIds.includes(f.id) && showHints) ||
(conformance.patternHintFeatureIds.includes(f.id) && showPatternHints) ||
(compareInstance && compareInstance.usedFeatures.includes(f.id)) ||
(patternInstance && patternInstance.usedFeatures.includes(f.id))"
[levelDepth]="levelDepth + 1"
[conformance]="conformance"
[showWarnings]="showWarnings"
[showStrengths]="showStrengths"
[showHints]="showHints"
[showPatternHints]="showPatternHints"
[compareInstance]="compareInstance"
[percentages]="percentages"
[patternInstance]="patternInstance"
[editable]="editable"
(addFeatureEmitter)="addFeatureForwardEmitter($event)"
(deleteFeatureEmitter)="deleteFeatureForwardEmitter($event)"></app-canvas-building-block>
</span>
</li>
</ul>
import { Component, EventEmitter, Input, Output } from '@angular/core';
import { Feature } from '../../../canvas-meta-model/feature';
import { Instance } from '../../../canvas-meta-model/instance';
import { ConformanceReport } from '../../conformance-report';
@Component({
selector: 'app-canvas-building-block',
templateUrl: './canvas-building-block.component.html',
styleUrls: ['./canvas-building-block.component.css']
})
/**
* Internal class to display single business model decisions of the business model canvas.
*
* @author Sebastian Gottschalk
*/
export class CanvasBuildingBlockComponent {
@Input() feature: Feature;
@Input() levelDepth = 1;
@Input() instance: Instance;
@Input() doubleBlock: boolean;
@Input() conformance: ConformanceReport;
@Input() showWarnings: boolean;
@Input() showStrengths: boolean;
@Input() showHints: boolean;
@Input() showPatternHints: boolean;
@Input() compareInstance: Instance = null;
@Input() percentages: { [id: string]: number } = null;
@Input() patternInstance: Instance = null;
@Input() editable: boolean;
@Output() addFeatureEmitter = new EventEmitter<string>();
@Output() deleteFeatureEmitter = new EventEmitter<string>();
/**
* Create a new instance of the CanvasBuildingBlockComponent.
*/
constructor() {
}
/**
* Emit Event to add feature.
* @param featureId current feature
*/
addFeature(featureId: string) {
this.addFeatureEmitter.emit(featureId);
}
/**
* Emit Event to delete feature.
* @param featureId current feature
*/
deleteFeature(featureId: string) {
this.deleteFeatureEmitter.emit(featureId);
}
/**
* Forward event emitter to add feature.
* @param featureId current feature
*/
addFeatureForwardEmitter(featureId: string) {
this.addFeature(featureId);
}
/**
* Forward event emitter to delete feature.
* @param featureId featureId
*/
deleteFeatureForwardEmitter(featureId: string) {
this.deleteFeature(featureId);
}
asList(map: { [id: string]: Feature }): Feature[] {
return Object.values(map);
}
}
<div class="modal-header">
<h4 class="modal-title" id="modal-basic-title">{{feature.name}}</h4>
<button type="button" class="close" aria-label="Close" (click)="closeModal.emit()">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body">
<div class="alert alert-warning" role="alert">
<p>You are trying to remove the decision "{{feature.name}}". Please keep in mind that you are removing
also all subdecisions.</p>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-block btn-warning" (click)="deleteBusinessModelDecision.emit(feature.id)">
Delete Decision
</button>
</div>
import { Component, EventEmitter, Input, Output } from '@angular/core';
import { Feature } from '../../../canvas-meta-model/feature';
@Component({
selector: 'app-delete-decision-modal',
templateUrl: './delete-decision-modal.component.html',
styleUrls: ['./delete-decision-modal.component.css']
})
export class DeleteDecisionModalComponent {
@Input() feature: Feature;
@Output() closeModal = new EventEmitter<void>();
@Output() deleteBusinessModelDecision = new EventEmitter<string>();
}
<form [formGroup]="instanceForm" (ngSubmit)="submitForm()">
<div class="form-group row">
<label for="name" class="col-sm-4 col-form-label">Instance Name</label>
<div class="col-sm-8">
<input type="text" formControlName="name" class="form-control" id="name">
</div>
</div>
<div class="form-group row">
<label for="description" class="col-sm-4 col-form-label">Instance Description</label>
<div class="col-sm-8">
<input type="text" formControlName="description" class="form-control" id="description">
</div>
</div>
<div class="form-group row">
<div class="col-sm-12">
<button type="submit" class="btn btn-sm btn-dark btn-block" [disabled]="!instanceForm.valid">
Update Instance
</button>
</div>
</div>
</form>
import { Component, EventEmitter, Input, OnChanges, Output, SimpleChanges } from '@angular/core';
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
import { Instance } from '../../../canvas-meta-model/instance';
@Component({
selector: 'app-instance-form',
templateUrl: './instance-form.component.html',
styleUrls: ['./instance-form.component.css']
})
export class InstanceFormComponent implements OnChanges {
@Input() instance: Instance;
@Output() submitInstanceForm = new EventEmitter<FormGroup>();
instanceForm: FormGroup;
constructor(
private fb: FormBuilder,
) {
}
ngOnChanges(changes: SimpleChanges) {
if (changes.instance) {
this.loadForm(changes.instance.currentValue);
}
}
submitForm() {
this.submitInstanceForm.emit(this.instanceForm);
this.loadForm(this.instance);
}
private loadForm(instance: Instance) {
this.instanceForm = this.fb.group({
name: [instance.name, Validators.required],
description: [instance.description ? instance.description : '']
});
}
}
<div class="my-3 p-3 bg-white rounded shadow-sm">
<h6 class="border-bottom border-gray pb-2 mb-0">Instance Info</h6>
<table class="table table-sm mb-0" style="table-layout: fixed">
<tbody>
<tr class="table-borderless">
<th scope="row" style="width: 250px">Instance Name</th>
<td>{{ instance.name }}</td>
</tr>
<tr>
<th scope="row">Instance Description</th>
<td>{{ instance.description }}</td>
</tr>
<tr>
<th scope="row">Instance Type</th>
<td>{{ instance.type }}</td>
</tr>
<tr>
<th scope="row">Feature Model</th>
<td>{{ featureModel.name }}<span *ngIf="featureModel.hasOwnProperty('version')"> ({{ $any(featureModel).version }}
)</span></td>
</tr>
<tr>
<th scope="row">Feature Model Type</th>
<td>{{ featureModel.hasOwnProperty('version') ? 'Expert Model' : 'Company Model' }}</td>
</tr>
</tbody>
</table>
</div>
import { Component, Input } from '@angular/core';
import { FeatureModel } from '../../../canvas-meta-model/feature-model';
import { Instance } from '../../../canvas-meta-model/instance';
@Component({
selector: 'app-instance-info-box',
templateUrl: './instance-info-box.component.html',
styleUrls: ['./instance-info-box.component.css']