3 * Copyright 2016 RIFT.IO Inc
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
9 * http://www.apache.org/licenses/LICENSE-2.0
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
20 window
['RIFT_wareLaunchpadComposerVersion'] = `semver 0.0.79`;
23 import 'babel-polyfill'
24 import alt
from '../alt'
25 import UID
from '../libraries/UniqueId'
26 import utils
from '../libraries/utils'
27 import React
from 'react'
28 import ReactDOM
from 'react-dom'
29 import Crouton
from 'react-crouton'
30 import ClassNames
from 'classnames'
31 import PureRenderMixin
from 'react-addons-pure-render-mixin'
32 import DeletionManager
from '../libraries/DeletionManager'
33 import SelectionManager
from '../libraries/SelectionManager'
34 import ResizableManager
from '../libraries/ResizableManager'
35 import DescriptorModelMetaFactory
from '../libraries/model/DescriptorModelMetaFactory'
36 import DescriptorModelFactory
from '../libraries/model/DescriptorModelFactory'
37 import RiftHeader
from './RiftHeader'
38 import CanvasPanel
from './CanvasPanel'
39 import CatalogPanel
from './CatalogPanel'
40 import DetailsPanel
from './DetailsPanel'
41 import ModalOverlay
from './ModalOverlay'
42 import ComposerAppToolbar
from './ComposerAppToolbar'
43 import PanelResizeAction
from '../actions/PanelResizeAction'
44 import ComposerAppActions
from '../actions/ComposerAppActions'
45 import ComposerAppStore
from '../stores/ComposerAppStore'
46 import CatalogDataStore
from '../stores/CatalogDataStore'
47 import TooltipManager
from '../libraries/TooltipManager'
48 import CatalogItemsActions
from '../actions/CatalogItemsActions'
49 import CommonUtils
from 'utils/utils.js'
50 import FileManagerActions
from './filemanager/FileManagerActions';
51 import 'normalize.css'
52 import '../styles/AppRoot.scss'
53 import 'style/layout.scss'
56 const resizeManager
= new ResizableManager(window
);
58 const clearLocalStorage
= utils
.getSearchParams(window
.location
).hasOwnProperty('clearLocalStorage');
60 const preventDefault
= e
=> e
.preventDefault();
61 const clearDragState
= () => ComposerAppActions
.setDragState(null);
64 const ComposerApp
= React
.createClass({
65 mixins
: [PureRenderMixin
],
67 return ComposerAppStore
.getState();
72 componentWillMount() {
73 if (clearLocalStorage
) {
74 window
.localStorage
.clear();
77 FileManagerActions
.openFileManagerSockets();
79 this.state
.isLoading
= CatalogDataStore
.getState().isLoading
;
80 ComposerAppStore
.listen(this.onChange
);
81 CatalogDataStore
.listen(this.onCatalogDataChanged
);
82 window
.addEventListener('resize', this.resize
);
83 window
.onbeforeunload
= this.onBeforeUnload
;
84 // prevent browser from downloading any drop outside of our specific drop zones
85 window
.addEventListener('dragover', preventDefault
);
86 window
.addEventListener('drop', preventDefault
);
87 // ensure drags initiated in the app clear the state on drop
88 window
.addEventListener('drop', clearDragState
);
89 DeletionManager
.addEventListeners();
91 componentWillUnmount() {
92 window
.removeEventListener('resize', this.resize
);
93 window
.removeEventListener('dragover', preventDefault
);
94 window
.removeEventListener('drop', preventDefault
);
95 window
.removeEventListener('drop', clearDragState
);
96 FileManagerActions
.closeFileManagerSockets();
97 // resizeManager automatically registered its event handlers
98 resizeManager
.removeAllEventListeners();
99 ComposerAppStore
.unlisten(this.onChange
);
100 CatalogDataStore
.unlisten(this.onCatalogDataChanged
);
101 DeletionManager
.removeEventListeners();
102 TooltipManager
.removeEventListeners();
104 componentDidMount() {
105 resizeManager
.addAllEventListeners();
106 const snapshot
= window
.localStorage
.getItem('composer');
108 alt
.bootstrap(snapshot
);
110 document
.body
.addEventListener('keydown', (event
) => {
111 // prevent details editor form from blowing up the app
112 const ENTER_KEY
= 13;
113 if (event
.which
=== ENTER_KEY
) {
114 event
.preventDefault();
118 const appRootElement
= ReactDOM
.findDOMNode(this.refs
.appRoot
);
119 TooltipManager
.addEventListeners(appRootElement
);
120 SelectionManager
.onClearSelection
= () => {
121 if (this.state
.item
) {
122 CatalogItemsActions
.catalogItemMetaDataChanged
.defer(this.state
.item
);
126 componentDidUpdate() {
127 if (this.state
.fullScreenMode
) {
128 document
.body
.classList
.add('-is-full-screen');
130 document
.body
.classList
.remove('-is-full-screen');
132 SelectionManager
.refreshOutline();
135 PanelResizeAction
.resize(e
);
140 DescriptorModelMetaFactory
.init().then(function(){
150 if(this.state
.hasModel
) {
152 function onClickUpdateSelection(event
) {
153 if (event
.defaultPrevented
) {
156 const element
= SelectionManager
.getClosestElementWithUID(event
.target
);
158 SelectionManager
.select(element
);
159 SelectionManager
.refreshOutline();
160 event
.preventDefault();
162 SelectionManager
.clearSelectionAndRemoveOutline();
167 let AppHeader
= (<div className
="AppHeader">
171 const classNames
= ClassNames('ComposerApp');
172 const isNew
= self
.state
.item
&& self
.state
.item
.uiState
.isNew
;
173 const hasItem
= self
.state
.item
&& self
.state
.item
.uiState
;
174 const isModified
= self
.state
.item
&& self
.state
.item
.uiState
.modified
;
175 const isEditingNSD
= self
.state
.item
&& self
.state
.item
.uiState
&& /nsd/.test(self
.state
.item
.uiState
.type
);
176 const isEditingVNFD
= self
.state
.item
&& self
.state
.item
.uiState
&& /vnfd/.test(self
.state
.item
.uiState
.type
);
177 const containers
= self
.state
.containers
;
178 const canvasTitle
= containers
.length
? containers
[0].model
.name
: '';
179 const hasNoCatalogs
= CatalogDataStore
.getState().catalogs
.length
=== 0;
180 const isLoading
= self
.state
.isLoading
;
182 //Bridge element for Crouton fix. Should eventually put Composer on same flux context
183 const Bridge
= this.state
.ComponentBridgeElement
;
186 <div ref
="appRoot" id
="RIFT_wareLaunchpadComposerAppRoot" className
="AppRoot" onClick
={onClickUpdateSelection
}>
188 <i className
="corner-accent top left" />
189 <i className
="corner-accent top right" />
190 <i className
="corner-accent bottom left" />
191 <i className
="corner-accent bottom right" />
193 <div className
="AppBody">
194 <div className
={classNames
}>
195 <CatalogPanel layout
={self
.state
.layout
}
196 isLoading
={isLoading
}
197 hasNoCatalogs
={hasNoCatalogs
}
198 filterByType
={self
.state
.filterCatalogByTypeValue
} />
199 <CanvasPanel layout
={self
.state
.layout
}
200 hasNoCatalogs
={hasNoCatalogs
}
201 showMore
={self
.state
.showMore
}
202 containers
={containers
}
204 zoom
={self
.state
.zoom
}
205 panelTabShown
={self
.state
.panelTabShown
}
206 files
={self
.state
.files
}
207 filesState
={self
.state
.filesState
}
208 item
={self
.state
.item
}
209 type
={self
.state
.filterCatalogByTypeValue
}
212 (self
.state
.panelTabShown
== 'descriptor') ?
213 <DetailsPanel layout
={self
.state
.layout
}
214 hasNoCatalogs
={hasNoCatalogs
}
215 showMore
={self
.state
.showMore
}
216 containers
={containers
}
217 showJSONViewer
={self
.state
.showJSONViewer
} />
221 <ComposerAppToolbar layout
={self
.state
.layout
}
222 showMore
={self
.state
.showMore
}
223 isEditingNSD
={isEditingNSD
}
224 isEditingVNFD
={isEditingVNFD
}
225 isModified
={isModified
}
228 onClick
={event
=> event
.stopPropagation()}
229 panelTabShown
={self
.state
.panelTabShown
}/>
241 this.setState(state
);
243 onCatalogDataChanged(catalogDataState
) {
244 const catalogs
= catalogDataState
.catalogs
;
245 const unsavedChanges
= catalogs
.reduce((result
, catalog
) => {
249 return catalog
.descriptors
.reduce((result
, descriptor
) => {
253 return descriptor
.uiState
.modified
;
257 unsavedChanges
: unsavedChanges
,
258 isLoading
: catalogDataState
.isLoading
262 // https://trello.com/c/c8v321Xx/160-prompt-user-to-save-changes
263 //const snapshot = alt.takeSnapshot();
264 //window.localStorage.setItem('composer', snapshot);
265 if (this.state
.unsavedChanges
) {
266 return 'You have unsaved changes. If you do not onboard (or update) your changes they will be lost.';
272 export default ComposerApp
;