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