Rift.IO OSM R1 Initial Submission
[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
38 import '../styles/CanvasPanel.scss'
39
40 const CanvasPanel = React.createClass({
41 mixins: [PureRenderMixin],
42 getInitialState() {
43 return {};
44 },
45 getDefaultProps() {
46 return {
47 title: '',
48 layout: {
49 left: 300,
50 right: 300
51 },
52 showMore: false,
53 containers: []
54 };
55 },
56 componentWillMount() {
57 },
58 componentDidMount() {
59 },
60 componentDidUpdate() {
61 SelectionManager.refreshOutline();
62 },
63 componentWillUnmount() {
64 },
65 render() {
66 var style = {
67 left: this.props.layout.left
68 };
69 var req = require.context("../", true, /^\.\/.*\.svg$/);
70 const hasItem = this.props.containers.length !== 0;
71 const isEditingNSD = DescriptorModelFactory.isNetworkService(this.props.containers[0]);
72 const hasNoCatalogs = this.props.hasNoCatalogs;
73 const bodyComponent = hasItem ? <CatalogItemCanvasEditor zoom={this.props.zoom} isShowingMoreInfo={this.props.showMore} containers={this.props.containers}/> : messages.canvasWelcome();
74 return (
75 <div id="canvasPanelDiv" className="CanvasPanel" style={style} onDragOver={this.onDragOver} onDrop={this.onDrop}>
76 <div onDoubleClick={this.onDblClickOpenFullScreen} className="CanvasPanelHeader panel-header" data-resizable="limit_bottom">
77 <h1>
78 {hasItem ? <img src={req('./' + DescriptorModelIconFactory.getUrlForType(this.props.containers[0].type, 'black'))} width="20px" /> : null}
79 <span className="model-name">{this.props.title}</span>
80 </h1>
81 </div>
82 <div className="CanvasPanelBody panel-body" style={{marginRight: this.props.layout.right, bottom: this.props.layout.bottom}} >
83 {hasNoCatalogs ? null : bodyComponent}
84 </div>
85 <CanvasZoom zoom={this.props.zoom} style={{bottom: this.props.layout.bottom + 20}}/>
86 <CanvasPanelTray layout={this.props.layout} show={isEditingNSD}>
87 <EditForwardingGraphPaths containers={this.props.containers} />
88 </CanvasPanelTray>
89 </div>
90 );
91 },
92 onDragOver(event) {
93 const isDraggingFiles = _.contains(event.dataTransfer.types, 'Files');
94 if (!isDraggingFiles) {
95 event.preventDefault();
96 event.dataTransfer.dropEffect = 'copy';
97 }
98 },
99 onDrop(event) {
100 // given a drop event determine which action to take in the canvas:
101 // open item or add item to an existing, already opened nsd
102 // note: nsd is the only editable container
103 const data = utils.parseJSONIgnoreErrors(event.dataTransfer.getData('text'));
104 if (data.type === 'catalog-item') {
105 this.handleDropCatalogItem(event, data);
106 } else if (data.type === 'action') {
107 this.handleDropCanvasAction(event, data);
108 }
109 },
110 handleDropCanvasAction(event, data) {
111 const action = cc.camel('on-' + data.action);
112 if (typeof this[action] === 'function') {
113 if (this[action]({clientX: event.clientX, clientY: event.clientY})) {
114 event.preventDefault();
115 }
116 } else {
117 console.warn(`no action defined for drop event ${data.action}. Did you forget to add CanvasPanel.${action}() event handler?`);
118 }
119 },
120 handleDropCatalogItem(event, data) {
121 let openItem = null;
122 const currentItem = this.props.containers[0];
123 if (data.item.uiState.type === 'nsd') {
124 // if item is an nsd then open the descriptor in the canvas
125 openItem = data.item;
126 // if item is a vnfd or pnfd then check if the current item is an nsd
127 } else if (DescriptorModelFactory.isNetworkService(currentItem)) {
128 // so add the item to the nsd and re-render the canvas
129 switch (data.item.uiState.type) {
130 case 'vnfd':
131 this.onAddVnfd(data.item, {clientX: event.clientX, clientY: event.clientY});
132 break;
133 case 'pnfd':
134 this.onAddPnfd(data.item, {clientX: event.clientX, clientY: event.clientY});
135 break;
136 default:
137 console.warn(`Unknown catalog-item type. Expect type "nsd", "vnfd" or "pnfd" but got ${data.item.uiState.type}.`);
138 }
139 } else {
140 // otherwise the default action is to open the item
141 openItem = data.item;
142 }
143 if (openItem) {
144 event.preventDefault();
145 CatalogItemsActions.editCatalogItem(openItem);
146 }
147 },
148 onAddVdu(dropCoordinates) {
149 const currentItem = this.props.containers[0];
150 if (DescriptorModelFactory.isVirtualNetworkFunction(currentItem)) {
151 const vdu = currentItem.createVdu();
152 vdu.uiState.dropCoordinates = dropCoordinates;
153 CatalogItemsActions.catalogItemDescriptorChanged(currentItem);
154 }
155 },
156 onAddVld(dropCoordinates) {
157 const currentItem = this.props.containers[0];
158 if (DescriptorModelFactory.isNetworkService(currentItem) || DescriptorModelFactory.isVirtualNetworkFunction(currentItem)) {
159 const vld = currentItem.createVld();
160 vld.uiState.dropCoordinates = dropCoordinates;
161 CatalogItemsActions.catalogItemDescriptorChanged(currentItem);
162 }
163 },
164 onAddVnffgd(dropCoordinates) {
165 const currentItem = this.props.containers[0];
166 if (DescriptorModelFactory.isNetworkService(currentItem)) {
167 const vld = currentItem.createVnffgd();
168 vld.uiState.dropCoordinates = dropCoordinates;
169 CatalogItemsActions.catalogItemDescriptorChanged(currentItem);
170 }
171 },
172 onAddVnfd(model, dropCoordinates) {
173 const currentItem = this.props.containers[0];
174 if (DescriptorModelFactory.isNetworkService(currentItem) || DescriptorModelFactory.isVirtualNetworkFunction(currentItem)) {
175 const vnfd = DescriptorModelFactory.newVirtualNetworkFunction(model);
176 const cvnfd = currentItem.createConstituentVnfdForVnfd(vnfd);
177 cvnfd.uiState.dropCoordinates = dropCoordinates;
178 CatalogItemsActions.catalogItemDescriptorChanged(currentItem);
179 }
180 },
181 onAddPnfd(model, dropCoordinates) {
182 const currentItem = this.props.containers[0];
183 if (DescriptorModelFactory.isNetworkService(currentItem)) {
184 const pnfd = DescriptorModelFactory.newPhysicalNetworkFunction(model);
185 pnfd.uiState.dropCoordinates = dropCoordinates;
186 currentItem.createPnfd(pnfd);
187 CatalogItemsActions.catalogItemDescriptorChanged(currentItem);
188 }
189 },
190 onDblClickOpenFullScreen(event) {
191 event.stopPropagation();
192 ComposerAppActions.enterFullScreenMode();
193 }
194 });
195
196 export default CanvasPanel;