X-Git-Url: https://osm.etsi.org/gitweb/?p=osm%2FUI.git;a=blobdiff_plain;f=skyquake%2Fplugins%2Fcomposer%2Fsrc%2Fsrc%2Fcomponents%2FComposerApp.js;h=d7a40d33523a0fcbb83ceb4f7ff148b99fee88e8;hp=861c38be03d6fa01d809d7af5a1102c4743250e2;hb=28412d0042632687d765d239cbb3ff0523a131b9;hpb=f2dc2462571800e62cba969964de621dca09299c diff --git a/skyquake/plugins/composer/src/src/components/ComposerApp.js b/skyquake/plugins/composer/src/src/components/ComposerApp.js index 861c38be0..d7a40d335 100644 --- a/skyquake/plugins/composer/src/src/components/ComposerApp.js +++ b/skyquake/plugins/composer/src/src/components/ComposerApp.js @@ -48,6 +48,11 @@ import TooltipManager from '../libraries/TooltipManager' import CatalogItemsActions from '../actions/CatalogItemsActions' import CommonUtils from 'utils/utils.js' import FileManagerActions from './filemanager/FileManagerActions'; +import { SkyquakeRBAC, isRBACValid } from 'widgets/skyquake_rbac/skyquakeRBAC.jsx'; +import ROLES from 'utils/roleConstants.js'; +import _isEmpty from 'lodash/isEmpty'; +import _isEqual from 'lodash/isEqual'; + import 'normalize.css' import '../styles/AppRoot.scss' import 'style/layout.scss' @@ -60,214 +65,221 @@ const clearLocalStorage = utils.getSearchParams(window.location).hasOwnProperty( const preventDefault = e => e.preventDefault(); const clearDragState = () => ComposerAppActions.setDragState(null); +const PROJECT_ROLES = ROLES.PROJECT; +const PLATFORM = ROLES.PLATFORM; + +const CATALOG_POLLING_INTERVAL = 2000; + const ComposerApp = React.createClass({ - mixins: [PureRenderMixin], - getInitialState() { - return ComposerAppStore.getState(); - }, - getDefaultProps() { - return {}; - }, - componentWillMount() { - if (clearLocalStorage) { - window.localStorage.clear(); - } - if(this.item) { + getInitialState() { + return ComposerAppStore.getState(); + }, + getDefaultProps() { + return {}; + }, + contextTypes: { + router: React.PropTypes.object, + userProfile: React.PropTypes.object + }, + componentWillUpdate(nextProps, nextState, nextContext) { + if (!_isEmpty(nextContext.userProfile)) { + CatalogDataStore.setUserProfile(nextContext.userProfile); + } + }, + shouldComponentUpdate: function (nextProps, nextState, nextContext) { + if (!this.userProfile && !_isEmpty(nextContext.userProfile)) { + this.userProfile = nextContext.userProfile; + CatalogDataStore.setUserProfile(nextContext.userProfile); + return true; + } + return !_isEqual(this.props, nextProps) || + !_isEqual(this.state, nextState); + }, + componentWillMount() { + if (clearLocalStorage) { + window.localStorage.clear(); + } + if (this.item) { FileManagerActions.openFileManagerSockets(); } - this.state.isLoading = CatalogDataStore.getState().isLoading; - ComposerAppStore.listen(this.onChange); - CatalogDataStore.listen(this.onCatalogDataChanged); - window.addEventListener('resize', this.resize); - window.onbeforeunload = this.onBeforeUnload; - // prevent browser from downloading any drop outside of our specific drop zones - window.addEventListener('dragover', preventDefault); - window.addEventListener('drop', preventDefault); - // ensure drags initiated in the app clear the state on drop - window.addEventListener('drop', clearDragState); - DeletionManager.addEventListeners(); - }, - componentWillUnmount() { - window.removeEventListener('resize', this.resize); - window.removeEventListener('dragover', preventDefault); - window.removeEventListener('drop', preventDefault); - window.removeEventListener('drop', clearDragState); + this.state.isLoading = CatalogDataStore.getState().isLoading; + ComposerAppStore.listen(this.onChange); + CatalogDataStore.listen(this.onCatalogDataChanged); + window.addEventListener('resize', this.resize); + // prevent browser from downloading any drop outside of our specific drop zones + window.addEventListener('dragover', preventDefault); + window.addEventListener('drop', preventDefault); + // ensure drags initiated in the app clear the state on drop + window.addEventListener('drop', clearDragState); + DeletionManager.addEventListeners(); + }, + componentWillUnmount() { + window.removeEventListener('resize', this.resize); + window.removeEventListener('dragover', preventDefault); + window.removeEventListener('drop', preventDefault); + window.removeEventListener('drop', clearDragState); FileManagerActions.closeFileManagerSockets(); - // resizeManager automatically registered its event handlers - resizeManager.removeAllEventListeners(); - ComposerAppStore.unlisten(this.onChange); - CatalogDataStore.unlisten(this.onCatalogDataChanged); - DeletionManager.removeEventListeners(); - TooltipManager.removeEventListeners(); - }, - componentDidMount() { - resizeManager.addAllEventListeners(); - const snapshot = window.localStorage.getItem('composer'); - if (snapshot) { - alt.bootstrap(snapshot); - } - document.body.addEventListener('keydown', (event) => { - // prevent details editor form from blowing up the app - const ENTER_KEY = 13; - if (event.which === ENTER_KEY) { - event.preventDefault(); - return false; - } - }); - const appRootElement = ReactDOM.findDOMNode(this.refs.appRoot); - TooltipManager.addEventListeners(appRootElement); - SelectionManager.onClearSelection = () => { - if (this.state.item) { - CatalogItemsActions.catalogItemMetaDataChanged.defer(this.state.item); - } - }; - }, - componentDidUpdate() { - if (this.state.fullScreenMode) { - document.body.classList.add('-is-full-screen'); - } else { - document.body.classList.remove('-is-full-screen'); - } - SelectionManager.refreshOutline(); - }, - resize(e) { - PanelResizeAction.resize(e); - }, - getModel() { - let html; - let self = this; - DescriptorModelMetaFactory.init().then(function(){ - - self.setState({ - hasModel: true - }) - }); - }, - render() { - let html = null; - let self = this; - if(this.state.hasModel) { + // resizeManager automatically registered its event handlers + resizeManager.removeAllEventListeners(); + ComposerAppStore.unlisten(this.onChange); + CatalogDataStore.unlisten(this.onCatalogDataChanged); + DeletionManager.removeEventListeners(); + TooltipManager.removeEventListeners(); + if (this.catalogMonitorId) { + clearTimeout(this.catalogMonitorId); + } + }, + componentDidMount() { + resizeManager.addAllEventListeners(); + const snapshot = window.localStorage.getItem('composer'); + if (snapshot) { + alt.bootstrap(snapshot); + } + document.body.addEventListener('keydown', (event) => { + // prevent details editor form from blowing up the app + const ENTER_KEY = 13; + if (event.which === ENTER_KEY) { + event.preventDefault(); + return false; + } + }); + const loadCatalogs = () => { + CatalogDataStore.loadCatalogs(); + if (CATALOG_POLLING_INTERVAL) { + this.catalogMonitorId = setTimeout(loadCatalogs, CATALOG_POLLING_INTERVAL); + } + }; + loadCatalogs(); + DescriptorModelMetaFactory.init().then(() => this.setState({ hasModel: true })); + }, + componentDidUpdate() { + if (this.state.fullScreenMode) { + document.body.classList.add('-is-full-screen'); + } else { + document.body.classList.remove('-is-full-screen'); + } + SelectionManager.refreshOutline(); + }, + resize(e) { + PanelResizeAction.resize(e); + }, + render() { + let html = null; + let self = this; + const User = this.userProfile || {}; + const rbacDisabled = !isRBACValid(User, [PROJECT_ROLES.PROJECT_ADMIN, PROJECT_ROLES.CATALOG_ADMIN]); + if (this.state.hasModel) { - function onClickUpdateSelection(event) { - if (event.defaultPrevented) { - return - } - const element = SelectionManager.getClosestElementWithUID(event.target); - if (element) { - SelectionManager.select(element); - SelectionManager.refreshOutline(); - event.preventDefault(); - } else { - SelectionManager.clearSelectionAndRemoveOutline(); - } - } + function onClickUpdateSelection(event) { + if (event.defaultPrevented) { + return + } + const element = SelectionManager.getClosestElementWithUID(event.target); + if (element) { + SelectionManager.select(element); + SelectionManager.refreshOutline(); + event.preventDefault(); + } else { + if (event.target.offsetParent && !event.target.offsetParent.classList.contains("tray-body")) { + SelectionManager.clearSelectionAndRemoveOutline(); + } + } + } + let cpNumber = 0; + let AppHeader = (
+ +
); + // AppHeader = null; + const classNames = ClassNames('ComposerApp'); + const isNew = self.state.item && self.state.item.uiState.isNew; + const hasItem = self.state.item && self.state.item.uiState; + const isModified = self.state.item && self.state.item.uiState.modified; + const isEditingNSD = self.state.item && self.state.item.uiState && /nsd/.test(self.state.item.uiState.type); + const isEditingVNFD = self.state.item && self.state.item.uiState && /vnfd/.test(self.state.item.uiState.type); + const containers = [self.state.item].reduce(DescriptorModelFactory.buildCatalogItemFactory(CatalogDataStore.getState().catalogs), []); - let AppHeader = (
- -
); - // AppHeader = null; - const classNames = ClassNames('ComposerApp'); - const isNew = self.state.item && self.state.item.uiState.isNew; - const hasItem = self.state.item && self.state.item.uiState; - const isModified = self.state.item && self.state.item.uiState.modified; - const isEditingNSD = self.state.item && self.state.item.uiState && /nsd/.test(self.state.item.uiState.type); - const isEditingVNFD = self.state.item && self.state.item.uiState && /vnfd/.test(self.state.item.uiState.type); - const containers = self.state.containers; - const canvasTitle = containers.length ? containers[0].model.name : ''; - const hasNoCatalogs = CatalogDataStore.getState().catalogs.length === 0; - const isLoading = self.state.isLoading; + containers.filter(d => DescriptorModelFactory.isConnectionPoint(d)).forEach(d => { + d.cpNumber = ++cpNumber; + containers.filter(d => DescriptorModelFactory.isVnfdConnectionPointRef(d)).filter(ref => ref.key === d.key).forEach(ref => ref.cpNumber = d.cpNumber); + }); + const canvasTitle = containers.length ? containers[0].model.name : ''; + const hasNoCatalogs = CatalogDataStore.getState().catalogs.length === 0; + const isLoading = self.state.isLoading; //Bridge element for Crouton fix. Should eventually put Composer on same flux context const Bridge = this.state.ComponentBridgeElement; - html = ( -
+ html = ( +
TooltipManager.addEventListeners(element)} id="RIFT_wareLaunchpadComposerAppRoot" className="AppRoot" onClick={onClickUpdateSelection}> - - - - - {AppHeader} -
-
- - - { - (self.state.panelTabShown == 'descriptor') ? - - : null - } - - event.stopPropagation()} - panelTabShown={self.state.panelTabShown}/> -
-
- -
- ); - } else { - this.getModel(); - } - return html; - }, - onChange(state) { - this.setState(state); - }, - onCatalogDataChanged(catalogDataState) { - const catalogs = catalogDataState.catalogs; - const unsavedChanges = catalogs.reduce((result, catalog) => { - if (result) { - return result; - } - return catalog.descriptors.reduce((result, descriptor) => { - if (result) { - return result; - } - return descriptor.uiState.modified; - }, false); - }, false); - this.setState({ - unsavedChanges: unsavedChanges, - isLoading: catalogDataState.isLoading - }); - }, - onBeforeUnload() { - // https://trello.com/c/c8v321Xx/160-prompt-user-to-save-changes - //const snapshot = alt.takeSnapshot(); - //window.localStorage.setItem('composer', snapshot); - if (this.state.unsavedChanges) { - return 'You have unsaved changes. If you do not onboard (or update) your changes they will be lost.'; - } - } + + + + + {AppHeader} +
+
+ + + { + (self.state.panelTabShown == 'descriptor') ? + + : null + } + event.stopPropagation()} + panelTabShown={self.state.panelTabShown} /> +
+
+ +
+ ); + } + return html; + }, + onChange(state) { + this.setState(state); + }, + onCatalogDataChanged(catalogDataState) { + this.setState({ + isLoading: catalogDataState.isLoading + }); + } }); + export default ComposerApp;