Loading js-apps/meep-frontend/src/js/containers/cfg/cfg-network-element-container.js +107 −30 Original line number Diff line number Diff line Loading @@ -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, Loading Loading @@ -765,7 +771,6 @@ const NCGroups = ({ prefixes, onUpdate, element }) => { return ( <NCGroup onUpdate={onUpdate} type={TYPE_CFG} element={element} prefix={p} key={p} Loading Loading @@ -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 }}> Loading Loading @@ -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); Loading @@ -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); Loading @@ -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> Loading @@ -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> Loading @@ -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 Loading @@ -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); }} /> Loading Loading @@ -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)) }; }; Loading js-apps/meep-frontend/src/js/containers/cfg/cfg-page-container.js +121 −124 Original line number Diff line number Diff line Loading @@ -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); Loading Loading @@ -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; } Loading @@ -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; } Loading @@ -186,7 +301,8 @@ class CfgPageContainer extends Component { } // CANCEL onCancelElement() { onCancelElement(e) { e.preventDefault(); this.props.cfgElemClear(); } Loading Loading @@ -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 // ---------------------------------------- Loading Loading @@ -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> Loading js-apps/meep-frontend/src/js/containers/exec/event-creation-pane.js +12 −1 Original line number Diff line number Diff line Loading @@ -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'; Loading @@ -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 { Loading Loading @@ -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>; } Loading js-apps/meep-frontend/src/js/containers/exec/exec-page-container.js +4 −3 Original line number Diff line number Diff line Loading @@ -72,6 +72,7 @@ import { IDC_DIALOG_SAVE_REPLAY, MOBILITY_EVENT, NETWORK_CHARACTERISTICS_EVENT, SCENARIO_UPDATE_EVENT, EXEC_SELECT_SANDBOX } from '../../meep-constants'; Loading Loading @@ -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()} Loading Loading @@ -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} Loading js-apps/meep-frontend/src/js/containers/exec/scenario-update-event-pane.js 0 → 100644 +428 −0 File added.Preview size limit exceeded, changes collapsed. Show changes Loading
js-apps/meep-frontend/src/js/containers/cfg/cfg-network-element-container.js +107 −30 Original line number Diff line number Diff line Loading @@ -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, Loading Loading @@ -765,7 +771,6 @@ const NCGroups = ({ prefixes, onUpdate, element }) => { return ( <NCGroup onUpdate={onUpdate} type={TYPE_CFG} element={element} prefix={p} key={p} Loading Loading @@ -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 }}> Loading Loading @@ -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); Loading @@ -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); Loading @@ -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> Loading @@ -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> Loading @@ -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 Loading @@ -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); }} /> Loading Loading @@ -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)) }; }; Loading
js-apps/meep-frontend/src/js/containers/cfg/cfg-page-container.js +121 −124 Original line number Diff line number Diff line Loading @@ -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); Loading Loading @@ -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; } Loading @@ -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; } Loading @@ -186,7 +301,8 @@ class CfgPageContainer extends Component { } // CANCEL onCancelElement() { onCancelElement(e) { e.preventDefault(); this.props.cfgElemClear(); } Loading Loading @@ -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 // ---------------------------------------- Loading Loading @@ -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> Loading
js-apps/meep-frontend/src/js/containers/exec/event-creation-pane.js +12 −1 Original line number Diff line number Diff line Loading @@ -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'; Loading @@ -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 { Loading Loading @@ -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>; } Loading
js-apps/meep-frontend/src/js/containers/exec/exec-page-container.js +4 −3 Original line number Diff line number Diff line Loading @@ -72,6 +72,7 @@ import { IDC_DIALOG_SAVE_REPLAY, MOBILITY_EVENT, NETWORK_CHARACTERISTICS_EVENT, SCENARIO_UPDATE_EVENT, EXEC_SELECT_SANDBOX } from '../../meep-constants'; Loading Loading @@ -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()} Loading Loading @@ -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} Loading
js-apps/meep-frontend/src/js/containers/exec/scenario-update-event-pane.js 0 → 100644 +428 −0 File added.Preview size limit exceeded, changes collapsed. Show changes