aboutsummaryrefslogtreecommitdiffstats
path: root/catalog-ui/src/app/ng2/pages/composition/graph/utils/composition-graph-nodes-utils.ts
blob: ea876c6d1ac574d90514294f93e53f2743fec85a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
/*-
 * ============LICENSE_START=======================================================
 * SDC
 * ================================================================================
 * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
 * ================================================================================
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 * ============LICENSE_END=========================================================
 */

import { Injectable } from '@angular/core';
import { Component as TopologyTemplate } from 'app/models';
import {
    ComponentInstance,
    CompositionCiNodeVl, Service
} from 'app/models';
import { CompositionCiServicePathLink } from 'app/models/graph/graph-links/composition-graph-links/composition-ci-service-path-link';
import { WorkspaceService } from 'app/ng2/pages/workspace/workspace.service';
import { ServiceServiceNg2 } from 'app/ng2/services/component-services/service.service';
import { TopologyTemplateService } from 'app/ng2/services/component-services/topology-template.service';
import { ServiceGenericResponse } from 'app/ng2/services/responses/service-generic-response';
import { QueueServiceUtils } from 'app/ng2/utils/queue-service-utils';
import { EventListenerService } from 'app/services';
import { GRAPH_EVENTS } from 'app/utils';
import * as _ from 'lodash';
import { SdcUiServices } from 'onap-ui-angular';
import { CompositionService } from '../../composition.service';
import { CommonGraphUtils } from '../common/common-graph-utils';
import { CompositionGraphGeneralUtils } from './composition-graph-general-utils';

/**
 * Created by obarda on 11/9/2016.
 */
@Injectable()
export class CompositionGraphNodesUtils {
    constructor(private generalGraphUtils: CompositionGraphGeneralUtils,
                private commonGraphUtils: CommonGraphUtils,
                private eventListenerService: EventListenerService,
                private queueServiceUtils: QueueServiceUtils,
                private serviceService: ServiceServiceNg2,
                private loaderService: SdcUiServices.LoaderService,
                private compositionService: CompositionService,
                private topologyTemplateService: TopologyTemplateService,
                private workspaceService: WorkspaceService) {
    }

    /**
     * Returns component instances for all nodes passed in
     * @param nodes - Cy nodes
     * @returns {any[]}
     */
    public getAllNodesData(nodes: Cy.CollectionNodes) {
        return _.map(nodes, (node: Cy.CollectionFirstNode) => {
            return node.data();
        });
    }

    public highlightMatchingNodesByName = (cy: Cy.Instance, nameToMatch: string) => {

        cy.batch(() => {
            cy.nodes("[name !@^= '" + nameToMatch + "']").style({'background-image-opacity': 0.4});
            cy.nodes("[name @^= '" + nameToMatch + "']").style({'background-image-opacity': 1});
        });

    }

    // Returns all nodes whose name starts with searchTerm
    public getMatchingNodesByName = (cy: Cy.Instance, nameToMatch: string): Cy.CollectionNodes => {
        return cy.nodes("[name @^= '" + nameToMatch + "']");
    }

