From: kashalkar Date: Mon, 8 May 2017 17:55:30 +0000 (+0200) Subject: Merge "Close button on view user in user management dashboard" into projects X-Git-Url: https://osm.etsi.org/gitweb/?p=osm%2FUI.git;a=commitdiff_plain;h=06dd5508070d4acc43bdcacca20cee5953d5a5a4;hp=c33cde7c8824d79e9825698fe957c24dfa1fe798 Merge "Close button on view user in user management dashboard" into projects --- diff --git a/Makefile b/Makefile index db2cda964..31c923383 100644 --- a/Makefile +++ b/Makefile @@ -36,7 +36,7 @@ BUILD_NUMBER = $(shell git describe | cut -d. -f2-) CONFD = XML_ONLY BUILD_TYPE = Debug -NOT_DEVELOPER_TYPE = FALSE +NOT_DEVELOPER_BUILD ?= FALSE COVERAGE_BUILD = FALSE RIFT_AGENT_BUILD = $(CONFD) PROJECT_TOP_DIR = $(TOP_ROOT_PATH) @@ -47,7 +47,7 @@ cmake:: mkdir -p $(RIFT_BUILD) mkdir -p $(RIFT_ARTIFACTS) mkdir -p $(RIFT_INSTALL) - cd $(RIFT_BUILD) && $(RIFT_SHELL_EXE) cmake $(TOP_SRC_PATH) -DCMAKE_INSTALL_PREFIX=$(TOP_ROOT_PATH) -DCMAKE_BUILD_TYPE=$(BUILD_TYPE) -DNOT_DEVELOPER_BUILD=$(NOT_DEVELOPER_TYPE) -DCOVERAGE_BUILD=$(COVERAGE_TYPE) -DRIFT_AGENT_BUILD=$(RIFT_AGENT_BUILD) -DPROJECT_TOP_DIR=$(PROJECT_TOP_DIR) -DCMAKE_MODULE_PATH=${CMAKE_MODULE_PATH} -DRIFT_SUBMODULE_NAME=$(PROJECT_TOP_DIR) -DRIFT_PACKAGE_GENERATOR=DEB -DRELEASE_NUMBER=$(RELEASE_NUMBER) -DBUILD_NUMBER=$(BUILD_NUMBER) + cd $(RIFT_BUILD) && $(RIFT_SHELL_EXE) cmake $(TOP_SRC_PATH) -DCMAKE_INSTALL_PREFIX=$(TOP_ROOT_PATH) -DCMAKE_BUILD_TYPE=$(BUILD_TYPE) -DNOT_DEVELOPER_BUILD=$(NOT_DEVELOPER_BUILD) -DCOVERAGE_BUILD=$(COVERAGE_TYPE) -DRIFT_AGENT_BUILD=$(RIFT_AGENT_BUILD) -DPROJECT_TOP_DIR=$(PROJECT_TOP_DIR) -DCMAKE_MODULE_PATH=${CMAKE_MODULE_PATH} -DRIFT_SUBMODULE_NAME=$(PROJECT_TOP_DIR) -DRIFT_PACKAGE_GENERATOR=DEB -DRELEASE_NUMBER=$(RELEASE_NUMBER) -DBUILD_NUMBER=$(BUILD_NUMBER) rw: cmake $(RIFT_SHELL_EXE) $(MAKE) -C $(RIFT_BUILD) diff --git a/skyquake/framework/core/modules/api/userManagementAPI.js b/skyquake/framework/core/modules/api/userManagementAPI.js index c05c2b343..1aee575d7 100644 --- a/skyquake/framework/core/modules/api/userManagementAPI.js +++ b/skyquake/framework/core/modules/api/userManagementAPI.js @@ -211,7 +211,7 @@ UserManagement.update = function(req) { var api_server = req.query['api_server']; var bodyData = req.body; data = { - "user":[bodyData] + "rw-user:user": bodyData } var updateTasks = []; if(bodyData.hasOwnProperty('old-password')) { @@ -237,7 +237,7 @@ UserManagement.update = function(req) { updateTasks.push(changePW); }; var updateUser = rp({ - uri: utils.confdPort(api_server) + '/api/config/user-config', + uri: utils.confdPort(api_server) + '/api/config/user-config/user/' + bodyData['user-name'] + ',' + bodyData['user-domain'], method: 'PUT', headers: _.extend({}, constants.HTTP_HEADERS.accept.data, { 'Authorization': req.session && req.session.authorization diff --git a/skyquake/framework/style/_colors.scss b/skyquake/framework/style/_colors.scss index 24a4475f6..a01c293f3 100644 --- a/skyquake/framework/style/_colors.scss +++ b/skyquake/framework/style/_colors.scss @@ -66,6 +66,7 @@ $neutral-light-3: hsl(360, 100%, 50%); $neutral-light-4: hsl(360, 100%, 50%); $neutral-light-5: hsl(360, 100%, 50%); +$neutral-dark-0: hsl(0, 0%, 80.7%); $neutral-dark-1: hsl(0, 0%, 63.7%); $neutral-dark-2: hsl(0, 0%, 56.7%); $neutral-dark-3: hsl(0, 0%, 49.7%); diff --git a/skyquake/plugins/composer/api/composer.js b/skyquake/plugins/composer/api/composer.js index b9d35ad54..31b3a005c 100644 --- a/skyquake/plugins/composer/api/composer.js +++ b/skyquake/plugins/composer/api/composer.js @@ -542,6 +542,9 @@ PackageManager.getJobStatus = function(req) { }) } +function makeAssetTypeParamName (type) { + return type.toLowerCase() + '-file-type'; +} FileManager.addFile = function(req) { console.log(' Uploading file', req.file.originalname, 'as', req.file.filename); var api_server = req.query['api_server']; @@ -549,21 +552,22 @@ FileManager.addFile = function(req) { var package_id = req.query['package_id']; var package_type = req.query['package_type'].toUpperCase(); var package_path = req.query['package_path']; - if (!download_host) { + if (!download_host) { download_host = req.protocol + '://' + req.get('host');//api_server + ':' + utils.getPortForProtocol(req.protocol); } var input = { 'external-url': download_host + '/composer/upload/' + req.query['package_id'] + '/' + req.file.filename, 'package-type': package_type, 'package-id': package_id, - 'package-path': package_path + '/' + req.file.filename + 'package-path': package_path ? package_path + '/' + req.file.filename : req.file.filename }; var uri = utils.projectContextUrl(req, utils.confdPort(api_server) + '/api/operations/package-file-add'); input = utils.addProjectContextToRPCPayload(req, uri, input); - + var assetType = req.query['asset_type'].toUpperCase(); + input[makeAssetTypeParamName(package_type)] = assetType; return new Promise(function(resolve, reject) { Promise.all([ rp({ @@ -605,16 +609,17 @@ FileManager.get = function(req) { var id = req.query['package_id']; var downloadUrl = req.query['url']; var path = req.query['package_path']; - var payload = { - "input": { - "package-type": type, - "package-id": id - } + var assetType = req.query['asset_type']; + var input = { + "package-type": type, + "package-id": id } + var payload = {input: input}; if(req.method == 'GET') { if(downloadUrl && path) { payload.input['external-url'] = downloadUrl; payload.input['package-path'] = path; + payload.input[makeAssetTypeParamName(type)] = assetType; return download(payload); } else { return list(payload); @@ -622,6 +627,7 @@ FileManager.get = function(req) { } if(req.method == 'DELETE') { payload.input['package-path'] = path; + payload.input[makeAssetTypeParamName(type)] = assetType; return deleteFile(payload) } diff --git a/skyquake/plugins/composer/src/src/components/EditDescriptorModelProperties.js b/skyquake/plugins/composer/src/src/components/EditDescriptorModelProperties.js index ed29b265a..4afa3ff59 100644 --- a/skyquake/plugins/composer/src/src/components/EditDescriptorModelProperties.js +++ b/skyquake/plugins/composer/src/src/components/EditDescriptorModelProperties.js @@ -25,6 +25,10 @@ import _includes from 'lodash/includes' import _isArray from 'lodash/isArray' import _cloneDeep from 'lodash/cloneDeep' import _debounce from 'lodash/debounce'; +import _uniqueId from 'lodash/uniqueId'; +import _set from 'lodash/set'; +import _get from 'lodash/get'; +import _has from 'lodash/has'; import utils from '../libraries/utils' import React from 'react' import ClassNames from 'classnames' @@ -50,6 +54,14 @@ import '../styles/EditDescriptorModelProperties.scss' const EMPTY_LEAF_PRESENT = '--empty-leaf-set--'; +function resolveReactKey(value) { + const keyPath = ['uiState', 'fieldKey']; + if (!_has(value, keyPath)) { + _set(value, keyPath, _uniqueId()); + } + return _get(value, keyPath); +} + function getDescriptorMetaBasicForType(type) { const basicPropertiesFilter = d => _includes(DESCRIPTOR_MODEL_FIELDS[type], d.name); return DescriptorModelMetaFactory.getModelMetaForType(type, basicPropertiesFilter) || {properties: []}; @@ -383,21 +395,35 @@ export default function EditDescriptorModelProperties(props) { } - function buildElement(container, property, valuePath, value) { - return property.properties.map((property, index) => { - let childValue; - const childPath = valuePath.slice(); - if (typeof value === 'object') { - childValue = value[property.name]; + /** + * buiid and return an array of components representing an editor for each property. + * + * @param {any} container the master document being edited + * @param {[property]} properties + * @param {string} pathToProperties path within the container to the properties + * @param {Object} data source for each property + * @param {any} props object containing main data panel information, e.g. panel width {width: 375} + * which may be useful/necessary to a components rendering. + * @returns an array of react components + */ + function buildComponentsForProperties(container, properties, pathToProperties, data, props) { + return properties.map((property) => { + let value; + let propertyPath = pathToProperties.slice(); + if (data && typeof data === 'object') { + value = data[property.name]; } if(property.type != 'choice'){ - childPath.push(property.name); + propertyPath.push(property.name); } - return build(container, property, childPath, childValue); - + return build(container, property, propertyPath, value, props); }); } + function buildElement(container, property, valuePath, value) { + return buildComponentsForProperties(container, property.properties, valuePath, value); + } + function buildChoice(container, property, path, value, key) { function processChoiceChange(name, value) { @@ -519,7 +545,7 @@ export default function EditDescriptorModelProperties(props) { selectedOptionValue = utils.resolvePath(container.model, ['uiState.choice', pathToChoice, 'selected'].join('.')); } else { property.properties.map(function(p) { - let pname = p.properties[0].name; + let pname = p.properties[0] && p.properties[0].name; if(container.model.hasOwnProperty(pname)) { utils.assignPathValue(container.model, ['uiState.choice', pathToChoice, 'selected'].join('.'), [p.name, pname].join('.')); } @@ -533,8 +559,15 @@ export default function EditDescriptorModelProperties(props) { const hasProperties = _isArray(valueProperty.properties) && valueProperty.properties.length; const isMissingDescriptorMeta = !hasProperties && !Property.isLeaf(valueProperty); //Some magic that prevents errors for arising - const valueResponse = valueProperty.properties && valueProperty.properties.length ? valueProperty.properties.map(valuePropertyFn) : (!isMissingDescriptorMeta) ? build(container, valueProperty, path.concat(valueProperty.name), utils.resolvePath(container.model, path.concat(valueProperty.name).join('.')) || container.model[valueProperty.name]) : - valueProperty.map && valueProperty.map(valuePropertyFn); + let valueResponse = null; + if (valueProperty.properties && valueProperty.properties.length) { + valueResponse = valueProperty.properties.map(valuePropertyFn); + } else if (!isMissingDescriptorMeta) { + let value = utils.resolvePath(container.model, path.concat(valueProperty.name).join('.')) || container.model[valueProperty.name]; + valueResponse = build(container, valueProperty, path.concat(valueProperty.name), value) + } else { + valueResponse = valueProperty.map && valueProperty.map(valuePropertyFn); + } function valuePropertyFn(d, i) { const childPath = path.concat(valueProperty.name, d.name); const childValue = utils.resolvePath(container.model, childPath.join('.')); @@ -664,7 +697,7 @@ export default function EditDescriptorModelProperties(props) { if (isArray) { valuePath.push(index); - fieldId += index; + fieldId = isLeafList ? fieldId + index + value : resolveReactKey(value); } if (isMetaField) { @@ -722,7 +755,7 @@ export default function EditDescriptorModelProperties(props) { value = utils.resolvePath(container.model, ['uiState.choice'].concat(path, 'selected').join('.')); if(!value) { property.properties.map(function(p) { - let pname = p.properties[0].name; + let pname = p.properties[0] && p.properties[0].name; if(container.model.hasOwnProperty(pname)) { value = container.model[pname]; } @@ -768,11 +801,7 @@ export default function EditDescriptorModelProperties(props) {

