Commit 8117fed5 authored by Nikhil Doifode's avatar Nikhil Doifode
Browse files

Added code for process lifecycle frontend changes

parent f5a7e77f
Loading
Loading
Loading
Loading
+107 −30
Original line number Diff line number Diff line
@@ -89,8 +89,14 @@ import {
  cfgElemClone
} from '../../state/cfg';

import {
  execElemUpdate,
  execElemClone
} from '@/js/state/exec';

import {
  TYPE_CFG,
  TYPE_EXEC,

  // Network element types
  ELEMENT_TYPE_SCENARIO,
@@ -765,7 +771,6 @@ const NCGroups = ({ prefixes, onUpdate, element }) => {
    return (
      <NCGroup
        onUpdate={onUpdate}
        type={TYPE_CFG}
        element={element}
        prefix={p}
        key={p}
@@ -1711,13 +1716,15 @@ const getElementTypeOverrideBack = (typeOverride) => {
  return type;
};

const HeaderGroup = ({ element, onTypeChange, onUpdate, typeDisabled, parentDisabled, nameDisabled }) => {
const HeaderGroup = ({ element, onTypeChange, onUpdate, typeDisabled, parentDisabled, nameDisabled, pageType }) => {
  var type = getElemFieldVal(element, FIELD_TYPE) || '';
  var parent = getElemFieldVal(element, FIELD_PARENT) || '';
  var parentElements = element.parentElements || [parent];

  var typeOverride = getElementTypeOverride(type);

  elementTypes.length === 5 && pageType === TYPE_EXEC ? elementTypes.splice(0, 3) : '';

  return (
    <>
      <Grid style={{ marginTop: 20 }}>
@@ -1765,29 +1772,90 @@ export class CfgNetworkElementContainer extends Component {
    super(props);
  }

  updateElement(elem) {
    switch (this.props.type) {
    case TYPE_CFG:
      this.props.cfgElemUpdate(elem);
      break;
    case TYPE_EXEC:
      this.props.execElemUpdate(elem);
      break;
    default:
      break;
    }
  }

  cloneElement(elem) {
    switch (this.props.type) {
    case TYPE_CFG:
      this.props.cfgElemClone(elem);
      break;
    case TYPE_EXEC:
      this.props.execElemClone(elem);
      break;
    default:
      break;
    }
  }

  getTableEntries() {
    switch (this.props.type) {
    case TYPE_CFG:
      return this.props.cfgTableData;
    case TYPE_EXEC:
      return this.props.execTableData;
    default:
      return null;
    }
  }

  getConfiguredElement() {
    switch (this.props.type) {
    case TYPE_CFG:
      return this.props.cfgConfiguredElement;
    case TYPE_EXEC:
      return this.props.execConfiguredElement;
    default:
      return null;
    }
  }

  getConfigMode() {
    switch (this.props.type) {
    case TYPE_CFG:
      return this.props.cfgConfigMode;
    case TYPE_EXEC:
      return this.props.execConfigMode;
    default:
      return null;
    }
  }

  // Element update handler
  onUpdateElement(name, val, err) {
    var updatedElem = updateObject({}, this.props.configuredElement);
    var updatedElem = updateObject({}, this.getConfiguredElement());
    setElemFieldVal(updatedElem, name, val);
    setElemFieldErr(updatedElem, name, err);

    this.props.cfgElemUpdate(updatedElem);
    // this.props.cfgElemUpdate(updatedElem);
    this.updateElement(updatedElem);
  }

  // Element clone handler
  onCloneElement(newName) {
    var clonedElem = updateObject({}, this.props.configuredElement);
    var clonedElem = updateObject({}, this.getConfiguredElement());
    setElemFieldVal(clonedElem, FIELD_NAME, newName);
    setElemFieldVal(clonedElem, FIELD_PARENT, null);
    var elementType = getElemFieldVal(clonedElem, FIELD_TYPE);
    clonedElem.parentElements = this.elementsOfType(getParentTypes(elementType));

    this.props.cfgElemClone(clonedElem);
    // this.props.cfgElemClone(clonedElem);
    this.cloneElement(clonedElem);
  }

  // Retrieve names of elements with matching type
  elementsOfType(types) {
    return _.chain(this.props.tableData)
    return _.chain(this.getTableEntries())
      .filter(e => {
        var elemType = getElemFieldVal(e, FIELD_TYPE);
        return _.includes(types, elemType);
@@ -1800,7 +1868,7 @@ export class CfgNetworkElementContainer extends Component {

  // Element configuration type change handler
  onElementTypeChange(elementType) {
    var elem = updateObject({}, this.props.configuredElement);
    var elem = updateObject({}, this.getConfiguredElement());

    //override the frontend terminology
    var elementTypeOverride = getElementTypeOverrideBack(elementType);
@@ -1813,24 +1881,25 @@ export class CfgNetworkElementContainer extends Component {

    elem.parentElements = this.elementsOfType(getParentTypes(elementTypeOverride));

    if (this.props.configMode !== CFG_ELEM_MODE_CLONE) {
      setElemFieldVal(elem, FIELD_NAME, getSuggestedName(elementTypeOverride, this.props.tableData));
    if (this.getConfigMode() !== CFG_ELEM_MODE_CLONE) {
      setElemFieldVal(elem, FIELD_NAME, getSuggestedName(elementTypeOverride, this.getTableEntries()));
    }
    this.props.cfgElemUpdate(elem);
    // this.props.cfgElemUpdate(elem);
    this.updateElement(elem);
  }

  onEditLocation() {
    var elem = updateObject({}, this.props.configuredElement);
    var elem = updateObject({}, this.getConfiguredElement());
    this.props.onEditLocation(elem);
  }

  onEditPath() {
    var elem = updateObject({}, this.props.configuredElement);
    var elem = updateObject({}, this.getConfiguredElement());
    this.props.onEditPath(elem);
  }

  render() {
    const element = this.props.configuredElement;
    const element = this.getConfiguredElement();
    return (
      <div className="cfg-network-element-div" style={styles.outer}>
        <Grid>
@@ -1839,18 +1908,18 @@ export class CfgNetworkElementContainer extends Component {
              <Typography use="headline6">Element Configuration</Typography>
            </div>
          </GridCell>
          <GridCell span={12}>
          <GridCell span={12} hidden={this.props.type === TYPE_EXEC}>
            <GridInner align={'left'}>
              <GridCell span={12}>
                <ElementCfgButtons
                  configuredElement={element}
                  configMode={this.props.configMode}
                  configMode={this.getConfigMode()}
                  onNewElement={this.props.onNewElement}
                  onDeleteElement={() => {
                    this.props.onDeleteElement(element);
                  }}
                  onCloneElement={() => {
                    this.onCloneElement(createUniqueName(this.props.tableData, getElemFieldVal(element, FIELD_NAME) + '-copy'));
                    this.onCloneElement(createUniqueName(this.getTableEntries(), getElemFieldVal(element, FIELD_NAME) + '-copy'));
                  }}
                />
              </GridCell>
@@ -1868,9 +1937,10 @@ export class CfgNetworkElementContainer extends Component {
              onUpdate={(name, val, err) => {
                this.onUpdateElement(name, val, err);
              }}
              typeDisabled={this.props.configMode === CFG_ELEM_MODE_CLONE || this.props.configMode === CFG_ELEM_MODE_EDIT}
              parentDisabled={this.props.configMode === CFG_ELEM_MODE_EDIT}
              nameDisabled={getElemFieldVal(element, FIELD_TYPE) === ELEMENT_TYPE_SCENARIO && this.props.configMode !== CFG_ELEM_MODE_NEW}
              typeDisabled={this.getConfigMode() === CFG_ELEM_MODE_CLONE || this.getConfigMode() === CFG_ELEM_MODE_EDIT}
              parentDisabled={this.getConfigMode() === CFG_ELEM_MODE_EDIT}
              nameDisabled={getElemFieldVal(element, FIELD_TYPE) === ELEMENT_TYPE_SCENARIO && this.getConfigMode() !== CFG_ELEM_MODE_NEW}
              pageType={this.props.type}
            />

            <TypeRelatedFormFields
@@ -1884,14 +1954,14 @@ export class CfgNetworkElementContainer extends Component {
              id="new-element-error-message"
              className="idcc-margin-top mdc-typography--body1"
            >
              {this.props.errorMessage}
              {this.props.type === TYPE_CFG ? this.props.cfgErrorMessage : this.props.execErrorMessage }
            </div>

            <CancelApplyPair
              saveDisabled={(this.props.isModified === false) ? true : false}
              onCancel={this.props.onCancelElement}
              saveDisabled={!(this.props.type === TYPE_CFG ? this.props.cfgIsModified : this.props.execIsModified)}
              onCancel={e => this.props.onCancelElement(e)}
              onApply={() => {
                (this.props.configMode === CFG_ELEM_MODE_CLONE) ? this.props.onApplyCloneElement(element) : this.props.onSaveElement(element);
                (this.getConfigMode() === CFG_ELEM_MODE_CLONE) ? this.props.onApplyCloneElement(element) : this.props.onSaveElement(element);
              }}

            />
@@ -1928,18 +1998,25 @@ const styles = {

const mapStateToProps = state => {
  return {
    tableData: state.cfg.table.entries,
    configuredElement: state.cfg.elementConfiguration.configuredElement,
    configMode: state.cfg.elementConfiguration.configurationMode,
    isModified: state.cfg.elementConfiguration.isModified,
    errorMessage: state.cfg.elementConfiguration.errorMessage
    cfgTableData: state.cfg.table.entries,
    cfgConfiguredElement: state.cfg.elementConfiguration.configuredElement,
    cfgConfigMode: state.cfg.elementConfiguration.configurationMode,
    cfgIsModified: state.cfg.elementConfiguration.isModified,
    cfgErrorMessage: state.cfg.elementConfiguration.errorMessage,
    execTableData: state.exec.table.entries,
    execConfiguredElement: state.exec.elementConfiguration.configuredElement,
    execConfigMode: state.exec.elementConfiguration.configurationMode,
    execIsModified: state.exec.elementConfiguration.isModified,
    execErrorMessage: state.exec.elementConfiguration.errorMessage
  };
};

const mapDispatchToProps = dispatch => {
  return {
    cfgElemUpdate: element => dispatch(cfgElemUpdate(element)),
    cfgElemClone: element => dispatch(cfgElemClone(element))
    cfgElemClone: element => dispatch(cfgElemClone(element)),
    execElemUpdate: element => dispatch(execElemUpdate(element)),
    execElemClone: element => dispatch(execElemClone(element))
  };
};

+121 −124
Original line number Diff line number Diff line
@@ -115,6 +115,121 @@ const hasExtPortsInCommon = elem1 => elem2 => {

const hasDifferentName = elem1 => elem2 => elem1.name.val !== elem2.name.val;

// Validate new network element form field entries
export const validateNetworkElement = (element, entries, elemSetErrMsg) => {
  var data = entries;

  // Clear previous error message
  elemSetErrMsg('');

  // Verify that no field is in error
  var fieldsInError = 0;
  _.forOwn(element, val => (fieldsInError = val.err ? fieldsInError + 1 : fieldsInError));
  if (fieldsInError) {
    elemSetErrMsg(`${fieldsInError} fields in error`);
    return false;
  }

  // Verify element type
  var type = getElemFieldVal(element, FIELD_TYPE);
  if (type === null) {
    elemSetErrMsg('Missing element type');
    return false;
  }

  // Check for valid & unique network element name (except if editing)
  var name = getElemFieldVal(element, FIELD_NAME);
  if (name === null || name === '') {
    elemSetErrMsg('Missing element name');
    return false;
  }

  if (data[name] && data[name].id !== element.id) {
    elemSetErrMsg('Element name already exists');
    return false;
  }

  // Nothing else to validate for Scenario element
  if (type === ELEMENT_TYPE_SCENARIO) {
    return true;
  }

  // Make sure parent exists
  if (!data[getElemFieldVal(element, FIELD_PARENT)]) {
    elemSetErrMsg('Parent does not exist');
    return false;
  }

  // If GPU requested, make sure type is set
  var gpuCount = getElemFieldVal(element, FIELD_GPU_COUNT);
  if (gpuCount) {
    var gpuType = getElemFieldVal(element, FIELD_GPU_TYPE);
    if (gpuType === null || gpuType === '') {
      elemSetErrMsg('GPU type not selected');
      return false;
    }
  }

  // If CPU limitations is requested, making sure Min CPU <= Max CPU
  var cpuMin = getElemFieldVal(element, FIELD_CPU_MIN);
  var cpuMax = getElemFieldVal(element, FIELD_CPU_MAX);
  if (cpuMin !== null && cpuMax !== null) {
    if (parseFloat(cpuMin) > parseFloat(cpuMax)) {
      elemSetErrMsg('Min CPU > Max CPU');
      return false;
    }
  }

  // If Memory limitations is requested, making sure Min Memory <= Max Memory
  var memoryMin = getElemFieldVal(element, FIELD_MEMORY_MIN);
  var memoryMax = getElemFieldVal(element, FIELD_MEMORY_MAX);
  if (memoryMin !== null && memoryMax !== null) {
    if (parseInt(memoryMin) > parseInt(memoryMax)) {
      elemSetErrMsg('Min Memory > Max Memory');
      return false;
    }
  }

  // Verify cellid/mac address if required
  if (type === ELEMENT_TYPE_POA_4G) {
    var cellId = getElemFieldVal(element, FIELD_CELL_ID);
    if (!cellId) {
      elemSetErrMsg('Missing Cell ID');
      return false;
    }
  } else if (type === ELEMENT_TYPE_POA_5G) {
    var nrCellId = getElemFieldVal(element, FIELD_NR_CELL_ID);
    if (!nrCellId) {
      elemSetErrMsg('Missing NR Cell ID');
      return false;
    }
  } else if (type === ELEMENT_TYPE_POA_WIFI) {
    var macId = getElemFieldVal(element, FIELD_MAC_ID);
    if (!macId) {
      elemSetErrMsg('Missing MAC Address');
      return false;
    }
  }

  // TODO -- verify node port not already used
  const extPorts = externalPorts(element);

  if (extPorts.length) {
    const elemsWithSameExtPort = pipe(
      filter(hasDifferentName(element)),
      filter(hasExtPortsInCommon(element))
    )(Object.values(data));

    if (elemsWithSameExtPort.length) {
      const elemNames = elemsWithSameExtPort.map((e) =>getElemFieldVal(e, FIELD_NAME));
      elemSetErrMsg(`External port already used in ${elemNames}`);
      return false;
    }
  }

  return true;
};

class CfgPageContainer extends Component {
  constructor(props) {
    super(props);
@@ -144,7 +259,7 @@ class CfgPageContainer extends Component {
  // SAVE
  onSaveElement(element) {
    // Validate network element
    if (this.validateNetworkElement(element) === false) {
    if (!validateNetworkElement(element, this.props.cfg.table.entries, this.props.cfgElemSetErrMsg)) {
      return;
    }

@@ -167,7 +282,7 @@ class CfgPageContainer extends Component {
  // CLONE
  onApplyCloneElement(element) {
    // Validate network element
    if (this.validateNetworkElement(element) === false) {
    if (!validateNetworkElement(element, this.props.cfg.table.entries, this.props.cfgElemSetErrMsg)) {
      return;
    }

@@ -186,7 +301,8 @@ class CfgPageContainer extends Component {
  }

  // CANCEL
  onCancelElement() {
  onCancelElement(e) {
    e.preventDefault();
    this.props.cfgElemClear();
  }

@@ -219,126 +335,6 @@ class CfgPageContainer extends Component {
    return -1;
  }

  // Validate new network element form field entries
  validateNetworkElement(element) {
    var data = this.props.cfg.table.entries;

    // Clear previous error message
    this.props.cfgElemSetErrMsg('');

    // Verify that no field is in error
    var fieldsInError = 0;
    _.forOwn(
      element,
      val => (fieldsInError = val.err ? fieldsInError + 1 : fieldsInError)
    );
    if (fieldsInError) {
      this.props.cfgElemSetErrMsg(`${fieldsInError} fields in error`);
      return false;
    }

    // Verify element type
    var type = getElemFieldVal(element, FIELD_TYPE);
    if (type === null) {
      this.props.cfgElemSetErrMsg('Missing element type');
      return false;
    }

    // Check for valid & unique network element name (except if editing)
    var name = getElemFieldVal(element, FIELD_NAME);
    if (name === null || name === '') {
      this.props.cfgElemSetErrMsg('Missing element name');
      return false;
    }

    if (data[name] && (data[name].id !== element.id)) {
      this.props.cfgElemSetErrMsg('Element name already exists');
      return false;
    }

    // Nothing else to validate for Scenario element
    if (type === ELEMENT_TYPE_SCENARIO) {
      return true;
    }

    // Make sure parent exists
    if (!data[getElemFieldVal(element, FIELD_PARENT)]) {
      this.props.cfgElemSetErrMsg('Parent does not exist');
      return false;
    }

    // If GPU requested, make sure type is set
    var gpuCount = getElemFieldVal(element, FIELD_GPU_COUNT);
    if (gpuCount) {
      var gpuType = getElemFieldVal(element, FIELD_GPU_TYPE);
      if (gpuType === null || gpuType === '') {
        this.props.cfgElemSetErrMsg('GPU type not selected');
        return false;
      }
    }

    // If CPU limitations is requested, making sure Min CPU <= Max CPU
    var cpuMin = getElemFieldVal(element, FIELD_CPU_MIN);
    var cpuMax = getElemFieldVal(element, FIELD_CPU_MAX);
    if (cpuMin !== null && cpuMax !== null) {
      if (parseFloat(cpuMin) > parseFloat(cpuMax)) {
        this.props.cfgElemSetErrMsg('Min CPU > Max CPU');
        return false;
      }
    }

    // If Memory limitations is requested, making sure Min Memory <= Max Memory
    var memoryMin = getElemFieldVal(element, FIELD_MEMORY_MIN);
    var memoryMax = getElemFieldVal(element, FIELD_MEMORY_MAX);
    if (memoryMin !== null && memoryMax !== null) {
      if (parseInt(memoryMin) > parseInt(memoryMax)) {
        this.props.cfgElemSetErrMsg('Min Memory > Max Memory');
        return false;
      }
    }

    // Verify cellid/mac address if required
    if (type === ELEMENT_TYPE_POA_4G) {
      var cellId = getElemFieldVal(element, FIELD_CELL_ID);
      if (!cellId) {
        this.props.cfgElemSetErrMsg('Missing Cell ID');
        return false;
      }
    } else if (type === ELEMENT_TYPE_POA_5G) {
      var nrCellId = getElemFieldVal(element, FIELD_NR_CELL_ID);
      if (!nrCellId) {
        this.props.cfgElemSetErrMsg('Missing NR Cell ID');
        return false;
      }
    } else if (type === ELEMENT_TYPE_POA_WIFI) {
      var macId = getElemFieldVal(element, FIELD_MAC_ID);
      if (!macId) {
        this.props.cfgElemSetErrMsg('Missing MAC Address');
        return false;
      }
    }

    // TODO -- verify node port not already used
    const extPorts = externalPorts(element);

    if (extPorts.length) {
      const elemsWithSameExtPort = pipe(
        filter(hasDifferentName(element)),
        filter(hasExtPortsInCommon(element))
      )(Object.values(data));

      if (elemsWithSameExtPort.length) {
        const elemNames = elemsWithSameExtPort.map(e => getElemFieldVal(e, FIELD_NAME));
        this.props.cfgElemSetErrMsg(
          `External port already used in ${elemNames}`
        );
        return false;
      }
    }

    return true;
  }

  // ----------------------------------------
  // SCENARIO CONFIGURATION
  // ----------------------------------------
@@ -728,9 +724,10 @@ class CfgPageContainer extends Component {
                      onSaveElement={elem => this.onSaveElement(elem)}
                      onDeleteElement={elem => this.onDeleteElement(elem)}
                      onApplyCloneElement={elem => this.onApplyCloneElement(elem)}
                      onCancelElement={() => this.onCancelElement()}
                      onCancelElement={e => this.onCancelElement(e)}
                      onEditLocation={elem => this.onEditLocation(elem)}
                      onEditPath={elem => this.onEditPath(elem)}
                      type={TYPE_CFG}
                    />
                  </Elevation>
                </GridCell>
+12 −1
Original line number Diff line number Diff line
@@ -22,6 +22,7 @@ import { Typography } from '@rmwc/typography';
import { updateObject } from '../../util/object-util';
import MobilityEventPane from './mobility-event-pane';
import NetworkCharacteristicsEventPane from './network-characteristics-event-pane';
import ScenarioUpdateEventPane from './scenario-update-event-pane';

import CancelApplyPair from '@/js/components/helper-components/cancel-apply-pair';

@@ -29,7 +30,8 @@ import { uiExecChangeCurrentEvent } from '../../state/ui';

import {
  MOBILITY_EVENT,
  NETWORK_CHARACTERISTICS_EVENT
  NETWORK_CHARACTERISTICS_EVENT,
  SCENARIO_UPDATE_EVENT
} from '../../meep-constants';

import {
@@ -100,6 +102,15 @@ const EventCreationFields = props => {
        networkElements={props.networkElements}
      />
    );
  case SCENARIO_UPDATE_EVENT:
    return (
      <ScenarioUpdateEventPane
        currentEvent={props.currentEvent}
        onSuccess={props.onSuccess}
        onClose={props.onClose}
        api={props.api}
      />
    );
  default:
    return <div></div>;
  }
+4 −3
Original line number Diff line number Diff line
@@ -72,6 +72,7 @@ import {
  IDC_DIALOG_SAVE_REPLAY,
  MOBILITY_EVENT,
  NETWORK_CHARACTERISTICS_EVENT,
  SCENARIO_UPDATE_EVENT,
  EXEC_SELECT_SANDBOX
} from '../../meep-constants';

@@ -365,8 +366,8 @@ class ExecPageContainer extends Component {
      this.props.cfgScenarioName;

    const eventPaneOpen = this.props.eventCreationMode || this.props.eventAutomationMode || this.props.eventReplayMode;
    const spanLeft = eventPaneOpen ? 9 : 12;
    const spanRight = eventPaneOpen ? 3 : 0;
    const spanLeft = eventPaneOpen ? 8 : 12;
    const spanRight = eventPaneOpen ? 4 : 0;
    return (
      <div style={{ width: '100%' }}>
        {this.renderDialogs()}
@@ -464,7 +465,7 @@ class ExecPageContainer extends Component {
                </Elevation>
                <Elevation className="component-style" z={2}>
                  <EventCreationPane
                    eventTypes={[MOBILITY_EVENT, NETWORK_CHARACTERISTICS_EVENT]}
                    eventTypes={[MOBILITY_EVENT, NETWORK_CHARACTERISTICS_EVENT, SCENARIO_UPDATE_EVENT]}
                    api={this.props.eventsApi}
                    hide={!this.props.eventCreationMode}
                    onSuccess={this.props.refreshScenario}
+428 −0

File added.

Preview size limit exceeded, changes collapsed.

Loading