|
| 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 | +} |
0 commit comments