Merging master to master_vca_intg
[osm/UI.git] / skyquake / plugins / composer / src / src / components / CanvasPanel.js
1
2 /*
3 *
4 * Copyright 2016 RIFT.IO Inc
5 *
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
17 *
18 */
19 'use strict';
20
21 import _ from 'lodash'
22 import cc from 'change-case'
23 import React from 'react'
24 import PureRenderMixin from 'react-addons-pure-render-mixin'
25 import utils from '../libraries/utils'
26 import messages from './messages'
27 import DescriptorModelFactory from '../libraries/model/DescriptorModelFactory'
28 import CatalogItemCanvasEditor from './CatalogItemCanvasEditor'
29 import CatalogItemsActions from '../actions/CatalogItemsActions'
30 import CanvasEditorActions from '../actions/CanvasEditorActions'
31 import ComposerAppActions from '../actions/ComposerAppActions'
32 import CanvasZoom from './CanvasZoom'
33 import CanvasPanelTray from './CanvasPanelTray'
34 import EditForwardingGraphPaths from './EditorForwardingGraph/EditForwardingGraphPaths'
35 import SelectionManager from '../libraries/SelectionManager'
36 import DescriptorModelIconFactory from '../libraries/model/IconFactory'
37 import FileManager from './filemanager/FileManager.jsx';
38
39 import ConfigPrimitiveParameters from './ConfigPrimitiveParameters/ConfigPrimitiveParameters'
40 import '../styles/CanvasPanel.scss'
41
42 const CanvasPanel = React.createClass({
43 mixins: [PureRenderMixin],
44 getInitialState() {
45 return {};
46 },
47 getDefaultProps() {
48 return {
49 title: '',
50 layout: {
51 left: 300,
52 right: 300
53 },
54 showMore: false,
55 containers: []
56 };
57 },
58 componentWillMount() {
59 },
60 componentDidMount() {
61 },
62 componentDidUpdate() {
63 SelectionManager.refreshOutline();
64 },
65 componentWillUnmount() {
66 },
67 render() {
68 var style = {
69 left: this.props.layout.left
70 };
71 var req = require.context("../", true, /^\.\/.*\.svg$/);
72 const hasItem = this.props.containers.length !== 0;
73 const isEditingNSD = DescriptorModelFactory.isNetworkService(this.props.containers[0]);
74 const isDescriptorView = (this.props.panelTabShown == 'descriptor');
75 const hasNoCatalogs = this.props.hasNoCatalogs;
76 const bodyComponent = hasItem ? <CatalogItemCanvasEditor zoom={this.props.zoom} isShowingMoreInfo={this.props.showMore} containers={this.props.containers}/> : messages.canvasWelcome();
77 const viewFiles = this.props.panelTabShown == 'assets';
78 const viewButtonTabs = !hasItem ? null : (
79 <div className="CanvasPanelTabs">
80 <div className="CatalogFilter">
81 <button className={isDescriptorView ? '-selected' : ''} onClick={ComposerAppActions.showDescriptor}>
82 Descriptor
83 </button>
84 {
85 this.props.files ?
86 <button className={!isDescriptorView ? '-selected' : ''} onClick={ComposerAppActions.showAssets}>
87 Assets
88 </button>
89 : null
90 }
91 </div>
92 </div>
93 )
94 //CanvasPanelTray panel to display
95 let displayedPanel = null;
96 switch (this.props.displayedPanel) {
97 case 'forwarding' : displayedPanel = (<EditForwardingGraphPaths containers={this.props.containers} />); break;
98 case 'parameter' : displayedPanel = (<ConfigPrimitiveParameters containers={this.props.containers} />); break;
99 default: displayedPanel = (<div><p className="welcome-message">Please select a tab</p></div>); break;
100 }
101 return (
102 <div id="canvasPanelDiv" className="CanvasPanel" style={style} onDragOver={this.onDragOver} onDrop={this.onDrop}>
103 <div onDoubleClick={this.onDblClickOpenFullScreen} className="CanvasPanelHeader panel-header" data-resizable="limit_bottom">
104 <h1>
105 {hasItem ? <img src={req('./' + DescriptorModelIconFactory.getUrlForType(this.props.containers[0].type, 'black'))} width="20px" /> : null}
106 <span className="model-name">{this.props.title}</span>
107 </h1>
108 </div>
109 {viewButtonTabs}
110 <div className="CanvasPanelBody panel-body" style={{marginRight: this.props.layout.right, bottom: this.props.layout.bottom}} >
111 {hasNoCatalogs ? null : viewFiles ? <FileManager files={this.props.files} type={this.props.type} item={this.props.item} filesState={this.props.filesState} newPathName={this.props.newPathName} /> : bodyComponent}
112 </div>
113 {
114 isDescriptorView ?
115 <CanvasZoom zoom={this.props.zoom} style={{bottom: this.props.layout.bottom + 20}}/>
116 : null
117 }
118 <CanvasPanelTray layout={this.props.layout} displayedPanel={this.props.displayedPanel} show={isEditingNSD && isDescriptorView}>
119 {displayedPanel}
120 </CanvasPanelTray>
121 </div>
122 );
123 },
124 onDragOver(event) {
125 const isDraggingFiles = _.includes(event.dataTransfer.types, 'Files');
126 if (!isDraggingFiles) {
127 event.preventDefault();
128 event.dataTransfer.dropEffect = 'copy';
129 }
130 },
131 onDrop(event) {
132 // given a drop event determine which action to take in the canvas:
133 // open item or add item to an existing, already opened nsd
134 // note: nsd is the only editable container
135 const data = utils.parseJSONIgnoreErrors(event.dataTransfer.getData('text'));
136 if (data.type === 'catalog-item') {
137 this.handleDropCatalogItem(event, data);
138 } else if (data.type === 'action') {
139 this.handleDropCanvasAction(event, data);
140 }
141 },
142 handleDropCanvasAction(event, data) {
143 const action = cc.camel('on-' + data.action);
144 if (typeof this[action] === 'function') {
145 if (this[action]({clientX: event.clientX, clientY: event.clientY})) {
146 event.preventDefault();
147 }
148 } else {
149 console.warn(`no action defined for drop event ${data.action}. Did you forget to add CanvasPanel.${action}() event handler?`);
150 }
151 },
152 handleDropCatalogItem(event, data) {
153 let openItem = null;
154 const currentItem = this.props.containers[0];
155 if (data.item.uiState.type === 'nsd') {
156 // if item is an nsd then open the descriptor in the canvas
157 openItem = data.item;
158 // if item is a vnfd or pnfd then check if the current item is an nsd
159 } else if (DescriptorModelFactory.isNetworkService(currentItem)) {
160 // so add the item to the nsd and re-render the canvas
161 switch (data.item.uiState.type) {
162 case 'vnfd':
163 this.onAddVnfd(data.item, {clientX: event.clientX, clientY: event.clientY});
164 break;
165 case 'pnfd':
166 this.onAddPnfd(data.item, {clientX: event.clientX, clientY: event.clientY});
167 break;
168 default:
169 console.warn(`Unknown catalog-item type. Expect type "nsd", "vnfd" or "pnfd" but got ${data.item.uiState.type}.`);
170 }
171 } else {
172 // otherwise the default action is to open the item
173 openItem = data.item;
174 }
175 if (openItem) {
176 event.preventDefault();
177 CatalogItemsActions.editCatalogItem(openItem);
178 }
179 },
180 onAddVdu(dropCoordinates) {
181 const currentItem = this.props.containers[0];
182 if (DescriptorModelFactory.isVirtualNetworkFunction(currentItem)) {
183 const vdu = currentItem.createVdu();
184 vdu.uiState.dropCoordinates = dropCoordinates;
185 CatalogItemsActions.catalogItemDescriptorChanged(currentItem);
186 }
187 },
188 onAddVld(dropCoordinates) {
189 const currentItem = this.props.containers[0];
190 if (DescriptorModelFactory.isNetworkService(currentItem) || DescriptorModelFactory.isVirtualNetworkFunction(currentItem)) {
191 const vld = currentItem.createVld();
192 vld.uiState.dropCoordinates = dropCoordinates;
193 CatalogItemsActions.catalogItemDescriptorChanged(currentItem);
194 }
195 },
196 onAddVnffgd(dropCoordinates) {
197 const currentItem = this.props.containers[0];
198 if (DescriptorModelFactory.isNetworkService(currentItem)) {
199 const vld = currentItem.createVnffgd();
200 vld.uiState.dropCoordinates = dropCoordinates;
201 CatalogItemsActions.catalogItemDescriptorChanged(currentItem);
202 }
203 },
204 onAddVnfd(model, dropCoordinates) {
205 const currentItem = this.props.containers[0];
206 if (DescriptorModelFactory.isNetworkService(currentItem) || DescriptorModelFactory.isVirtualNetworkFunction(currentItem)) {
207 const vnfd = DescriptorModelFactory.newVirtualNetworkFunction(model);
208 const cvnfd = currentItem.createConstituentVnfdForVnfd(vnfd);
209 cvnfd.uiState.dropCoordinates = dropCoordinates;
210 CatalogItemsActions.catalogItemDescriptorChanged(currentItem);
211 }
212 },
213 onAddPnfd(model, dropCoordinates) {
214 const currentItem = this.props.containers[0];
215 if (DescriptorModelFactory.isNetworkService(currentItem)) {
216 const pnfd = DescriptorModelFactory.newPhysicalNetworkFunction(model);
217 pnfd.uiState.dropCoordinates = dropCoordinates;
218 currentItem.createPnfd(pnfd);
219 CatalogItemsActions.catalogItemDescriptorChanged(currentItem);
220 }
221 },
222 onDblClickOpenFullScreen(event) {
223 event.stopPropagation();
224 ComposerAppActions.enterFullScreenMode();
225 }
226 });
227
228 export default CanvasPanel;