[SDC] rebase 1710 code
[sdc.git] / catalog-ui / src / app / directives / graphs-v2 / palette / palette.directive.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 import {Component, IAppMenu, LeftPanelModel, NodesFactory, LeftPaletteComponent, CompositionCiNodeBase, ComponentInstance} from "app/models";
21 import {CompositionGraphGeneralUtils} from "../composition-graph/utils/composition-graph-general-utils";
22 import {EventListenerService} from "app/services";
23 import {ResourceType, GRAPH_EVENTS, EVENTS, ComponentInstanceFactory, ModalsHandler} from "app/utils";
24 import 'sdc-angular-dragdrop';
25 import {LeftPaletteLoaderService} from "../../../services/components/utils/composition-left-palette-service";
26 import {Resource} from "app/models/components/resource";
27 import {ComponentType} from "app/utils/constants";
28
29 interface IPaletteScope {
30     components:Array<LeftPaletteComponent>;
31     currentComponent:Component;
32     model:any;
33     displaySortedCategories:any;
34     expandedSection:string;
35     dragElement:JQuery;
36     dragbleNode:{
37         event:JQueryEventObject,
38         components:LeftPaletteComponent,
39         ui:any
40     }
41
42     sectionClick:(section:string)=>void;
43     searchComponents:(searchText:string)=>void;
44     onMouseOver:(displayComponent:LeftPaletteComponent)=>void;
45     onMouseOut:(displayComponent:LeftPaletteComponent)=>void;
46     dragStartCallback:(event:JQueryEventObject, ui, displayComponent:LeftPaletteComponent)=>void;
47     dragStopCallback:()=>void;
48     onDragCallback:(event:JQueryEventObject) => void;
49
50     setElementTemplate:(e:JQueryEventObject)=>void;
51
52     isOnDrag:boolean;
53     isDragable:boolean;
54     isLoading:boolean;
55     isViewOnly:boolean;
56 }
57
58 export class Palette implements ng.IDirective {
59     constructor(private $log:ng.ILogService,
60                 private LeftPaletteLoaderService: LeftPaletteLoaderService,
61                 private sdcConfig,
62                 private ComponentFactory,
63                 private ComponentInstanceFactory:ComponentInstanceFactory,
64                 private NodesFactory:NodesFactory,
65                 private CompositionGraphGeneralUtils:CompositionGraphGeneralUtils,
66                 private EventListenerService:EventListenerService,
67                 private sdcMenu:IAppMenu,
68                 private ModalsHandler:ModalsHandler) {
69
70     }
71
72     private fetchingComponentFromServer:boolean = false;
73     private nodeHtmlSubstitute:JQuery;
74
75     scope = {
76         currentComponent: '=',
77         isViewOnly: '=',
78         isLoading: '='
79     };
80     restrict = 'E';
81     template = require('./palette.html');
82
83     link = (scope:IPaletteScope, el:JQuery) => {
84         this.nodeHtmlSubstitute = $('<div class="node-substitute"><span></span><img /></div>');
85         el.append(this.nodeHtmlSubstitute);
86         this.registerEventListenerForLeftPalette(scope);
87         // this.LeftPaletteLoaderService.loadLeftPanel(scope.currentComponent.componentType);
88
89         this.initComponents(scope);
90         this.initEvents(scope);
91         this.initDragEvents(scope);
92         this._initExpandedSection(scope, '');
93         el.on('$destroy', ()=> {
94             //remove listener of download event
95             this.unRegisterEventListenerForLeftPalette(scope);
96         });
97     };
98
99     private getUpdateLeftPaletteEventName = (component:Component):string => {
100         switch (component.componentType) {
101             case ComponentType.SERVICE:
102                 return EVENTS.SERVICE_LEFT_PALETTE_UPDATE_EVENT;
103             case ComponentType.RESOURCE:
104                 if((<Resource>component).resourceType == ResourceType.PNF){
105                     return EVENTS.RESOURCE_PNF_LEFT_PALETTE_UPDATE_EVENT;
106                 }else{
107                     return EVENTS.RESOURCE_LEFT_PALETTE_UPDATE_EVENT;
108                 }
109             default:
110                 console.log('ERROR: Component type '+ component.componentType + ' is not exists');
111         }
112     };
113
114     private registerEventListenerForLeftPalette = (scope:IPaletteScope):void => {
115         let updateEventName:string = this.getUpdateLeftPaletteEventName(scope.currentComponent);
116         this.EventListenerService.registerObserverCallback(updateEventName, () => {
117             this.updateLeftPanelDisplay(scope);
118         });
119     };
120
121     private unRegisterEventListenerForLeftPalette = (scope:IPaletteScope):void => {
122         let updateEventName:string = this.getUpdateLeftPaletteEventName(scope.currentComponent);
123         this.EventListenerService.unRegisterObserver(updateEventName);
124     };
125
126     private leftPanelResourceFilter(resourcesNotAbstract:Array<LeftPaletteComponent>, resourceFilterTypes:Array<string>):Array<LeftPaletteComponent> {
127         let filterResources = _.filter(resourcesNotAbstract, (component) => {
128             return resourceFilterTypes.indexOf(component.getComponentSubType()) > -1;
129         });
130         return filterResources;
131     }
132
133     private initLeftPanel(leftPanelComponents:Array<LeftPaletteComponent>, resourceFilterTypes:Array<string>):LeftPanelModel {
134         let leftPanelModel = new LeftPanelModel();
135
136         if (resourceFilterTypes && resourceFilterTypes.length) {
137             leftPanelComponents = this.leftPanelResourceFilter(leftPanelComponents, resourceFilterTypes);
138         }
139         leftPanelModel.numberOfElements = leftPanelComponents && leftPanelComponents.length || 0;
140
141         if (leftPanelComponents && leftPanelComponents.length) {
142
143             let categories:any = _.groupBy(leftPanelComponents, 'mainCategory');
144             for (let category in categories)
145                 categories[category] = _.groupBy(categories[category], 'subCategory');
146
147             leftPanelModel.sortedCategories = categories;
148         }
149         return leftPanelModel;
150     }
151
152
153     private initEvents(scope:IPaletteScope) {
154         /**
155          *
156          * @param section
157          */
158         scope.sectionClick = (section:string) => {
159             if (section === scope.expandedSection) {
160                 scope.expandedSection = '';
161                 return;
162             }
163             scope.expandedSection = section;
164         };
165
166         scope.onMouseOver = (displayComponent:LeftPaletteComponent) => {
167             if (scope.isOnDrag) {
168                 return;
169             }
170             scope.isOnDrag = true;
171
172             this.EventListenerService.notifyObservers(GRAPH_EVENTS.ON_PALETTE_COMPONENT_HOVER_IN, displayComponent);
173             this.$log.debug('palette::onMouseOver:: fired');
174             //
175             // if (this.CompositionGraphGeneralUtils.componentRequirementsAndCapabilitiesCaching.containsKey(displayComponent.uniqueId)) {
176             //     this.$log.debug(`palette::onMouseOver:: component id ${displayComponent.uniqueId} found in cache`);
177             //     let cacheComponent:Component = this.CompositionGraphGeneralUtils.componentRequirementsAndCapabilitiesCaching.getValue(displayComponent.uniqueId);
178             //
179             //     //TODO: Danny: fire event to highlight matching nodes
180             //     //showMatchingNodes(cacheComponent);
181             //     return;
182             // }
183             //
184             // this.$log.debug(`palette::onMouseOver:: component id ${displayComponent.uniqueId} not found in cache, initiating server get`);
185             // // This will bring the component from the server including requirements and capabilities
186             // // Check that we do not fetch many times, because only in the success we add the component to componentRequirementsAndCapabilitiesCaching
187             // if (this.fetchingComponentFromServer) {
188             //     return;
189             // }
190             //
191             // this.fetchingComponentFromServer = true;
192             // this.ComponentFactory.getComponentFromServer(displayComponent.componentSubType, displayComponent.uniqueId)
193             //     .then((component:Component) => {
194             //         this.$log.debug(`palette::onMouseOver:: component id ${displayComponent.uniqueId} fetch success`);
195             //         // this.LeftPaletteLoaderService.updateSpecificComponentLeftPalette(component, scope.currentComponent.componentType);
196             //         this.CompositionGraphGeneralUtils.componentRequirementsAndCapabilitiesCaching.setValue(component.uniqueId, component);
197             //         this.fetchingComponentFromServer = false;
198             //
199             //         //TODO: Danny: fire event to highlight matching nodes
200             //         //showMatchingNodes(component);
201             //     })
202             //     .catch(() => {
203             //         this.$log.debug('palette::onMouseOver:: component id fetch error');
204             //         this.fetchingComponentFromServer = false;
205             //     });
206
207
208         };
209
210         scope.onMouseOut = () => {
211             scope.isOnDrag = false;
212             this.EventListenerService.notifyObservers(GRAPH_EVENTS.ON_PALETTE_COMPONENT_HOVER_OUT);
213         }
214     }
215
216     private initComponents(scope:IPaletteScope) {
217         scope.searchComponents = (searchText:any):void => {
218             scope.displaySortedCategories = this._searchComponents(searchText, scope.model.sortedCategories);
219             this._initExpandedSection(scope, searchText);
220         };
221
222         scope.isDragable = scope.currentComponent.isComplex();
223         this.updateLeftPanelDisplay(scope);
224     }
225
226     private updateLeftPanelDisplay(scope:IPaletteScope) {
227         let entityType:string = scope.currentComponent.componentType.toLowerCase();
228         let resourceFilterTypes:Array<string> = this.sdcConfig.resourceTypesFilter[entityType];
229         scope.components = this.LeftPaletteLoaderService.getLeftPanelComponentsForDisplay(scope.currentComponent);
230         scope.model = this.initLeftPanel(scope.components, resourceFilterTypes);
231         scope.displaySortedCategories = angular.copy(scope.model.sortedCategories);
232     };
233
234     private _initExpandedSection(scope:IPaletteScope, searchText:string):void {
235         if (searchText == '') {
236             let isContainingCategory:boolean = false;
237             let categoryToExpand:string;
238             if (scope.currentComponent && scope.currentComponent.categories && scope.currentComponent.categories[0]) {
239                 categoryToExpand = this.sdcMenu.categoriesDictionary[scope.currentComponent.categories[0].name];
240                 for (let category in scope.model.sortedCategories) {
241                     if (categoryToExpand == category) {
242                         isContainingCategory = true;
243                         break;
244                     }
245                 }
246             }
247             isContainingCategory ? scope.expandedSection = categoryToExpand : scope.expandedSection = 'Generic';
248         }
249         else {
250             scope.expandedSection = Object.keys(scope.displaySortedCategories).sort()[0];
251         }
252     };
253
254     private initDragEvents(scope:IPaletteScope) {
255         scope.dragStartCallback = (event:IDragDropEvent, ui, displayComponent:LeftPaletteComponent):void => {
256             if (scope.isLoading || !scope.isDragable || scope.isViewOnly) {
257                 return;
258             }
259
260             let component = _.find(this.LeftPaletteLoaderService.getLeftPanelComponentsForDisplay(scope.currentComponent), (componentFullData:LeftPaletteComponent) => {
261                 return displayComponent.uniqueId === componentFullData.uniqueId;
262             });
263             this.EventListenerService.notifyObservers(GRAPH_EVENTS.ON_PALETTE_COMPONENT_DRAG_START, scope.dragElement, component);
264
265             scope.isOnDrag = true;
266
267             // this.graphUtils.showMatchingNodes(component, myDiagram, scope.sdcConfig.imagesPath);
268             // document.addEventListener('mousemove', moveOnDocument);
269             event.dataTransfer.component = component;
270         };
271
272         scope.dragStopCallback = () => {
273             scope.isOnDrag = false;
274         };
275
276         scope.onDragCallback = (event:IDragDropEvent):void => {
277             this.EventListenerService.notifyObservers(GRAPH_EVENTS.ON_PALETTE_COMPONENT_DRAG_ACTION, event);
278         };
279         scope.setElementTemplate = (e) => {
280             let dragComponent:LeftPaletteComponent = _.find(this.LeftPaletteLoaderService.getLeftPanelComponentsForDisplay(scope.currentComponent),
281                 (fullComponent:LeftPaletteComponent) => {
282                     return (<any>angular.element(e.currentTarget).scope()).component.uniqueId === fullComponent.uniqueId;
283                 });
284             let componentInstance:ComponentInstance = this.ComponentInstanceFactory.createComponentInstanceFromComponent(dragComponent);
285             let node:CompositionCiNodeBase = this.NodesFactory.createNode(componentInstance);
286
287             // myDiagram.dragFromPalette = node;
288             this.nodeHtmlSubstitute.find("img").attr('src', node.img);
289             scope.dragElement = this.nodeHtmlSubstitute.clone().show();
290
291             return scope.dragElement;
292         };
293     }
294
295     private _searchComponents = (searchText:string, categories:any):void => {
296         let displaySortedCategories = angular.copy(categories);
297         if (searchText != '') {
298             angular.forEach(categories, function (category:any, categoryKey) {
299
300                 angular.forEach(category, function (subcategory:Array<LeftPaletteComponent>, subcategoryKey) {
301                     let filteredResources = [];
302                     angular.forEach(subcategory, function (component:LeftPaletteComponent) {
303
304                         let resourceFilterTerm:string = component.searchFilterTerms;
305                         if (resourceFilterTerm.indexOf(searchText.toLowerCase()) >= 0) {
306                             filteredResources.push(component);
307                         }
308                     });
309                     if (filteredResources.length > 0) {
310                         displaySortedCategories[categoryKey][subcategoryKey] = filteredResources;
311                     }
312                     else {
313                         delete  displaySortedCategories[categoryKey][subcategoryKey];
314                     }
315                 });
316                 if (!(Object.keys(displaySortedCategories[categoryKey]).length > 0)) {
317                     delete  displaySortedCategories[categoryKey];
318                 }
319
320             });
321         }
322         return displaySortedCategories;
323     };
324
325     public static factory = ($log,
326                              LeftPaletteLoaderService,
327                              sdcConfig,
328                              ComponentFactory,
329                              ComponentInstanceFactory,
330                              NodesFactory,
331                              CompositionGraphGeneralUtils,
332                              EventListenerService,
333                              sdcMenu,
334                              ModalsHandler) => {
335         return new Palette($log,
336             LeftPaletteLoaderService,
337             sdcConfig,
338             ComponentFactory,
339             ComponentInstanceFactory,
340             NodesFactory,
341             CompositionGraphGeneralUtils,
342             EventListenerService,
343             sdcMenu,
344             ModalsHandler);
345     };
346 }
347
348 Palette.factory.$inject = [
349     '$log',
350     'LeftPaletteLoaderService',
351     'sdcConfig',
352     'ComponentFactory',
353     'ComponentInstanceFactory',
354     'NodesFactory',
355     'CompositionGraphGeneralUtils',
356     'EventListenerService',
357     'sdcMenu',
358     'ModalsHandler'
359 ];