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'
37 import FileManager
from './filemanager/FileManager.jsx';
38 import { isRBACValid
} from 'widgets/skyquake_rbac/skyquakeRBAC';
39 import ROLES
from 'utils/roleConstants.js';
41 import ConfigPrimitiveParameters
from './ConfigPrimitiveParameters/ConfigPrimitiveParameters'
42 import '../styles/CanvasPanel.scss'
44 const CanvasPanel
= React
.createClass({
45 mixins
: [PureRenderMixin
],
60 componentWillMount() {
64 componentDidUpdate() {
65 SelectionManager
.refreshOutline();
67 componentWillUnmount() {
71 left
: this.props
.layout
.left
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
}>
95 <button className
={!isDescriptorView
? '-selected' : ''} onClick
={ComposerAppActions
.showAssets
}>
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;
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">
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
>
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
}
125 <CanvasZoom zoom
={this.props
.zoom
} style
={{ bottom
: this.props
.layout
.bottom
+ 20 }} />
128 <CanvasPanelTray layout
={this.props
.layout
} displayedPanel
={this.props
.displayedPanel
} show
={isEditingNSD
&& isDescriptorView
}>
135 const isDraggingFiles
= _includes(event
.dataTransfer
.types
, 'Files');
136 if (!isDraggingFiles
) {
137 event
.preventDefault();
138 event
.dataTransfer
.dropEffect
= 'copy';
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
);
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();
159 console
.warn(`no action defined for drop event ${data.action}. Did you forget to add CanvasPanel.${action}() event handler?`);
162 handleDropCatalogItem(event
, data
) {
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
) {
173 this.onAddVnfd(data
.item
, { clientX
: event
.clientX
, clientY
: event
.clientY
});
176 this.onAddPnfd(data
.item
, { clientX
: event
.clientX
, clientY
: event
.clientY
});
179 console
.warn(`Unknown catalog-item type. Expect type "nsd", "vnfd" or "pnfd" but got ${data.item.uiState.type}.`);
182 // otherwise the default action is to open the item
183 openItem
= data
.item
;
186 event
.preventDefault();
187 CatalogItemsActions
.editCatalogItem(openItem
);
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
);
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
);
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
);
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
);
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
);
232 onDblClickOpenFullScreen(event
) {
233 event
.stopPropagation();
234 ComposerAppActions
.enterFullScreenMode();
238 export default CanvasPanel
;