Skip to content

Commit de6b901

Browse files
committed
Merge branch 'master' into ustutt
2 parents ac26331 + 5b9d45b commit de6b901

12 files changed

+416
-1
lines changed

NOTICE

+1
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@ Copyright (c) 2018 Vladimir Yussupov
7171
Copyright (c) 2019 Dominik Voigt
7272
Copyright (c) 2019 Lisa Podszun
7373
Copyright (c) 2019 Ruben Verma
74+
Copyright (c) 2019 Tobias Mathony
7475
Copyright (c) 2019 Yannik Dietrich
7576
Copyright (c) 2019 Yuye Tong
7677

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
/********************************************************************************
2+
* Copyright (c) 2019 Contributors to the Eclipse Foundation
3+
*
4+
* See the NOTICE file(s) distributed with this work for additional
5+
* information regarding copyright ownership.
6+
*
7+
* This program and the accompanying materials are made available under the
8+
* terms of the Eclipse Public License 2.0 which is available at
9+
* http://www.eclipse.org/legal/epl-2.0, or the Apache Software License 2.0
10+
* which is available at https://www.apache.org/licenses/LICENSE-2.0.
11+
*
12+
* SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
13+
*******************************************************************************/
14+
div.enrichmentContainer {
15+
margin-top: 1em;
16+
margin-left: 1em;
17+
margin-right: 1em;
18+
}
19+
20+
a.title {
21+
font-weight: bold;
22+
}
23+
.innerContainer {
24+
margin: 1em auto;
25+
}
26+
27+
button.btn.btn-sm {
28+
margin-left: 1em;
29+
margin-bottom: 1em;
30+
margin-right: 1em;
31+
width: 40%;
32+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
<!--~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2+
~ Copyright (c) 2019 Contributors to the Eclipse Foundation
3+
~
4+
~ See the NOTICE file(s) distributed with this work for additional
5+
~ information regarding copyright ownership.
6+
~
7+
~ This program and the accompanying materials are made available under the
8+
~ terms of the Eclipse Public License 2.0 which is available at
9+
~ http://www.eclipse.org/legal/epl-2.0, or the Apache Software License 2.0
10+
~ which is available at https://www.apache.org/licenses/LICENSE-2.0.
11+
~
12+
~ SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
13+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~-->
14+
15+
<div id="EnricherView" *ngIf="availableFeatures" class="sidebar-root">
16+
<div class="enrichmentContainer">
17+
<a class="title">Management Feature Enrichment</a>
18+
<accordion>
19+
<accordion-group class="innerContainer" [isOpen]="i === 0"
20+
heading="{{availableFeatures[i].nodeTemplateId}}"
21+
panelClass="panel-info"
22+
(mouseover)="onHoverOver(entry)"
23+
(mouseleave)="hoverOut()"
24+
*ngFor="let entry of availableFeatures; let i = index;">
25+
Available Enrichments:
26+
<div *ngFor="let feature of entry.features">
27+
<input type="checkbox" (change)="featureSelectionChanged(feature, entry, $event)">
28+
{{feature.featureName}}
29+
</div>
30+
</accordion-group>
31+
</accordion>
32+
</div>
33+
<div class="innerContainer">
34+
<button type="button" class="btn btn-sm btn-primary"
35+
[disabled]="toApply.length===0"
36+
(click)="applyEnrichment()">Apply
37+
</button>
38+
<button type="button" class="btn btn-sm btn-danger"
39+
(click)="cancel()">
40+
Cancel
41+
</button>
42+
</div>
43+
</div>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,214 @@
1+
/*******************************************************************************
2+
* Copyright (c) 2019 Contributors to the Eclipse Foundation
3+
*
4+
* See the NOTICE file(s) distributed with this work for additional
5+
* information regarding copyright ownership.
6+
*
7+
* This program and the accompanying materials are made available under the
8+
* terms of the Eclipse Public License 2.0 which is available at
9+
* http://www.eclipse.org/legal/epl-2.0, or the Apache Software License 2.0
10+
* which is available at https://www.apache.org/licenses/LICENSE-2.0.
11+
*
12+
* SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
13+
*******************************************************************************/
14+
import { Component } from '@angular/core';
15+
import { NgRedux } from '@angular-redux/store';
16+
import { IWineryState } from '../redux/store/winery.store';
17+
import { TopologyRendererActions } from '../redux/actions/topologyRenderer.actions';
18+
import { WineryActions } from '../redux/actions/winery.actions';
19+
import { TopologyRendererState } from '../redux/reducers/topologyRenderer.reducer';
20+
import { HttpErrorResponse } from '@angular/common/http';
21+
import { ToastrService } from 'ngx-toastr';
22+
import { TTopologyTemplate } from '../models/ttopology-template';
23+
import { Utils } from '../models/utils';
24+
import { EnricherService } from './enricher.service';
25+
import { Enrichment, FeatureEntity } from './enrichmentEntity';
26+
27+
@Component({
28+
selector: 'winery-enricher',
29+
templateUrl: './enricher.component.html',
30+
styleUrls: ['./enricher.component.css']
31+
})
32+
export class EnricherComponent {
33+
34+
// enrichment object containing available features
35+
availableFeatures: Enrichment;
36+
// array to store enrichment to be applied
37+
toApply = [];
38+
39+
constructor(private ngRedux: NgRedux<IWineryState>,
40+
private actions: TopologyRendererActions,
41+
private wineryActions: WineryActions,
42+
private alert: ToastrService,
43+
private enricherService: EnricherService) {
44+
this.ngRedux.select(state => state.topologyRendererState)
45+
.subscribe(currentButtonsState => this.checkButtonsState(currentButtonsState));
46+
}
47+
48+
/**
49+
* This method checks the current button state of Winery UI to take action when the Enrichment Button was clicked.
50+
* @param currentButtonsState TopologyRendererState object containt state of Winery UI Buttons
51+
*/
52+
private checkButtonsState(currentButtonsState: TopologyRendererState) {
53+
// check if Enrichment Button is clicked and available features are pulled
54+
if (currentButtonsState.buttonsState.enrichmentButton && !this.availableFeatures) {
55+
this.enricherService.getAvailableFeatures().subscribe(
56+
data => this.showAvailableFeatures(data),
57+
error => this.handleError(error)
58+
);
59+
// if button is unclicked, reset available features
60+
} else if (!currentButtonsState.buttonsState.enrichmentButton) {
61+
this.availableFeatures = null;
62+
}
63+
}
64+
65+
/**
66+
* This method is called when the selection of a enrichment is changed.
67+
* It pushs/removes the selected/removed enrichment from the array of enrichments to be applied
68+
* @param feature: feature which changed
69+
* @param node: node template id where enrichment shall be applied later
70+
* @param event: selection changed event from checkbox
71+
*/
72+
protected featureSelectionChanged(feature: FeatureEntity, node: Enrichment, event: any) {
73+
const isChecked = event.target.checked;
74+
const nodeTemplate = node.nodeTemplateId;
75+
// if a new feature was selected and to applicable enrichment array is empty or node template is not added yet
76+
if (isChecked && (this.toApply.length === 0) || !this.checkIfNodeTypeSelected(nodeTemplate)) {
77+
const selectedEnrichment = {
78+
nodeTemplateId: nodeTemplate,
79+
features: []
80+
};
81+
selectedEnrichment.features.push(feature);
82+
this.toApply.push(selectedEnrichment);
83+
// if feature was selected and node template id is already existing
84+
} else if (isChecked && this.checkIfNodeTypeSelected(nodeTemplate)) {
85+
this.toApply[this.checkWhichIndexNodeType(nodeTemplate)].features.push(feature);
86+
// if feature was unselected
87+
} else if (!event.target.checked && this.checkIfNodeTypeSelected(nodeTemplate)) {
88+
this.removeFeatureForNodeTemplate(feature, this.checkWhichIndexNodeType(nodeTemplate));
89+
}
90+
}
91+
92+
/**
93+
* This method checks whether to applicable enrichments array already contains an entry for a given node template.
94+
* @param nodeTemplateId: id of node template which shall be checked
95+
* @return boolean: true if array already contains node template, false else
96+
*/
97+
private checkIfNodeTypeSelected(nodeTemplateId: string): boolean {
98+
for (const element of this.toApply) {
99+
// if entry node template matches node template we're searching for, return true
100+
if (element.nodeTemplateId === nodeTemplateId) {
101+
return true;
102+
}
103+
}
104+
// if node template id was not found after iterating over all entries, return false
105+
return false;
106+
}
107+
108+
/**
109+
* This method returns the index of an node template entry in the to applicable enrichments array.
110+
* This is used to determine the entry which shall be removed when unselecting the last feature of a node template.
111+
* @param nodeTemplateId: id of node template to be checked
112+
* @return i: number of index of node template entry in to applicable enrichments array
113+
*/
114+
private checkWhichIndexNodeType(nodeTemplateId: string): number {
115+
for (let i = 0; i < this.toApply.length; i++) {
116+
// if node template id is found, return the index of the entry
117+
if (this.toApply[i].nodeTemplateId === nodeTemplateId) {
118+
return i;
119+
}
120+
}
121+
}
122+
123+
/**
124+
* This method removes a feature of a node template entry in the to applicable enrichments array.
125+
* @param feature: feature entry which shall be modified
126+
* @param index: index of entry to be removed
127+
*/
128+
private removeFeatureForNodeTemplate(feature: FeatureEntity, index: number): void {
129+
for (let i = 0; i < this.toApply[index].features.length; i++) {
130+
// check if feature is feature to be modified
131+
if (this.toApply[index].features[i] === feature) {
132+
this.toApply[index].features.splice(i, 1);
133+
}
134+
}
135+
// delete entry if no feature selected anymore
136+
if (this.toApply[index].features.length === 0) {
137+
this.toApply.splice(index, 1);
138+
}
139+
}
140+
141+
/**
142+
* This method is called when clicking the "Apply" button.
143+
* It starts the Enricher Service to apply the selected enrichments.
144+
*/
145+
protected applyEnrichment() {
146+
this.enricherService.applySelectedFeatures(this.toApply).subscribe(
147+
data => this.enrichmentApplied(data),
148+
error => this.handleError(error)
149+
);
150+
}
151+
152+
/**
153+
* This method is called when available features are retrieved and fills the available features array with the
154+
* gathered data.
155+
* @param data: json response of backend containing available features for all node templates
156+
*/
157+
private showAvailableFeatures(data: Enrichment): void {
158+
// check if array contains data at all (data != null does not work, as data is not null but an empty array)
159+
if (data.length > 0) {
160+
this.availableFeatures = data;
161+
} else {
162+
this.alert.info('No enrichment found!');
163+
}
164+
}
165+
166+
/**
167+
* This method is called when an error occurs durring fetching or pushing the enrichments.
168+
* It alerts the merror message in the UI.
169+
* @param error: error message
170+
*/
171+
private handleError(error: HttpErrorResponse) {
172+
this.alert.error(error.message);
173+
}
174+
175+
/**
176+
* This method is called when the User hovers over a node template in the enrichment sidebar
177+
* It highlights the respective node template in the topology modeler.
178+
* @param entry: entry of available features displayed in the UI
179+
*/
180+
protected onHoverOver(entry: Enrichment) {
181+
const nodeTemplateIds: string[] = [];
182+
nodeTemplateIds.push(entry.nodeTemplateId);
183+
this.ngRedux.dispatch(this.actions.highlightNodes(nodeTemplateIds));
184+
}
185+
186+
/**
187+
* This method is called when the user hovers out of a node template.
188+
*/
189+
protected hoverOut() {
190+
this.ngRedux.dispatch(this.actions.highlightNodes([]));
191+
}
192+
193+
/**
194+
* This method is called when the User clicks "Cancel".
195+
* It resets the available features, which lets the enrichment sidebar disappear.
196+
*/
197+
protected cancel() {
198+
this.availableFeatures = null;
199+
this.ngRedux.dispatch(this.actions.enrichNodeTemplates());
200+
}
201+
202+
/**
203+
* This method is called when the enrichment is successfully applied in the backend.
204+
* It updates the topology template then, resets the available features and displays an success message.
205+
* @param data: topology template that was updated
206+
*/
207+
private enrichmentApplied(data: TTopologyTemplate) {
208+
Utils.updateTopologyTemplate(this.ngRedux, this.wineryActions, data);
209+
// reset available features since they are no longer valid
210+
this.availableFeatures = null;
211+
this.alert.success('Updated Topology Template!');
212+
this.ngRedux.dispatch(this.actions.enrichNodeTemplates());
213+
}
214+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
/*******************************************************************************
2+
* Copyright (c) 2019 Contributors to the Eclipse Foundation
3+
*
4+
* See the NOTICE file(s) distributed with this work for additional
5+
* information regarding copyright ownership.
6+
*
7+
* This program and the accompanying materials are made available under the
8+
* terms of the Eclipse Public License 2.0 which is available at
9+
* http://www.eclipse.org/legal/epl-2.0, or the Apache Software License 2.0
10+
* which is available at https://www.apache.org/licenses/LICENSE-2.0.
11+
*
12+
* SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
13+
*******************************************************************************/
14+
import { Injectable } from '@angular/core';
15+
import { HttpClient, HttpHeaders } from '@angular/common/http';
16+
import { BackendService } from '../services/backend.service';
17+
import { TopologyModelerConfiguration } from '../models/topologyModelerConfiguration';
18+
import { Observable } from 'rxjs';
19+
import { Enrichment } from './enrichmentEntity';
20+
import { TTopologyTemplate } from '../models/ttopology-template';
21+
22+
@Injectable({
23+
providedIn: 'root'
24+
})
25+
export class EnricherService {
26+
27+
private readonly configuration: TopologyModelerConfiguration;
28+
private readonly httpHeaders: HttpHeaders;
29+
30+
constructor(private http: HttpClient,
31+
backendService: BackendService) {
32+
this.configuration = backendService.configuration;
33+
this.httpHeaders = new HttpHeaders().set('Accept', 'application/json');
34+
}
35+
36+
/**
37+
* This method fetches available enrichments/features for a topology template.
38+
*/
39+
getAvailableFeatures(): Observable<Enrichment> {
40+
const url = this.configuration.repositoryURL
41+
+ '/servicetemplates/'
42+
+ encodeURIComponent(encodeURIComponent(this.configuration.ns))
43+
+ '/'
44+
+ encodeURIComponent(this.configuration.id)
45+
+ '/topologytemplate/availablefeatures';
46+
return this.http.get<Enrichment>(url, { headers: this.httpHeaders });
47+
}
48+
49+
/**
50+
* This method applies selected enrichments/features for a topology template.
51+
* @param toApplyFeatures: Enrichment Object containing selected features for node templates.
52+
*/
53+
applySelectedFeatures(toApplyFeatures: Enrichment[]): Observable<TTopologyTemplate> {
54+
const url = this.configuration.repositoryURL
55+
+ '/servicetemplates/'
56+
+ encodeURIComponent(encodeURIComponent(this.configuration.ns))
57+
+ '/'
58+
+ encodeURIComponent(this.configuration.id)
59+
+ '/topologytemplate/availablefeatures';
60+
return this.http.put<TTopologyTemplate>(url, toApplyFeatures, { headers: this.httpHeaders });
61+
}
62+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
/********************************************************************************
2+
* Copyright (c) 2019 Contributors to the Eclipse Foundation
3+
*
4+
* See the NOTICE file(s) distributed with this work for additional
5+
* information regarding copyright ownership.
6+
*
7+
* This program and the accompanying materials are made available under the
8+
* terms of the Eclipse Public License 2.0 which is available at
9+
* http://www.eclipse.org/legal/epl-2.0, or the Apache Software License 2.0
10+
* which is available at https://www.apache.org/licenses/LICENSE-2.0.
11+
*
12+
* SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
13+
*******************************************************************************/
14+
import { QName } from '../models/qname';
15+
16+
/**
17+
* Enrichment interface containing features of FeatureEntity type and a node template id.
18+
*/
19+
export interface Enrichment {
20+
features: FeatureEntity[];
21+
nodeTemplateId: string;
22+
length: number;
23+
}
24+
25+
/**
26+
* FeatureEntity interface containing type of the feature and the feature name.
27+
*/
28+
export interface FeatureEntity {
29+
type: QName;
30+
featureName: string;
31+
}

0 commit comments

Comments
 (0)