[AAI-92 Amsterdam] Update license
[aai/sparky-fe.git] / src / generic-components / componentManager / ComponentManager.jsx
1 /*
2  * ============LICENSE_START=======================================================
3  * org.onap.aai
4  * ================================================================================
5  * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
6  * Copyright © 2017 Amdocs
7  * ================================================================================
8  * Licensed under the Apache License, Version 2.0 (the "License");
9  * you may not use this file except in compliance with the License.
10  * You may obtain a copy of the License at
11  *
12  *       http://www.apache.org/licenses/LICENSE-2.0
13  *
14  * Unless required by applicable law or agreed to in writing, software
15  * distributed under the License is distributed on an "AS IS" BASIS,
16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17  * See the License for the specific language governing permissions and
18  * limitations under the License.
19  * ============LICENSE_END=========================================================
20  *
21  * ECOMP is a trademark and service mark of AT&T Intellectual Property.
22  */
23 import React, {Component} from 'react';
24
25 import ComponentManagerContainer from
26   'generic-components/componentManager/ComponentManagerContainer.jsx';
27 import {
28   MIN_PANEL_WIDTH,
29   MIN_PANEL_HEIGHT,
30   MAX_PANEL_WIDTH,
31   EDIT_ICON,
32   LAYOUT_STATIC
33 } from 'generic-components/componentManager/ComponentManagerConstants.js';
34
35 var widthProvider = require('react-grid-layout').WidthProvider;
36 var ReactGridLayout = require('react-grid-layout');
37 ReactGridLayout = widthProvider(ReactGridLayout);
38
39 export default class ComponentManager extends Component {
40   constructor(props) {
41     super(props);
42
43     if (props.layoutType === LAYOUT_STATIC &&
44       Object.keys(props.layoutFormat).length > 0) {
45       this.state = {
46         layout: props.layoutFormat.layout,
47         panels: props.layoutFormat.panels,
48         containers: props.layoutFormat.containers
49       };
50     } else {
51       this.state = {
52         layout: [],
53         panels: [],
54         containers: []
55       };
56     }
57     this.onLayoutChange = this.onLayoutChange.bind(this);
58   }
59
60   createContainer(
61     containerId, xPos, yPos, width, height, staticLayout = false) {
62     if (staticLayout) {
63       return {
64         id: containerId,
65         properties: {
66           x: xPos,
67           y: yPos,
68           w: width,
69           h: height,
70           isDraggable: false,
71           isResizable: false
72         }
73       };
74     } else {
75       return {
76         id: containerId,
77         properties: {
78           x: xPos,
79           y: yPos,
80           w: width,
81           h: height,
82           minW: MIN_PANEL_WIDTH,
83           maxW: MAX_PANEL_WIDTH,
84           minH: MIN_PANEL_HEIGHT
85         }
86       };
87     }
88   }
89
90   createPanel(id, title, panelSource, panelProps, actionList) {
91     return {
92       id: id,
93       title: title,
94       source: panelSource,
95       props: panelProps,
96       actions: actionList
97     };
98   }
99
100   addNewComponent(compProps, containingContainerId) {
101     let containerId = containingContainerId;
102     let actionsList = [];
103
104     if (typeof containerId === 'undefined' || containerId === null) {
105       // new component being added isn't associated with a
106       // container yet, so create one
107       containerId = 'container:' + (new Date).getTime();
108       let updatedContainerProps = [];
109       this.state.containers.forEach((containerProps) => {
110         updatedContainerProps.push(containerProps);
111       });
112       updatedContainerProps.push(
113         this.createContainer(containerId, 0, Infinity, 12, 2));
114       this.setState({containers: updatedContainerProps});
115
116       actionsList = [
117         {
118           type: 'close', id: containerId, callback: () => {
119             this.removeExistingComponent(containerId);
120           }
121         }
122       ];
123     } else {
124       // we are updating a static container with a new panel, add the edit
125       // action so it can be updated moving forward
126       actionsList = [
127         {
128           type: 'custom',
129           id: containingContainerId,
130           icon: EDIT_ICON,
131           callback: () => {
132             this.props.addPanelCallback(containingContainerId);
133           }
134         }
135       ];
136     }
137
138     let updatedPanelProps = [];
139     this.state.panels.forEach((panelProp) => {
140       if (panelProp.id !== containingContainerId) {
141         // add all existing panels except the one with a
142         // matching id (this is an edit scenario, will replace
143         // with new panel below
144         updatedPanelProps.push(panelProp);
145       }
146     });
147     updatedPanelProps.push(
148       this.createPanel(
149         containerId,
150         compProps.title,
151         compProps.visualizationSource,
152         compProps.visualizationProps,
153         actionsList));
154     this.setState({panels: updatedPanelProps});
155   }
156
157   removeExistingComponent(id) {
158     let updatedPanelProps = this.state.panels.filter((panelProp) => {
159       return id !== panelProp.id;
160     });
161     this.setState({panels: updatedPanelProps});
162
163     let updatedContainerProps = this.state.containers.filter(
164       (containerProp) => {
165         return id !== containerProp.id;
166       });
167     this.setState({containers: updatedContainerProps});
168   }
169
170   getLayoutProperties() {
171     return {
172       layout: this.state.layout,
173       containers: this.state.containers,
174       panels: this.state.panels
175     };
176   }
177
178   setLayoutProperties(layoutProperties) {
179     this.setState({
180       layout: layoutProperties.layout,
181       containers: layoutProperties.containers,
182       panels: layoutProperties.panels
183     });
184   }
185
186   fetchMatchingPanel(containerId) {
187     let actionsList = [];
188     let matchingPanel = (
189       <ComponentManagerContainer
190         showHeader={this.props.showHeader}
191         showTitle={this.props.showTitle}
192         showBorder={this.props.showBorder}
193         actions={actionsList}>
194         {'Please select a visualization'}
195       </ComponentManagerContainer>
196     );
197     this.state.panels.forEach((panel) => {
198       if (panel.id === containerId) {
199         let GeneratedComponent =
200                                         this.props.componentPropertiesProvider[panel.source].component.class;
201         let visProps = panel.props;
202         matchingPanel = (
203           <ComponentManagerContainer
204             showHeader={this.props.showHeader}
205             showTitle={this.props.showTitle}
206             showBorder={this.props.showBorder}
207             title={panel.title}
208             actions={panel.actions}>
209             <GeneratedComponent {...visProps}/>
210           </ComponentManagerContainer>
211         );
212       }
213     });
214     return matchingPanel;
215   }
216
217   preparedContainers() {
218     let containersToRender = [];
219
220     this.state.containers.forEach((container) => {
221       let matchingPanel = this.fetchMatchingPanel(container.id);
222
223       containersToRender.push(<div key={container.id}
224                                    data-grid={{...(container.properties)}}>
225         {matchingPanel}
226       </div>);
227     });
228
229     return containersToRender;
230   }
231
232   onLayoutChange(layout) {
233     this.setState({layout: layout});
234     this.props.onLayoutChange(layout);
235   }
236
237   buildStaticContainers(layoutFormat) {
238     let staticContainers = [];
239     let nextRowIndex = 0;
240
241     layoutFormat.layout.forEach((row) => {
242       let nextColIndex = 0;
243       let currentTallestContainer = 0;
244
245       row.forEach((col) => {
246         let containerId = 'container:' + nextRowIndex + '-' + nextColIndex;
247         let xPos = nextColIndex;
248         let yPos = nextRowIndex;
249         let width = 12 * col.width;
250         let height = col.height;
251
252         nextColIndex = nextColIndex + width;
253         currentTallestContainer = Math.max(currentTallestContainer, col.height);
254
255         staticContainers.push(
256           this.createContainer(
257             containerId,
258             xPos,
259             yPos,
260             width,
261             height,
262             true
263           )
264         );
265       });
266
267       nextRowIndex = currentTallestContainer;
268     });
269
270     return staticContainers;
271   }
272
273   componentWillReceiveProps(nextProps) {
274     if (nextProps.layoutFormat !== this.props.layoutFormat) {
275       // layout format being passed in are the containers, panels and layout
276       // for the newly view
277       this.setState({
278         layout: nextProps.layoutFormat.layout,
279         panels: nextProps.layoutFormat.panels,
280         containers: nextProps.layoutFormat.containers
281       });
282     }
283   }
284
285   render() {
286
287     return (
288       <div className='component-manager'>
289         <ReactGridLayout
290           className='content app-components'
291           {...this.props}
292           onLayoutChange={this.onLayoutChange}
293           layout={this.state.layout}>
294           {this.preparedContainers()}
295         </ReactGridLayout>
296       </div>
297     );
298   }
299 }
300 ComponentManager.defaultProps = {
301   cols: 12,
302   rewHeight: 100,
303   onLayoutChange: function () {
304   },
305   showHeader: true,
306   showTitle: true,
307   showBorder: true
308 };