Basic

- {basicProperties.map(property => { - const path = [property.name]; - const value = container.model[property.name]; - return build(container, property, path, value); - })} + {buildComponentsForProperties(container, basicProperties, [], container.model)}
); @@ -792,11 +821,7 @@ export default function EditDescriptorModelProperties(props) { less…
- {properties.map(property => { - const path = [property.name]; - const value = container.model[property.name]; - return build(container, property, path, value, {toggle: true, width: props.width}); - })} + {buildComponentsForProperties(container, properties, [], container.model, {toggle: true, width: props.width})}
We need this so when the user closes the panel it won't shift away and scare the bj out of them!
diff --git a/skyquake/plugins/composer/src/src/components/filemanager/FileManager.jsx b/skyquake/plugins/composer/src/src/components/filemanager/FileManager.jsx index ed9ea93a5..87029571a 100644 --- a/skyquake/plugins/composer/src/src/components/filemanager/FileManager.jsx +++ b/skyquake/plugins/composer/src/src/components/filemanager/FileManager.jsx @@ -20,6 +20,7 @@ //https://raw.githubusercontent.com/RIFTIO/RIFT.ware/master/rift-shell import _cloneDeep from 'lodash/cloneDeep' import _findIndex from 'lodash/findIndex' +import _uniqueId from 'lodash/uniqueId' import React from 'react'; import ReactDOM from 'react-dom'; import TreeView from 'react-treeview'; @@ -28,7 +29,7 @@ import Button from '../Button'; import './FileMananger.scss'; import FileManagerActions from './FileManagerActions.js'; import imgSave from '../../../../node_modules/open-iconic/svg/data-transfer-upload.svg' -import {Panel, PanelWrapper} from 'widgets/panel/panel'; +import { Panel, PanelWrapper } from 'widgets/panel/panel'; import SkyquakeComponent from 'widgets/skyquake_container/skyquakeComponent.jsx'; import LoadingIndicator from 'widgets/loading-indicator/loadingIndicator.jsx'; @@ -37,17 +38,61 @@ import Utils from '../../libraries/utils' import FileManagerUploadDropZone from '../../libraries/FileManagerUploadDropZone'; let API_SERVER = require('utils/rw.js').getSearchParams(window.location).api_server; -const createDropZone = function (action, clickable, type, id, path, dropTarget) { - const dropZone = new FileManagerUploadDropZone(ReactDOM.findDOMNode(dropTarget), [clickable], action, type, id, path); +const ASSET_TYPE = { + 'nsd': [ + { id: 'ICONS', folder: 'icons', title: "Icons", allowFolders: false }, + { id: 'SCRIPTS', folder: 'scripts', title: "scripts", allowFolders: true }, + { id: 'NS_CONFIG', folder: 'ns_config', title: "NS Config", allowFolders: false }, + { id: 'VNF_CONFIG', folder: 'vnf_config', title: "VNF Config", allowFolders: false } + ], + 'vnfd': [ + { id: 'ICONS', folder: 'icons', title: "Icons", allowFolders: false }, + { id: 'CHARMS', folder: 'charms', title: "charms", allowFolders: true }, + { id: 'SCRIPTS', folder: 'scripts', title: "scripts", allowFolders: true }, + { id: 'IMAGES', folder: 'images', title: "images", allowFolders: false }, + { id: 'CLOUD_INIT', folder: 'cloud_init', title: "cloud_init", allowFolders: false }, + { id: 'README', folder: '.', title: ".", allowFolders: false } + ] +} + +const createDropZone = function (action, clickable, getUploadPropsCallback, dropTarget) { + const dropZone = new FileManagerUploadDropZone(ReactDOM.findDOMNode(dropTarget), [clickable], action, getUploadPropsCallback); // dropZone.on('dragover', this.onDragOver); // dropZone.on('dragend', this.onDragEnd); // dropZone.on('addedfile', this.onFileAdded); return dropZone; }; -//updateFileLocationInput + +function normalizeAssets(packageType, assetInfo, filesStatus) { + let assets = {}; + let assetTypes = ASSET_TYPE[packageType]; + assetTypes.forEach(assetGroup => { + const typeFolder = assetGroup.folder; + let folders = assetInfo.id.filter(name => name.startsWith(typeFolder)); + if (folders.length) { + folders.reverse(); + assets[assetGroup.id] = folders.map(fullName => { + let path = fullName.slice(typeFolder.length + 1); + let files = assetInfo.data[fullName].map(info => ({ + name: info.name.startsWith(fullName) ? info.name.slice(fullName.length + 1) : info.name, + status: filesStatus[info.name] + })); + return { path, files }; + }); + } + }); + return assets; +} + +function sendDeleteFileRequest(assetType, path, name) { + path = path ? path + '/' + name : name; + FileManagerActions.deletePackageFile({ assetType, path }); +} + class FileManager extends React.Component { constructor(props) { super(props) + let assests = props.files; } componentWillMount() { // FileManagerActions.openFileManagerSockets() @@ -57,153 +102,202 @@ class FileManager extends React.Component { } generateFolder(data, nesting) { let nestingLevel = nesting || 1; + } + render() { + let { files, filesState, type, item, actions } = this.props; + let assets = normalizeAssets(type, files, filesState); + let children = []; + let assetTypes = ASSET_TYPE[type]; + assetTypes.forEach(assetGroup => { + const typeFolder = assetGroup.folder; + let folders = assets[assetGroup.id]; + let rootAssets = { path: '', files: [] }; + let subFolders = null; + if (folders && folders.length) { + rootAssets = folders[0]; + subFolders = folders.slice(1); + } + children.push( + + ) + }, this); + let html = ( +
+ + {children} + +
+ ) + return html; } - deleteFile(name) { - return function(e) { - FileManagerActions.deletePackageFile(name); - } +} + +function NewHierachy(props) { + return ( + +
+ +
+
+ ); +} + +class AssetGroup extends React.Component { + constructor(props) { + super(props); + this.state = { downloadPath: "" }; } - updateFileLocationInput(name) { - return function(e) { - FileManagerActions.updateFileLocationInput({ - name: name, - value: e.target.value + + render() { + let { title, packageType, packageId, assetGroup, files, allowsFolders, folders, path, inputState, showNotification } = this.props; + let children = []; + if (folders && folders.length) { + folders.map(function (folder, i) { + children.push( + + ) }); } - } - sendDownloadFileRequst = (url, path) => { - let self = this; - return function(e) { - if(!url || url == "") { - return self.props.actions.showNotification.defer({type: 'error', msg: 'Value missing in download request'});; + let folderCreateComponent = allowsFolders ? : null; + let entries = null + + function uploadFileFromUrl(url) { + if (!url || url == "") { + return; } - let files = self.props.files.data; - let folder = path.split('/'); let splitUrl = url.split('/'); let fileName = splitUrl[splitUrl.length - 1]; - folder.pop; - let fullPath = _cloneDeep(folder); - fullPath.push(fileName); - fullPath = fullPath.join('/'); - folder = folder.join('/'); - let fileIndex = _findIndex(files[folder], function(f) { - return f.name == fullPath; - }) - if (fileIndex == -1) { - FileManagerActions.sendDownloadFileRequst({ - url: url, - path: path - }); + if (files.findIndex(f => f.name === fileName) > -1) { + showNotification('It seems you\'re attempting to upload a file with a duplicate file name'); } else { - self.props.actions.showNotification('It seems you\'re attempting to upload a file with a duplicate file name'); + FileManagerActions.sendDownloadFileRequest({ url, assetType: assetGroup.id, path: path }); } } - } - render() { - let self = this; - let html = ( -
- - -
- -
+
+
+ {children} +
+
+ + ); } - } -function buildList(self, data) { - let toReturn = []; - data.id.map(function(k,i) { - toReturn.push (contentFolder(self, data.data[k], k, k+i, self.props.filesState, self.updateFileLocationInput, self.sendDownloadFileRequst, self.deleteFile)); - }); - return toReturn.reverse(); +function FileAssetList(props) { + let { packageType, packageId, assetGroup, files, path } = props; + let children = null; + if (files) { + children = files.map(function (file, i) { + if (!file.hasOwnProperty('contents')) { + return + } + }) + } + return ( +
+ {children} +
+ ); + } -function contentFolder(context, folder, path, key, inputState, updateFn, sendDownloadFileRequst, deleteFn) { - let type = context.props.type; - let id = context.props.item.id; - let classId = `DZ-${path.replace(/\/|\s+/g, '-')}`; - const onboardDropZone = createDropZone.bind(this, FileManagerUploadDropZone.ACTIONS.onboard, '.ComposerAppAddFile.' + classId, type, id, path); +function FileAsset(props) { + let { file, path, type, assetGroup, id } = props; + const name = file.name; + const downloadHost = API_SERVER.match('localhost') || API_SERVER.match('127.0.0.1') ? `${window.location.protocol}//${window.location.hostname}` : API_SERVER; + //{`${window.location.protocol}//${API_SERVER}:4567/api/package${type}/${id}/${path}/${name}`} return ( - -
- { - folder.map(function(f, i) { - if( !f.hasOwnProperty('contents') ){ - return contentFile(context, f, path, i, deleteFn); - } - }) - } - - -
- OR +
+
+
+
+ {file.status && (file.status == 'IN_PROGRESS' || file.status == 'DOWNLOADING') ? : file.status} +
+
+ {name} +
-
- -
- - ); +
+ ) } + class ItemUpload extends React.Component { constructor(props) { super(props); + this.state = { dropzoneIdClass: 'DZ-' + _uniqueId() }; } componentDidMount() { - if (this.props.dropZone) { - const dropTarget = this; - const dropZone = this.props.dropZone(dropTarget); - } + createDropZone( + FileManagerUploadDropZone.ACTIONS.onboard, + '.ComposerAppAddFile.' + this.state.dropzoneIdClass, + () => { + let theCode = 'crap'; + return ({ + packageType: this.props.packageType, + packageId: this.props.packageId, + assetGroup: this.props.assetGroup, + path: this.props.path + })}, + this); } + render() { - let {type, id, path, key, ...props} = this.props; - let classId = `DZ-${path.replace(/\/|\s+/g, '-')}`; + let { dropzoneIdClass } = this.props; return (
-
) } } -function contentFile(context, file, path, key, deleteFn) { - const name = stripPath(file.name, path); - const id = context.props.item.id; - const type = context.props.type; - const downloadHost = API_SERVER.match('localhost') || API_SERVER.match('127.0.0.1') ? `${window.location.protocol}//${window.location.hostname}` : API_SERVER; - //{`${window.location.protocol}//${API_SERVER}:4567/api/package${type}/${id}/${path}/${name}`} - return ( -
-
-
-
- {file.status && (file.status == 'IN_PROGRESS' || file.status == 'DOWNLOADING' ) ? : file.status } -
-
- {name} -
-
-
X
-
-
- ) -} function stripPath(name, path, returnPath) { let stripSlash = (name.indexOf('/') > -1) ? '/' : ''; diff --git a/skyquake/plugins/composer/src/src/components/filemanager/FileManagerActions.js b/skyquake/plugins/composer/src/src/components/filemanager/FileManagerActions.js index 93e1e5edf..e5791a440 100644 --- a/skyquake/plugins/composer/src/src/components/filemanager/FileManagerActions.js +++ b/skyquake/plugins/composer/src/src/components/filemanager/FileManagerActions.js @@ -21,11 +21,26 @@ import alt from '../../alt'; class FileManagerActions { constructor() { - this.generateActions('getFilelistSuccess', 'getFilelistError', 'updateFileLocationInput','sendDownloadFileRequst', 'addFileSuccess', 'addFileError','deletePackageFile','deleteFileSuccess','deleteFileError','openDownloadMonitoringSocketSuccess', 'openDownloadMonitoringSocketError', - 'getFilelistSocketSuccess', - 'openFileManagerSockets', 'closeFileManagerSockets','newPathNameUpdated', 'createDirectory'); + this.generateActions( + 'getFilelistSuccess', + 'getFilelistError', + 'updateFileLocationInput', + 'sendDownloadFileRequest', + 'addFileSuccess', + 'addFileError', + 'deletePackageFile', + 'deleteFileSuccess', + 'deleteFileError', + 'openDownloadMonitoringSocketSuccess', + 'openDownloadMonitoringSocketError', + 'getFilelistSocketSuccess', + 'openFileManagerSockets', + 'closeFileManagerSockets', + 'newPathNameUpdated', + 'createDirectory' + ); } } -export default alt.createActions(FileManagerActions); +export default alt.createActions(FileManagerActions); \ No newline at end of file diff --git a/skyquake/plugins/composer/src/src/components/filemanager/FileManagerSource.js b/skyquake/plugins/composer/src/src/components/filemanager/FileManagerSource.js index ddfac1694..6c9c0eab2 100644 --- a/skyquake/plugins/composer/src/src/components/filemanager/FileManagerSource.js +++ b/skyquake/plugins/composer/src/src/components/filemanager/FileManagerSource.js @@ -57,20 +57,29 @@ const FileManagerSource = { }, addFile: function() { return { - remote: function(state, id, type, path, url, refresh) { + remote: function(state, id, type, assetType, path, url, refresh) { return new Promise(function(resolve, reject) { console.log('Adding file'); console.log(id, type, path, url); let splitUrl = url.split('/'); let fileName = splitUrl[splitUrl.length -1]; - let packagePath = refresh ? path + ((path[path.length - 1] == '/') ? '' : '/') : path + '/' + fileName; + let packagePath = refresh ? path + ((path[path.length - 1] == '/') ? '' : '/') : (path ? path + '/' + fileName : fileName); + let assetFolder = assetType.toLowerCase(); $.ajax({ - beforeSend: Utils.addAuthorizationStub, - url: 'api/file-manager?api_server=' + utils.getSearchParams(window.location).api_server +'&package_type=' + type + '&package_id=' + id + '&package_path=' + packagePath + '&url=' + url, + beforeSend: (xhr) => { + Utils.addAuthorizationStub(xhr); + // lets get the buzy graphic rolling + FileManagerActions.addFileSuccess.defer({ + path: assetFolder + (path ? '/' + path: ''), + fileName: fileName, + refresh: refresh + }); + }, + url: 'api/file-manager?api_server=' + utils.getSearchParams(window.location).api_server +'&package_type=' + type + '&package_id=' + id + '&package_path=' + packagePath + '&asset_type=' + assetType + '&url=' + url, success: function(data) { resolve({ - data:data, - path: path, + data: data, + path: assetFolder + (path ? '/' + path: ''), fileName: fileName, refresh: refresh }); @@ -93,33 +102,25 @@ const FileManagerSource = { }, deleteFile: function() { return { - remote: function(state, id, type, path) { + remote: function(state, id, type, assetType, path) { + let assetFolder = assetType.toLowerCase(); return new Promise(function(resolve, reject) { $.ajax({ method: 'DELETE', beforeSend: Utils.addAuthorizationStub, - url: 'api/file-manager?api_server=' + utils.getSearchParams(window.location).api_server +'&package_type=' + type + '&package_id=' + id + '&package_path=' + path , + url: 'api/file-manager?api_server=' + utils.getSearchParams(window.location).api_server +'&package_type=' + type + '&package_id=' + id + '&asset_type=' + assetType + '&package_path=' + path , success: function(data) { if (data.output.status == 'True') { - resolve({ - data: data, - path: path - }); + resolve({data, assetFolder, path}); } else { - reject({ - data: data, - path: path - }) + reject({data, assetFolder, path}) } }, error: function(error) { if (typeof error == 'string') { error = JSON.parse(error); } - reject({ - path: path, - data: error - }); + reject({data, assetFolder, path}); } }).fail(function(xhr){ //Authentication and the handling of fail states should be wrapped up into a connection class. diff --git a/skyquake/plugins/composer/src/src/libraries/FileManagerUploadDropZone.js b/skyquake/plugins/composer/src/src/libraries/FileManagerUploadDropZone.js index 963e57ee1..680a02f9d 100644 --- a/skyquake/plugins/composer/src/src/libraries/FileManagerUploadDropZone.js +++ b/skyquake/plugins/composer/src/src/libraries/FileManagerUploadDropZone.js @@ -40,17 +40,26 @@ function getCatalogPackageManagerServerOrigin() { return window.location.origin; } -function initializeDropZone(element = '#dropzone', button = false, action = ACTIONS.onboard, type, id, path) { +function initializeDropZone(element = '#dropzone', button = false, action = ACTIONS.onboard, getUploadProps) { let Auth = 'Basic ' + window.sessionStorage.getItem("auth"); let dev_download_server = Utils.getSearchParams(window.location).dev_download_server; DropZone.autoDiscover = false; return new DropZone(element, { paramName: 'package', url() { + let {packageType, packageId, assetGroup, path} = getUploadProps(); if (action === ACTIONS.update) { return getCatalogPackageManagerServerOrigin() + '/api/update'; } - return getCatalogPackageManagerServerOrigin() + '/composer/api/file-manager?api_server=' + Utils.getSearchParams(window.location).api_server + '&package_type=' + type + '&package_id=' + id + '&package_path=' + path + ( dev_download_server ? '&dev_download_server=' + dev_download_server : ''); + let url = getCatalogPackageManagerServerOrigin() + + '/composer/api/file-manager?api_server=' + + Utils.getSearchParams(window.location).api_server + + '&package_type=' + packageType + + '&package_id=' + packageId + + '&package_path=' + path + + '&asset_type=' + assetGroup.id + + ( dev_download_server ? '&dev_download_server=' + dev_download_server : ''); + return url; }, headers: { 'Authorization': Auth @@ -61,11 +70,12 @@ function initializeDropZone(element = '#dropzone', button = false, action = ACTI previewTemplate: '', sending(file, xhr, formData) { // NOTE ie11 does not get this form data + let {packageType, packageId, assetGroup, path} = getUploadProps(); formData.append('id', file.id); FileManagerActions.addFileSuccess({ - fileName: file.name, - path: path - }) + path: assetGroup.folder + (path ? '/' + path: ''), + fileName: file.name + }); }, error(file, errorMessage) { const response = { @@ -119,10 +129,10 @@ function initializeDropZone(element = '#dropzone', button = false, action = ACTI }); } -export default class CatalogPackageManagerUploadDropZone { +export default class FileManagerUploadDropZone { - constructor(element, button, action, type, id, path) { - this.dropZone = initializeDropZone(element, button, action, type, id, path); + constructor(element, button, action, getUploadProps) { + this.dropZone = initializeDropZone(element, button, action, getUploadProps); } static get ACTIONS() { diff --git a/skyquake/plugins/composer/src/src/libraries/model/DescriptorModelMetaFactory.js b/skyquake/plugins/composer/src/src/libraries/model/DescriptorModelMetaFactory.js index 69098ec2d..1ba891256 100644 --- a/skyquake/plugins/composer/src/src/libraries/model/DescriptorModelMetaFactory.js +++ b/skyquake/plugins/composer/src/src/libraries/model/DescriptorModelMetaFactory.js @@ -102,19 +102,15 @@ function serialize_leaf_empty(data) { function serialize_leaf_list(data) { data = data[this.name]; if (data) { - commaSeparatedValues = data.reduce((d, v) => { - let leaf = Serializer.leaf.call(this, d); - let value = leaf & leaf[this.name]; - if (value && value.length) { - if (v.length) { - v += ', '; - } - v += value; + data = data.reduce((result, value) => { + if (value !== '' && value !== null && value !== undefined && typeof value !== 'object') { + result.push(value); } - }, ""); - if (commaSeparatedValues.length) { + return result; + }, []); + if (data.length){ let obj = {}; - obj[this.name] = commaSeparatedValues; + obj[this.name] = data; return obj; } } diff --git a/skyquake/plugins/composer/src/src/stores/ComposerAppStore.js b/skyquake/plugins/composer/src/src/stores/ComposerAppStore.js index c677a44a6..c9675b70c 100644 --- a/skyquake/plugins/composer/src/src/stores/ComposerAppStore.js +++ b/skyquake/plugins/composer/src/src/stores/ComposerAppStore.js @@ -168,7 +168,7 @@ class ComposerAppStore { showDescriptor: ComposerAppActions.showDescriptor, getFilelistSuccess: FileManagerActions.getFilelistSuccess, updateFileLocationInput: FileManagerActions.updateFileLocationInput, - sendDownloadFileRequst: FileManagerActions.sendDownloadFileRequst, + sendDownloadFileRequest: FileManagerActions.sendDownloadFileRequest, addFileSuccess: FileManagerActions.addFileSuccess, deletePackageFile: FileManagerActions.deletePackageFile, deleteFileSuccess: FileManagerActions.deleteFileSuccess, @@ -485,7 +485,7 @@ class ComposerAppStore { if (self.fileMonitoringSocketID) { let newState = {}; if(data.hasOwnProperty('contents')) { - filesState = addInputState( _cloneDeep(this.filesState),data); + filesState = updateFileState( _cloneDeep(this.filesState),data); let normalizedData = normalizeTree(data); newState = { files: { @@ -511,7 +511,6 @@ class ComposerAppStore { id:[], data:{} }; - data.contents.map(getContents); function getContents(d) { if(d.hasOwnProperty('contents')) { let contents = []; @@ -526,25 +525,26 @@ class ComposerAppStore { f.data[d.name] = contents; } } + getContents(data); return f; } - function addInputState(obj, d) { + function updateFileState(obj, d) { d.newFile = ''; if(d.hasOwnProperty('contents')) { - d.contents.map(addInputState.bind(null, obj)) - } - if(!obj[d.name]) { - obj[d.name] = ''; + d.contents.map(updateFileState.bind(null, obj)) } + // override any "pending" state we may have initialized + obj[d.name] = ''; return obj; } } - sendDownloadFileRequst(data) { + sendDownloadFileRequest(data) { let id = data.id || this.item.id; let type = data.type || this.item.uiState.type; + let assetType = data.assetType; let path = data.path; let url = data.url; - this.getInstance().addFile(id, type, path, url, data.refresh); + this.getInstance().addFile(id, type, assetType, path, url, data.refresh); } updateFileLocationInput = (data) => { let name = data.name; @@ -558,13 +558,27 @@ class ComposerAppStore { addFileSuccess = (data) => { if(!data.refresh) { let path = data.path; + if (path.startsWith('readme')) { + // this asset type stuff should be in a more common location + // this is a wee bit of a hack till it is + path = '.' + path.slice(6); + } 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}); + let assetGroup = files.data[path] || []; + if (fileName) { + let name = path + '/' + fileName; + if (assetGroup.findIndex(f => f.name === name) == -1){ + assetGroup.push({name}); + } + } + files.data[path] = assetGroup; + if (files.id.indexOf(path) == -1){ + files.id.push(path); + } + let filesState = _cloneDeep(this.filesState); + filesState[name] = "DOWNLOADING"; + this.setState({files, filesState}); } } @@ -634,6 +648,11 @@ class ComposerAppStore { } this.setState({ + filesState: [], + files: { + id:[], + data:{} + }, fileMonitoringSocketID: id, fileMonitoringSocket: ws }) @@ -663,19 +682,28 @@ class ComposerAppStore { endWatchingJob(id) { } - deletePackageFile(name) { + deletePackageFile(asset) { + let {assetType, path} = asset; let id = this.item.id; let type = this.item.uiState.type; - this.getInstance().deleteFile(id, type, name); + this.getInstance().deleteFile(id, type, assetType, path); } deleteFileSuccess = (data) => { - let path = data.path.split('/') + let name = null; + let path = null; + if (data.assetFolder === 'readme'){ + // freak'n root folder is special + name = data.path; + path = ['.']; + } else { + name = data.assetFolder + '/' + data.path; + path = name.split('/'); + path.pop(); + } let files = _cloneDeep(this.files); - path.pop(); - path = path.join('/'); - let pathFiles = files.data[path] - _remove(pathFiles, function(c) { - return c.name == data.path; + let filesForPath = files.data[path.join('/')] + _remove(filesForPath, function(c) { + return c.name == name; }); this.setState({ @@ -697,12 +725,13 @@ class ComposerAppStore { newPathName: value }) } - createDirectory = () => { + createDirectory = (assetType) => { console.log(this.newPathName); - this.sendDownloadFileRequst({ + this.sendDownloadFileRequest({ id: this.item.id, type: this.item.uiState.type, - path: this.item.name + '/' + this.newPathName, + assetType: assetType, + path: this.newPathName, url: utils.getSearchParams(window.location).dev_download_server || window.location.protocol + '//' + window.location.host, refresh: true }); diff --git a/skyquake/plugins/launchpad/src/instantiate/instantiateInputParams.jsx b/skyquake/plugins/launchpad/src/instantiate/instantiateInputParams.jsx index d1e295c03..6273d8cab 100644 --- a/skyquake/plugins/launchpad/src/instantiate/instantiateInputParams.jsx +++ b/skyquake/plugins/launchpad/src/instantiate/instantiateInputParams.jsx @@ -105,12 +105,13 @@ export default class InstantiateInputParams extends Component { } inputParametersHTML = (props) => { let inputParameters = props.inputParameters; + const handleChange = (i, event) => props.updateInputParam(i, event.target.value); return inputParameters && inputParameters.map(function(input, i) { return (

Input Parameters

- +
) diff --git a/skyquake/plugins/launchpad/src/instantiate/instantiateStore.js b/skyquake/plugins/launchpad/src/instantiate/instantiateStore.js index 3ec2a8029..0e91ee384 100644 --- a/skyquake/plugins/launchpad/src/instantiate/instantiateStore.js +++ b/skyquake/plugins/launchpad/src/instantiate/instantiateStore.js @@ -189,10 +189,10 @@ class LaunchNetworkServiceStore { }); return window.location.hash = 'launchpad/' + tokenizedHash[2]; } - launchNSRError(error) { + launchNSRError(data) { var msg = 'Something went wrong while trying to instantiate. Check the error logs for more information'; - if(error) { - msg = error; + if (data.error) { + msg = data.error; } Alt.actions.global.showNotification.defer(msg); Alt.actions.global.hideScreenLoader.defer(); diff --git a/skyquake/plugins/launchpad/src/recordViewer/recordCard.jsx b/skyquake/plugins/launchpad/src/recordViewer/recordCard.jsx index 69b4bbd98..c9717c280 100644 --- a/skyquake/plugins/launchpad/src/recordViewer/recordCard.jsx +++ b/skyquake/plugins/launchpad/src/recordViewer/recordCard.jsx @@ -375,11 +375,11 @@ export default class RecordCard extends React.Component { consoleUrlsTabTitle = 'VDU Console Links'; tabList.push( - {consoleUrlsTabTitle} + {consoleUrlsTabTitle} ); tabPanels.push( - +
{consoleUrlsComponent}
diff --git a/skyquake/plugins/project_management/src/dashboard/dashboard.jsx b/skyquake/plugins/project_management/src/dashboard/dashboard.jsx index 66c3f4873..c0adc7a4a 100644 --- a/skyquake/plugins/project_management/src/dashboard/dashboard.jsx +++ b/skyquake/plugins/project_management/src/dashboard/dashboard.jsx @@ -311,7 +311,7 @@ class ProjectManagementDashboard extends React.Component { - +
{!state.isReadOnly ? : null} diff --git a/skyquake/plugins/project_management/src/dashboard/projectMgmt.scss b/skyquake/plugins/project_management/src/dashboard/projectMgmt.scss index eca6a5993..3b23963ab 100644 --- a/skyquake/plugins/project_management/src/dashboard/projectMgmt.scss +++ b/skyquake/plugins/project_management/src/dashboard/projectMgmt.scss @@ -151,6 +151,11 @@ justify-content:center; } } + tbody tr { + &:nth-child(even) { + background:$neutral-dark-0; + } + } } .userTable { .FormSection-body { @@ -239,6 +244,9 @@ font-weight:bold; } &--data { + &:nth-child(even) { + background:$neutral-dark-0; + } &:hover:not(&-active) { background:$neutral-dark-1; } diff --git a/skyquake/plugins/user_management/src/dashboard/userMgmt.scss b/skyquake/plugins/user_management/src/dashboard/userMgmt.scss index a265f0dbf..a332c556a 100644 --- a/skyquake/plugins/user_management/src/dashboard/userMgmt.scss +++ b/skyquake/plugins/user_management/src/dashboard/userMgmt.scss @@ -131,6 +131,9 @@ font-weight:bold; } &--data { + &:nth-child(even) { + background:$neutral-dark-0; + } &:hover:not(&-active) { background:$neutral-dark-1; } diff --git a/skyquake/plugins/user_management/src/platformRoleManagement/platformRoleManagement.scss b/skyquake/plugins/user_management/src/platformRoleManagement/platformRoleManagement.scss index dc8fcce60..ac81d90e2 100644 --- a/skyquake/plugins/user_management/src/platformRoleManagement/platformRoleManagement.scss +++ b/skyquake/plugins/user_management/src/platformRoleManagement/platformRoleManagement.scss @@ -147,6 +147,11 @@ justify-content:center; } } + tbody tr { + &:nth-child(even) { + background:$neutral-dark-0; + } + } } } @@ -229,6 +234,9 @@ font-weight:bold; } &--data { + &:nth-child(even) { + background:$neutral-dark-0; + } &:hover:not(&-active) { background:$neutral-dark-1; }