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