Merge branch 'master' into v1.0 67/567/1
authorRajesh <rajesh.velandy@riftio.com>
Sat, 22 Oct 2016 12:42:59 +0000 (12:42 +0000)
committerRajesh Velandy <rajesh.velandy@riftio.com>
Sat, 22 Oct 2016 12:50:53 +0000 (12:50 +0000)
Signed-off-by: Rajesh Velandy <rajesh.velandy@riftio.com>
Author:    rajesh.velandy@riftio.com
Date:      Sat Oct 22 12:42:59 2016 +0000
Signed-off-by: Rajesh Velandy <rajesh.velandy@riftio.com>
26 files changed:
skyquake/plugins/accounts/src/account_sidebar/accountSidebar.jsx
skyquake/plugins/composer/src/src/components/EditDescriptorModelProperties.js
skyquake/plugins/composer/src/src/libraries/model/DescriptorModel.js
skyquake/plugins/composer/src/src/libraries/model/DescriptorModelFactory.js
skyquake/plugins/composer/src/src/libraries/model/DescriptorModelSerializer.js
skyquake/plugins/composer/src/src/libraries/model/descriptors/InternalConnectionPoint.js
skyquake/plugins/composer/src/src/libraries/model/descriptors/InternalConnectionPointRef.js
skyquake/plugins/composer/src/src/libraries/model/descriptors/InternalVirtualLink.js
skyquake/plugins/composer/src/src/libraries/model/descriptors/VirtualDeploymentUnitInternalConnectionPoint.js
skyquake/plugins/composer/src/src/libraries/model/descriptors/VirtualLink.js
skyquake/plugins/launchpad/src/carousel/carousel-react.jsx
skyquake/plugins/launchpad/src/instantiate/instantiateInputParams.jsx
skyquake/plugins/launchpad/src/instantiate/instantiateInputParams.scss
skyquake/plugins/launchpad/src/instantiate/instantiateStore.js
skyquake/plugins/launchpad/src/launchpad.scss
skyquake/plugins/launchpad/src/monitoring_params/monitoringParamComponents.js
skyquake/plugins/launchpad/src/recordViewer/recordCard.jsx
skyquake/plugins/launchpad/src/recordViewer/recordViewStore.js
skyquake/plugins/launchpad/src/virtual_links/nsVirtualLinkCreateStore.js
skyquake/plugins/logging/api/logging.js
skyquake/plugins/logging/api/transforms.js
skyquake/plugins/logging/routes.js
skyquake/plugins/logging/src/categorySeverityGrid.jsx
skyquake/plugins/logging/src/loggingGeneral.jsx
skyquake/plugins/logging/src/loggingSource.js
skyquake/plugins/logging/src/loggingStore.js

