Merge remote-tracking branch 'origin/v1.0' 57/757/1
authorKIRAN KASHALKAR <kiran.kashalkar@riftio.com>
Sun, 4 Dec 2016 09:18:45 +0000 (04:18 -0500)
committerKIRAN KASHALKAR <kiran.kashalkar@riftio.com>
Sun, 4 Dec 2016 09:20:01 +0000 (04:20 -0500)
Signed-off-by: KIRAN KASHALKAR <kiran.kashalkar@riftio.com>
skyquake/framework/utils/utils.js
skyquake/plugins/composer/src/src/components/EditDescriptorModelProperties.js
skyquake/plugins/composer/src/src/libraries/model/DescriptorModelSerializer.js
skyquake/plugins/launchpad/src/instantiate/catalogCard.jsx
skyquake/plugins/launchpad/src/launchpad.scss
skyquake/plugins/launchpad/src/nsListPanel/nsListPanel.jsx
skyquake/plugins/launchpad/src/recordViewer/recordNavigator.jsx
skyquake/plugins/launchpad/src/recordViewer/recordViewStore.js

index 7442027..8a54ff3 100644 (file)
@@ -295,4 +295,20 @@ Utils.arrayIntersperse = (arr, sep) => {
     }, [arr[0]]);
 }
 
+Utils.cleanImageDataURI = (imageString, type, id) => {
+    if (/\bbase64\b/g.test(imageString)) {
+        return imageString;
+    } else if (/<\?xml\b/g.test(imageString)) {
+        const imgStr = imageString.substring(imageString.indexOf('<?xml'));
+        return 'data:image/svg+xml;charset=utf-8,' + encodeURIComponent(imgStr);
+    } else if (/\.(svg|png|gif|jpeg|jpg)$/.test(imageString)) {
+        return '/composer/assets/logos/' + type + '/' + id + '/' + imageString;
+        // return require('../images/logos/' + imageString);
+    }
+    if(type == 'nsd' || type == 'vnfd') {
+        return require('style/img/catalog-'+type+'-default.svg');
+    }
+    return require('style/img/catalog-default.svg');
+}
+
 module.exports = Utils;
index 20c84da..4dc4b28 100644 (file)
@@ -287,16 +287,16 @@ export default function EditDescriptorModelProperties(props) {
                                }
                                utils.assignPathValue(stateObject, [selected].join('.'), _.cloneDeep(choiceObject));
 
-                               if(this.model.uiState.choice.hasOwnProperty(name)) {
-                                       delete this.model[selected];
-                                       utils.removePathValue(this.model, [name, selected].join('.'), isTopCase);
-                               } else {
-                                       // remove the current choice value from the model
-                               utils.removePathValue(this.model, [name, selected].join('.'), isTopCase);
+                               if(selected) {
+                                       if(this.model.uiState.choice.hasOwnProperty(name)) {
+                                               delete this.model[selected];
+                                               utils.removePathValue(this.model, [name, selected].join('.'), isTopCase);
+                                       } else {
+                                               // remove the current choice value from the model
+                                               utils.removePathValue(this.model, [name, selected].join('.'), isTopCase);
+                                       }
                                }
 
-
-
                                // get any state for the new selected choice
                                const newChoiceObject = utils.resolvePath(stateObject, [value].join('.')) || {};
 
@@ -333,7 +333,7 @@ export default function EditDescriptorModelProperties(props) {
                        return {optionName: d.name};
                });
 
