[SDC-29] rebase continue work to align source
[sdc.git] / catalog-ui / src / app / directives / graphs-v2 / composition-graph / composition-graph.directive.ts
1 import {
2     MatchBase,
3     LinkMenu,
4     ComponentInstance,
5     LeftPaletteComponent,
6     Component,
7     RelationMenuDirectiveObj,
8     CompositionCiNodeBase,
9     CompositionCiNodeVl,
10     NodesFactory/*,
11     AssetPopoverObj*/
12 } from "app/models";
13 import {ComponentInstanceFactory, ComponentFactory, GRAPH_EVENTS, GraphColors} from "app/utils";
14 import {EventListenerService, LoaderService} from "app/services";
15 import {CompositionGraphLinkUtils} from "./utils/composition-graph-links-utils";
16 import {CompositionGraphGeneralUtils} from "./utils/composition-graph-general-utils";
17 import {CompositionGraphNodesUtils} from "./utils/composition-graph-nodes-utils";
18 import {CommonGraphUtils} from "../common/common-graph-utils";
19 import {MatchCapabilitiesRequirementsUtils} from "./utils/match-capability-requierment-utils";
20 import {CompositionGraphPaletteUtils} from "./utils/composition-graph-palette-utils";
21 import {ComponentInstanceNodesStyle} from "../common/style/component-instances-nodes-style";
22 import {CytoscapeEdgeEditation} from 'third-party/cytoscape.js-edge-editation/CytoscapeEdgeEditation.js';
23 import {ComponentServiceNg2} from "../../../ng2/services/component-services/component.service";
24 import {ComponentGenericResponse} from "../../../ng2/services/responses/component-generic-response";
25
26 interface ICompositionGraphScope extends ng.IScope {
27
28     component:Component;
29     isLoading: boolean;
30     isViewOnly:boolean;
31     // Link menu - create link menu
32     relationMenuDirectiveObj:RelationMenuDirectiveObj;
33     isLinkMenuOpen:boolean;
34     createLinkFromMenu:(chosenMatch:MatchBase, vl:Component)=>void;
35
36     //modify link menu - for now only delete menu
37     relationMenuTimeout:ng.IPromise<any>;
38     linkMenuObject:LinkMenu;
39
40     //left palette functions callbacks
41     dropCallback(event:JQueryEventObject, ui:any):void;
42     beforeDropCallback(event:IDragDropEvent):void;
43     verifyDrop(event:JQueryEventObject, ui:any):void;
44
45     //Links menus
46     deleteRelation(link:Cy.CollectionEdges):void;
47     hideRelationMenu();
48     /*//asset popover menu
49     assetPopoverObj:AssetPopoverObj;
50     assetPopoverOpen:boolean;
51     hideAssetPopover():void;
52     deleteNode(nodeId:string):void;*/
53 }
54
55 export class CompositionGraph implements ng.IDirective {
56     private _cy:Cy.Instance;
57     private _currentlyCLickedNodePosition:Cy.Position;
58     // private $document:JQuery = $(document);
59     private dragElement:JQuery;
60     private dragComponent:ComponentInstance;
61
62     constructor(private $q:ng.IQService,
63                 private $log:ng.ILogService,
64                 private $timeout:ng.ITimeoutService,
65                 private NodesFactory:NodesFactory,
66                 private CompositionGraphLinkUtils:CompositionGraphLinkUtils,
67                 private GeneralGraphUtils:CompositionGraphGeneralUtils,
68                 private ComponentInstanceFactory:ComponentInstanceFactory,
69                 private NodesGraphUtils:CompositionGraphNodesUtils,
70                 private eventListenerService:EventListenerService,
71                 private ComponentFactory:ComponentFactory,
72                 private LoaderService:LoaderService,
73                 private commonGraphUtils:CommonGraphUtils,
74                 private matchCapabilitiesRequirementsUtils:MatchCapabilitiesRequirementsUtils,
75                 private CompositionGraphPaletteUtils:CompositionGraphPaletteUtils,
76                 private ComponentServiceNg2: ComponentServiceNg2) {
77
78     }
79
80     restrict = 'E';
81     template = require('./composition-graph.html');
82     scope = {
83         component: '=',
84         isViewOnly: '='
85     };
86
87     link = (scope:ICompositionGraphScope, el:JQuery) => {
88
89         this.loadGraph(scope, el);
90
91         if(scope.component.componentInstances && scope.component.componentInstancesRelations) {
92             this.loadGraphData(scope);
93         } else {
94             //when we don't have the data we register to on graph load event
95             this.eventListenerService.registerObserverCallback(GRAPH_EVENTS.ON_COMPOSITION_GRAPH_DATA_LOADED, () => {
96                 this.loadGraphData(scope);
97             });
98         }
99         scope.$on('$destroy', () => {
100             this._cy.destroy();
101             _.forEach(GRAPH_EVENTS, (event) => {
102                 this.eventListenerService.unRegisterObserver(event);
103             });
104         });
105
106     };
107
108     private loadGraphData = (scope:ICompositionGraphScope) => {
109         this.initGraphNodes(scope.component.componentInstances, scope.isViewOnly);
110         this.commonGraphUtils.initGraphLinks(this._cy, scope.component.componentInstancesRelations);
111         this.commonGraphUtils.initUcpeChildren(this._cy);
112     }
113
114     private loadGraph = (scope:ICompositionGraphScope, el:JQuery) => {
115
116         let graphEl = el.find('.sdc-composition-graph-wrapper');
117         this.initGraph(graphEl, scope.isViewOnly);
118         this.initDropZone(scope);
119         this.registerCytoscapeGraphEvents(scope);
120         this.registerCustomEvents(scope, el);
121         this.initViewMode(scope.isViewOnly);
122
123     };
124
125     private initGraph(graphEl:JQuery, isViewOnly:boolean) {
126
127         this._cy = cytoscape({
128             container: graphEl,
129             style: ComponentInstanceNodesStyle.getCompositionGraphStyle(),
130             zoomingEnabled: false,
131             selectionType: 'single',
132             boxSelectionEnabled: true,
133             autolock: isViewOnly,
134             autoungrabify: isViewOnly
135         });
136     }
137
138     private initViewMode(isViewOnly:boolean) {
139
140         if (isViewOnly) {
141             //remove event listeners
142             this._cy.off('drag');
143             this._cy.off('handlemouseout');
144             this._cy.off('handlemouseover');
145             this._cy.edges().unselectify();
146         }
147     };
148
149     private registerCustomEvents(scope:ICompositionGraphScope, el:JQuery) {
150
151         this.eventListenerService.registerObserverCallback(GRAPH_EVENTS.ON_PALETTE_COMPONENT_HOVER_IN, (leftPaletteComponent:LeftPaletteComponent) => {
152             this.$log.info(`composition-graph::registerEventServiceEvents:: palette hover on component: ${leftPaletteComponent.uniqueId}`);
153
154             let nodesData = this.NodesGraphUtils.getAllNodesData(this._cy.nodes());
155             let nodesLinks = this.GeneralGraphUtils.getAllCompositionCiLinks(this._cy);
156
157             if (this.GeneralGraphUtils.componentRequirementsAndCapabilitiesCaching.containsKey(leftPaletteComponent.uniqueId)) {
158                 let cacheComponent = this.GeneralGraphUtils.componentRequirementsAndCapabilitiesCaching.getValue(leftPaletteComponent.uniqueId);
159                 let filteredNodesData = this.matchCapabilitiesRequirementsUtils.findByMatchingCapabilitiesToRequirements(cacheComponent, nodesData, nodesLinks);
160
161                 this.matchCapabilitiesRequirementsUtils.highlightMatchingComponents(filteredNodesData, this._cy);
162                 this.matchCapabilitiesRequirementsUtils.fadeNonMachingComponents(filteredNodesData, nodesData, this._cy);
163
164                 return;
165             }
166
167             //----------------------- ORIT TO FIX------------------------//
168
169             this.ComponentServiceNg2.getCapabilitiesAndRequirements(leftPaletteComponent.componentType, leftPaletteComponent.uniqueId).subscribe((response: ComponentGenericResponse) => {
170
171                     let component = this.ComponentFactory.createEmptyComponent(leftPaletteComponent.componentType);
172                     component.uniqueId = component.uniqueId;
173                     component.capabilities = response.capabilities;
174                     component.requirements = response.requirements;
175                     this.GeneralGraphUtils.componentRequirementsAndCapabilitiesCaching.setValue(leftPaletteComponent.uniqueId, component);
176                     let filteredNodesData = this.matchCapabilitiesRequirementsUtils.findByMatchingCapabilitiesToRequirements(component, nodesData, nodesLinks);
177                     this.matchCapabilitiesRequirementsUtils.fadeNonMachingComponents(filteredNodesData, nodesData, this._cy);
178                     this.matchCapabilitiesRequirementsUtils.highlightMatchingComponents(filteredNodesData, this._cy)
179                 });
180         });
181
182         this.eventListenerService.registerObserverCallback(GRAPH_EVENTS.ON_PALETTE_COMPONENT_HOVER_OUT, () => {
183             this._cy.emit('hidehandles');
184             this.matchCapabilitiesRequirementsUtils.resetFadedNodes(this._cy);
185         });
186
187         this.eventListenerService.registerObserverCallback(GRAPH_EVENTS.ON_PALETTE_COMPONENT_DRAG_START, (dragElement, dragComponent) => {
188
189             this.dragElement = dragElement;
190             this.dragComponent = this.ComponentInstanceFactory.createComponentInstanceFromComponent(dragComponent);
191         });
192
193         this.eventListenerService.registerObserverCallback(GRAPH_EVENTS.ON_PALETTE_COMPONENT_DRAG_ACTION, (event:IDragDropEvent) => {
194             this.CompositionGraphPaletteUtils.onComponentDrag(this._cy, event, this.dragElement, this.dragComponent);
195
196         });
197
198         this.eventListenerService.registerObserverCallback(GRAPH_EVENTS.ON_COMPONENT_INSTANCE_NAME_CHANGED, (component:ComponentInstance) => {
199
200             let selectedNode = this._cy.getElementById(component.uniqueId);
201             selectedNode.data().componentInstance.name = component.name;
202             selectedNode.data('name', component.name); //used for tooltip
203             selectedNode.data('displayName', selectedNode.data().getDisplayName()); //abbreviated
204
205         });
206
207         this.eventListenerService.registerObserverCallback(GRAPH_EVENTS.ON_DELETE_COMPONENT_INSTANCE, (componentInstance:ComponentInstance) => {
208             let nodeToDelete = this._cy.getElementById(componentInstance.uniqueId);
209             this.NodesGraphUtils.deleteNode(this._cy, scope.component, nodeToDelete);
210         });
211
212         this.eventListenerService.registerObserverCallback(GRAPH_EVENTS.ON_DELETE_MULTIPLE_COMPONENTS, () => {
213
214             this._cy.$('node:selected').each((i:number, node:Cy.CollectionNodes) => {
215                 this.NodesGraphUtils.deleteNode(this._cy, scope.component, node);
216             });
217
218         });
219
220         this.eventListenerService.registerObserverCallback(GRAPH_EVENTS.ON_DELETE_EDGE, (releaseLoading:boolean, linksToDelete:Cy.CollectionEdges) => {
221             this.CompositionGraphLinkUtils.deleteLink(this._cy, scope.component, releaseLoading, linksToDelete);
222         });
223
224         this.eventListenerService.registerObserverCallback(GRAPH_EVENTS.ON_INSERT_NODE_TO_UCPE, (node:Cy.CollectionNodes, ucpe:Cy.CollectionNodes, updateExistingNode:boolean) => {
225
226             this.commonGraphUtils.initUcpeChildData(node, ucpe);
227             //check if item is a VL, and if so, skip adding the binding to ucpe
228             if (!(node.data() instanceof CompositionCiNodeVl)) {
229                 this.CompositionGraphLinkUtils.createVfToUcpeLink(scope.component, this._cy, ucpe.data(), node.data()); //create link from the node to the ucpe
230             }
231
232             if (updateExistingNode) {
233                 let vlsPendingDeletion:Cy.CollectionNodes = this.NodesGraphUtils.deleteNodeVLsUponMoveToOrFromUCPE(scope.component, node.cy(), node); //delete connected VLs that no longer have 2 links
234                 this.CompositionGraphLinkUtils.deleteLinksWhenNodeMovedFromOrToUCPE(scope.component, node.cy(), node, vlsPendingDeletion); //delete all connected links if needed
235                 this.GeneralGraphUtils.pushUpdateComponentInstanceActionToQueue(scope.component, true, node.data().componentInstance); //update componentInstance position
236             }
237
238         });
239
240         this.eventListenerService.registerObserverCallback(GRAPH_EVENTS.ON_REMOVE_NODE_FROM_UCPE, (node:Cy.CollectionNodes, ucpe:Cy.CollectionNodes) => {
241             this.commonGraphUtils.removeUcpeChildData(node);
242             let vlsPendingDeletion:Cy.CollectionNodes = this.NodesGraphUtils.deleteNodeVLsUponMoveToOrFromUCPE(scope.component, node.cy(), node);
243             this.CompositionGraphLinkUtils.deleteLinksWhenNodeMovedFromOrToUCPE(scope.component, node.cy(), node, vlsPendingDeletion); //delete all connected links if needed
244             this.GeneralGraphUtils.pushUpdateComponentInstanceActionToQueue(scope.component, true, node.data().componentInstance); //update componentInstance position
245         });
246
247         this.eventListenerService.registerObserverCallback(GRAPH_EVENTS.ON_VERSION_CHANGED, (component:Component) => {
248             scope.component = component;
249             this._cy.elements().remove();
250             this.loadGraphData(scope);
251         });
252
253
254         scope.createLinkFromMenu = (chosenMatch:MatchBase):void => {
255             scope.isLinkMenuOpen = false;
256             this.CompositionGraphLinkUtils.createLinkFromMenu(this._cy, chosenMatch, scope.component);
257         };
258
259         scope.hideRelationMenu = () => {
260             this.commonGraphUtils.safeApply(scope, () => {
261                 scope.linkMenuObject = null;
262                 this.$timeout.cancel(scope.relationMenuTimeout);
263             });
264         };
265
266
267         scope.deleteRelation = (link:Cy.CollectionEdges) => {
268             scope.hideRelationMenu();
269
270             //if multiple edges selected, delete the VL itself so edges get deleted automatically
271             if (this._cy.$('edge:selected').length > 1) {
272                 this.NodesGraphUtils.deleteNode(this._cy, scope.component, this._cy.$('node:selected'));
273             } else {
274                 this.CompositionGraphLinkUtils.deleteLink(this._cy, scope.component, true, link);
275             }
276         };
277
278         /*
279         scope.hideAssetPopover = ():void => {
280
281             this.commonGraphUtils.safeApply(scope, () => {
282                 scope.assetPopoverOpen = false;
283                 scope.assetPopoverObj = null;
284             });
285         };
286
287         scope.deleteNode = (nodeId:string):void => {
288             if (!scope.isViewOnly) {
289                 this.NodesGraphUtils.confirmDeleteNode(nodeId, this._cy, scope.component);
290                 //scope.hideAssetPopover();
291             }
292         };*/
293     }
294
295     private registerCytoscapeGraphEvents(scope:ICompositionGraphScope) {
296
297         this._cy.on('addedgemouseup', (event, data) => {
298             scope.relationMenuDirectiveObj = this.CompositionGraphLinkUtils.onLinkDrawn(this._cy, data.source, data.target);
299             if (scope.relationMenuDirectiveObj != null) {
300                 scope.$apply(() => {
301                     scope.isLinkMenuOpen = true;
302                 });
303             }
304         });
305         this._cy.on('tapstart', 'node', (event:Cy.EventObject) => {
306             this._currentlyCLickedNodePosition = angular.copy(event.cyTarget[0].position()); //update node position on drag
307             if (event.cyTarget.data().isUcpe) {
308                 this._cy.nodes('.ucpe-cp').unlock();
309                 event.cyTarget.style('opacity', 0.5);
310             }
311             //scope.hideAssetPopover();
312         });
313
314         this._cy.on('drag', 'node', (event:Cy.EventObject) => {
315
316             if (event.cyTarget.data().isDraggable) {
317                 event.cyTarget.style({'overlay-opacity': 0.24});
318                 if (this.GeneralGraphUtils.isValidDrop(this._cy, event.cyTarget)) {
319                     event.cyTarget.style({'overlay-color': GraphColors.NODE_BACKGROUND_COLOR});
320                 } else {
321                     event.cyTarget.style({'overlay-color': GraphColors.NODE_OVERLAPPING_BACKGROUND_COLOR});
322                 }
323             }
324
325             if (event.cyTarget.data().isUcpe) {
326                 let pos = event.cyTarget.position();
327
328                 this._cy.nodes('[?isInsideGroup]').positions((i, node)=> {
329                     return {
330                         x: pos.x + node.data("ucpeOffset").x,
331                         y: pos.y + node.data("ucpeOffset").y
332                     }
333                 });
334             }
335         });
336
337        /* this._cy.on('mouseover', 'node', (event:Cy.EventObject) => {
338             if (!this._cy.scratch('_edge_editation_highlights')) {
339                 this.commonGraphUtils.safeApply(scope, () => {
340                     this.showNodePopoverMenu(scope, event.cyTarget[0]);
341                 });
342             }
343         });
344
345         this._cy.on('mouseout', 'node', (event:Cy.EventObject) => {
346             scope.hideAssetPopover();
347         });*/
348         this._cy.on('handlemouseover', (event, payload) => {
349
350             if (payload.node.grabbed() /* || this._cy.scratch('_edge_editation_highlights') === true*/) { //no need to add opacity while we are dragging and hovering othe nodes- or if opacity was already calculated for these nodes
351                 return;
352             }
353             let nodesData = this.NodesGraphUtils.getAllNodesData(this._cy.nodes());
354             let nodesLinks = this.GeneralGraphUtils.getAllCompositionCiLinks(this._cy);
355
356             let linkableNodes = this.commonGraphUtils.getLinkableNodes(this._cy, payload.node);
357             let filteredNodesData = this.matchCapabilitiesRequirementsUtils.findByMatchingCapabilitiesToRequirements(payload.node.data().componentInstance, linkableNodes, nodesLinks);
358             this.matchCapabilitiesRequirementsUtils.highlightMatchingComponents(filteredNodesData, this._cy);
359             this.matchCapabilitiesRequirementsUtils.fadeNonMachingComponents(filteredNodesData, nodesData, this._cy, payload.node.data());
360             /*
361             this._cy.scratch()._edge_editation_highlights = true;
362             scope.hideAssetPopover();*/
363         });
364
365         this._cy.on('handlemouseout', () => {
366             if (this._cy.scratch('_edge_editation_highlights') === true) {
367                 this._cy.removeScratch('_edge_editation_highlights');
368                 this._cy.emit('hidehandles');
369                 this.matchCapabilitiesRequirementsUtils.resetFadedNodes(this._cy);
370             }
371         });
372
373
374         this._cy.on('tapend', (event:Cy.EventObject) => {
375
376             if (event.cyTarget === this._cy) { //On Background clicked
377                 if (this._cy.$('node:selected').length === 0) { //if the background click but not dragged
378                     this.eventListenerService.notifyObservers(GRAPH_EVENTS.ON_GRAPH_BACKGROUND_CLICKED);
379                 }
380                 scope.hideRelationMenu();
381             }
382
383             else if (event.cyTarget.isEdge()) { //On Edge clicked
384                 if (scope.isViewOnly) return;
385                 this.CompositionGraphLinkUtils.handleLinkClick(this._cy, event);
386                 this.openModifyLinkMenu(scope, this.CompositionGraphLinkUtils.getModifyLinkMenu(event.cyTarget[0], event), 6000);
387             }
388
389             else { //On Node clicked
390                 this._cy.nodes(':grabbed').style({'overlay-opacity': 0});
391
392                 let isUcpe:boolean = event.cyTarget.data().isUcpe;
393                 let newPosition = event.cyTarget[0].position();
394                 //node position changed (drop after drag event) - we need to update position
395                 if (this._currentlyCLickedNodePosition.x !== newPosition.x || this._currentlyCLickedNodePosition.y !== newPosition.y) {
396                     let nodesMoved:Cy.CollectionNodes = this._cy.$(':grabbed');
397                     if (isUcpe) {
398                         nodesMoved = nodesMoved.add(this._cy.nodes('[?isInsideGroup]:free')); //'child' nodes will not be recognized as "grabbed" elements within cytoscape. manually add them to collection of nodes moved.
399                     }
400                     this.NodesGraphUtils.onNodesPositionChanged(this._cy, scope.component, nodesMoved);
401                 } else {
402                     this.$log.debug('composition-graph::onNodeSelectedEvent:: fired');
403                     scope.$apply(() => {
404                         this.eventListenerService.notifyObservers(GRAPH_EVENTS.ON_NODE_SELECTED, event.cyTarget.data().componentInstance);
405                         //open node popover menu
406                         //this.showNodePopoverMenu(scope, event.cyTarget[0]);
407                     });
408                 }
409
410                 if (isUcpe) {
411                     this._cy.nodes('.ucpe-cp').lock();
412                     event.cyTarget.style('opacity', 1);
413                 }
414
415             }
416         });
417
418         this._cy.on('boxselect', 'node', (event:Cy.EventObject) => {
419             this.eventListenerService.notifyObservers(GRAPH_EVENTS.ON_NODE_SELECTED, event.cyTarget.data().componentInstance);
420         });
421     }
422
423     /*
424     private showNodePopoverMenu = (scope:ICompositionGraphScope, node:Cy.CollectionNodes) => {
425
426         scope.assetPopoverObj = this.NodesGraphUtils.createAssetPopover(this._cy, node, scope.isViewOnly);
427         scope.assetPopoverOpen = true;
428
429     };*/
430     private openModifyLinkMenu = (scope:ICompositionGraphScope, linkMenuObject:LinkMenu, timeOutInMilliseconds?:number) => {
431
432         this.commonGraphUtils.safeApply(scope, () => {
433             scope.linkMenuObject = linkMenuObject;
434         });
435
436         scope.relationMenuTimeout = this.$timeout(() => {
437             scope.hideRelationMenu();
438         }, timeOutInMilliseconds ? timeOutInMilliseconds : 6000);
439     };
440
441     private initGraphNodes(componentInstances:ComponentInstance[], isViewOnly:boolean) {
442
443         if (!isViewOnly) { //Init nodes handle extension - enable dynamic links
444             setTimeout(()=> {
445                 let handles = new CytoscapeEdgeEditation;
446                 handles.init(this._cy, 18);
447                 handles.registerHandle(ComponentInstanceNodesStyle.getBasicNodeHanlde());
448                 handles.registerHandle(ComponentInstanceNodesStyle.getBasicSmallNodeHandle());
449                 handles.registerHandle(ComponentInstanceNodesStyle.getUcpeCpNodeHandle());
450             }, 0);
451         }
452
453         _.each(componentInstances, (instance) => {
454             let compositionGraphNode:CompositionCiNodeBase = this.NodesFactory.createNode(instance);
455             this.commonGraphUtils.addComponentInstanceNodeToGraph(this._cy, compositionGraphNode);
456         });
457     }
458
459
460     private initDropZone(scope:ICompositionGraphScope) {
461
462         if (scope.isViewOnly) {
463             return;
464         }
465         scope.dropCallback = (event:IDragDropEvent) => {
466             this.$log.debug(`composition-graph::dropCallback:: fired`);
467             this.CompositionGraphPaletteUtils.addNodeFromPalette(this._cy, event, scope.component);
468         };
469
470         scope.verifyDrop = (event:JQueryEventObject) => {
471
472             if (this.dragElement.hasClass('red')) {
473                 return false;
474             }
475             return true;
476         };
477
478         scope.beforeDropCallback = (event:IDragDropEvent):ng.IPromise<void> => {
479             let deferred:ng.IDeferred<void> = this.$q.defer<void>();
480             if (this.dragElement.hasClass('red')) {
481                 deferred.reject();
482             } else {
483                 deferred.resolve();
484             }
485
486             return deferred.promise;
487         }
488     }
489
490     public static factory = ($q,
491                              $log,
492                              $timeout,
493                              NodesFactory,
494                              LinksGraphUtils,
495                              GeneralGraphUtils,
496                              ComponentInstanceFactory,
497                              NodesGraphUtils,
498                              EventListenerService,
499                              ComponentFactory,
500                              LoaderService,
501                              CommonGraphUtils,
502                              MatchCapabilitiesRequirementsUtils,
503                              CompositionGraphPaletteUtils,
504                              ComponentServiceNg2) => {
505         return new CompositionGraph(
506             $q,
507             $log,
508             $timeout,
509             NodesFactory,
510             LinksGraphUtils,
511             GeneralGraphUtils,
512             ComponentInstanceFactory,
513             NodesGraphUtils,
514             EventListenerService,
515             ComponentFactory,
516             LoaderService,
517             CommonGraphUtils,
518             MatchCapabilitiesRequirementsUtils,
519             CompositionGraphPaletteUtils,
520             ComponentServiceNg2);
521     }
522 }
523
524 CompositionGraph.factory.$inject = [
525     '$q',
526     '$log',
527     '$timeout',
528     'NodesFactory',
529     'CompositionGraphLinkUtils',
530     'CompositionGraphGeneralUtils',
531     'ComponentInstanceFactory',
532     'CompositionGraphNodesUtils',
533     'EventListenerService',
534     'ComponentFactory',
535     'LoaderService',
536     'CommonGraphUtils',
537     'MatchCapabilitiesRequirementsUtils',
538     'CompositionGraphPaletteUtils',
539     'ComponentServiceNg2'
540 ];