Catalog alignment
[sdc.git] / catalog-ui / src / app / ng2 / pages / composition / graph / utils / composition-graph-nodes-utils.ts
1 /*-
2  * ============LICENSE_START=======================================================
3  * SDC
4  * ================================================================================
5  * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
6  * ================================================================================
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  *      http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  * ============LICENSE_END=========================================================
19  */
20
21 import { Injectable } from '@angular/core';
22 import { Component as TopologyTemplate } from 'app/models';
23 import {
24     ComponentInstance,
25     CompositionCiNodeVl, Service
26 } from 'app/models';
27 import { CompositionCiServicePathLink } from 'app/models/graph/graph-links/composition-graph-links/composition-ci-service-path-link';
28 import { WorkspaceService } from 'app/ng2/pages/workspace/workspace.service';
29 import { ServiceServiceNg2 } from 'app/ng2/services/component-services/service.service';
30 import { TopologyTemplateService } from 'app/ng2/services/component-services/topology-template.service';
31 import { ServiceGenericResponse } from 'app/ng2/services/responses/service-generic-response';
32 import { QueueServiceUtils } from 'app/ng2/utils/queue-service-utils';
33 import { EventListenerService } from 'app/services';
34 import { GRAPH_EVENTS } from 'app/utils';
35 import * as _ from 'lodash';
36 import { SdcUiServices } from 'onap-ui-angular';
37 import { CompositionService } from '../../composition.service';
38 import { CommonGraphUtils } from '../common/common-graph-utils';
39 import { CompositionGraphGeneralUtils } from './composition-graph-general-utils';
40
41 /**
42  * Created by obarda on 11/9/2016.
43  */
44 @Injectable()
45 export class CompositionGraphNodesUtils {
46     constructor(private generalGraphUtils: CompositionGraphGeneralUtils,
47                 private commonGraphUtils: CommonGraphUtils,
48                 private eventListenerService: EventListenerService,
49                 private queueServiceUtils: QueueServiceUtils,
50                 private serviceService: ServiceServiceNg2,
51                 private loaderService: SdcUiServices.LoaderService,
52                 private compositionService: CompositionService,
53                 private topologyTemplateService: TopologyTemplateService,
54                 private workspaceService: WorkspaceService) {
55     }
56
57     /**
58      * Returns component instances for all nodes passed in
59      * @param nodes - Cy nodes
60      * @returns {any[]}
61      */
62     public getAllNodesData(nodes: Cy.CollectionNodes) {
63         return _.map(nodes, (node: Cy.CollectionFirstNode) => {
64             return node.data();
65         });
66     }
67
68     public highlightMatchingNodesByName = (cy: Cy.Instance, nameToMatch: string) => {
69
70         cy.batch(() => {
71             cy.nodes("[name !@^= '" + nameToMatch + "']").style({'background-image-opacity': 0.4});
72             cy.nodes("[name @^= '" + nameToMatch + "']").style({'background-image-opacity': 1});
73         });
74
75     }
76
77     // Returns all nodes whose name starts with searchTerm
78     public getMatchingNodesByName = (cy: Cy.Instance, nameToMatch: string): Cy.CollectionNodes => {
79         return cy.nodes("[name @^= '" + nameToMatch + "']");
80     }
81
82     /**
83      * Deletes component instances on server and then removes it from the graph as well
84      * @param cy
85      * @param component
86      * @param nodeToDelete
87      */
88     public deleteNode(cy: Cy.Instance, component: TopologyTemplate, nodeToDelete: Cy.CollectionNodes): void {
89
90         this.loaderService.activate();
91         const onSuccess: (response: ComponentInstance) => void = (response: ComponentInstance) => {
92             // check whether the node is connected to any VLs that only have one other connection. If so, delete that VL as well
93             this.loaderService.deactivate();
94             this.compositionService.deleteComponentInstance(response.uniqueId);
95
96             const nodeToDeleteIsNotVl = nodeToDelete.data().componentInstance && !(nodeToDelete.data().componentInstance.isVl());
97             if (nodeToDeleteIsNotVl) {
98                 const connectedVls: Cy.CollectionFirstNode[] = this.getConnectedVlToNode(nodeToDelete);
99                 this.handleConnectedVlsToDelete(connectedVls);
100             }
101
102             // check whether there is a service path going through this node, and if so clean it from the graph.
103             const nodeId = nodeToDelete.data().id;
104             const connectedPathLinks = cy.collection(`[type="${CompositionCiServicePathLink.LINK_TYPE}"][source="${nodeId}"], [type="${CompositionCiServicePathLink.LINK_TYPE}"][target="${nodeId}"]`);
105             _.forEach(connectedPathLinks, (link, key) => {
106                 cy.remove(`[pathId="${link.data().pathId}"]`);
107             });
108
109             // update service path list
110             this.serviceService.getComponentCompositionData(component).subscribe((serviceResponse: ServiceGenericResponse) => {
111                 (component as Service).forwardingPaths = serviceResponse.forwardingPaths;
112             });
113
114             this.eventListenerService.notifyObservers(GRAPH_EVENTS.ON_DELETE_COMPONENT_INSTANCE_SUCCESS, nodeId);
115
116             // update UI
117             cy.remove(nodeToDelete);
118         };
119
120         const onFailed: (response: any) => void = (response: any) => {
121             this.loaderService.deactivate();
122         };
123
124         this.queueServiceUtils.addBlockingUIAction(
125             () => {
126                 const uniqueId = this.workspaceService.metadata.uniqueId;
127                 const componentType = this.workspaceService.metadata.componentType;
128                 this.topologyTemplateService.deleteComponentInstance(componentType, uniqueId, nodeToDelete.data().componentInstance.uniqueId).subscribe(onSuccess, onFailed);
129             }
130         );
131     }
132
133     /**
134      * Finds all VLs connected to a single node
135      * @param node
136      * @returns {Array<Cy.CollectionFirstNode>}
137      */
138     public getConnectedVlToNode = (node: Cy.CollectionNodes): Cy.CollectionFirstNode[] => {
139         const connectedVls: Cy.CollectionFirstNode[] = new Array<Cy.CollectionFirstNode>();
140         _.forEach(node.connectedEdges().connectedNodes(), (connectedNode: Cy.CollectionFirstNode) => {
141             const connectedNodeIsVl = connectedNode.data().componentInstance.isVl();
142             if (connectedNodeIsVl) {
143                 connectedVls.push(connectedNode);
144             }
145         });
146         return connectedVls;
147     }
148
149     /**
150      * Delete all VLs that have only two connected nodes (this function is called when deleting a node)
151      * @param connectedVls
152      */
153     public handleConnectedVlsToDelete = (connectedVls: Cy.CollectionFirstNode[]) => {
154         _.forEach(connectedVls, (vlToDelete: Cy.CollectionNodes) => {
155
156             if (vlToDelete.connectedEdges().length === 2) { // if vl connected only to 2 nodes need to delete the vl
157                 this.eventListenerService.notifyObservers(GRAPH_EVENTS.ON_DELETE_COMPONENT_INSTANCE, vlToDelete.data().componentInstance.uniqueId);
158             }
159         });
160     }
161
162     /**
163      * This function will update nodes position.
164      * @param cy
165      * @param component
166      * @param nodesMoved - the node/multiple nodes now moved by the user
167      */
168     public onNodesPositionChanged = (cy: Cy.Instance, component: TopologyTemplate, nodesMoved: Cy.CollectionNodes): void => {
169
170         if (nodesMoved.length === 0) {
171             return;
172         }
173
174         const isValidMove: boolean = this.generalGraphUtils.isGroupValidDrop(cy, nodesMoved);
175         if (isValidMove) {
176
177             const instancesToUpdate: ComponentInstance[] = new Array<ComponentInstance>();
178
179             _.each(nodesMoved, (node: Cy.CollectionFirstNode) => {  // update all nodes new position
180
181                 // update position
182                 const newPosition: Cy.Position = this.commonGraphUtils.getNodePosition(node);
183                 node.data().componentInstance.updatePosition(newPosition.x, newPosition.y);
184                 instancesToUpdate.push(node.data().componentInstance);
185
186             });
187
188             if (instancesToUpdate.length > 0) {
189                 this.generalGraphUtils.pushMultipleUpdateComponentInstancesRequestToQueue(instancesToUpdate);
190             }
191         } else {
192             // reset nodes position
193             nodesMoved.positions((i, node) => {
194                 return {
195                     x: +node.data().componentInstance.posX,
196                     y: +node.data().componentInstance.posY
197                 };
198             });
199         }
200     }
201
202 }