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