Merge "RIFT-15944 - editing an ‘id’ field is troublesome as focus is lost on each...
authorkashalkar <kiran.kashalkar@riftio.com>
Tue, 4 Apr 2017 21:57:18 +0000 (23:57 +0200)
committerGerrit Code Review <root@osm.etsi.org>
Tue, 4 Apr 2017 21:57:18 +0000 (23:57 +0200)
skyquake/framework/widgets/header/header.jsx
skyquake/framework/widgets/skyquake_container/skyquakeContainer.jsx
skyquake/plugins/accounts/src/account/account.jsx
skyquake/plugins/composer/src/src/components/filemanager/FileManager.jsx
skyquake/plugins/composer/src/src/components/filemanager/FileManagerSource.js
skyquake/plugins/composer/src/src/stores/CatalogDataStore.js
skyquake/plugins/composer/src/src/stores/ComposerAppStore.js
skyquake/plugins/debug/src/crash.jsx
skyquake/plugins/debug/src/crashStore.js
skyquake/plugins/launchpad/api/launchpad.js

index 21f4c10..3cfaaf6 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * 
+ *
  *   Copyright 2016 RIFT.IO Inc
  *
  *   Licensed under the Apache License, Version 2.0 (the "License");
@@ -55,6 +55,7 @@ export default class AppHeader extends React.Component {
                 type={"error"}
                 hidden={!(this.state.validateErrorEvent && this.state.validateErrorMsg)}
                 onDismiss={HeaderStore.validateReset}
+                timeout= {5000}
             />
 
         // html = (
index d53d85f..d83c836 100644 (file)
@@ -106,6 +106,7 @@ export default class skyquakeContainer extends React.Component {
                             type={notificationType}
                             hidden={!(displayNotification && notificationMessage)}
                             onDismiss={SkyquakeContainerActions.hideNotification}
+                            timeout= {5000}
                         />
                         <ScreenLoader show={displayScreenLoader}/>
                         <SkyquakeNav nav={this.state.nav}
index e588e74..b7dbf35 100644 (file)
@@ -169,7 +169,7 @@ class Account extends React.Component {
     }
     evaluateSubmit = (e) => {
         if (e.keyCode == 13) {
-            if (this.props.edit) {
+            if (this.props.params.name != 'create') {
                 this.update(e);
             } else {
                 this.create(e);
index d1e5c93..ed9ea93 100644 (file)
@@ -124,7 +124,7 @@ class FileManager extends React.Component {
 function buildList(self, data) {
     let toReturn = [];
     data.id.map(function(k,i) {
-        toReturn.push (contentFolder(self, data.data[k], k, i, self.props.filesState, self.updateFileLocationInput, self.sendDownloadFileRequst, self.deleteFile));
+        toReturn.push (contentFolder(self, data.data[k], k, k+i, self.props.filesState, self.updateFileLocationInput, self.sendDownloadFileRequst, self.deleteFile));
     });
     return toReturn.reverse();
 }
@@ -132,7 +132,8 @@ function buildList(self, data) {
 function contentFolder(context, folder, path, key, inputState, updateFn, sendDownloadFileRequst, deleteFn) {
     let type = context.props.type;
     let id = context.props.item.id;
-    const onboardDropZone = createDropZone.bind(this, FileManagerUploadDropZone.ACTIONS.onboard, '.ComposerAppAddFile.' + path.replace(/\//g, '-'), type, id, path);
+    let classId = `DZ-${path.replace(/\/|\s+/g, '-')}`;
+    const onboardDropZone = createDropZone.bind(this, FileManagerUploadDropZone.ACTIONS.onboard, '.ComposerAppAddFile.' + classId, type, id, path);
     return (
         <Panel title={path} key={key} itemClassName="nested" no-corners>
         <div className="folder">
@@ -170,11 +171,12 @@ class ItemUpload extends React.Component {
     }
     render() {
         let {type, id, path, key, ...props} = this.props;
+        let classId = `DZ-${path.replace(/\/|\s+/g, '-')}`;
         return (
             <div className="inputSection">
                 <label className="sqTextInput" style={{flexDirection: 'row', alignItems:'center'}}>
                     <span>Upload File</span>
-                    <Button className={'ComposerAppAddFile ' + path.replace(/\//g, '-')} label="BROWSE"/>
+                    <Button className={'ComposerAppAddFile ' + classId} label="BROWSE"/>
                 </label>
             </div>
         )
index 4b36277..1f0fd80 100644 (file)
@@ -100,16 +100,26 @@ const FileManagerSource = {
                         beforeSend: Utils.addAuthorizationStub,
                         url: 'api/file-manager?api_server=' + utils.getSearchParams(window.location).api_server +'&package_type=' + type + '&package_id=' + id + '&package_path=' + path ,
                         success: function(data) {
-                            resolve({
-                                data: data,
-                                path: path
-                            });
+                            if (data.output.status == 'True') {
+                                resolve({
+                                    data: data,
+                                    path: path
+                                });
+                            } else {
+                                reject({
+                                    data: data,
+                                    path: path
+                                })
+                            }
                         },
                         error: function(error) {
                             if (typeof error == 'string') {
                                 error = JSON.parse(error);
                             }
-                            reject(error);
+                            reject({
+                                path: path,
+                                data: error
+                            });
                         }
                     }).fail(function(xhr){
                         //Authentication and the handling of fail states should be wrapped up into a connection class.
index 9345bc3..3e4ac7f 100644 (file)
@@ -1,6 +1,6 @@
 
 /*
- * 
+ *
  *   Copyright 2016 RIFT.IO Inc
  *
  *   Licensed under the Apache License, Version 2.0 (the "License");
@@ -591,6 +591,13 @@ class CatalogDataStore {
                        this.resetSelectionState();
                }
        }
+       saveCatalogItemError(data){
+               let error = JSON.parse(data.error.responseText);
+               const errorMsg = error && error.body && error.body['rpc-reply'] && JSON.stringify(error.body['rpc-reply']['rpc-error'], null, ' ')
+               ComposerAppActions.showError.defer({
+                       errorMessage: 'Unable to save the descriptor.\n' + errorMsg
+               });
+       }
 }
 
 export default alt.createStore(CatalogDataStore, 'CatalogDataStore');
index c07fffd..c677a44 100644 (file)
@@ -172,6 +172,7 @@ class ComposerAppStore {
                        addFileSuccess: FileManagerActions.addFileSuccess,
                        deletePackageFile: FileManagerActions.deletePackageFile,
                        deleteFileSuccess: FileManagerActions.deleteFileSuccess,
+                       deleteFileError: FileManagerActions.deleteFileError,
                        closeFileManagerSockets: FileManagerActions.closeFileManagerSockets,
                        openFileManagerSockets: FileManagerActions.openFileManagerSockets,
                        openDownloadMonitoringSocketSuccess: FileManagerActions.openDownloadMonitoringSocketSuccess,
@@ -681,6 +682,15 @@ class ComposerAppStore {
                        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({
index 6c659c3..bed1dbf 100644 (file)
@@ -21,114 +21,126 @@ import './crash.scss';
 import TreeView from 'react-treeview';
 import '../node_modules/react-treeview/react-treeview.css';
 import AppHeader from 'widgets/header/header.jsx';
+import ScreenLoader from 'widgets/screen-loader/screenLoader.jsx';
 var crashActions = require('./crashActions.js');
 var crashStore = require('./crashStore.js');
 // var MissionControlStore = require('../missioncontrol/missionControlStore.js');
 function openDashboard() {
-  window.location.hash = "#/";
+    window.location.hash = "#/";
 }
 class CrashDetails extends React.Component {
-  constructor(props) {
-    super(props)
-    var self = this;
-    this.state = crashStore.getState();
-    crashStore.listen(this.storeListener);
-  }
-  storeListener = (data) => {
-     this.setState({
-        list:data.crashList,
-        noDebug:!this.hasDebugData(data.crashList)
-      });
-  }
-  componentWillUnmount(){
-    crashStore.unlisten(this.storeListener);
-  }
-  componentWillMount() {
-    crashStore.get();
-  }
-  hasDebugData(list) {
-    console.log(list);
-    if (list && list.length > 0) {
-      for (let i = 0; i < list.length; i++) {
-        var trace = list[i].backtrace;
-        for (let j = 0; j < trace.length; j++) {
-          console.log(trace[j])
-          if (trace[j].detail) {
-            return true;
-          }
+    constructor(props) {
+        super(props)
+        this.state = crashStore.getState();
+        crashStore.listen(this.storeListener);
+    }
+    storeListener = (data) => {
+        this.setState({
+            isLoading: data.isLoading,
+            list: data.crashList,
+            noDebug: !this.hasDebugData(data.crashList)
+        });
+    }
+    componentWillUnmount() {
+        crashStore.unlisten(this.storeListener);
+    }
+    componentWillMount() {
+        crashStore.get();
+    }
+    hasDebugData(list) {
+        console.log(list);
+        if (list && list.length > 0) {
+            for (let i = 0; i < list.length; i++) {
+                var trace = list[i].backtrace;
+                for (let j = 0; j < trace.length; j++) {
+                    console.log(trace[j])
+                    if (trace[j].detail) {
+                        return true;
+                    }
+                }
+            }
         }
-      }
+        return false;
     }
-    return false;
-  }
-  downloadFile(fileName, urlData) {
-    var replacedNewLines = urlData.replace(/\\n/g, '\n');
-    var replacedTabs = replacedNewLines.replace(/\\t/g, '\t');
-    var replacedQuotes= replacedTabs.replace(/\\"/g, '"');
-    var textFileBlob = new Blob([replacedQuotes], {type: 'text/plain;charset=UTF-8'});
-    var aLink = document.createElement('a');
-    var evt = document.createEvent("HTMLEvents");
-    evt.initEvent("click");
-    aLink.download = fileName;
-    aLink.href = window.URL.createObjectURL(textFileBlob);
-    aLink.dispatchEvent(evt);
-  }
-  render() {
-    let html;
-    var list = null;
-    if (this.state != null) {
-      var tree = <div style={{'marginLeft':'auto', 'marginRight':'auto', 'width':'230px', 'padding':'90px'}}> No Debug Information Available </div>;
-      if (!this.state.noDebug)
-      {
-        var tree = this.state.list && this.state.list.map((node, i) => {
-                  var vm = node.name;
-                  var vm_label = <span>{vm}</span>;
-                  var backtrace = node.backtrace;
-                  return (
-                    <TreeView key={vm + '|' + i} nodeLabel={vm_label} defaultCollapsed={false}>
-                      {backtrace.map(details => {
-
-                        //Needed to decode HTML
-                        var text_temp = document.createElement("textarea")
-                        text_temp.innerHTML = details.detail;
-                        var text_temp = text_temp.value;
-                        var arr = text_temp.split(/\n/);
-                        var text = [];
-                        for (let i = 0; i < arr.length; i++) {
-                          text.push(arr[i]);
-                          text.push(<br/>)
-                        }
+    downloadFile(fileName) {
+        // wait till download selected to create text blob
+        let urlData = JSON.stringify(this.state.list, null, 2);
+        let replacedNewLines = urlData.replace(/\\n/g, '\n');
+        let replacedTabs = replacedNewLines.replace(/\\t/g, '\t');
+        let replacedQuotes = replacedTabs.replace(/\\"/g, '"');
+        let textFileBlob = new Blob([replacedQuotes], { type: 'text/plain;charset=UTF-8' });
+        let aLink = document.createElement('a');
+        aLink.download = fileName;
+        aLink.href = window.URL.createObjectURL(textFileBlob);
+        aLink.click(); // suprise, this works without being on the page
+        // it seems to cause no problems cleaning up the blob right away
+        window.URL.revokeObjectURL(aLink.href);
+        // assuming aLink just goes away when this function ends
+    }
+    render() {
+        let html;
+        if (this.state != null) {
+            if (!this.state.noDebug) {
+                let tree = this.state.list && this.state.list.map((node, i) => {
+                    const vm = node.name;
+                    const vm_label = <span>{vm}</span>;
+                    const backtrace = node.backtrace;
+                    return (
+                        <TreeView key={vm + '|' + i} nodeLabel={vm_label} defaultCollapsed={false}>
+                            {backtrace.map(details => {
+                                // do some trickery to normalize details 'new line' char(s)
+                                let textareaElement = document.createElement("textarea")
+                                textareaElement.innerHTML = details.detail;
+                                let detailsFormatted = textareaElement.value;
+                                let arr = detailsFormatted.split(/\n/);
+                                let text = [];
+                                for (let i = 0; i < arr.length; i++) {
+                                    text.push(arr[i]);
+                                    text.push(<br key={'line-' + i} />); // react likes keys on array children
+                                }
 
-                        return (
-                          <TreeView nodeLabel={<span>{details.id}</span>} key={vm + '||' + details.id} defaultCollapsed={false}>
-                            <p>{text}</p>
-                          </TreeView>
-                        );
-                      })}
-                    </TreeView>
-                  );
-                })}
-      html = (
-        <div className="crash-details-wrapper">
-              <div className="form-actions">
-                <button role="button" className="dark" onClick={this.state.noDebug ? false : this.downloadFile.bind(this, 'crash.txt', 'data:text;charset=UTF-8,' + decodeURIComponent(JSON.stringify(this.state.list, null, 2)))}> Download Crash Details</button>
-              </div>
-              <div className="crash-container">
-                <h2> Debug Information </h2>
-                <div className="tree">{tree}</div>
-              </div>
-        </div>
-              );
-    } else {
-      html = <div className="crash-container"></div>
-    };
-    let refPage = window.sessionStorage.getItem('refPage');
-    refPage = JSON.parse(refPage);
-    return (
+                                return (
+                                    <TreeView nodeLabel={<span>{details.id}</span>} key={vm + '||' + details.id} defaultCollapsed={false}>
+                                        <p>{text}</p>
+                                    </TreeView>
+                                );
+                            })}
+                        </TreeView>
+                    );
+                });
+                let doDownload = this.downloadFile.bind(this, 'crash.txt');
+                html = (
+                    <div className="crash-details-wrapper">
+                        <div className="form-actions">
+                            <button role="button" className="dark" onClick={this.state.noDebug ? false : doDownload}>Download Crash Details</button>
+                        </div>
+                        <div className="crash-container">
+                            <h2> Debug Information </h2>
+                            <div className="tree">{tree}</div>
+                        </div>
+                    </div>
+                );
+            } else {
+                let text = this.state.isLoading ? "Loading Debug Information" : "No Debug Information Available"
+                html = (
+                    <div className="crash-details-wrapper">
+                        <div className="crash-container">
+                            <div style={{ 'marginLeft': 'auto', 'marginRight': 'auto', 'width': '230px', 'padding': '90px' }}>{text}</div>
+                        </div>
+                    </div>
+                );
+            }
+        } else {
+            html = <div className="crash-container"></div>
+        };
+        let refPage = window.sessionStorage.getItem('refPage');
+        refPage = JSON.parse(refPage);
+        return (
             <div className="crash-app">
-              {html}
+                {html}
+                <ScreenLoader show={this.state.isLoading}/> 
             </div>
-            );
-  }
+        );
+    }
 }
 export default CrashDetails;
index 51857d5..0b04445 100644 (file)
@@ -20,18 +20,29 @@ import Alt from 'widgets/skyquake_container/skyquakeAltInstance';
 function crashStore () {
   this.exportAsync(require('./crashSource.js'));
   this.bindActions(require('./crashActions.js'));
+  this.isLoading = false;
+  this.crashList = null;
 }
 
 crashStore.prototype.getCrashDetailsSuccess = function(list) {
   this.setState({
-    crashList:list
+    isLoading: false,
+    crashList: list
   })
-  console.log('success', list)
+  console.log('Crash details load success', list)
 };
 crashStore.prototype.getCrashDetailsLoading = function(info) {
+  this.setState({
+    isLoading: true,
+    crashList: null,
+  })
   console.log('Loading crash details...', info)
 };
 crashStore.prototype.getCrashDetailsFailure = function(info) {
+  this.setState({
+    isLoading: false,
+    error: info
+  })
   console.log('Failed to retrieve crash/debug details', info)
 };
 
index 6fb0170..d74bb3e 100644 (file)
@@ -790,8 +790,14 @@ NSR.addVnfrDataPromise = function(req, nsrs) {
                 try {
                     if (nsr["monitoring-param"]) {
                         nsr["monitoring-param"].map(function(m) {
-                            var vnfr = vnfrs[m["vnfr-id"]] || {};
+                            // var vnfr = vnfrs[m["vnfr-id"]] || {};
+                            // m["vnfr-name"] = vnfr['name'] ? vnfr['name'] : (vnfr['short-name'] ? vnfr['short-name'] : 'VNFR');
+                            var groupTag = m['group-tag'];
+                            var vnfrId = m['vnfr-mon-param-ref'] && m['vnfr-mon-param-ref'][0] && m['vnfr-mon-param-ref'][0]['vnfr-id-ref'];
+                            var vnfr = vnfrs[vnfrId] || {};
                             m["vnfr-name"] = vnfr['name'] ? vnfr['name'] : (vnfr['short-name'] ? vnfr['short-name'] : 'VNFR');
+                            m['group-tag'] = (groupTag ? (groupTag + ' - ') : '') + m['vnfr-name'] + (vnfrId ? ' (' + vnfrId.substring(1,8) + '...)' : '');
+
                         });
                     }
                 } catch (e) {