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