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 React
from 'react'
23 import ReactDOM
from 'react-dom'
24 import messages
from './messages'
25 import ClassNames
from 'classnames'
26 import UploadDropZone
from '../libraries/CatalogPackageManagerUploadDropZone'
27 import PureRenderMixin
from 'react-addons-pure-render-mixin'
28 import DropTarget
from './DropTarget'
29 import DropZonePanel
from './DropZonePanel'
30 import CatalogItems
from './CatalogItems'
31 import CatalogFilter
from './CatalogFilter'
32 import CatalogPanelTray
from './CatalogPanelTray'
33 import CatalogPanelToolbar
from './CatalogPanelToolbar'
34 import CatalogPackageManager
from './CatalogPackageManager'
35 import CatalogItemsActions
from '../actions/CatalogItemsActions'
36 import CatalogPanelTrayActions
from '../actions/CatalogPanelTrayActions'
37 import ComposerAppActions
from '../actions/ComposerAppActions'
38 import ComposerAppStore
from '../stores/ComposerAppStore'
39 import CatalogPanelStore
from '../stores/CatalogPanelStore'
40 import LoadingIndicator
from './LoadingIndicator'
41 import SelectionManager
from '../libraries/SelectionManager'
42 import { isRBACValid
} from 'widgets/skyquake_rbac/skyquakeRBAC';
43 import ROLES
from 'utils/roleConstants.js';
45 import '../styles/CatalogPanel.scss'
47 const createDropZone = function (action
, clickable
, dropTarget
) {
48 const dropZone
= new UploadDropZone(ReactDOM
.findDOMNode(dropTarget
), [clickable
], action
);
49 dropZone
.on('dragover', this.onDragOver
);
50 dropZone
.on('dragend', this.onDragEnd
);
51 dropZone
.on('addedfile', this.onFileAdded
);
55 const uiTransientState
= {
58 isDraggingFiles
: false,
62 const CatalogPanel
= React
.createClass({
63 mixins
: [PureRenderMixin
],
65 return CatalogPanelStore
.getState();
69 componentWillMount() {
72 CatalogPanelStore
.listen(this.onChange
);
73 document
.body
.addEventListener('dragover', this.onDragOver
);
74 document
.body
.addEventListener('dragend', this.onDragEnd
);
75 window
.addEventListener('dragend', this.onDragEnd
);
77 componentDidUpdate() {
79 componentWillUnmount() {
80 CatalogPanelStore
.unlisten(this.onChange
);
81 document
.body
.removeEventListener('dragover', this.onDragOver
);
82 document
.body
.removeEventListener('dragend', this.onDragEnd
);
83 window
.removeEventListener('dragend', this.onDragEnd
);
86 userProfile
: React
.PropTypes
.object
89 const User
= this.context
.userProfile
|| {};
90 const isModifiableByUser
= isRBACValid(User
, [ROLES
.PROJECT
.PROJECT_ADMIN
, ROLES
.PROJECT
.CATALOG_ADMIN
]);
92 const onDropCatalogItem
= e
=> {
94 clearTimeout(uiTransientState
.timeoutId
);
95 uiTransientState
.isDragging
= false;
96 uiTransientState
.isDrop
= true;
97 const item
= JSON
.parse(e
.dataTransfer
.getData('text')).item
;
98 CatalogItemsActions
.exportSelectedCatalogItems(item
);
99 CatalogPanelTrayActions
.open();
102 const onDropUpdatePackage
= e
=> {
104 clearTimeout(uiTransientState
.timeoutId
);
105 uiTransientState
.isDragging
= false;
106 uiTransientState
.isDrop
= true;
107 CatalogPanelTrayActions
.open();
110 const onDropOnboardPackage
= e
=> {
112 clearTimeout(uiTransientState
.timeoutId
);
113 uiTransientState
.isDragging
= false;
114 uiTransientState
.isDrop
= true;
115 CatalogPanelTrayActions
.open();
118 const isDraggingItem
= uiTransientState
.isDragging
&& !uiTransientState
.isDraggingFiles
;
119 const isDraggingFiles
= uiTransientState
.isDragging
&& uiTransientState
.isDraggingFiles
;
120 const updateDropZone
= createDropZone
.bind(this, UploadDropZone
.ACTIONS
.update
, '.action-update-catalog-package');
121 const onboardDropZone
= createDropZone
.bind(this, UploadDropZone
.ACTIONS
.onboard
, '.action-onboard-catalog-package');
122 const className
= ClassNames('CatalogPanel', { '-is-tray-open': this.state
.isTrayOpen
});
123 const hasNoCatalogs
= this.props
.hasNoCatalogs
;
124 const isLoading
= this.props
.isLoading
;
125 const packageManagerPanel
= (
126 <CatalogPanelTray show
={this.state
.isTrayOpen
}>
127 <DropZonePanel show
={isDraggingItem
} title
="Drop catalog item to export.">
128 <DropTarget className
="action-export-catalog-items" onDrop
={onDropCatalogItem
}>
129 <span
>Export catalog item
.</span
>
132 <DropZonePanel show
={isDraggingFiles
}>
133 <DropTarget className
="action-onboard-catalog-package" dropZone
={onboardDropZone
} onDrop
={onDropOnboardPackage
}>
134 <span
>On
-board
new catalog
package.</span
>
136 <DropTarget className
="action-update-catalog-package" dropZone
={updateDropZone
} onDrop
={onDropUpdatePackage
}>
137 <span
>Update existing catalog
package.</span
>
140 <CatalogPackageManager
/>
144 <div className
={className
} data
-resizable
="right" data
-resizable
-handle
-offset
="0 6" style
={{ width
: this.props
.layout
.left
}}>
145 <CatalogPanelToolbar rbacDisabled
={this.props
.rbacDisabled
} />
146 <div className
="CatalogPanelBody">
150 <div className
="LoaderWrapper">
156 return messages
.catalogWelcome(isModifiableByUser
);
160 <CatalogFilter filterByType
={this.props
.filterByType
} />
161 <CatalogItems filterByType
={this.props
.filterByType
} />
166 {isModifiableByUser
? packageManagerPanel
: null}
172 this.setState(state
);
175 // NOTE do not call preventDefault here - see DropTarget
176 if (!uiTransientState
.isDragging
) {
177 uiTransientState
.isDrop
= false;
178 uiTransientState
.isDragging
= true;
179 uiTransientState
.wasTrayOpen
= this.state
.isTrayOpen
;
180 uiTransientState
.isDraggingFiles
= _includes(e
.dataTransfer
.types
, 'Files');
181 const dragState
= ComposerAppStore
.getState().drag
|| {};
182 if (uiTransientState
.isDraggingFiles
|| (dragState
.type
=== 'catalog-item')) {
183 CatalogPanelTrayActions
.open();
186 e
.dataTransfer
.dropEffect
= 'none';
187 // the drag-end event does not fire on drag events that originate
188 // outside of the browser, e.g. dragging files from desktop, so
189 // we use this debounced callback to simulate a drag-end event
190 clearTimeout(uiTransientState
.timeoutId
);
191 uiTransientState
.timeoutId
= setTimeout(() => {
196 clearTimeout(uiTransientState
.timeoutId
);
197 if (uiTransientState
.isDragging
) {
198 uiTransientState
.isDragging
= false;
199 if (uiTransientState
.isDrop
|| uiTransientState
.wasTrayOpen
) {
200 CatalogPanelTrayActions
.open();
202 CatalogPanelTrayActions
.close();
207 CatalogPanelTrayActions
.open();
211 export default CatalogPanel
;