-               const options = [{optionName: ''}].concat(cases).map((d, i) => {
+               const options = [{optionName: '', optionValue: false}].concat(cases).map((d, i) => {
                        return (
                                <option key={i} value={d.optionValue} title={d.optionTitle}>
                                        {d.optionName}
@@ -353,7 +353,7 @@ export default function EditDescriptorModelProperties(props) {
                        if(fieldProperties) {
                                //Check each case statement in model and see if it is present in container model.
                                cases.map(function(c){
-                                       if(fieldProperties.hasOwnProperty(c.optionName)) {
+                                       if(fieldProperties.hasOwnProperty(c.optionValue.split('.')[1])) {
                                                utils.assignPathValue(container.model, ['uiState.choice', selectName, 'selected'].join('.'), c.optionValue);
                                        }
                                });
index 014beb3..8ce90cf 100644 (file)
@@ -129,7 +129,7 @@ const DescriptorModelSerializer = {
                                return DescriptorModelSerializer.serialize(d);
                        });
 
-                       return confd;
+                       return cleanEmptyTopKeys(confd);
 
                }
        },
@@ -161,7 +161,7 @@ const DescriptorModelSerializer = {
                        }
                        // fix-end
                        confd[property] = confd[property].map(d => DescriptorModelSerializer[property].serialize(d));
-                       return confd;
+                       return cleanEmptyTopKeys(confd);
                }
        },
        'vnfd-connection-point-ref': {
@@ -185,7 +185,7 @@ const DescriptorModelSerializer = {
                        if(!vnfdFields) vnfdFields = DescriptorModelMetaFactory.getModelFieldNamesForType('vnfd').concat('uiState');
                        const confd = _.pick(vnfdModel, vnfdFields);
                        confd.vdu = confd.vdu.map(d => DescriptorModelSerializer.serialize(d));
-                       return confd;
+                       return cleanEmptyTopKeys(confd);
                }
        },
        vdu: {
@@ -195,26 +195,48 @@ const DescriptorModelSerializer = {
                                checkForChoiceAndRemove(k, copy, vduModel)
                        }
                        const confd = _.omit(copy, ['uiState']);
-                       return confd;
+                       return cleanEmptyTopKeys(confd);
                }
        }
 };
 
 
 function checkForChoiceAndRemove(k, confd, model) {
-       let state = model.uiState;
-       if (state.choice) {
-               let choice = state.choice[k]
-               if(choice) {
-                       for (let key in confd[k]) {
-                               if(choice && (choice.selected.indexOf(key) > -1)) {
-                                       confd[key] = confd[k][key]
-                               }
-                       };
-                       delete confd[k];
-               }
-       }
-       return confd;
+    let state = model.uiState;
+    if (state.choice) {
+        let choice = state.choice[k]
+        if(choice) {
+            if (choice.constructor.name == "Array") {
+                for(let i = 0; i < choice.length; i++) {
+                    for (let key in confd[k][i]) {
+                        if(choice[i] && (choice[i].selected.indexOf(key) > -1)) {
+                            confd[k][i][key] = confd[k][i][key]
+                        }
+                        confd[key];
+                    };
+                }
+            } else {
+                for (let key in confd[k]) {
+                    if(choice && (choice.selected.indexOf(key) > -1)) {
+                        confd[key] = confd[k][key]
+                    }
+                };
+                delete confd[k];
+            }
+
+        }
+    }
+    return confd;
+}
+
+function cleanEmptyTopKeys(m){
+    Object.keys(m).forEach(k => {
+        const isEmptyObject = typeof m[k] === 'object' && _.isEmpty(m[k]);
+        if (typeof m[k] === 'undefined' || isEmptyObject || m[k] === '') {
+            delete m[k];
+        }
+    });
+    return m;
 }
 
 export default DescriptorModelSerializer;
index d44bd2e..cf17fc5 100644 (file)
@@ -18,6 +18,7 @@
 import './catalogCard.scss';
 import 'style/common.scss';
 import React, {Component} from 'react';
+import Utils from 'utils/utils.js'
 export default class CatalogCard extends Component {
     constructor(props) {
         super(props);
@@ -66,7 +67,7 @@ export default class CatalogCard extends Component {
                                     <div key={i} className="details-section-item">
                                         <img
                                             onError={self.handleImageError}
-                                            src={cleanDataURI(descriptor.logo, 'vnfd', descriptor.id)}
+                                            src={Utils.cleanImageDataURI(descriptor.logo, 'vnfd', descriptor.id)}
                                         />
                                         {v['name']}
                                     </div>
@@ -125,7 +126,7 @@ export default class CatalogCard extends Component {
         className = "CatalogCard " + buildClass(this.props);
         return (
             <div className={className} onClick={props.onClick} onDoubleClick={props.onDoubleClick}>
-                <img className="CatalogCard-thumbnail"  onError={this.handleImageError} src={cleanDataURI(descriptor.logo, 'nsd', descriptor.id)} />
+                <img className="CatalogCard-thumbnail"  onError={this.handleImageError} src={Utils.cleanImageDataURI(descriptor.logo, 'nsd', descriptor.id)} />
                 <div className="CatalogCard-body">
                     <div className="CatalogCard-header">
                         <div className="CatalogCard-name">
@@ -178,19 +179,3 @@ function cardHandler(element) {
         ''
     }
 }
-
-function cleanDataURI(imageString, type, id) {
-        if (/\bbase64\b/g.test(imageString)) {
-            return imageString;
-        } else if (/<\?xml\b/g.test(imageString)) {
-            const imgStr = imageString.substring(imageString.indexOf('<?xml'));
-            return 'data:image/svg+xml;charset=utf-8,' + encodeURIComponent(imgStr);
-        } else if (/\.(svg|png|gif|jpeg|jpg)$/.test(imageString)) {
-            return '/composer/assets/logos/' + type + '/' + id + '/' + imageString;
-            // return require('../images/logos/' + imageString);
-        }
-        if(type == 'nsd' || type == 'vnfd') {
-            return require('style/img/catalog-'+type+'-default.svg');
-        }
-        return require('style/img/catalog-default.svg');
-    }
index 927727a..b871f51 100644 (file)
       -ms-flex-flow: col wrap;
           flex-flow: col wrap;
     }
+
+    .nsrSummary {
+      font-size: 50%;
+      padding-top: 1rem;
+      .nsrSummaryItem {
+        padding-right: 0.5rem;
+      }
+    }
   }
 
   .nsListPanelToggle {
index c8c8412..c391392 100644 (file)
@@ -326,10 +326,47 @@ export default class NsListPanel extends React.Component {
         const {nsrs, openedNsrIDs, emptyRows, isVisible, ...props} = this.props;
         const fieldKeys = FIELD_KEYS;
         let glyphValue = (isVisible) ? "chevron-left" : "chevron-right";
+
+        let totalNSRs = nsrs && nsrs.length;
+        let runningNSRs = 0;
+        let failedNSRs = 0;
+        let scalingOutNSRs = 0;
+        let scalingInNSRs = 0;
+        let initializingNSRs = 0;
+
+        nsrs && nsrs.map((nsr) => {
+            nsr['operational-status'] == 'running' && runningNSRs++;
+            nsr['operational-status'] == 'failed' && failedNSRs++;
+            nsr['operational-status'] == 'scaling-out' && scalingOutNSRs++;
+            nsr['operational-status'] == 'scaling-in' && scalingInNSRs++;
+            (
+                nsr['operational-status'] == 'init' ||
+                nsr['operational-status'] == 'vl-init-phase' ||
+                nsr['operational-status'] == 'vnf-init-phase'
+            ) && initializingNSRs++;
+        });
+
+
         if (isVisible) {
+
+            let title = (
+                <div>
+                    NETWORK SERVICES
+                    <div className='nsrSummary'>
+                        <span className='nsrSummaryItem'>Total: {totalNSRs}</span>
+                        <span className='nsrSummaryItem'>Running: {runningNSRs}</span>
+                        <span className='nsrSummaryItem'>Failed: {failedNSRs}</span>
+                        <span className='nsrSummaryItem'>Scaling Out: {scalingOutNSRs}</span>
+                        <span className='nsrSummaryItem'>Scaling In: {scalingInNSRs}</span>
+                        <span className='nsrSummaryItem'>Initializing: {initializingNSRs}</span>
+                    </div>
+                </div>
+            );
+
+
             return (
                 <DashboardCard className="nsListPanel" showHeader={true}
-                    title="NETWORK SERVICES">
+                    title={title}>
                     {this.panelToolbar()}
                     <a onClick={this.handleShowHideToggle(!isVisible)}
                         className={"nsListPanelToggle"}>
index d7a86d4..95107ca 100644 (file)
@@ -20,13 +20,29 @@ import React from 'react';
 import RecordViewActions from './recordViewActions.js';
 import LoadingIndicator from 'widgets/loading-indicator/loadingIndicator.jsx';
 import DashboardCard from 'widgets/dashboard_card/dashboard_card.jsx';
+import Utils from 'utils/utils.js';
+
 import './recordNavigator.scss';
-import nsdImg from 'style/img/catalog-default.svg';
 
 export default class RecordNavigator extends React.Component{
   constructor(props) {
     super(props)
   }
+  handleImageError = (e) => {
+      console.log('Bad logo path, using default');
+      e.target.src = require('style/img/catalog-default.svg');
+  }
+
+  getDescriptorTypeFromRecordType = (recordType) => {
+      if (recordType == 'nsr') {
+          return 'nsd';
+      } else if (recordType == 'vnfr') {
+          return 'vnfd';
+      }
+
+      return null;
+  }
+
   render(){
     let navClass = 'catalogItems';
 
@@ -53,7 +69,10 @@ export default class RecordNavigator extends React.Component{
           }
           navObj.push(
             <div key={'id' + k + '-' + vnfr.id}  onClick={self.props.loadRecord.bind(self,vnfr)} className={iClassName}>
-              <img src={nsdImg} />
+              <img
+                  onError={self.handleImageError}
+                  src={Utils.cleanImageDataURI(vnfr.logo, self.getDescriptorTypeFromRecordType(vnfr.type), vnfr.logoId)}
+              />
               <section id={vnfr.id}>
               <h1 title={vnfr.name}>{vnfr.name}</h1>
                 <h2>{vnfr.type}</h2>
@@ -67,7 +86,10 @@ export default class RecordNavigator extends React.Component{
         }
         navObj.push(
           <div key={'id' + k + '-' + n.id}  onClick={self.props.loadRecord.bind(self,n)} className={itemClassName}>
-            <img src={nsdImg} />
+            <img
+                onError={self.handleImageError}
+                src={Utils.cleanImageDataURI(n.logo, self.getDescriptorTypeFromRecordType(n.type), n.logoId)}
+            />
             <section id={n.id}>
             <h1 title={n.name}>{n.name}</h1>
               <h2>{n.type}</h2>
index b9fded5..b9f7499 100644 (file)
@@ -407,7 +407,9 @@ function connectionManager(type, connection) {
                 name: nsrs.name,
                 id: nsrs.id,
                 nsd_name: nsrs.nsd_name,
-                type: 'nsr'
+                type: 'nsr',
+                logo: nsrs.nsd && nsrs.nsd.logo,
+                logoId: nsrs.nsd && nsrs.nsd && nsrs.nsd.id
             });
 
             // Scaled VNFRs
@@ -424,10 +426,13 @@ function connectionManager(type, connection) {
 
                     sgInstance['vnfrs'] && sgInstance['vnfrs'].map((vnfr, vnfrIndex) => {
                         scaledVnfrs.push(vnfr);
+                        let vnfrObj = _.findWhere(nsrs.vnfrs, {id: vnfr});
                         scaledVnfNav.vnfr.push({
-                            name: _.findWhere(nsrs.vnfrs, {id: vnfr})['short-name'],
+                            name: vnfrObj['short-name'],
                             id: vnfr,
-                            type: 'vnfr'
+                            type: 'vnfr',
+                            logo: vnfrObj['vnfd'] && vnfrObj['vnfd']['logo'],
+                            logoId: vnfrObj['vnfd'] && vnfrObj['vnfd']['id']
                         });
                     });
                     nav.push(scaledVnfNav);
@@ -440,7 +445,9 @@ function connectionManager(type, connection) {
                     nav.push({
                         name: vnfr["short-name"],
                         id: vnfr.id,
-                        type: 'vnfr'
+                        type: 'vnfr',
+                        logo: vnfr['vnfd'] && vnfr['vnfd']['logo'],
+                        logoId: vnfr['vnfd'] && vnfr['vnfd']['id']
                     });
                 }
             });