4 * Copyright 2016 RIFT.IO Inc
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
10 * http://www.apache.org/licenses/LICENSE-2.0
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.
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'
38 import FileManager
from './filemanager/FileManager.jsx';
40 import '../styles/CanvasPanel.scss'
42 const CanvasPanel
= React
.createClass({
43 mixins
: [PureRenderMixin
],
58 componentWillMount() {
62 componentDidUpdate() {
63 SelectionManager
.refreshOutline();
65 componentWillUnmount() {
69 left
: this.props
.layout
.left
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
}>
86 <button className
={!isDescriptorView
? '-selected' : ''} onClick
={ComposerAppActions
.showAssets
}>
95 <div id
="canvasPanelDiv" className
="CanvasPanel" style
={style
} onDragOver
={this.onDragOver
} onDrop
={this.onDrop
}>
96 <div onDoubleClick
={this.onDblClickOpenFullScreen
} className
="CanvasPanelHeader panel-header" data
-resizable
="limit_bottom">
98 {hasItem
? <img src
={req('./' + DescriptorModelIconFactory
.getUrlForType(this.props
.containers
[0].type
, 'black'))} width
="20px" /> : null}
99 <span className
="model-name">{this.props
.title
}</span
>
103 <div className
="CanvasPanelBody panel-body" style
={{marginRight
: this.props
.layout
.right
, bottom
: this.props
.layout
.bottom
}} >
104 {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
}
108 <CanvasZoom zoom
={this.props
.zoom
} style
={{bottom
: this.props
.layout
.bottom
+ 20}}/>
111 <CanvasPanelTray layout
={this.props
.layout
} show
={isEditingNSD
&& isDescriptorView
}>
112 <EditForwardingGraphPaths containers
={this.props
.containers
} />
118 const isDraggingFiles
= _includes(event
.dataTransfer
.types
, 'Files');
119 if (!isDraggingFiles
) {
120 event
.preventDefault();
121 event
.dataTransfer
.dropEffect
= 'copy';
125 // given a drop event determine which action to take in the canvas:
126 // open item or add item to an existing, already opened nsd
127 // note: nsd is the only editable container
128 const data
= utils
.parseJSONIgnoreErrors(event
.dataTransfer
.getData('text'));
129 if (data
.type
=== 'catalog-item') {
130 this.handleDropCatalogItem(event
, data
);
131 } else if (data
.type
=== 'action') {
132 this.handleDropCanvasAction(event
, data
);
135 handleDropCanvasAction(event
, data
) {
136 const action
= cc
.camel('on-' + data
.action
);
137 if (typeof this[action
] === 'function') {
138 if (this[action
]({clientX
: event
.clientX
, clientY
: event
.clientY
})) {
139 event
.preventDefault();
142 console
.warn(`no action defined for drop event ${data.action}. Did you forget to add CanvasPanel.${action}() event handler?`);
145 handleDropCatalogItem(event
, data
) {
147 const currentItem
= this.props
.containers
[0];
148 if (data
.item
.uiState
.type
=== 'nsd') {
149 // if item is an nsd then open the descriptor in the canvas
150 openItem
= data
.item
;
151 // if item is a vnfd or pnfd then check if the current item is an nsd
152 } else if (DescriptorModelFactory
.isNetworkService(currentItem
)) {
153 // so add the item to the nsd and re-render the canvas
154 switch (data
.item
.uiState
.type
) {
156 this.onAddVnfd(data
.item
, {clientX
: event
.clientX
, clientY
: event
.clientY
});
159 this.onAddPnfd(data
.item
, {clientX
: event
.clientX
, clientY
: event
.clientY
});
162 console
.warn(`Unknown catalog-item type. Expect type "nsd", "vnfd" or "pnfd" but got ${data.item.uiState.type}.`);
165 // otherwise the default action is to open the item
166 openItem
= data
.item
;
169 event
.preventDefault();
170 CatalogItemsActions
.editCatalogItem(openItem
);
173 onAddVdu(dropCoordinates
) {
174 const currentItem
= this.props
.containers
[0];
175 if (DescriptorModelFactory
.isVirtualNetworkFunction(currentItem
)) {
176 const vdu
= currentItem
.createVdu();
177 vdu
.uiState
.dropCoordinates
= dropCoordinates
;
178 CatalogItemsActions
.catalogItemDescriptorChanged(currentItem
);
181 onAddVld(dropCoordinates
) {
182 const currentItem
= this.props
.containers
[0];
183 if (DescriptorModelFactory
.isNetworkService(currentItem
) || DescriptorModelFactory
.isVirtualNetworkFunction(currentItem
)) {
184 const vld
= currentItem
.createVld();
185 vld
.uiState
.dropCoordinates
= dropCoordinates
;
186 CatalogItemsActions
.catalogItemDescriptorChanged(currentItem
);
189 onAddVnffgd(dropCoordinates
) {
190 const currentItem
= this.props
.containers
[0];
191 if (DescriptorModelFactory
.isNetworkService(currentItem
)) {
192 const vld
= currentItem
.createVnffgd();
193 vld
.uiState
.dropCoordinates
= dropCoordinates
;
194 CatalogItemsActions
.catalogItemDescriptorChanged(currentItem
);
197 onAddVnfd(model
, dropCoordinates
) {
198 const currentItem
= this.props
.containers
[0];
199 if (DescriptorModelFactory
.isNetworkService(currentItem
) || DescriptorModelFactory
.isVirtualNetworkFunction(currentItem
)) {
200 const vnfd
= DescriptorModelFactory
.newVirtualNetworkFunction(model
);
201 const cvnfd
= currentItem
.createConstituentVnfdForVnfd(vnfd
);
202 cvnfd
.uiState
.dropCoordinates
= dropCoordinates
;
203 CatalogItemsActions
.catalogItemDescriptorChanged(currentItem
);
206 onAddPnfd(model
, dropCoordinates
) {
207 const currentItem
= this.props
.containers
[0];
208 if (DescriptorModelFactory
.isNetworkService(currentItem
)) {
209 const pnfd
= DescriptorModelFactory
.newPhysicalNetworkFunction(model
);
210 pnfd
.uiState
.dropCoordinates
= dropCoordinates
;
211 currentItem
.createPnfd(pnfd
);
212 CatalogItemsActions
.catalogItemDescriptorChanged(currentItem
);
215 onDblClickOpenFullScreen(event
) {
216 event
.stopPropagation();
217 ComposerAppActions
.enterFullScreenMode();
221 export default CanvasPanel
;