update from RIFT as of 696b75d2fe9fb046261b08c616f1bcf6c0b54a9b third try
[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 _includes from 'lodash/includes'
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 import { isRBACValid } from 'widgets/skyquake_rbac/skyquakeRBAC';
39 import ROLES from 'utils/roleConstants.js';
40
41 import ConfigPrimitiveParameters from './ConfigPrimitiveParameters/ConfigPrimitiveParameters'
42 import '../styles/CanvasPanel.scss'
43
44 const CanvasPanel = React.createClass({
45 mixins: [PureRenderMixin],
46 getInitialState() {
47 return {};
48 },
49 getDefaultProps() {
50 return {
51 title: '',
52 layout: {
53 left: 300,
54 right: 300
55 },
56 showMore: false,
57 containers: []
58 };
59 },
60 componentWillMount() {
61 },
62 componentDidMount() {
63 },
64 componentDidUpdate() {
65 SelectionManager.refreshOutline();
66 },
67 componentWillUnmount() {
68 },
69 render() {
70 var style = {
71 left: this.props.layout.left
72 };
73 var req = require.context("../", true, /^\.\/.*\.svg$/);
74 const User = this.props.User || {};
75 const isModifiableByUser = isRBACValid(User, [ROLES.PROJECT.PROJECT_ADMIN, ROLES.PROJECT.CATALOG_ADMIN]);
76 const hasItem = this.props.containers.length !== 0;
77 const isEditingNSD = DescriptorModelFactory.isNetworkService(this.props.containers[0]);
78 const isDescriptorView = (this.props.panelTabShown == 'descriptor');
79 const hasNoCatalogs = this.props.hasNoCatalogs;
80 const bodyComponent = hasItem ? (
81 <CatalogItemCanvasEditor
82 readOnly={!isModifiableByUser}
83 zoom={this.props.zoom}
84 isShowingMoreInfo={this.props.showMore}
85 containers={this.props.containers} />) : messages.canvasWelcome();
86 const viewFiles = this.props.panelTabShown == 'assets';
87 const viewButtonTabs = !hasItem ? null : (
88 <div className="CanvasPanelTabs">
89 <div className="CatalogFilter">
90 <button className={isDescriptorView ? '-selected' : ''} onClick={ComposerAppActions.showDescriptor}>
91 Descriptor
92 </button>
93 {
94 this.props.files ?
95 <button className={!isDescriptorView ? '-selected' : ''} onClick={ComposerAppActions.showAssets}>
96 Assets
97 </button>
98 : null
99 }
100 </div>
101 </div>
102 )
103 //CanvasPanelTray panel to display
104 let displayedPanel = null;
105 switch (this.props.displayedPanel) {
106 case 'forwarding': displayedPanel = (<EditForwardingGraphPaths containers={this.props.containers} />); break;
107 case 'parameter': displayedPanel = (<ConfigPrimitiveParameters containers={this.props.containers} />); break;
108 default: displayedPanel = (<div><p className="welcome-message">Please select a tab</p></div>); break;
109 }
110 return (
111 <div id="canvasPanelDiv" className="CanvasPanel" style={style}
112 onDragOver={isModifiableByUser ? this.onDragOver : null} onDrop={isModifiableByUser ? this.onDrop : null}>
113 <div onDoubleClick={this.onDblClickOpenFullScreen} className="CanvasPanelHeader panel-header" data-resizable="limit_bottom">
114 <h1>
115 {hasItem ? <img src={req('./' + DescriptorModelIconFactory.getUrlForType(this.props.containers[0].type, 'black'))} width="20px" /> : null}
116 <span className="model-name">{this.props.title}</span>
117 </h1>
118 </div>
119 {viewButtonTabs}
120 <div className="CanvasPanelBody panel-body" style={{ marginRight: this.props.layout.right, bottom: this.props.layout.bottom }} >
121 {hasNoCatalogs ? null : viewFiles ? <FileManager files={this.props.files} type={this.props.type} item={this.props.item} filesState={this.props.filesState} newPathName={this.props.newPathName} User={User} /> : bodyComponent}
122 </div>
123 {
124 isDescriptorView ?
125 <CanvasZoom zoom={this.props.zoom} style={{ bottom: this.props.layout.bottom + 20 }} />
126 : null
127 }
128 <CanvasPanelTray layout={this.props.layout} displayedPanel={this.props.displayedPanel} show={isEditingNSD && isDescriptorView}>
129 {displayedPanel}
130 </CanvasPanelTray>
131 </div>
132 );
133 },
134 onDragOver(event) {
135 const isDraggingFiles = _includes(event.dataTransfer.types, 'Files');
136 if (!isDraggingFiles) {
137 event.preventDefault();
138 event.dataTransfer.dropEffect = 'copy';
139 }
140 },
141 onDrop(event) {
142 // given a drop event determine which action to take in the canvas:
143 // open item or add item to an existing, already opened nsd
144 // note: nsd is the only editable container
145 const data = utils.parseJSONIgnoreErrors(event.dataTransfer.getData('text'));
146 if (data.type === 'catalog-item') {
147 this.handleDropCatalogItem(event, data);
148 } else if (data.type === 'action') {
149 this.handleDropCanvasAction(event, data);
150 }
151 },
152 handleDropCanvasAction(event, data) {
153 const action = cc.camel('on-' + data.action);
154 if (typeof this[action] === 'function') {
155 if (this[action]({ clientX: event.clientX, clientY: event.clientY })) {
156 event.preventDefault();
157 }
158 } else {
159 console.warn(`no action defined for drop event ${data.action}. Did you forget to add CanvasPanel.${action}() event handler?`);
160 }
161 },
162 handleDropCatalogItem(event, data) {
163 let openItem = null;
164 const currentItem = this.props.containers[0];
165 if (data.item.uiState.type === 'nsd') {
166 // if item is an nsd then open the descriptor in the canvas
167 openItem = data.item;
168 // if item is a vnfd or pnfd then check if the current item is an nsd
169 } else if (DescriptorModelFactory.isNetworkService(currentItem)) {
170 // so add the item to the nsd and re-render the canvas
171 switch (data.item.uiState.type) {
172 case 'vnfd':
173 this.onAddVnfd(data.item, { clientX: event.clientX, clientY: event.clientY });
174 break;
175 case 'pnfd':
176 this.onAddPnfd(data.item, { clientX: event.clientX, clientY: event.clientY });
177 break;
178 default:
179 console.warn(`Unknown catalog-item type. Expect type "nsd", "vnfd" or "pnfd" but got ${data.item.uiState.type}.`);
180 }
181 } else {
182 // otherwise the default action is to open the item
183 openItem = data.item;
184 }
185 if (openItem) {
186 event.preventDefault();
187 CatalogItemsActions.editCatalogItem(openItem);
188 }
189 },
190 onAddVdu(dropCoordinates) {
191 const currentItem = this.props.containers[0];
192 if (DescriptorModelFactory.isVirtualNetworkFunction(currentItem)) {
193 const vdu = currentItem.createVdu();
194 vdu.uiState.dropCoordinates = dropCoordinates;
195 CatalogItemsActions.catalogItemDescriptorChanged(currentItem);
196 }
197 },
198 onAddVld(dropCoordinates) {
199 const currentItem = this.props.containers[0];
200 if (DescriptorModelFactory.isNetworkService(currentItem) || DescriptorModelFactory.isVirtualNetworkFunction(currentItem)) {
201 const vld = currentItem.createVld();
202 vld.uiState.dropCoordinates = dropCoordinates;
203 CatalogItemsActions.catalogItemDescriptorChanged(currentItem);
204 }
205 },
206 onAddVnffgd(dropCoordinates) {
207 const currentItem = this.props.containers[0];
208 if (DescriptorModelFactory.isNetworkService(currentItem)) {
209 const vld = currentItem.createVnffgd();
210 vld.uiState.dropCoordinates = dropCoordinates;
211 CatalogItemsActions.catalogItemDescriptorChanged(currentItem);
212 }
213 },
214 onAddVnfd(model, dropCoordinates) {
215 const currentItem = this.props.containers[0];
216 if (DescriptorModelFactory.isNetworkService(currentItem) || DescriptorModelFactory.isVirtualNetworkFunction(currentItem)) {
217 const vnfd = DescriptorModelFactory.newVirtualNetworkFunction(model);
218 const cvnfd = currentItem.createConstituentVnfdForVnfd(vnfd);
219 cvnfd.uiState.dropCoordinates = dropCoordinates;
220 CatalogItemsActions.catalogItemDescriptorChanged(currentItem);
221 }
222 },
223 onAddPnfd(model, dropCoordinates) {
224 const currentItem = this.props.containers[0];
225 if (DescriptorModelFactory.isNetworkService(currentItem)) {
226 const pnfd = DescriptorModelFactory.newPhysicalNetworkFunction(model);
227 pnfd.uiState.dropCoordinates = dropCoordinates;
228 currentItem.createPnfd(pnfd);
229 CatalogItemsActions.catalogItemDescriptorChanged(currentItem);
230 }
231 },
232 onDblClickOpenFullScreen(event) {
233 event.stopPropagation();
234 ComposerAppActions.enterFullScreenMode();
235 }
236 });
237
238 export default CanvasPanel;