index 6276194..723d893 100644 (file)
@@ -92,6 +92,7 @@ class AccountSidebar extends React.Component{
                      <header>
                         <Link to={'accounts/sdn/' + account.name} title="Edit Account">
                          <div className="accountSidebarCard--content">
+                            <img className="accountSidebarCard--logo" src={store.getImage(account['account-type'])} />
                             <h3>{account.name}<AccountConnectivityStatus status={status}/></h3>
                         </div>
                 </Link>
index 36e7445..59d2f95 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * 
+ *
  *   Copyright 2016 RIFT.IO Inc
  *
  *   Licensed under the Apache License, Version 2.0 (the "License");
@@ -182,6 +182,7 @@ export default function EditDescriptorModelProperties(props) {
                const onFocus = onFocusPropertyFormInputElement.bind(container, property, path, value);
                const placeholder = changeCase.title(property.name);
                const className = ClassNames(property.name + '-input', {'-is-guid': isGuid});
+               const fieldValue = value ? value.constructor.name == "String" ? value : '' : undefined;
                if (isEnumeration) {
                        const enumeration = Property.getEnumeration(property, value);
                        const options = enumeration.map((d, i) => {
@@ -207,7 +208,7 @@ export default function EditDescriptorModelProperties(props) {
                                          id={fieldKey.toString()}
                                          type="text"
                                          name={name}
-                                         value={value}
+                                         value={fieldValue}
                                          className={className}
                                          placeholder={placeholder}
                                          onChange={onChange}
@@ -229,8 +230,9 @@ export default function EditDescriptorModelProperties(props) {
                        if (typeof value === 'object') {
                                childValue = value[property.name];
                        }
-                       childPath.push(property.name);
-
+                       if(property.type != 'choice'){
+                                               childPath.push(property.name);
+                       }
                        return build(container, property, childPath, childValue);
 
                });
@@ -271,17 +273,18 @@ export default function EditDescriptorModelProperties(props) {
 
                                const statePath = ['uiState.choice'].concat(name);
                                const stateObject = utils.resolvePath(this.model, statePath.join('.')) || {};
+                               const selected = stateObject.selected ? stateObject.selected.split('.')[1] : undefined;
                                // write state back to the model so the new state objects are captured
                                utils.assignPathValue(this.model, statePath.join('.'), stateObject);
 
                                // write the current choice value into the state
-                               const choiceObject = utils.resolvePath(this.model, [name, stateObject.selected].join('.'));
+                               const choiceObject = utils.resolvePath(this.model, [name, selected].join('.'));
                                if (choiceObject) {
-                                       utils.assignPathValue(stateObject, ['case', stateObject.selected].join('.'), _.cloneDeep(choiceObject));
+                                       utils.assignPathValue(stateObject, ['case', selected].join('.'), _.cloneDeep(choiceObject));
                                }
 
                                // remove the current choice value from the model
-                               utils.removePathValue(this.model, [name, stateObject.selected].join('.'));
+                               utils.removePathValue(this.model, [name, selected].join('.'));
 
                                // get any state for the new selected choice
                                const newChoiceObject = utils.resolvePath(stateObject, ['case', value].join('.')) || {};
@@ -303,7 +306,12 @@ export default function EditDescriptorModelProperties(props) {
                const cases = property.properties.map(d => {
                        if (d.type === 'case') {
                                caseByNameMap[d.name] = d.properties[0];
-                               return {optionName: d.name, optionTitle: d.description};
+                               return {
+                                       optionName: d.name,
+                                       optionTitle: d.description,
+                                       //represents case name and case element name
+                                       optionValue: [d.name, d.properties[0].name].join('.')
+                               };
                        }
                        caseByNameMap[d.name] = d;
                        return {optionName: d.name};
@@ -311,7 +319,7 @@ export default function EditDescriptorModelProperties(props) {
 
                const options = [{optionName: ''}].concat(cases).map((d, i) => {
                        return (
-                               <option key={i} value={d.optionName} title={d.optionTitle}>
+                               <option key={i} value={d.optionValue} title={d.optionTitle}>
                                        {d.optionName}
                                        {i ? null : changeCase.title(property.name)}
                                </option>
@@ -319,11 +327,30 @@ export default function EditDescriptorModelProperties(props) {
                });
 
                const selectName = path.join('.');
-               const selectedOptionPath = ['uiState.choice', selectName, 'selected'].join('.');
-               const selectedOptionValue = utils.resolvePath(container.model, selectedOptionPath);
-               const valueProperty = caseByNameMap[selectedOptionValue] || {properties: []};
-
-               const valueResponse = valueProperty.properties.map((d, i) => {
+               let selectedOptionPath = ['uiState.choice', selectName, 'selected'].join('.');
+               //Currently selected choice/case statement on UI model
+               let selectedOptionValue = utils.resolvePath(container.model, selectedOptionPath);
+               //If first time loaded, and none is selected, check if there is a value corresponding to a case statement in the container model
+               if(!selectedOptionValue) {
+                       //get field properties for choice on container model
+                       let fieldProperties = utils.resolvePath(container.model, selectName);
+                       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)) {
+                                               utils.assignPathValue(container.model, ['uiState.choice', selectName, 'selected'].join('.'), c.optionValue);
+                                       }
+                               });
+                               selectedOptionValue = utils.resolvePath(container.model, ['uiState.choice', selectName, 'selected'].join('.'));
+                       }
+               }
+               //If selectedOptionValue is present, take first item in string which represents the case name.
+               const valueProperty = caseByNameMap[selectedOptionValue ? selectedOptionValue.split('.')[0] : undefined] || {properties: []};
+               const isLeaf = Property.isLeaf(valueProperty);
+               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.length ? valueProperty.properties.map((d, i) => {
                        const childPath = path.concat(valueProperty.name, d.name);
                        const childValue = utils.resolvePath(container.model, childPath.join('.'));
                        return (
@@ -331,8 +358,8 @@ export default function EditDescriptorModelProperties(props) {
                                        {build(container, d, childPath, childValue, props)}
                                </div>
                        );
-               });
-
+               }) : (!isMissingDescriptorMeta) ? build(container, valueProperty, path.concat(valueProperty.name), utils.resolvePath(container.model, path.concat(valueProperty.name).join('.'))) : null
+               // end magic
                const onFocus = onFocusPropertyFormInputElement.bind(container, property, path, value);
 
                return (
index 02bbfcd..1a2ba4f 100644 (file)
@@ -182,7 +182,10 @@ export default class DescriptorModel {
                        throw new ReferenceError('child must be an instance of DescriptorModel class');
                }
                if (this.findChildByUid(child.uid)) {
-                       throw new ReferenceError('child already exists');
+                       console.warn('Child already exists');
+                       // NOTE: Commented out this line because it was causing issues with Internal VLD.
+                       // TODO: Check why it caused issues with Internal VLD
+                       // throw new ReferenceError('child already exists');
                }
                if (child.parent instanceof DescriptorModel) {
                        throw new ReferenceError('child already has a parent');
index 68b70d7..ac59872 100644 (file)
@@ -262,7 +262,7 @@ class DescriptorModelFactory {
 
        static newInternalConnectionPointRef(model, parent) {
                // note do not find children bc model is not an object it is a leaf-list primative and so the class manages it
-               return new InternalConnectionPointRef(model, parent);
+               return findChildDescriptorModelAndUpdateModel(model, parent) || new InternalConnectionPointRef(model, parent);
        }
 
        /**
index 7581ed5..4e6b792 100644 (file)
@@ -165,6 +165,11 @@ const DescriptorModelSerializer = {
                        return _.pick(ref, ['member-vnf-index-ref', 'vnfd-id-ref', 'vnfd-connection-point-ref']);
                }
        },
+       'internal-connection-point': {
+               serialize(ref) {
+                       return _.pick(ref, ['id-ref']);
+               }
+       },
        'constituent-vnfd': {
                serialize(cvnfdModel) {
                        if(!cvnfdFields) cvnfdFields = DescriptorModelMetaFactory.getModelFieldNamesForType('nsd.constituent-vnfd');
index 6648dc9..14a74f0 100644 (file)
  *   limitations under the License.
  *
  */
-/**
- * Created by onvelocity on 11/23/15.
- */
 
 'use strict';
 
-import Position from '../../graph/Position'
-import DescriptorModel from '../DescriptorModel'
-import DescriptorModelFactory from '../DescriptorModelFactory'
+import Position from '../../graph/Position';
+import DescriptorModel from '../DescriptorModel';
+import DescriptorModelFactory from '../DescriptorModelFactory';
+import InternalConnectionPointRef from './InternalConnectionPointRef';
 
 export default class InternalConnectionPoint extends DescriptorModel {
 
@@ -56,8 +54,31 @@ export default class InternalConnectionPoint extends DescriptorModel {
                return this.id;
        }
 
+       get id() {
+               return this.model.id;
+       }
+
+       get name() {
+               return this.model.name
+       }
+
+       get idRef() {
+               return this.parent.idRef;
+       }
+
+       get cpNumber() {
+               return this.uiState.cpNumber;
+       }
+
+       set cpNumber(n) {
+               this.uiState.cpNumber = n;
+       }
+
        toInternalConnectionPointRef() {
-               return DescriptorModelFactory.newInternalConnectionPointRef(this.id);
+               const ref = new InternalConnectionPointRef({});
+               ref.idRef = this.id;
+               // ref.cpNumber = this.cpNumber;
+               return ref;
        }
 
        canConnectTo(obj) {
index a7ea751..ad70b57 100644 (file)
@@ -15,9 +15,6 @@
  *   limitations under the License.
  *
  */
-/**
- * Created by onvelocity on 11/23/15.
- */
 
 'use strict';
 
@@ -27,7 +24,7 @@ import DescriptorModelFactory from '../DescriptorModelFactory'
 export default class InternalConnectionPointRef extends DescriptorModel {
 
        static get type() {
-               return 'internal-connection-point-ref';
+               return 'internal-connection-point';
        }
 
        static get className() {
@@ -39,23 +36,35 @@ export default class InternalConnectionPointRef extends DescriptorModel {
        }
 
        constructor(m, parent) {
-               super(!m || typeof m === 'string' ? {id: m, isLeaf: true} : m, parent);
+               super(m, parent);
                this.uid = this.id;
                this.type = InternalConnectionPointRef.type;
                this.uiState['qualified-type'] = InternalConnectionPointRef.qualifiedType;
                this.className = InternalConnectionPointRef.className;
        }
 
-       toString() {
-               return this.valueOf();
+       get key() {
+               return this.model['id-ref'];
        }
 
-       remove() {
-               return this.parent.removeInternalConnectionPointRefForId(this.id);
+       get idRef() {
+               return this.model['id-ref'];
        }
 
-       valueOf() {
-               return this.id;
+       set idRef(id) {
+               return this.model['id-ref'] = id;
+       }
+
+       get cpNumber() {
+               return this.uiState.cpNumber;
+       }
+
+       set cpNumber(n) {
+               this.uiState.cpNumber = n;
+       }
+
+       remove() {
+               return this.parent.removeInternalConnectionPointRefForId(this.idRef);
        }
 
 }
index c3822d5..b3e4fc6 100644 (file)
  *   limitations under the License.
  *
  */
-/**
- * Created by onvelocity on 11/23/15.
- */
 
 'use strict';
 
 import DescriptorModel from '../DescriptorModel'
 import DescriptorModelFactory from '../DescriptorModelFactory'
+import DescriptorModelMetaFactory from '../DescriptorModelMetaFactory'
 
 export default class InternalVirtualLink extends DescriptorModel {
 
@@ -50,22 +48,37 @@ export default class InternalVirtualLink extends DescriptorModel {
        }
 
        get connection() {
-               const list = this.model['internal-connection-point-ref'] || (this.model['internal-connection-point-ref'] = []);
-               return list.map(d => DescriptorModelFactory.newInternalConnectionPointRef(d, this));
+               if (!this.model['internal-connection-point']) {
+                       this.model['internal-connection-point'] = [];
+               }
+               return this.model['internal-connection-point'].map(d => DescriptorModelFactory.newInternalConnectionPointRef(d, this));
        }
 
        set connection(connections) {
-               return this.updateModelList('internal-connection-point-ref', connections, DescriptorModelFactory.InternalConnectionPointRef);
+               return this.updateModelList('internal-connection-point', connections, DescriptorModelFactory.InternalConnectionPointRef);
+       }
+
+       createInternalConnectionPoint(model) {
+               model = model || DescriptorModelMetaFactory.createModelInstanceForType('vnfd.internal-vld.internal-connection-point');
+               return this.connection = DescriptorModelFactory.newInternalConnectionPointRef(model, this);
+       }
+
+       removeInternalConnectionPointRefForIdRefKey(cpRefKey) {
+               const child = this.connection.filter(d => d.key === cpRefKey)[0];
+               return this.removeModelListItem('connection', child);
        }
 
        addConnectionPoint(icp) {
-               icp.model['internal-vld-ref'] = this.id;
                this.parent.removeAnyConnectionsForConnector(icp);
-               this.connection = icp.toInternalConnectionPointRef();
+               const icpRef = icp.toInternalConnectionPointRef();
+               // this.connection = icp.toInternalConnectionPointRef();
+               this.connection = this.connection.concat(icpRef);
        }
 
-       removeInternalConnectionPointRefForId(id) {
-               return this.connection = this.connection.filter(d => d.id !== id).map(d => d.id);
+       removeInternalConnectionPointRefForId(idRef) {
+               // return this.connection = this.connection.filter(d => d.idRef !== idRef).map(d => d.idRef);
+               // KKTODO: Check if below works instead
+               return this.connection = this.connection.filter(d => d.idRef !== idRef).map(d => d.model);
        }
 
        remove() {
index 47947c8..c34d823 100644 (file)
  *   limitations under the License.
  *
  */
-/**
- * Created by onvelocity on 11/23/15.
- */
 
 'use strict';
 
 import Position from '../../graph/Position'
-import DescriptorModel from '../DescriptorModel'
 import InternalConnectionPoint from './InternalConnectionPoint'
-import RspConnectionPointRef from './RspConnectionPointRef'
-import VnfdConnectionPointRef from './VnfdConnectionPointRef'
-import DescriptorModelFactory from '../DescriptorModelFactory'
+
 
 /**
- * A VirtualNetworkFunctionConnectionPoint is always a child of a VNFD. We use it to build VnfdConnectionPointRef instances. So convenience
+ * A VirtualDeploymentUnitInternalConnectionPoint is always a child of a VDU.
+ * We use it to build internal-connection-point.id-ref instances. So convenience
  * methods are add to access the fields needed to do that.
  */
 export default class VirtualDeploymentUnitInternalConnectionPoint extends InternalConnectionPoint {
index e3fd003..edc19f9 100644 (file)
@@ -1,6 +1,6 @@
 
 /*
- * 
+ *
  *   Copyright 2016 RIFT.IO Inc
  *
  *   Licensed under the Apache License, Version 2.0 (the "License");
@@ -128,7 +128,6 @@ var SimpleSlider = React.createClass({
         list.push(<div key={i}  className={"component"}><h2 style={{flex: '0 1 auto', justifyContent: 'center', alignSelf: 'center', display: displayTitle, padding: '0.5rem'}}>{title}</h2><div className="componentWrapper">{this.props.component_list[i].component}</div></div>);
       }
     }
-
     return (
       <div className={list.length > 1 ? '' : 'hideButtons'}>
         <Slider {...settings}>
index dc40ed6..d1e295c 100644 (file)
@@ -82,7 +82,7 @@ export default class InstantiateInputParams extends Component {
                         isOpenMano(props.ro) ?
                           dataCentersHTML(
                                           props.dataCenters[props.ro.name],
-                                          props.vnfFn.updateSelectedDataCenter.bind(null, v['member-vnf-index']))
+                                          props.vnfFn.updateSelectedDataCenter.bind(null, v['member-vnf-index']), true)
                           : null
                       }
                       {
@@ -259,10 +259,11 @@ export default class InstantiateInputParams extends Component {
             {vlds && vlds.map(function(v, i) {
                   let currentType = v.type;
                   let isVIM = (currentType == 'vim-network-name');
-                  let isUnknown = (currentType == 'unknown') || ((currentType != 'vim-network-name') && (currentType != 'ip-profile-ref'));
+                  let isUnknown = (currentType == 'none') || ((currentType != 'vim-network-name') && (currentType != 'ip-profile-ref'));
                   return (
                     <div key={self.props.nsd.id + '-' + i} className="inputControls">
                         <h4 className="inputControls-title">VLD: {v['short-name'] ? v['short-name'] : v['name']}</h4>
+                        <label><span>Specify VLD Parameters</span></label>
                         <div  className="inputControls-radioGroup">
                           <label className="inputControls-radio" style={{display: ipProfileList ? 'flex' : 'none'}}>
                             <input type="radio" name={'vld-' + i } onChange={self.props.vldFn.updateType(i)} checked={!isVIM && !isUnknown} value='ip-profile-ref' />
@@ -273,8 +274,8 @@ export default class InstantiateInputParams extends Component {
                             VIM Network Name
                           </label>
                           <label className="inputControls-radio">
-                            <input type="radio" name={'vld-' + i } onChange={self.props.vldFn.updateType(i)} checked={isUnknown} value='unknown' />
-                            Unknown
+                            <input type="radio" name={'vld-' + i } onChange={self.props.vldFn.updateType(i)} checked={isUnknown} value='none' />
+                            None
                           </label>
                         </div>
                           {
@@ -354,6 +355,11 @@ export default class InstantiateInputParams extends Component {
                     onChange={props.ipProfileFn.updateProfile(j, 'security-group')}
                     value={ipl['security-group']}
                     />
+                  <TextInput
+                    label="subnet prefix pool"
+                    onChange={props.ipProfileFn.updateProfile(j, 'subnet-prefix-pool')}
+                    value={ipl['subnet-prefix-pool']}
+                    />
                     <label>
                       <div style={{display:'flex'}}>
                         DNS SERVERS <span onClick={props.dnsFn.addDNS(j)} className="addInput"><img src={imgAdd} />Add</span>
@@ -363,8 +369,8 @@ export default class InstantiateInputParams extends Component {
                           return (
                             <div key={k} style={{display:'flex'}}>
                               <TextInput
-                                  onChange={props.ipProfileFn.updateProfile(j,k)}
-                                  value={ipl['dns-server'][k]}
+                                  onChange={props.dnsFn.updateDNS(j,k)}
+                                  value={ipl['dns-server'][k].address}
                                   />
                               <span onClick={props.dnsFn.removeDNS(j,k)} className="removeInput">
                                 <img src={imgRemove} />Remove</span>
@@ -403,12 +409,12 @@ export default class InstantiateInputParams extends Component {
     function dhcpHTML(props, ipl, j){
       return (<div>
                   <TextInput
-                    label="DCHP Start Address"
+                    label="DHCP Start Address"
                     onChange={props.ipProfileFn.updateDHCP(j, 'start-address')}
                     value={ipl['dhcp-params'] && ipl['dhcp-params']['start-address']}
                     />
                   <TextInput
-                    label="DCHP Count"
+                    label="DHCP Count"
                     onChange={props.ipProfileFn.updateDHCP(j, 'count')}
                     value={ipl['dhcp-params'] && ipl['dhcp-params']['count']}
                     />
@@ -471,14 +477,61 @@ export default class InstantiateInputParams extends Component {
   }
   usersHTML = (props) => {
     let usersFn = props.usersFn;
+    let sshKeysList = props.sshKeysList;
     let usersList = props.usersList && props.usersList.map(function(u, i) {
+      let sshKeysRef = u['ssh-authorized-key'];
       return (
         <div className="input_group input_group-users" key={i}>
           <div className="inputControls">
           <div style={{fontWeight: 'bold', display: 'flex'}}>USER <span onClick={usersFn.remove(i)} className="removeInput"><img src={imgRemove} />Remove</span></div>
             <TextInput onChange={usersFn.update(i, 'name')} label="USERNAME" value={i.name} />
-            <TextInput onChange={usersFn.update(i, 'gecos')} label="REAL NAME" value={i.gecos} />
-            <TextInput onChange={usersFn.update(i, 'passwd')} type="password" label="PASSWORD" value={i.passwd} />
+            <TextInput onChange={usersFn.update(i, 'user-info')} label="REAL NAME" value={i.gecos} />
+            {
+              sshKeysRef.map(function(ref, j) {
+                let keyref = JSON.stringify(ref)
+                return (
+                  <div key={keyref.name + '-' + i + '-' + j} className="inputControls inputControls-sshkeys">
+                    <label>
+                      <div>
+                      <SelectOption
+                        label="Key Pair"
+                        options={sshKeysList && sshKeysList.map(function(k) {
+                          return {
+                            label: k.name,
+                            value: k
+                          }
+                        })}
+                        ref="keyPairSelection"
+                        initial={false}
+                        defaultValue={ref}
+                        onChange={usersFn.updateSSHkeyRef(i, j)}>
+                      </SelectOption>
+                      </div>
+                    </label>
+                    {
+                      sshKeysRef.length > 0 ?
+                        <label>
+                          <span onClick={usersFn.updateSSHkeyRef(i, j, true)} className="removeInput">
+                            <img src={imgRemove} />
+                            Remove
+                          </span>
+                        </label>
+                      : null
+                    }
+
+                  </div>
+                )
+              })
+            }
+              <div className="inputControls inputControls-sshkeys ">
+                <label style={{display: 'flex', 'flexDirection': 'row', 'alignItems': 'center'}}>
+                SSH KEY PAIR
+                  <span onClick={usersFn.updateSSHkeyRef(i).bind(null, {target:{value: JSON.stringify(sshKeysList[0])}})} className="addInput">
+                    <img src={imgAdd} />
+                    ADD
+                  </span>
+                </label>
+              </div>
           </div>
         </div>
       )
@@ -487,9 +540,9 @@ export default class InstantiateInputParams extends Component {
       <div className="configure-nsd_section">
         <h3 className="launchpadCard_title">USERS</h3>
         {usersList}
-        <div className="inputControls inputControls-sshkeys ">
-            <span onClick={usersFn.add} className="addInput">
-              <img src={imgAdd} onClick={usersFn.add} />
+        <div className="inputControls inputControls-sshkeys inputControls-addUser ">
+            <span onClick={usersFn.add(sshKeysList)} className="addInput">
+              <img src={imgAdd} />
               ADD USER
             </span>
         </div>
@@ -574,7 +627,7 @@ function constructCloudAccountOptions(cloudAccounts){
   });
   return CloudAccountOptions;
 }
-function dataCentersHTML(dataCenters, onChange) {
+function dataCentersHTML(dataCenters, onChange, initial) {
   //Build DataCenter options
   //Relook at this, why is it an object?
   let DataCenterOptions = [];
@@ -587,7 +640,7 @@ function dataCentersHTML(dataCenters, onChange) {
   if (dataCenters && dataCenters.length > 0) {
     return (
       <label>Select Data Center
-        <SelectOption options={DataCenterOptions} onChange={onChange} />
+        <SelectOption initial={!!initial} options={DataCenterOptions} onChange={onChange} />
       </label>
     )
   }
index 3494316..ba96660 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * 
+ *
  *   Copyright 2016 RIFT.IO Inc
  *
  *   Licensed under the Apache License, Version 2.0 (the "License");
               -ms-flex: 0 1;
                   flex: 0 1;
             }
+            .inputControls-sshkeys {
+              margin-bottom:1rem;
+              padding-top:0;
+              -ms-flex-align: end;
+              align-items: flex-end;
+              > label {
+                width:auto;
+                &:nth-child(2) {
+                    margin-bottom: 1.25rem;
+                }
+              }
+            }
           }
           button {
             /*remove button*/
         display:-ms-flexbox;
         display:flex;
       }
+      &-addUser {
+        margin-top:1rem;
+        .addInput {
+          margin-left:0;
+          font-size:1rem;
+          >span {
+            color: #5b5b5b;
+          }
+        }
+      }
     }
      .addInput, .removeInput {
           display:-ms-flexbox;
index 96c134d..4807816 100644 (file)
@@ -233,7 +233,7 @@ class LaunchNetworkServiceStore {
                     if(v['vim-network-name']) {
                         v.type = 'vim-network-name';
                     } else {
-                        v.type = 'unknown';
+                        v.type = 'none';
                     }
                 }
                 return v;
@@ -447,7 +447,7 @@ class LaunchNetworkServiceStore {
                     } else {
                         delete vld[i]['dns-server'];
                     }
-                    if(type == 'unknown') {
+                    if(type == 'none') {
                         delete vld[i]['ip-profile-ref'];
                         delete vld[i]['vim-network-name'];
                     }
@@ -509,7 +509,9 @@ class LaunchNetworkServiceStore {
                     }
                     //Removing DCHP property on disable to allow instantiation
                     if(!value) {
-                        delete self.ipProfiles[i]['ip-profile-params']['dhcp-params'];
+                        self.ipProfiles[i]['ip-profile-params']['dhcp-params'] = {
+                            enabled: false
+                        };
                     } else {
                         self.ipProfiles[i]['ip-profile-params']['dhcp-params'][property] = value;
                     }
@@ -525,9 +527,9 @@ class LaunchNetworkServiceStore {
                 let self = this;
                 return function(e) {
                     if(self.ipProfiles[i]['ip-profile-params']['dns-server']) {
-                        self.ipProfiles[i]['ip-profile-params']['dns-server'].unshift('')
+                        self.ipProfiles[i]['ip-profile-params']['dns-server'].unshift({})
                     } else {
-                        self.ipProfiles[i]['ip-profile-params']['dns-server'] = [''];
+                        self.ipProfiles[i]['ip-profile-params']['dns-server'] = [{}];
                     }
 
                     self.setState({ipProfiles:self.ipProfiles});
@@ -542,6 +544,14 @@ class LaunchNetworkServiceStore {
                     }
                     self.setState({ipProfiles:self.ipProfiles});
                 }
+            },
+            updateDNS: (i, k) => {
+                let self = this;
+                return function(e) {
+                    let value = e.target.value;
+                    self.ipProfiles[i]['ip-profile-params']['dns-server'][k].address = value;
+                    self.setState({ipProfiles:self.ipProfiles});
+                }
             }
         }
     }
@@ -582,18 +592,19 @@ class LaunchNetworkServiceStore {
     usersFn = () => {
         let self = this;
         return {
-            add: function() {
-                console.log('adding user')
-                let newUser = {
-                    name: '',
-                    gecos: '',
-                    passwd: ''
+            add: function(sshKeysList) {
+                return function(e) {
+                    let newUser = {
+                        name: '',
+                        'user-info': '',
+                        'ssh-authorized-key': [sshKeysList[0].name]
+                    }
+                    let usersList = self.usersList;
+                    usersList.push(newUser);
+                    self.setState({
+                        usersList:  usersList
+                    })
                 }
-                let usersList = self.usersList;
-                usersList.push(newUser);
-                self.setState({
-                    usersList:  usersList
-                })
             },
             remove: function(i) {
                 return function() {
@@ -611,6 +622,25 @@ class LaunchNetworkServiceStore {
                         usersList: self.usersList
                     })
                 }
+            },
+            updateSSHkeyRef: function(i, j, remove){
+                return function(e) {
+                    let usersList = _.cloneDeep(self.usersList)
+                    let keys = usersList[i]['ssh-authorized-key'];
+                    if(!remove) {
+                        let keyRef = JSON.parse(e.target.value).name;
+                        if(!isNaN(j)) {
+                            keys.splice(j, 1);
+                        }
+                        keys.push(keyRef);
+                    } else {
+                        keys.splice(j, 1);
+                    }
+                    usersList[i]['ssh-authorized-key'] = keys;
+                    self.setState({
+                        usersList: usersList
+                    })
+                }
             }
         }
     }
@@ -644,7 +674,7 @@ class LaunchNetworkServiceStore {
             nsdPayload['vnf-placement-groups'] && delete nsdPayload['vnf-placement-groups'];
             nsdPayload.vld = this.state.vld;
             nsdPayload.vld && nsdPayload.vld.map(function(v){
-                delete v['unknown'];
+                delete v['none'];
                 delete v.type;
             })
         }
@@ -658,7 +688,7 @@ class LaunchNetworkServiceStore {
             "nsd": nsdPayload
         }
 
-        if (this.state.ro['account-type'] == 'openmano') {
+        if (this.state.ro && this.state.ro['account-type'] == 'openmano') {
             payload['om-datacenter'] = this.state.dataCenterID;
         } else {
             payload["cloud-account"] = this.state.selectedCloudAccount.name;
@@ -768,7 +798,7 @@ class LaunchNetworkServiceStore {
             return {'key-pair-ref': JSON.parse(k).name};
         });
         //Add Users
-        payload['user'] = this.state.usersList;
+        payload['user'] = addKeyPairRefToUsers(this.state.usersList);
         // console.log(payload)
         this.launchNSR({
             'nsr': [payload]
@@ -777,6 +807,19 @@ class LaunchNetworkServiceStore {
 }
 
 
+function addKeyPairRefToUsers(list) {
+    return list.map(function(u) {
+        return {
+            name: u.name,
+            'user-info': u['user-info'],
+            'ssh-authorized-key': u['ssh-authorized-key'].map(function(k) {
+                return {
+                    'key-pair-ref' : k
+                }
+            })
+        }
+    })
+}
 
 function getMockSLA(id) {
     console.log('Getting mock SLA Data for id: ' + id);
index 4ef6d1c..927727a 100644 (file)
@@ -1,6 +1,6 @@
 
 /*
- * 
+ *
  *   Copyright 2016 RIFT.IO Inc
  *
  *   Licensed under the Apache License, Version 2.0 (the "License");
 @import '../node_modules/open-iconic/font/css/open-iconic.css';
 
 .app-body {
+    display:-ms-flexbox;
     display:flex;
-    flex-direction:column;
+    -ms-flex-direction:column;
+        flex-direction:column;
     display: flex;
     flex-direction: column;
-    align-items: stretch;
+    -ms-flex-align: stretch;
+        align-items: stretch;
     height: 100%;
 }
 
   color: $gray-darkest;
 }
 .lpReactDashboard {
+  display:-ms-flexbox;
   display:flex;
   height:100%;
   .app-body {
     > header {
-      flex: 0 1 auto;
-      flex-shrink: 0;
+      -ms-flex: 0 1 auto;
+          flex: 0 1 auto;
+      -ms-flex-negative: 0;
+          flex-shrink: 0;
     }
   }
 }
 .lp-react-launch {
+  display: -ms-flexbox;
   display: flex;
 }
 .app-body.create-fleet {
 }
 
 .baseGridCell {
-  align-items: center;
+  -ms-flex-align: center;
+      align-items: center;
+  display: -ms-flexbox;
   display: flex;
-  flex: 0 0 auto;
+  -ms-flex: 0 0 auto;
+      flex: 0 0 auto;
   min-height: 30px;
   overflow: hidden;
   padding-left: 2px;
 }
 
 .lp_dashboard {
+  display: -ms-flexbox;
   display: flex;
-  flex: 1;
-  flex-direction: row;
+  -ms-flex: 1;
+      flex: 1;
+  -ms-flex-direction: row;
+      flex-direction: row;
   height: 100%;
 
   /* Network service list styles */
 
   .leftMinimizedNsListPanel {
+    display: -ms-flexbox;
     display: flex;
-    flex: 1 100%;
+    -ms-flex: 1 100%;
+        flex: 1 100%;
     height: auto;
     max-width: 30px;
     min-width: 30px;
       background-color: white;
       display:block;
       h3 {
-        // vertical | horizontal
-        // top | horizonal | bottom
-        // top right bottom left
+        /* vertical | horizontal*/
+        /* top | horizonal | bottom*/
+        /* top right bottom left*/
         padding: 1.5rem 0;
         color: white;
 
   }
 
   .nsListPanel {
+    display: -ms-flexbox;
     display: flex;
-    flex: 1 100%;
+    -ms-flex: 0 1;
+        flex: 0 1;
     height: auto;
-    max-width: 500px;
-    min-width: 500px;
+    width: auto;
+    /* max-width: 500px;*/
+    /* min-width: 500px;*/
 
     header {
       background-color: white;
     }
 
     &-body {
-      flex-flow: col wrap;
+      -ms-flex-flow: col wrap;
+          flex-flow: col wrap;
     }
   }
 
     top:1.5rem;
     right:0.5rem;
     cursor:pointer;
+    display:-ms-flexbox;
     display:flex;
     &:before {
     }
 
   .nsListPanelToolbar {
     background-color: $gray;
+    display: -ms-flexbox;
     display: flex;
-    flex: 0 0 auto;
-    flex-direction: row;
+    -ms-flex: 0 0 auto;
+        flex: 0 0 auto;
+    -ms-flex-direction: row;
+        flex-direction: row;
     padding-left: 1rem;
     .button {
       cursor: pointer;
+      display: -ms-flexbox;
       display: flex;
-      //flex: 0;
+      /*flex: 0;*/
       margin: 4px;
       margin: 0.5rem;
       img {
     }
   }
   .nsList {
+    display: -ms-flexbox;
     display: flex;
-    flex: 1;
-    flex-direction: column;
+    -ms-flex: 1;
+        flex: 1;
+    -ms-flex-direction: column;
+        flex-direction: column;
     overflow: auto;
     padding-left: 0;
     padding-right: 0;
     &-body {
-      overflow-y: scroll;
+      overflow-y: auto;
+      overflow-x: hidden;
     }
   }
   .nsListItemRow {
+    display: -ms-flexbox;
     display: flex;
-    flex-direction: row;
+    -ms-flex-direction: row;
+        flex-direction: row;
   }
   .cellValue {
     overflow: hidden;
     background-color: $gray;
     border-top: 1px solid $gray-lightest;
     border-bottom: 1px solid $gray-lightest;
+    display: -ms-flexbox;
     display: flex;
-    flex: 0 0 auto;
-    flex-direction: row;
+    -ms-flex: 0 0 auto;
+        flex: 0 0 auto;
+    -ms-flex-direction: row;
+        flex-direction: row;
   }
   .nsListItemField {
     @extend .baseGridCell;
 
   .actionButton {
     cursor: pointer;
-    // margin-top is a hack to fix the top of the glyph from
-    // being chopped off
+    /* margin-top is a hack to fix the top of the glyph from*/
+    /* being chopped off*/
     margin-top: 5px;
   }
 
   /* Network service detail card styles */
 
   .nsCardPanel {
-    //border: 1px solid black;
+    /*border: 1px solid black;*/
+    display: -ms-flexbox;
     display: flex;
-    flex: 1 1 auto;
-    flex-wrap: nowrap;
+    -ms-flex: 1 1 auto;
+        flex: 1 1 auto;
+    -ms-flex-wrap: nowrap;
+        flex-wrap: nowrap;
     height: auto;
     header {
       background-color: white;
     }
     &-body {
       background-color: $gray;
+      display: -ms-flexbox;
       display: flex;
-      flex: 1;
-      flex-direction: row;
+      -ms-flex: 1;
+          flex: 1;
+      -ms-flex-direction: row;
+          flex-direction: row;
       min-width: 0;
       min-height: 0;
       overflow-y: auto;
 
   /* Angular wrapping */
   lp-react-dashboard {
+    display:-ms-flexbox;
     display:flex;
   }
 }
index 2990d18..ab12fcd 100644 (file)
@@ -1,6 +1,6 @@
 /*
 
- * 
+ *
  *   Copyright 2016 RIFT.IO Inc
  *
  *   Licensed under the Apache License, Version 2.0 (the "License");
@@ -117,7 +117,9 @@ export default function parseCardObj(obj_list, type) {
       }
       ret.push(html)
     }
-    return ret.sort(function(a, b){
-      return (a.title > b.title) ? -1 : 1;
-    });
+    return ret.sort(function(a,b) {
+            var titleA = a.title && a.title.toUpperCase();
+            var titleB = b.title && b.title.toUpperCase();
+            return (titleA < titleB) ? -1 : (titleA > titleB) ? 1 : 0;
+          });
   }
index dc092bc..c928ffd 100644 (file)
@@ -1,6 +1,6 @@
 
 /*
- * 
+ *
  *   Copyright 2016 RIFT.IO Inc
  *
  *   Licensed under the Apache License, Version 2.0 (the "License");
@@ -90,16 +90,18 @@ export default class RecordCard extends React.Component {
                 <div className="scrollContainer">
                 {
                   //Sort for recent on top
-                    this.props.jobData.sort(function(a,b){
+                  this.props.jobData
+                  .sort(function(a,b){
                     return parseInt(b['job-id']) - parseInt(a['job-id']);
-                  }).map(function(job){
+                  })
+                  .map(function(job){
                     //Return only vnfr configs
                     if(job["triggered-by"] == 'vnf-primitive') {
                       return job.vnfr.map(function(v){
                         //That match the currently selected job id
                         if(v.id == cardData.id) {
                           return v.primitive.map(function(p, i) {
-                            return <JobListCard type="vnfr" job-id={job['job-id']} cardData={cardData} key={i} {...p} />
+                            return <JobListCard type="vnfr" job-id={job['job-id']} cardData={cardData} key={ob['job-id'] + '-' + i} {...p} />
                           })
                         }
                       })
@@ -157,16 +159,16 @@ export default class RecordCard extends React.Component {
                 <div className="scrollContainer">
                   {sortedJobs.map(function(job, i){
                     if(job["triggered-by"] == 'ns-primitive') {
-                      return <JobListCard type="nsr" job-id={job['job-id']} cardData={cardData} key={i} {...job} />
+                      return <JobListCard type="nsr" job-id={job['job-id']} cardData={cardData} key={job['job-id'] + '-' + 'nsr'} {...job} />
                     }
                   })
                   .concat(sortedJobs.map(function(job) {
                     if(!job.hasOwnProperty('job-name') && (job["triggered-by"] == 'ns-primitive')) {
-                      return job.vnfr.map(function(v){
+                      return job.vnfr.map(function(v, h){
                         //That match the currently selected job id
                         if(v.id == cardData.id) {
                           return v.primitive.map(function(p, i) {
-                            return <JobListCard type="vnfr" job-id={job['job-id']} cardData={cardData} key={i} {...p} />
+                            return <JobListCard type="vnfr" job-id={job['job-id']} cardData={cardData} key={ob['job-id'] + '-' + 'vnfr' + '-' + h} {...p} />
                           })
                         }
                       })
@@ -207,7 +209,7 @@ export default class RecordCard extends React.Component {
 
     let nfviMetrics = <LpCardNfviMetrics data={cardData["nfvi-metrics"]} />;
     metricsAndParams.push(<div className="monitoringParams" key="mp">
-                          {components.sort().map(function(c, k) {
+                          {components.map(function(c, k) {
                             return <div key={k} className="mpSlide">{c.title}{c.component}</div>
                           })}
                           </div>)
@@ -325,7 +327,7 @@ export default class RecordCard extends React.Component {
         if (consoleUrlsComponent) {
           let consoleUrlsTabTitle = '';
           consoleUrlsTabTitle = 'VDU Console Links';
-          
+
           tabList.push(
             <Tab key={cardData.id + '-cp'}>{consoleUrlsTabTitle}</Tab>
           );
index 589af02..b9fded5 100644 (file)
@@ -192,12 +192,23 @@ class RecordViewStore {
                 let parameterList = [];
 
                 const filterAndAddByValue = (paramObj) => {
+                    let nameValuePair = null;
+
                     if (paramObj['value'] != undefined) {
-                        parameterList.push({
+                        nameValuePair = {
                             name: paramObj.name,
                             value: paramObj.value
-                        });
+                        };
+                    } else if (paramObj['default-value'] != undefined) {
+                        nameValuePair = {
+                            name: paramObj.name,
+                            value: paramObj['default-value']
+                        }
                     }
+                    if (nameValuePair) {
+                        parameterList.push(nameValuePair);
+                    }
+
                     return paramObj['value'] != undefined;
                 }
 
index a3708fe..61ebe3d 100644 (file)
@@ -172,7 +172,8 @@ class NSVirtualLinkCreateStore {
                let vld = _.cloneDeep(this.vld);
                this.vldInitParamsTypes.map((vldInitParamType) => {
                        if (currentVLDInitParamsType == vldInitParamType) {
-                               vld[currentVLDInitParamsType] = e.target.value;
+                               let value = e.target.nodeName == "SELECT" ? JSON.parse(e.target.value) : e.target.value;
+                               vld[currentVLDInitParamsType] = value;
                        } else {
                                vld[vldInitParamType] && delete vld[vldInitParamType];
                        }
index 086d864..3ef9027 100644 (file)
@@ -1,6 +1,6 @@
 
 /*
- * 
+ *
  *   Copyright 2016 RIFT.IO Inc
  *
  *   Licensed under the Apache License, Version 2.0 (the "License");
  *   limitations under the License.
  *
  */
+'use strict';
 var Promise = require('bluebird');
 var utils = require('../../../framework/core/api_utils/utils.js');
 var request = utils.request;
 var constants = require('../../../framework/core/api_utils/constants.js');
 var _ = require('lodash');
-var APIVersion = '/v1';
+var APIVersion = '/v2';
 var transforms = require('./transforms.js');
 
 var foreverOn = true;
@@ -111,10 +112,10 @@ function requestCallback(resolve, reject, transformFunc) {
       } else {
         var data = JSON.stringify(response.body);
       }
-      return resolve_with_delay(resolve, {
+      return resolve({
         statusCode: response.statusCode,
         data: data
-      }, 0);
+      });
     };
   };
 }
@@ -251,11 +252,13 @@ Aggregate.set = function(req) {
   // Do nothing to test delay in response
   var encoder = new transforms.LoggingConfigEncoder();
   var data = encoder.encode(req.body);
-  //console.log("Aggregate.set. encoded data=");
-  //console.log(data);
+  // console.log("Aggregate.set. encoded data=");
+  // console.log(data);
   // dumpLoggingConfig(data);
-
-  return handlePutRequest(req, APIVersion + '/api/config/logging', data);
+  let setData = {
+    'rwlog-mgmt:logging' : data
+  }
+  return handlePutRequest(req, APIVersion + '/api/config/logging', setData);
   // if (this.mockResponse['set']) {
   //   return handleMockResponse(req, true, 201, data, delay=100);
   // }
@@ -319,6 +322,34 @@ Config.deleteDefaultSeverity = function(req) {
 
 }
 
+// NOTE: In rel_4.3 we are going to affect syslog sink category by default
+
+Config.setDefaultSyslogSeverity = function(req) {
+  // TODO: verify there is one key at root of data: 'default-severity'
+  // OR just filter on the request body
+  return handlePutRequest(req, APIVersion + '/api/config/logging/sink/syslog');
+}
+
+Config.deleteDefaultSyslogSeverity = function(req) {
+  // TODO: verify there is one key at root of data: 'default-severity'
+  // OR just filter on the request body
+  var Categories = req.params.nulledCategories.split(',');
+  var promises = [];
+  return new Promise(function(resolve, reject) {
+    promises.concat(Categories.map(function(categoryName) {
+        return handleDeleteRequest(req, APIVersion + '/api/config/logging/sink/syslog/filter/category/' + categoryName);
+      }));
+      return Promise.all(promises).then(
+        function(data) {
+          resolve({statusCode:  data[0].statusCode, data: data[0].data});
+        },
+        function(data) {
+          reject({statusCode:  data[0].statusCode, data: data[0].data});
+        }
+      )
+    });
+}
+
 /*
   get body of forms
 
@@ -338,15 +369,14 @@ Config.deleteDefaultSeverity = function(req) {
 Config.setAllowDuplicateEvents = function(req) {
   // TODO: verify there is one key at root of data: 'default-severity'
   // OR just filter on the request body
-
-  if (req.body.hasOwnProperty('allowDuplicateEvents') &&
-    typeof req.body.allowDuplicateEvents == 'boolean') {
-    if (req.body.allowDuplicateEvents) {
-      return handlePutRequest(req, APIVersion + '/api/config/logging/allow', {
+console.log(req.body)
+  if (req.body.hasOwnProperty('allowDuplicateEvents')) {
+    if (req.body.allowDuplicateEvents.toUpperCase() == "TRUE") {
+      return handlePutRequest(req, '/api/config/logging/allow', {
         "duplicate": "events"
       });
     } else { // false, remove entry from logging config
-      return handleDeleteRequest(req, APIVersion + '/api/config/logging/allow/duplicate');
+      return handleDeleteRequest(req, '/api/config/logging/allow/duplicate');
     }
   } else {
     return handleReject(statusCode=400,
@@ -398,6 +428,7 @@ Config.setSyslogViewer = function(req) {
 // Operational calls
 
 Operational.get = function(req) {
+  var APIVersion = '/v1'
   return handleGetRequest(req, APIVersion + '/api/operational/logging?deep',
     transformLoggingRootResponseCallback
   );
index eb17b7a..2e2b8dc 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * 
+ *
  *   Copyright 2016 RIFT.IO Inc
  *
  *   Licensed under the Apache License, Version 2.0 (the "License");
@@ -168,7 +168,7 @@ LoggingConfigEncoder.prototype.denyEvents = function(data) {
  * or absence of the { "allow": { "duplicate": "events" }} key/value hierarchy
  */
 LoggingConfigEncoder.prototype.allow = function(data) {
-  if (data.allowDuplicateEvents) {
+  if (data.allowDuplicateEvents && data.allowDuplicateEvents.toUpperCase() == "TRUE") {
     return { duplicate: "events" };
   } else {
     return null;
index af410c2..02b4514 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * 
+ *
  *   Copyright 2016 RIFT.IO Inc
  *
  *   Licensed under the Apache License, Version 2.0 (the "License");
@@ -64,6 +64,16 @@ var loggingRoutes = [
         endpoint: '/api/config/default-severity',
         apiHandler: loggingAPI['config'].deleteDefaultSeverity
     },
+    {
+        method: 'PUT',
+        endpoint: '/api/config/default-syslog-severity',
+        apiHandler: loggingAPI['config'].setDefaultSyslogSeverity
+    },
+    {
+        method: 'DELETE',
+        endpoint: '/api/config/default-syslog-severity/:nulledCategories',
+        apiHandler: loggingAPI['config'].deleteDefaultSyslogSeverity
+    },
     {
         method: 'PUT',
         endpoint: '/api/config/allow-duplicate-events',
index 86a42c1..12cb99c 100644 (file)
@@ -27,17 +27,29 @@ export default class CategorySeverityGrid extends React.Component {
   generateRows(defaultSeverities, severityOptions) {
     let self = this;
     return defaultSeverities.map(function(catsev) {
+      // let dropList = (<DropList options={severityOptions}
+      //   selectedOption={catsev.severity}
+      //   onChange={self.onChangeSeverity(catsev.category)} />);
       let dropList = (<DropList options={severityOptions}
         selectedOption={catsev.severity}
-        onChange={self.onChangeSeverity(catsev.category)} />);
-      return [catsev.category, dropList];
+        onChange={self.onChangeSyslogSeverity(catsev.name)} />);
+      return [catsev.name, dropList];
     });
   }
 
-  onChangeSeverity (category) {
+  // onChangeSeverity (category) {
+  //   return function(e) {
+  //     LoggingStore.updateCategoryDefaultSeverity({
+  //       category: category,
+  //       severity: e
+  //     });
+  //   }
+  // }
+
+  onChangeSyslogSeverity (name) {
     return function(e) {
-      LoggingStore.updateCategoryDefaultSeverity({
-        category: category,
+      LoggingStore.updateCategoryDefaultSyslogSeverity({
+        name: name,
         severity: e
       });
     }
@@ -60,7 +72,7 @@ export default class CategorySeverityGrid extends React.Component {
 
 CategorySeverityGrid.defaultProps = {
   cellLabels: [
-    'Category', 'Severity'
+    'Name', 'Severity'
   ],
   columnClasses: [
     'category', 'severity'
index dd04a57..7b50c76 100644 (file)
@@ -42,7 +42,7 @@ class DefaultCategorySeverityPanel extends React.Component {
     return (
       <DashboardCard className="defaultCategorySeverityPanel"
         showHeader={true}
-        title="Default Category Severity">
+        title="Syslog Category Severity">
         <CategorySeverityGrid defaultSeverities={defaultSeverities}
           severityOptions={severities}/>
       </DashboardCard>
@@ -223,45 +223,60 @@ export default class LoggingGeneral extends React.Component {
         isLoading: true
       });
       LoggingStore.updateLoggingConfig(
-         this.collectNulledCategories(
+         /* this.collectNulledCategories(
             this.state.initialLoggingConfig,
             this.state.loggingConfig),
-         this.removeCategoryNulls(
-            this.state.loggingConfig
-          )
-     );
+            this.removeCategoryNulls(
+            this.state.loggingConfig */
+        this.state.nulledCategories,
+        this.cleanupConfig(
+          this.state.loggingConfig
+        )
+      )
     } else {
       console.log("LoggingGeneral.handleSave failed validation");
     }
     this.context.router.push({pathname: ''});
   }
-  removeCategoryNulls(config) {
+  // removeCategoryNulls(config) {
+  //   let cleanConfig = _.cloneDeep(config);
+  //   let cleanSeverities = [];
+  //   config.defaultSeverities.map(function(d) {
+  //     if (d.severity) {
+  //       cleanSeverities.push(d);
+  //     }
+  //   });
+  //   cleanConfig.defaultSeverities = cleanSeverities;
+  //   return cleanConfig;
+  // }
+  cleanupConfig(config) {
     let cleanConfig = _.cloneDeep(config);
     let cleanSeverities = [];
-    config.defaultSeverities.map(function(d) {
-      if (d.severity) {
-        cleanSeverities.push(d);
+    cleanConfig.defaultSeverities && cleanConfig.defaultSeverities.map((defSev) => {
+      if (defSev.severity) {
+        cleanSeverities.push(defSev);
       }
     });
     cleanConfig.defaultSeverities = cleanSeverities;
+
     return cleanConfig;
   }
-  collectNulledCategories(oldCat, newCat) {
-    let nulledCategories = [];
-    let newSeverities = newCat.defaultSeverities;
-    let oldSeverities = oldCat.defaultSeverities;
-    newSeverities.map(function(c, i) {
-      if(!c.severity) {
-        if(oldSeverities[i].severity) {
-          //verify that categories are the same
-          if(oldSeverities[i].category == c.category) {
-            nulledCategories.push({category: c.category})
-          }
-        }
-      }
-    });
-    return nulledCategories;
-  }
+  // collectNulledCategories(oldCat, newCat) {
+  //   let nulledCategories = [];
+  //   let newSeverities = newCat.defaultSeverities;
+  //   let oldSeverities = oldCat.defaultSeverities;
+  //   newSeverities.map(function(c, i) {
+  //     if(!c.severity) {
+  //       if(oldSeverities[i].severity) {
+  //         //verify that categories are the same
+  //         if(oldSeverities[i].category == c.category) {
+  //           nulledCategories.push({category: c.category})
+  //         }
+  //       }
+  //     }
+  //   });
+  //   return nulledCategories;
+  // }
   validateData() {
 
     function isEventIdValid(eventID) {
@@ -341,6 +356,25 @@ export default class LoggingGeneral extends React.Component {
 
     let syslogViewerURL = this.state.loggingConfig.syslogviewer;
     let defaultSeverities = this.state.loggingConfig.defaultSeverities;
+    // NOTE: There are modifications to original code here
+    // for RIFT-14856 so that default severities map to syslog sink
+    
+    // Find first syslog sink with (WTF - no type on sinks!) name syslog.
+    let syslogSink = this.state.loggingConfig.sinks && _.find(this.state.loggingConfig.sinks, {
+      name: 'syslog'
+    });
+    let defaultSyslogSeverities = [];
+
+    this.state.loggingConfig && this.state.loggingConfig.defaultSeverities && this.state.loggingConfig.defaultSeverities.map((defaultSeverity) => {
+      // Mapping between default categories and names inside a sink
+      let syslogFilterCategory = (syslogSink.filter && syslogSink.filter.category && _.find(syslogSink.filter.category, {
+        name: defaultSeverity.category
+      })) || {
+        name: defaultSeverity.category,
+        severity: null
+      };
+      defaultSyslogSeverities.push(syslogFilterCategory);
+    });
     let severities = this.state.loggingConfig.severities;
     let allowDuplicateEvents = this.state.loggingConfig.allowDuplicateEvents;
     let denyEventIDs = this.state.loggingConfig.denyEventIDs;
@@ -361,7 +395,10 @@ export default class LoggingGeneral extends React.Component {
           {errorMessage}
           <ScreenLoader show={this.state.isLoading}/>
           <div className="panelContainer">
-            <DefaultCategorySeverityPanel defaultSeverities={defaultSeverities}
+            {/*<DefaultCategorySeverityPanel defaultSeverities={defaultSeverities}
+              severities={severities}
+              />*/}
+            <DefaultCategorySeverityPanel defaultSeverities={defaultSyslogSeverities}
               severities={severities}
               />
             <LoggingEventsPanel allowDuplicateEvents={allowDuplicateEvents}
index e073809..bf2f06a 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * 
+ *
  *   Copyright 2016 RIFT.IO Inc
  *
  *   Licensed under the Apache License, Version 2.0 (the "License");
@@ -66,7 +66,43 @@ export default {
         return new Promise(function(resolve, reject) {
           let promises = [];
           let remove = null;
-          let change = $.ajax({
+          if(loggingConfig.hasOwnProperty('allowDuplicateEvents')) {
+            promises.push($.ajax({
+              url: apiUrl('api/config/allow-duplicate-events'),
+              type: 'PUT',
+              beforeSend: Utils.addAuthorizationStub,
+              data: {
+                allowDuplicateEvents: loggingConfig.allowDuplicateEvents
+              },
+              success: function(data) {
+                resolve(data);
+              },
+              error: function(error) {
+                console.log("There was an error updating the logging config data",
+                  error);
+                reject(error);
+              }
+            }))
+          }
+          // if(nulledCategories.length > 0) {
+          //   remove = $.ajax({
+          //     // url: apiUrl('api/config/default-severity'),
+          //     url: apiUrl('api/config/default-syslog-severity/' + nulledCategories.join(',')),
+          //     type: 'DELETE',
+          //     beforeSend: Utils.addAuthorizationStub,
+          //     success: function(data) {
+          //       resolve(data);
+          //     },
+          //     error: function(error) {
+          //       console.log("There was an error updating the logging config data",
+          //         error);
+          //       reject(error);
+          //     }
+          //   });
+          //   promises.push(remove);
+          // }
+          Promise.all(promises).then(function(data) {
+            return $.ajax({
                 url: apiUrl('api/aggregate'),
                 type: 'PUT',
                 beforeSend: Utils.addAuthorizationStub,
@@ -80,29 +116,7 @@ export default {
                   reject(error);
                 }
           });
-          promises.push(change);
-          if(nulledCategories.length > 0) {
-            remove = $.ajax({
-              url: apiUrl('api/config/default-severity'),
-              type: 'DELETE',
-              beforeSend: Utils.addAuthorizationStub,
-              data: {
-                'default-severity' : nulledCategories
-              },
-              success: function(data) {
-                resolve(data);
-              },
-              error: function(error) {
-                console.log("There was an error updating the logging config data",
-                  error);
-                reject(error);
-              }
-            });
-            promises.push(remove);
-          }
-
-
-          Promise.all(promises).then(function(data){
+          }).then(function(data){
             resolve(data)
           }, function(){
             reject(arguments)
index 860ff9f..53575eb 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * 
+ *
  *   Copyright 2016 RIFT.IO Inc
  *
  *   Licensed under the Apache License, Version 2.0 (the "License");
@@ -26,10 +26,12 @@ class LoggingStore {
     this.loggingConfig = {};
     // initialLoggingConfig is the saved state
     this.initialLoggingConfig = {};
+    this.nulledCategories = [];
     this.bindActions(LoggingActions);
     this.registerAsync(LoggingSource);
     this.exportPublicMethods({
       updateCategoryDefaultSeverity: this.updateCategoryDefaultSeverity,
+      updateCategoryDefaultSyslogSeverity: this.updateCategoryDefaultSyslogSeverity,
       updateAllowDuplicateEvents: this.updateAllowDuplicateEvents,
       addDenyEvent: this.addDenyEvent,
       updateDenyEvent: this.updateDenyEvent,
@@ -97,6 +99,64 @@ class LoggingStore {
     }
   }
 
+  updateCategoryDefaultSyslogSeverity = (catsev) => {
+    console.log("LoggingStore.updateCategoryDefaultSyslogSeverity:", catsev);
+    // find the category (name) in the syslog sink
+
+    let self = this;
+    let loggingConfig = _.cloneDeep(this.loggingConfig);
+    let syslogSinkIndex = -1;
+    let nulledCategories = this.nulledCategories;
+
+    loggingConfig.sinks && loggingConfig.sinks.map((sink, sinkIndex) => {
+      if (sink.name == 'syslog') {
+        if (sink.filter) {
+          if (sink.filter.category) {
+            let catIndex = _.findIndex(sink.filter.category, {
+              name: catsev.name
+            });
+            if (catIndex != -1) {
+              // found it
+              if (catsev.severity == "") {
+                // blank was selected
+                nulledCategories.push(catsev.name);
+                this.setState({
+                  nulledCategories: nulledCategories
+                });
+                // TODO/NOTE: Can't delete from model as sending a top-level payload with
+                // missing elements is not allowed!
+                // When backend supports it, in loggingSource change the order of operations
+                // // Delete first followed by save/put.
+                // _.remove(loggingConfig.sinks[sinkIndex].filter.category, {
+                //   name: catsev.name
+                // });
+              } else {
+                sink.filter.category[catIndex] = catsev;
+              }
+            } else {
+              _.remove(nulledCategories, (v) => v == catsev.name);
+              this.setState({
+                nulledCategories: nulledCategories
+              });
+              sink.filter.category.push(catsev);
+            }
+          } else {
+            sink.filter.category = [];
+            sink.filter.category.push(catsev);
+          }
+        } else {
+          sink.filter = {};
+          sink.filter.category = [];
+          sink.filter.category.push(catsev);
+        }
+      }
+    });
+
+    this.setState({
+      loggingConfig: loggingConfig
+    });
+  }
+
   updateAllowDuplicateEvents = (allowFlag) => {
     console.log("LoggingStore.updateAllowDuplicateEvents called. allowFlag=", allowFlag);
     const loggingConfig = this.loggingConfig;