X-Git-Url: https://osm.etsi.org/gitweb/?p=osm%2FUI.git;a=blobdiff_plain;f=skyquake%2Fplugins%2Fcomposer%2Fsrc%2Fsrc%2Fstores%2FComposerAppStore.js;h=c677a44a699ca88952bff81d01bf60f34bc26c9a;hp=67e8e8d3577f74c6b20c2bbc462940c3023d34b2;hb=efb2d7e8df66f52c5e26c575197fc92da2b3e99a;hpb=e29efc315df33d546237e270470916e26df391d6 diff --git a/skyquake/plugins/composer/src/src/stores/ComposerAppStore.js b/skyquake/plugins/composer/src/src/stores/ComposerAppStore.js index 67e8e8d35..c677a44a6 100644 --- a/skyquake/plugins/composer/src/src/stores/ComposerAppStore.js +++ b/skyquake/plugins/composer/src/src/stores/ComposerAppStore.js @@ -1,6 +1,6 @@ /* - * + * * Copyright 2016 RIFT.IO Inc * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -18,7 +18,14 @@ */ 'use strict'; -import _ from 'lodash' +import _isNumber from 'lodash/isNumber' +import _cloneDeep from 'lodash/cloneDeep' +import _isEmpty from 'lodash/isEmpty' +import _mergeWith from 'lodash/mergeWith' +import _uniqBy from 'lodash/uniqBy' +import _isEqual from 'lodash/isEqual' +import _findIndex from 'lodash/findIndex' +import _remove from 'lodash/remove' import d3 from 'd3' import alt from '../alt' import UID from '../libraries/UniqueId' @@ -33,10 +40,30 @@ import SelectionManager from '../libraries/SelectionManager' import CatalogDataStore from '../stores/CatalogDataStore' import isFullScreen from '../libraries/isFullScreen' +import FileManagerSource from '../components/filemanager/FileManagerSource'; +import FileManagerActions from '../components/filemanager/FileManagerActions'; + +import React from 'react'; + +//Hack for crouton fix. Should eventually put composer in skyquake alt context +import SkyquakeComponent from 'widgets/skyquake_container/skyquakeComponent.jsx'; +let NotificationError = null; + +import utils from '../libraries/utils'; + +class ComponentBridge extends React.Component { + constructor(props) { + super(props); + NotificationError = this.props.flux.actions.global.showNotification; + } + render(){ + return + } +} const getDefault = (name, defaultValue) => { const val = window.localStorage.getItem('defaults-' + name); if (val) { - if (_.isNumber(val)) { + if (_isNumber(val)) { if (val < 0) { return setDefault(name, 0); } @@ -79,6 +106,10 @@ const uiTransientState = {}; class ComposerAppStore { constructor() { + //Bridge for crouton fix + this.ComponentBridgeElement = SkyquakeComponent(ComponentBridge); + + this.exportAsync(FileManagerSource) // the catalog item currently being edited in the composer this.item = null; // the left and right sides of the canvas area @@ -99,6 +130,14 @@ class ComposerAppStore { this.showClassifiers = {}; this.editPathsMode = false; this.fullScreenMode = false; + this.panelTabShown = 'descriptor'; + //File manager values + this.files = false; + this.filesState = {}; + this.downloadJobs = {}; + this.containers = []; + this.newPathName = ''; + //End File manager values this.bindListeners({ onResize: PanelResizeAction.RESIZE, editCatalogItem: CatalogItemsActions.EDIT_CATALOG_ITEM, @@ -124,8 +163,26 @@ class ComposerAppStore { openCanvasPanelTray: CanvasPanelTrayActions.OPEN, closeCanvasPanelTray: CanvasPanelTrayActions.CLOSE, enterFullScreenMode: ComposerAppActions.ENTER_FULL_SCREEN_MODE, - exitFullScreenMode: ComposerAppActions.EXIT_FULL_SCREEN_MODE + exitFullScreenMode: ComposerAppActions.EXIT_FULL_SCREEN_MODE, + showAssets: ComposerAppActions.showAssets, + showDescriptor: ComposerAppActions.showDescriptor, + getFilelistSuccess: FileManagerActions.getFilelistSuccess, + updateFileLocationInput: FileManagerActions.updateFileLocationInput, + sendDownloadFileRequst: FileManagerActions.sendDownloadFileRequst, + addFileSuccess: FileManagerActions.addFileSuccess, + deletePackageFile: FileManagerActions.deletePackageFile, + deleteFileSuccess: FileManagerActions.deleteFileSuccess, + deleteFileError: FileManagerActions.deleteFileError, + closeFileManagerSockets: FileManagerActions.closeFileManagerSockets, + openFileManagerSockets: FileManagerActions.openFileManagerSockets, + openDownloadMonitoringSocketSuccess: FileManagerActions.openDownloadMonitoringSocketSuccess, + getFilelistSocketSuccess: FileManagerActions.getFilelistSocketSuccess, + newPathNameUpdated: FileManagerActions.newPathNameUpdated, + createDirectory: FileManagerActions.createDirectory }); + this.exportPublicMethods({ + closeFileManagerSockets: this.closeFileManagerSockets.bind(this) + }) } onResize(e) { @@ -159,13 +216,24 @@ class ComposerAppStore { } updateItem(item) { + const self = this; + let containers = []; + let cpNumber = 0; if(!document.body.classList.contains('resizing')) { - this.setState({item: _.cloneDeep(item)}); + containers = [item].reduce(DescriptorModelFactory.buildCatalogItemFactory(CatalogDataStore.getState().catalogs), []); + + 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); + }); + this.setState({containers: containers, item: _cloneDeep(item)}); } SelectionManager.refreshOutline(); } editCatalogItem(item) { + let self = this; + self.closeFileManagerSockets(); if (item && item.uiState) { item.uiState.isOpenForEdit = true; if (item.uiState.type !== 'nsd') { @@ -174,8 +242,10 @@ class ComposerAppStore { } SelectionManager.select(item); this.updateItem(item); + if (item) { + this.openFileManagerSockets(item); + } } - catalogItemMetaDataChanged(item) { this.updateItem(item); } @@ -193,7 +263,8 @@ class ComposerAppStore { } showError(data) { - this.setState({message: data.errorMessage, messageType: 'error'}); + NotificationError.defer({msg: data.errorMessage, type: 'error'}) + // this.setState({message: data.errorMessage, messageType: 'error'}); } clearError() { @@ -206,7 +277,7 @@ class ComposerAppStore { applyDefaultLayout() { if (this.item && this.item.uiState && this.item.uiState.containerPositionMap) { - if (!_.isEmpty(this.item.uiState.containerPositionMap)) { + if (!_isEmpty(this.item.uiState.containerPositionMap)) { this.item.uiState.containerPositionMap = {}; CatalogItemsActions.catalogItemMetaDataChanged.defer(this.item); } @@ -349,7 +420,7 @@ class ComposerAppStore { if (isFullScreen()) { const layout = comp.layout; - const restoreLayout = _.cloneDeep(layout); + const restoreLayout = _cloneDeep(layout); uiTransientState.restoreLayout = restoreLayout; layout.left = 0; layout.right = 0; @@ -396,7 +467,249 @@ class ComposerAppStore { this.setState({fullScreenMode: false}); } + showAssets() { + this.setState({ + panelTabShown: 'assets' + }); + } + showDescriptor() { + this.setState({ + panelTabShown: 'descriptor' + }); + } + + //File Manager methods + getFilelistSuccess(data) { + let self = this; + let filesState = null; + if (self.fileMonitoringSocketID) { + let newState = {}; + if(data.hasOwnProperty('contents')) { + filesState = addInputState( _cloneDeep(this.filesState),data); + let normalizedData = normalizeTree(data); + newState = { + files: { + data: _mergeWith(normalizedData.data, self.files.data, function(obj, src) { + return _uniqBy(obj? obj.concat(src) : src, 'name'); + }), + id: normalizedData.id + }, + filesState: filesState + } + } else { + newState = { + files: false + } + } + if(!_isEqual(newState.files, this.files) || ! _isEqual(newState.fileState, this.fileState)) { + this.setState(newState); + } + + } + function normalizeTree(data) { + let f = { + id:[], + data:{} + }; + data.contents.map(getContents); + function getContents(d) { + if(d.hasOwnProperty('contents')) { + let contents = []; + d.contents.map(function(c,i) { + if (!c.hasOwnProperty('contents')) { + contents.push(c); + } else { + getContents(c); + } + }) + f.id.push(d.name); + f.data[d.name] = contents; + } + } + return f; + } + function addInputState(obj, d) { + d.newFile = ''; + if(d.hasOwnProperty('contents')) { + d.contents.map(addInputState.bind(null, obj)) + } + if(!obj[d.name]) { + obj[d.name] = ''; + } + return obj; + } + } + sendDownloadFileRequst(data) { + let id = data.id || this.item.id; + let type = data.type || this.item.uiState.type; + let path = data.path; + let url = data.url; + this.getInstance().addFile(id, type, path, url, data.refresh); + } + updateFileLocationInput = (data) => { + let name = data.name; + let value = data.value; + var filesState = _cloneDeep(this.filesState); + filesState[name] = value; + this.setState({ + filesState: filesState + }); + } + addFileSuccess = (data) => { + if(!data.refresh) { + let path = data.path; + let fileName = data.fileName; + let files = _cloneDeep(this.files); + let loadingIndex = files.data[path].push({ + status: 'DOWNLOADING', + name: path + '/' + fileName + }) - 1; + this.setState({files: files}); + } + + } + startWatchingJob = () => { + let ws = window.multiplexer.channel(this.jobSocketId); + this.setState({ + jobSocket:null + }) + } + openDownloadMonitoringSocketSuccess = (id) => { + let self = this; + let ws = window.multiplexer.channel(id); + let downloadJobs = _cloneDeep(self.downloadJobs); + let newFiles = false; + ws.onmessage = (socket) => { + if (self.files && self.files.length > 0) { + let jobs = []; + try { + jobs = JSON.parse(socket.data); + } catch(e) {} + newFiles = _cloneDeep(self.files); + jobs.map(function(j) { + //check if not in completed state + let fullPath = j['package-path']; + let path = fullPath.split('/'); + let fileName = path.pop(); + path = path.join('/'); + let index = _findIndex(self.files.data[path], function(o){ + return fullPath == o.name + }); + if((index > -1) && newFiles.data[path][index]) { + newFiles.data[path][index].status = j.status + } else { + if(j.status.toUpperCase() == 'LOADING...' || j.status.toUpperCase() == 'IN_PROGRESS') { + newFiles.data[path].push({ + status: j.status, + name: fullPath + }) + } else { + // if () + } + } + }) + self.setState({ + files: newFiles + }) + // console.log(JSON.parse(socket.data)); + } + } + this.setState({ + jobSocketId: id, + jobSocket: ws + }) + + } + getFilelistSocketSuccess = (id) => { + let self = this; + let ws = window.multiplexer.channel(id); + ws.onmessage = (socket) => { + if (self.fileMonitoringSocketID) { + let data = []; + try { + data = JSON.parse(socket.data); + } catch(e) {} + self.getFilelistSuccess(data) + } + } + + this.setState({ + fileMonitoringSocketID: id, + fileMonitoringSocket: ws + }) + + } + closeFileManagerSockets() { + this.fileMonitoringSocketID = null; + this.setState({ + jobSocketId : null, + fileMonitoringSocketID : null + // jobSocket : null, + // fileMonitoringSocket : null, + }); + this.jobSocket && this.jobSocket.close(); + this.fileMonitoringSocket && this.fileMonitoringSocket.close(); + console.log('closing'); + } + openFileManagerSockets(i) { + let self = this; + let item = i || self.item; + // this.closeFileManagerSockets(); + this.getInstance().openFileMonitoringSocket(item.id, item.uiState.type).then(function() { + // // self.getInstance().openDownloadMonitoringSocket(item.id); + }); + this.getInstance().openDownloadMonitoringSocket(item.id); + } + endWatchingJob(id) { + + } + deletePackageFile(name) { + let id = this.item.id; + let type = this.item.uiState.type; + this.getInstance().deleteFile(id, type, name); + } + deleteFileSuccess = (data) => { + let path = data.path.split('/') + let files = _cloneDeep(this.files); + path.pop(); + path = path.join('/'); + let pathFiles = files.data[path] + _remove(pathFiles, function(c) { + return c.name == data.path; + }); + this.setState({ + files: files + }) + } + deleteFileError = (error) => { + const filepath = error.path; + const message = error.data && error.data.output ? ' (' + error.data.output['error-trace'] + ')' : ' (server error)'; + console.log('Unable to delete', filepath, 'Error:', message); + ComposerAppActions.showError.defer({ + errorMessage: 'Unable to delete ' + filepath + message + '. ' + }); + } + + newPathNameUpdated = (event) => { + const value = event.target.value; + this.setState({ + newPathName: value + }) + } + createDirectory = () => { + console.log(this.newPathName); + this.sendDownloadFileRequst({ + id: this.item.id, + type: this.item.uiState.type, + path: this.item.name + '/' + this.newPathName, + url: utils.getSearchParams(window.location).dev_download_server || window.location.protocol + '//' + window.location.host, + refresh: true + }); + this.setState({ + newPathName: '' + }) + } } export default alt.createStore(ComposerAppStore, 'ComposerAppStore');