    /**
     * Deletes component instances on server and then removes it from the graph as well
     * @param cy
     * @param component
     * @param nodeToDelete
     */
    public deleteNode(cy: Cy.Instance, component: TopologyTemplate, nodeToDelete: Cy.CollectionNodes): void {

        this.loaderService.activate();
        const onSuccess: (response: ComponentInstance) => void = (response: ComponentInstance) => {
            // check whether the node is connected to any VLs that only have one other connection. If so, delete that VL as well
            this.loaderService.deactivate();
            this.compositionService.deleteComponentInstance(response.uniqueId);

            const nodeToDeleteIsNotVl = nodeToDelete.data().componentInstance && !(nodeToDelete.data().componentInstance.isVl());
            if (nodeToDeleteIsNotVl) {
                const connectedVls: Cy.CollectionFirstNode[] = this.getConnectedVlToNode(nodeToDelete);
                this.handleConnectedVlsToDelete(connectedVls);
            }

            // check whether there is a service path going through this node, and if so clean it from the graph.
            const nodeId = nodeToDelete.data().id;
            const connectedPathLinks = cy.collection(`[type="${CompositionCiServicePathLink.LINK_TYPE}"][source="${nodeId}"], [type="${CompositionCiServicePathLink.LINK_TYPE}"][target="${nodeId}"]`);
            _.forEach(connectedPathLinks, (link, key) => {
                cy.remove(`[pathId="${link.data().pathId}"]`);
            });

            // update service path list
            this.serviceService.getComponentCompositionData(component).subscribe((serviceResponse: ServiceGenericResponse) => {
                (component as Service).forwardingPaths = serviceResponse.forwardingPaths;
            });

            this.eventListenerService.notifyObservers(GRAPH_EVENTS.ON_DELETE_COMPONENT_INSTANCE_SUCCESS, nodeId);

            // update UI
            cy.remove(nodeToDelete);
        };

        const onFailed: (response: any) => void = (response: any) => {
            this.loaderService.deactivate();
        };

        this.queueServiceUtils.addBlockingUIAction(
            () => {
                const uniqueId = this.workspaceService.metadata.uniqueId;
                const componentType = this.workspaceService.metadata.componentType;
                this.topologyTemplateService.deleteComponentInstance(componentType, uniqueId, nodeToDelete.data().componentInstance.uniqueId).subscribe(onSuccess, onFailed);
            }
        );
    }

    /**
     * Finds all VLs connected to a single node
     * @param node
     * @returns {Array<Cy.CollectionFirstNode>}
     */
    public getConnectedVlToNode = (node: Cy.CollectionNodes): Cy.CollectionFirstNode[] => {
        const connectedVls: Cy.CollectionFirstNode[] = new Array<Cy.CollectionFirstNode>();
        _.forEach(node.connectedEdges().connectedNodes(), (connectedNode: Cy.CollectionFirstNode) => {
            const connectedNodeIsVl = connectedNode.data().componentInstance.isVl();
            if (connectedNodeIsVl) {
                connectedVls.push(connectedNode);
            }
        });
        return connectedVls;
    }

    /**
     * Delete all VLs that have only two connected nodes (this function is called when deleting a node)
     * @param connectedVls
     */
    public handleConnectedVlsToDelete = (connectedVls: Cy.CollectionFirstNode[]) => {
        _.forEach(connectedVls, (vlToDelete: Cy.CollectionNodes) => {

            if (vlToDelete.connectedEdges().length === 2) { // if vl connected only to 2 nodes need to delete the vl
                this.eventListenerService.notifyObservers(GRAPH_EVENTS.ON_DELETE_COMPONENT_INSTANCE, vlToDelete.data().componentInstance.uniqueId);
            }
        });
    }

    /**
     * This function will update nodes position.
     * @param cy
     * @param component
     * @param nodesMoved - the node/multiple nodes now moved by the user
     */
    public onNodesPositionChanged = (cy: Cy.Instance, component: TopologyTemplate, nodesMoved: Cy.CollectionNodes): void => {

        if (nodesMoved.length === 0) {
            return;
        }

        const isValidMove: boolean = this.generalGraphUtils.isGroupValidDrop(cy, nodesMoved);
        if (isValidMove) {

            const instancesToUpdate: ComponentInstance[] = new Array<ComponentInstance>();

            _.each(nodesMoved, (node: Cy.CollectionFirstNode) => {  // update all nodes new position

                // update position
                const newPosition: Cy.Position = this.commonGraphUtils.getNodePosition(node);
                node.data().componentInstance.updatePosition(newPosition.x, newPosition.y);
                instancesToUpdate.push(node.data().componentInstance);

            });

            if (instancesToUpdate.length > 0) {
                this.generalGraphUtils.pushMultipleUpdateComponentInstancesRequestToQueue(instancesToUpdate);
            }
        } else {
            // reset nodes position
            nodesMoved.positions((i, node) => {
                return {
                    x: +node.data().componentInstance.posX,
                    y: +node.data().componentInstance.posY
                };
            });
        }
    }

}