Loading charts/open-map-tiles/config.json 0 → 100644 +38 −0 Original line number Diff line number Diff line { "styles": { "standard": [ "dark-matter", "klokantech-basic", "osm-bright", "positron" ], "custom": [], "lang": "", "langLatin": true, "langAlts": true }, "settings": { "serve": { "vector": true, "raster": true, "services": true, "static": true }, "raster": { "format": "PNG_256", "hidpi": 2, "maxsize": 2048 }, "server": { "title": "", "redirect": "", "domains": [] }, "memcache": { "size": 56.5, "servers": [ "localhost:11211" ] } } } No newline at end of file js-apps/meep-frontend/package-lock.json +92 −0 Original line number Diff line number Diff line Loading @@ -927,6 +927,17 @@ "minimist": "^1.2.0" } }, "@geoman-io/leaflet-geoman-free": { "version": "2.5.0", "resolved": "https://registry.npmjs.org/@geoman-io/leaflet-geoman-free/-/leaflet-geoman-free-2.5.0.tgz", "integrity": "sha512-Zq/gOGPpsRurTrW3d3qiXlvEPHZfU/PZ7jr02jtweaN0kXyHo/WqkihMS9h5yUySjJBXdUC9Xuuo4/ZzHqEH4g==", "requires": { "@turf/difference": "^6.0.2", "@turf/intersect": "^6.1.3", "@turf/kinks": "6.x", "lodash": "^4.17.15" } }, "@jest/console": { "version": "24.9.0", "resolved": "https://registry.npmjs.org/@jest/console/-/console-24.9.0.tgz", Loading Loading @@ -3773,6 +3784,66 @@ } } }, "@turf/area": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/@turf/area/-/area-6.0.1.tgz", "integrity": "sha512-Zv+3N1ep9P5JvR0YOYagLANyapGWQBh8atdeR3bKpWcigVXFsEKNUw03U/5xnh+cKzm7yozHD6MFJkqQv55y0g==", "requires": { "@turf/helpers": "6.x", "@turf/meta": "6.x" } }, "@turf/difference": { "version": "6.0.2", "resolved": "https://registry.npmjs.org/@turf/difference/-/difference-6.0.2.tgz", "integrity": "sha512-WtXkvFgOyHqsG3xtYG/m5Su+gkvyCUTbdW0XOuc3Ha2u9UeeBSGwEzTc2y9THDLDhHqR+DlTl1MMEBihXcy3fg==", "requires": { "@turf/area": "6.x", "@turf/helpers": "6.x", "@turf/invariant": "6.x", "@turf/meta": "6.x", "martinez-polygon-clipping": "^0.4.3" } }, "@turf/helpers": { "version": "6.1.4", "resolved": "https://registry.npmjs.org/@turf/helpers/-/helpers-6.1.4.tgz", "integrity": "sha512-vJvrdOZy1ngC7r3MDA7zIGSoIgyrkWcGnNIEaqn/APmw+bVLF2gAW7HIsdTxd12s5wQMqEpqIQrmrbRRZ0xC7g==" }, "@turf/intersect": { "version": "6.1.3", "resolved": "https://registry.npmjs.org/@turf/intersect/-/intersect-6.1.3.tgz", "integrity": "sha512-SeAJG/zPRRTeyK2OifkPoyLq60q8tv8prpPIH3R8ZhyF4MdLOnMv5MURaQ6kQd+3UTDrL+pYm6rqbPvln1zqIw==", "requires": { "@turf/helpers": "6.x", "@turf/invariant": "6.x", "martinez-polygon-clipping": "^0.4.3" } }, "@turf/invariant": { "version": "6.1.2", "resolved": "https://registry.npmjs.org/@turf/invariant/-/invariant-6.1.2.tgz", "integrity": "sha512-WU08Ph8j0J2jVGlQCKChXoCtI50BB3yEH21V++V0T4cR1T27HKCxkehV2sYMwTierfMBgjwSwDIsxnR4/2mWXg==", "requires": { "@turf/helpers": "6.x" } }, "@turf/kinks": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/@turf/kinks/-/kinks-6.0.0.tgz", "integrity": "sha512-X2xk3+Sr9aeu51t1vBa7Iwowvjxcbl5fePLIo/dDOU4j5WeFoqGCto+DdEHQcC3y8HVUin4i8GaHVaM9sVTphg==", "requires": { "@turf/helpers": "6.x" } }, "@turf/meta": { "version": "6.0.2", "resolved": "https://registry.npmjs.org/@turf/meta/-/meta-6.0.2.tgz", "integrity": "sha512-VA7HJkx7qF1l3+GNGkDVn2oXy4+QoLP6LktXAaZKjuT1JI0YESat7quUkbCMy4zP9lAUuvS4YMslLyTtr919FA==", "requires": { "@turf/helpers": "6.x" } }, "@types/babel__core": { "version": "7.1.3", "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.1.3.tgz", Loading Loading @@ -10847,6 +10918,22 @@ "resolved": "https://registry.npmjs.org/mapbox-gl-leaflet/-/mapbox-gl-leaflet-0.0.12.tgz", "integrity": "sha512-bfGl+CdAYc51ua8s9OOq5J0EcAnHuxS0OoQP5EWsVmSUGFvKkgOD+Od2sFmDOl+zBUjdBEvqLaf9t/tf2BtrWw==" }, "martinez-polygon-clipping": { "version": "0.4.3", "resolved": "https://registry.npmjs.org/martinez-polygon-clipping/-/martinez-polygon-clipping-0.4.3.tgz", "integrity": "sha512-3ZNS0ksKhWTLsmCUkNf+/UimndZ5U2cVOS0I+IjiwF+M23E77TmeOZSmbRJbfCoQUog/vcQ42s3DXrhgOhgPqw==", "requires": { "splaytree": "^0.1.4", "tinyqueue": "^1.2.0" }, "dependencies": { "tinyqueue": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/tinyqueue/-/tinyqueue-1.2.3.tgz", "integrity": "sha512-Qz9RgWuO9l8lT+Y9xvbzhPT2efIUIFd69N7eF7tJ9lnQl0iLj1M7peK7IoUGZL9DJHw9XftqLreccfxcQgYLxA==" } } }, "material-components-web": { "version": "0.38.1", "resolved": "https://registry.npmjs.org/material-components-web/-/material-components-web-0.38.1.tgz", Loading Loading @@ -15151,6 +15238,11 @@ "integrity": "sha512-J+FWzZoynJEXGphVIS+XEh3kFSjZX/1i9gFBaWQcB+/tmpe2qUsSBABpcxqxnAxFdiUFEgAX1bjYGQvIZmoz9Q==", "dev": true }, "splaytree": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/splaytree/-/splaytree-0.1.4.tgz", "integrity": "sha512-D50hKrjZgBzqD3FT2Ek53f2dcDLAQT8SSGrzj3vidNH5ISRgceeGVJ2dQIthKOuayqFXfFjXheHNo4bbt9LhRQ==" }, "split-string": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz", js-apps/meep-frontend/package.json +1 −0 Original line number Diff line number Diff line Loading @@ -38,6 +38,7 @@ "webpack-serve": "^0.3.1" }, "dependencies": { "@geoman-io/leaflet-geoman-free": "2.5.0", "@material-ui/core": "^1.5.1", "@material-ui/icons": "^1.1.1", "axios": "^0.18.0", Loading js-apps/meep-frontend/src/js/containers/cfg/cfg-network-element-container.js +199 −19 Original line number Diff line number Diff line Loading @@ -20,12 +20,13 @@ import React, { Component } from 'react'; import { Select } from '@rmwc/select'; import { Grid, GridCell, GridInner } from '@rmwc/grid'; import { Button } from '@rmwc/button'; import { TextField, TextFieldHelperText } from '@rmwc/textfield'; import { TextField, TextFieldIcon, TextFieldHelperText } from '@rmwc/textfield'; import { Checkbox } from '@rmwc/checkbox'; import { Typography } from '@rmwc/typography'; import { updateObject } from '../../util/object-util'; import { createUniqueName } from '../../util/elem-utils'; import L from 'leaflet'; import IDSelect from '../../components/helper-components/id-select'; import CancelApplyPair from '../../components/helper-components/cancel-apply-pair'; Loading @@ -52,6 +53,11 @@ import { FIELD_MNC, FIELD_DEFAULT_CELL_ID, FIELD_CELL_ID, FIELD_GEO_LOCATION, FIELD_GEO_RADIUS, FIELD_GEO_PATH, FIELD_GEO_EOP_MODE, FIELD_GEO_VELOCITY, FIELD_CHART_ENABLED, FIELD_CHART_LOC, FIELD_CHART_VAL, Loading Loading @@ -123,6 +129,11 @@ import { CFG_ELEM_MCC, CFG_ELEM_DEFAULT_CELL_ID, CFG_ELEM_CELL_ID, CFG_ELEM_GEO_LOCATION, CFG_ELEM_GEO_RADIUS, CFG_ELEM_GEO_PATH, CFG_ELEM_GEO_EOP_MODE, CFG_ELEM_GEO_VELOCITY, CFG_ELEM_CHART_CHECK, CFG_ELEM_CHART_LOC, CFG_ELEM_CHART_GROUP, Loading @@ -134,7 +145,9 @@ import { CFG_BTN_CLONE_ELEM, // Layout type MEEP_COMPONENT_TABLE_LAYOUT MEEP_COMPONENT_TABLE_LAYOUT, GEO_EOP_MODE_LOOP, GEO_EOP_MODE_REVERSE } from '../../meep-constants'; // ELEMENT VALIDATION Loading @@ -145,6 +158,7 @@ const SERVICE_NODE_PORT_MIN = 30000; const SERVICE_NODE_PORT_MAX = 32767; const GPU_COUNT_MIN = 1; const GPU_COUNT_MAX = 4; const EOP_MODES = [GEO_EOP_MODE_LOOP, GEO_EOP_MODE_REVERSE]; const validateName = val => { if (val) { Loading Loading @@ -215,6 +229,14 @@ const validateInt = val => { return val.indexOf('.') === -1 ? null : 'Must be an integer'; }; const validatePositiveInt = val => { const intError = validateInt(val); if (intError) { return intError; } return val >= 0 ? null : 'Must be a positive integer'; }; const validatePath = val => { /*eslint-disable */ if (val.match(/^.*?(?=[\^#%&$\*<>\?\{\|\} ]).*$/)) { Loading Loading @@ -280,6 +302,29 @@ const validateCellularCellId = val => { return null; }; const validateLocation = val => { if (val) { try { L.GeoJSON.coordsToLatLng(JSON.parse(val)); } catch(e) { return '[longitude,latitude]'; } } return null; }; const validateGeoPath = val => { if (val) { // TODO -- Validate location format try { L.GeoJSON.coordsToLatLngs(JSON.parse(val),0); } catch(e) { return '[[longitude,latitude],...]'; } } return null; }; const validateExternalPort = port => { if (port === '') { return null; Loading Loading @@ -409,8 +454,15 @@ const CfgTextField = props => { <> <TextField outlined style={{ width: '100%' }} style={{ width: '100%', marginBottom: 0 }} label={props.label} withLeadingIcon={!props.icon ? null : <TextFieldIcon tabIndex="0" icon={props.icon} onClick={props.onIconClick} /> } type={props.type} onChange={event => { var err = props.validate ? props.validate(event.target.value) : null; Loading Loading @@ -610,10 +662,11 @@ const UserChartFields = ({ element, onUpdate }) => { }; // Display element-specific form fields const TypeRelatedFormFields = ({ onUpdate, element }) => { const TypeRelatedFormFields = ({ onUpdate, onEditLocation, onEditPath, element }) => { var type = getElemFieldVal(element, FIELD_TYPE); var isExternal = getElemFieldVal(element, FIELD_IS_EXTERNAL); var chartEnabled = getElemFieldVal(element, FIELD_CHART_ENABLED); var eopMode = getElemFieldVal(element, FIELD_GEO_EOP_MODE) || ''; switch (type) { case ELEMENT_TYPE_SCENARIO: Loading Loading @@ -683,11 +736,36 @@ const TypeRelatedFormFields = ({ onUpdate, element }) => { ); case ELEMENT_TYPE_POA: return ( <> <NCGroups onUpdate={onUpdate} element={element} prefixes={[PREFIX_TERM_LINK]} /> <Grid> <CfgTextFieldCell span={8} icon='location_on' onIconClick={onEditLocation} onUpdate={onUpdate} element={element} validate={validateLocation} label='Location Coordinates' fieldName={FIELD_GEO_LOCATION} cydata={CFG_ELEM_GEO_LOCATION} /> <CfgTextFieldCell span={4} onUpdate={onUpdate} element={element} isNumber={true} label='Radius (m)' validate={validatePositiveInt} fieldName={FIELD_GEO_RADIUS} cydata={CFG_ELEM_GEO_RADIUS} /> </Grid> </> ); case ELEMENT_TYPE_POA_CELL: return ( Loading @@ -697,6 +775,29 @@ const TypeRelatedFormFields = ({ onUpdate, element }) => { element={element} prefixes={[PREFIX_TERM_LINK]} /> <Grid> <CfgTextFieldCell span={8} icon='location_on' onIconClick={onEditLocation} onUpdate={onUpdate} element={element} validate={validateLocation} label='Location Coordinates' fieldName={FIELD_GEO_LOCATION} cydata={CFG_ELEM_GEO_LOCATION} /> <CfgTextFieldCell span={4} onUpdate={onUpdate} element={element} isNumber={true} label='Radius (m)' validate={validateNumber} fieldName={FIELD_GEO_RADIUS} cydata={CFG_ELEM_GEO_RADIUS} /> </Grid> <CfgTextFieldCell onUpdate={onUpdate} element={element} Loading @@ -708,15 +809,84 @@ const TypeRelatedFormFields = ({ onUpdate, element }) => { </> ); case ELEMENT_TYPE_UE: return ( <> <NCGroups onUpdate={onUpdate} element={element} prefixes={[PREFIX_LINK]} /> <Grid> <CfgTextFieldCell span={12} icon='location_on' onIconClick={onEditLocation} onUpdate={onUpdate} element={element} validate={validateLocation} label='Location Coordinates' fieldName={FIELD_GEO_LOCATION} cydata={CFG_ELEM_GEO_LOCATION} /> <CfgTextFieldCell span={12} icon='location_on' onIconClick={onEditPath} onUpdate={onUpdate} element={element} validate={validateGeoPath} label='Path Coordinates' fieldName={FIELD_GEO_PATH} cydata={CFG_ELEM_GEO_PATH} /> <GridCell span={6} style={{ paddingTop: 16 }}> <IDSelect label='End-of-Path Mode' span={12} options={EOP_MODES} onChange={elem => onUpdate(FIELD_GEO_EOP_MODE, elem.target.value, null)} value={eopMode} disabled={false} cydata={CFG_ELEM_GEO_EOP_MODE} /> </GridCell> <CfgTextFieldCell span={6} onUpdate={onUpdate} element={element} validate={validateNumber} isNumber={true} label='Velocity (m/s)' fieldName={FIELD_GEO_VELOCITY} cydata={CFG_ELEM_GEO_VELOCITY} /> </Grid> </> ); case ELEMENT_TYPE_DC: case ELEMENT_TYPE_EDGE: case ELEMENT_TYPE_FOG: return ( <> <NCGroups onUpdate={onUpdate} element={element} prefixes={[PREFIX_LINK]} /> <Grid> <CfgTextFieldCell span={12} icon='location_on' onIconClick={onEditLocation} onUpdate={onUpdate} element={element} validate={validateLocation} label='Location Coordinates' fieldName={FIELD_GEO_LOCATION} cydata={CFG_ELEM_GEO_LOCATION} /> </Grid> </> ); case ELEMENT_TYPE_UE_APP: return ( Loading Loading @@ -1236,6 +1406,16 @@ export class CfgNetworkElementContainer extends Component { this.props.cfgElemUpdate(elem); } onEditLocation() { var elem = updateObject({}, this.props.configuredElement); this.props.onEditLocation(elem); } onEditPath() { var elem = updateObject({}, this.props.configuredElement); this.props.onEditPath(elem); } render() { const element = this.props.configuredElement; return ( Loading Loading @@ -1282,9 +1462,9 @@ export class CfgNetworkElementContainer extends Component { <TypeRelatedFormFields element={element} onUpdate={(name, val, err) => { this.onUpdateElement(name, val, err); }} onUpdate={(name, val, err) => this.onUpdateElement(name, val, err)} onEditLocation={() => this.onEditLocation()} onEditPath={() => this.onEditPath()} /> <div Loading Loading @@ -1315,10 +1495,10 @@ const styles = { height: '100%' }, block: { marginBottom: 10 marginBottom: 0 }, field: { marginBottom: 10 marginBottom: 0 }, button: { color: 'white' Loading js-apps/meep-frontend/src/js/containers/cfg/cfg-page-container.js +67 −19 Original line number Diff line number Diff line Loading @@ -20,6 +20,8 @@ import React, { Component } from 'react'; import * as YAML from 'yamljs'; import { Grid, GridCell, GridInner } from '@rmwc/grid'; import { Elevation } from '@rmwc/elevation'; import IDSelect from '../../components/helper-components/id-select'; import IDCMap from '../idc-map'; import IDCVis from '../idc-vis'; import CfgNetworkElementContainer from './cfg-network-element-container'; import CfgPageScenarioButtons from './cfg-page-scenario-buttons'; Loading @@ -45,7 +47,8 @@ import { } from '../../state/cfg'; import { uiChangeCurrentDialog uiChangeCurrentDialog, uiCfgChangeView } from '../../state/ui'; import { Loading @@ -53,6 +56,9 @@ import { CFG_STATE_LOADED, CFG_STATE_NEW, CFG_STATE_IDLE, CFG_VIEW_NETWORK, CFG_VIEW_MAP, CFG_VIEW_TYPE, PAGE_CONFIGURE, ELEMENT_TYPE_SCENARIO, IDC_DIALOG_OPEN_SCENARIO, Loading Loading @@ -115,7 +121,9 @@ class CfgPageContainer extends Component { // EDIT onEditElement(element) { if (element !== null) { if (!this.props.configuredElement || (element.id !== this.props.configuredElement.id)) { this.props.cfgElemEdit(element); } } else { this.props.cfgElemClear(); } Loading @@ -129,10 +137,7 @@ class CfgPageContainer extends Component { } // Add/update element in scenario if ( this.props.cfg.elementConfiguration.configurationMode === CFG_ELEM_MODE_NEW ) { if (this.props.cfg.elementConfiguration.configurationMode === CFG_ELEM_MODE_NEW) { this.props.newScenarioElem(element, true); } else { this.props.updateScenarioElem(element); Loading Loading @@ -173,6 +178,24 @@ class CfgPageContainer extends Component { this.props.cfgElemClear(); } // Edit Location onEditLocation() { this.toggleCfgView(); } // Edit Path onEditPath() { this.toggleCfgView(); } toggleCfgView() { if (this.props.cfgView === CFG_VIEW_NETWORK) { this.props.changeView(CFG_VIEW_MAP); } else { this.props.changeView(CFG_VIEW_NETWORK); } } findIndexByKeyValue(_array, key, value) { for (var i = 0; i < _array.length; i++) { if (getElemFieldVal(_array[i], key) === value) { Loading Loading @@ -585,13 +608,26 @@ class CfgPageContainer extends Component { style={styles.headline} > <GridInner> <GridCell align={'middle'} span={4}> <IDSelect label="View" span={2} options={[CFG_VIEW_NETWORK, CFG_VIEW_MAP]} onChange={(e) => this.props.changeView(e.target.value)} value={this.props.cfgView} disabled={false} cydata={CFG_VIEW_TYPE} /> <GridCell align={'middle'} style={{ height: '100%'}} span={3}> <GridInner style={{ marginLeft: 10, height: '100%', borderLeft: '2px solid #e4e4e4'}}> <GridCell align={'middle'} style={{ marginLeft: 20}} span={12}> <HeadlineBar titleLabel="Scenario" scenarioName={this.props.scenarioName} /> </GridCell> <GridCell align={'middle'} span={8}> </GridInner> </GridCell> <GridCell align={'middle'} span={7}> <GridInner align={'right'}> <GridCell span={12}> <CfgPageScenarioButtons Loading Loading @@ -629,12 +665,20 @@ class CfgPageContainer extends Component { <GridCell span={8}> <Elevation className="component-style" z={2}> <div style={{ padding: 10, height: '70vh' }}> {this.props.cfgView === CFG_VIEW_NETWORK && ( <IDCVis type={TYPE_CFG} width='100%' height='100%' onEditElement={elem => this.onEditElement(elem)} /> )} {this.props.cfgView === CFG_VIEW_MAP && ( <IDCMap type={TYPE_CFG} onEditElement={elem => this.onEditElement(elem)} /> )} </div> </Elevation> </GridCell> Loading @@ -647,6 +691,8 @@ class CfgPageContainer extends Component { onDeleteElement={elem => this.onDeleteElement(elem)} onApplyCloneElement={elem => this.onApplyCloneElement(elem)} onCancelElement={() => this.onCancelElement()} onEditLocation={elem => this.onEditLocation(elem)} onEditPath={elem => this.onEditPath(elem)} /> </Elevation> </GridCell> Loading Loading @@ -695,6 +741,7 @@ const mapStateToProps = state => { return { cfg: state.cfg, cfgState: state.cfg.state, cfgView: state.ui.cfgView, configuredElement: state.cfg.elementConfiguration.configuredElement, table: state.cfg.table, selectedElements: state.cfg.table.selected, Loading @@ -715,7 +762,8 @@ const mapDispatchToProps = dispatch => { changeCurrentDialog: type => dispatch(uiChangeCurrentDialog(type)), changeScenarioList: scenarios => dispatch(cfgChangeScenarioList(scenarios)), changeState: s => dispatch(cfgChangeState(s)), changeScenario: scenario => dispatch(cfgChangeScenario(scenario)) changeScenario: scenario => dispatch(cfgChangeScenario(scenario)), changeView: view => dispatch(uiCfgChangeView(view)) }; }; Loading Loading
charts/open-map-tiles/config.json 0 → 100644 +38 −0 Original line number Diff line number Diff line { "styles": { "standard": [ "dark-matter", "klokantech-basic", "osm-bright", "positron" ], "custom": [], "lang": "", "langLatin": true, "langAlts": true }, "settings": { "serve": { "vector": true, "raster": true, "services": true, "static": true }, "raster": { "format": "PNG_256", "hidpi": 2, "maxsize": 2048 }, "server": { "title": "", "redirect": "", "domains": [] }, "memcache": { "size": 56.5, "servers": [ "localhost:11211" ] } } } No newline at end of file
js-apps/meep-frontend/package-lock.json +92 −0 Original line number Diff line number Diff line Loading @@ -927,6 +927,17 @@ "minimist": "^1.2.0" } }, "@geoman-io/leaflet-geoman-free": { "version": "2.5.0", "resolved": "https://registry.npmjs.org/@geoman-io/leaflet-geoman-free/-/leaflet-geoman-free-2.5.0.tgz", "integrity": "sha512-Zq/gOGPpsRurTrW3d3qiXlvEPHZfU/PZ7jr02jtweaN0kXyHo/WqkihMS9h5yUySjJBXdUC9Xuuo4/ZzHqEH4g==", "requires": { "@turf/difference": "^6.0.2", "@turf/intersect": "^6.1.3", "@turf/kinks": "6.x", "lodash": "^4.17.15" } }, "@jest/console": { "version": "24.9.0", "resolved": "https://registry.npmjs.org/@jest/console/-/console-24.9.0.tgz", Loading Loading @@ -3773,6 +3784,66 @@ } } }, "@turf/area": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/@turf/area/-/area-6.0.1.tgz", "integrity": "sha512-Zv+3N1ep9P5JvR0YOYagLANyapGWQBh8atdeR3bKpWcigVXFsEKNUw03U/5xnh+cKzm7yozHD6MFJkqQv55y0g==", "requires": { "@turf/helpers": "6.x", "@turf/meta": "6.x" } }, "@turf/difference": { "version": "6.0.2", "resolved": "https://registry.npmjs.org/@turf/difference/-/difference-6.0.2.tgz", "integrity": "sha512-WtXkvFgOyHqsG3xtYG/m5Su+gkvyCUTbdW0XOuc3Ha2u9UeeBSGwEzTc2y9THDLDhHqR+DlTl1MMEBihXcy3fg==", "requires": { "@turf/area": "6.x", "@turf/helpers": "6.x", "@turf/invariant": "6.x", "@turf/meta": "6.x", "martinez-polygon-clipping": "^0.4.3" } }, "@turf/helpers": { "version": "6.1.4", "resolved": "https://registry.npmjs.org/@turf/helpers/-/helpers-6.1.4.tgz", "integrity": "sha512-vJvrdOZy1ngC7r3MDA7zIGSoIgyrkWcGnNIEaqn/APmw+bVLF2gAW7HIsdTxd12s5wQMqEpqIQrmrbRRZ0xC7g==" }, "@turf/intersect": { "version": "6.1.3", "resolved": "https://registry.npmjs.org/@turf/intersect/-/intersect-6.1.3.tgz", "integrity": "sha512-SeAJG/zPRRTeyK2OifkPoyLq60q8tv8prpPIH3R8ZhyF4MdLOnMv5MURaQ6kQd+3UTDrL+pYm6rqbPvln1zqIw==", "requires": { "@turf/helpers": "6.x", "@turf/invariant": "6.x", "martinez-polygon-clipping": "^0.4.3" } }, "@turf/invariant": { "version": "6.1.2", "resolved": "https://registry.npmjs.org/@turf/invariant/-/invariant-6.1.2.tgz", "integrity": "sha512-WU08Ph8j0J2jVGlQCKChXoCtI50BB3yEH21V++V0T4cR1T27HKCxkehV2sYMwTierfMBgjwSwDIsxnR4/2mWXg==", "requires": { "@turf/helpers": "6.x" } }, "@turf/kinks": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/@turf/kinks/-/kinks-6.0.0.tgz", "integrity": "sha512-X2xk3+Sr9aeu51t1vBa7Iwowvjxcbl5fePLIo/dDOU4j5WeFoqGCto+DdEHQcC3y8HVUin4i8GaHVaM9sVTphg==", "requires": { "@turf/helpers": "6.x" } }, "@turf/meta": { "version": "6.0.2", "resolved": "https://registry.npmjs.org/@turf/meta/-/meta-6.0.2.tgz", "integrity": "sha512-VA7HJkx7qF1l3+GNGkDVn2oXy4+QoLP6LktXAaZKjuT1JI0YESat7quUkbCMy4zP9lAUuvS4YMslLyTtr919FA==", "requires": { "@turf/helpers": "6.x" } }, "@types/babel__core": { "version": "7.1.3", "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.1.3.tgz", Loading Loading @@ -10847,6 +10918,22 @@ "resolved": "https://registry.npmjs.org/mapbox-gl-leaflet/-/mapbox-gl-leaflet-0.0.12.tgz", "integrity": "sha512-bfGl+CdAYc51ua8s9OOq5J0EcAnHuxS0OoQP5EWsVmSUGFvKkgOD+Od2sFmDOl+zBUjdBEvqLaf9t/tf2BtrWw==" }, "martinez-polygon-clipping": { "version": "0.4.3", "resolved": "https://registry.npmjs.org/martinez-polygon-clipping/-/martinez-polygon-clipping-0.4.3.tgz", "integrity": "sha512-3ZNS0ksKhWTLsmCUkNf+/UimndZ5U2cVOS0I+IjiwF+M23E77TmeOZSmbRJbfCoQUog/vcQ42s3DXrhgOhgPqw==", "requires": { "splaytree": "^0.1.4", "tinyqueue": "^1.2.0" }, "dependencies": { "tinyqueue": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/tinyqueue/-/tinyqueue-1.2.3.tgz", "integrity": "sha512-Qz9RgWuO9l8lT+Y9xvbzhPT2efIUIFd69N7eF7tJ9lnQl0iLj1M7peK7IoUGZL9DJHw9XftqLreccfxcQgYLxA==" } } }, "material-components-web": { "version": "0.38.1", "resolved": "https://registry.npmjs.org/material-components-web/-/material-components-web-0.38.1.tgz", Loading Loading @@ -15151,6 +15238,11 @@ "integrity": "sha512-J+FWzZoynJEXGphVIS+XEh3kFSjZX/1i9gFBaWQcB+/tmpe2qUsSBABpcxqxnAxFdiUFEgAX1bjYGQvIZmoz9Q==", "dev": true }, "splaytree": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/splaytree/-/splaytree-0.1.4.tgz", "integrity": "sha512-D50hKrjZgBzqD3FT2Ek53f2dcDLAQT8SSGrzj3vidNH5ISRgceeGVJ2dQIthKOuayqFXfFjXheHNo4bbt9LhRQ==" }, "split-string": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz",
js-apps/meep-frontend/package.json +1 −0 Original line number Diff line number Diff line Loading @@ -38,6 +38,7 @@ "webpack-serve": "^0.3.1" }, "dependencies": { "@geoman-io/leaflet-geoman-free": "2.5.0", "@material-ui/core": "^1.5.1", "@material-ui/icons": "^1.1.1", "axios": "^0.18.0", Loading
js-apps/meep-frontend/src/js/containers/cfg/cfg-network-element-container.js +199 −19 Original line number Diff line number Diff line Loading @@ -20,12 +20,13 @@ import React, { Component } from 'react'; import { Select } from '@rmwc/select'; import { Grid, GridCell, GridInner } from '@rmwc/grid'; import { Button } from '@rmwc/button'; import { TextField, TextFieldHelperText } from '@rmwc/textfield'; import { TextField, TextFieldIcon, TextFieldHelperText } from '@rmwc/textfield'; import { Checkbox } from '@rmwc/checkbox'; import { Typography } from '@rmwc/typography'; import { updateObject } from '../../util/object-util'; import { createUniqueName } from '../../util/elem-utils'; import L from 'leaflet'; import IDSelect from '../../components/helper-components/id-select'; import CancelApplyPair from '../../components/helper-components/cancel-apply-pair'; Loading @@ -52,6 +53,11 @@ import { FIELD_MNC, FIELD_DEFAULT_CELL_ID, FIELD_CELL_ID, FIELD_GEO_LOCATION, FIELD_GEO_RADIUS, FIELD_GEO_PATH, FIELD_GEO_EOP_MODE, FIELD_GEO_VELOCITY, FIELD_CHART_ENABLED, FIELD_CHART_LOC, FIELD_CHART_VAL, Loading Loading @@ -123,6 +129,11 @@ import { CFG_ELEM_MCC, CFG_ELEM_DEFAULT_CELL_ID, CFG_ELEM_CELL_ID, CFG_ELEM_GEO_LOCATION, CFG_ELEM_GEO_RADIUS, CFG_ELEM_GEO_PATH, CFG_ELEM_GEO_EOP_MODE, CFG_ELEM_GEO_VELOCITY, CFG_ELEM_CHART_CHECK, CFG_ELEM_CHART_LOC, CFG_ELEM_CHART_GROUP, Loading @@ -134,7 +145,9 @@ import { CFG_BTN_CLONE_ELEM, // Layout type MEEP_COMPONENT_TABLE_LAYOUT MEEP_COMPONENT_TABLE_LAYOUT, GEO_EOP_MODE_LOOP, GEO_EOP_MODE_REVERSE } from '../../meep-constants'; // ELEMENT VALIDATION Loading @@ -145,6 +158,7 @@ const SERVICE_NODE_PORT_MIN = 30000; const SERVICE_NODE_PORT_MAX = 32767; const GPU_COUNT_MIN = 1; const GPU_COUNT_MAX = 4; const EOP_MODES = [GEO_EOP_MODE_LOOP, GEO_EOP_MODE_REVERSE]; const validateName = val => { if (val) { Loading Loading @@ -215,6 +229,14 @@ const validateInt = val => { return val.indexOf('.') === -1 ? null : 'Must be an integer'; }; const validatePositiveInt = val => { const intError = validateInt(val); if (intError) { return intError; } return val >= 0 ? null : 'Must be a positive integer'; }; const validatePath = val => { /*eslint-disable */ if (val.match(/^.*?(?=[\^#%&$\*<>\?\{\|\} ]).*$/)) { Loading Loading @@ -280,6 +302,29 @@ const validateCellularCellId = val => { return null; }; const validateLocation = val => { if (val) { try { L.GeoJSON.coordsToLatLng(JSON.parse(val)); } catch(e) { return '[longitude,latitude]'; } } return null; }; const validateGeoPath = val => { if (val) { // TODO -- Validate location format try { L.GeoJSON.coordsToLatLngs(JSON.parse(val),0); } catch(e) { return '[[longitude,latitude],...]'; } } return null; }; const validateExternalPort = port => { if (port === '') { return null; Loading Loading @@ -409,8 +454,15 @@ const CfgTextField = props => { <> <TextField outlined style={{ width: '100%' }} style={{ width: '100%', marginBottom: 0 }} label={props.label} withLeadingIcon={!props.icon ? null : <TextFieldIcon tabIndex="0" icon={props.icon} onClick={props.onIconClick} /> } type={props.type} onChange={event => { var err = props.validate ? props.validate(event.target.value) : null; Loading Loading @@ -610,10 +662,11 @@ const UserChartFields = ({ element, onUpdate }) => { }; // Display element-specific form fields const TypeRelatedFormFields = ({ onUpdate, element }) => { const TypeRelatedFormFields = ({ onUpdate, onEditLocation, onEditPath, element }) => { var type = getElemFieldVal(element, FIELD_TYPE); var isExternal = getElemFieldVal(element, FIELD_IS_EXTERNAL); var chartEnabled = getElemFieldVal(element, FIELD_CHART_ENABLED); var eopMode = getElemFieldVal(element, FIELD_GEO_EOP_MODE) || ''; switch (type) { case ELEMENT_TYPE_SCENARIO: Loading Loading @@ -683,11 +736,36 @@ const TypeRelatedFormFields = ({ onUpdate, element }) => { ); case ELEMENT_TYPE_POA: return ( <> <NCGroups onUpdate={onUpdate} element={element} prefixes={[PREFIX_TERM_LINK]} /> <Grid> <CfgTextFieldCell span={8} icon='location_on' onIconClick={onEditLocation} onUpdate={onUpdate} element={element} validate={validateLocation} label='Location Coordinates' fieldName={FIELD_GEO_LOCATION} cydata={CFG_ELEM_GEO_LOCATION} /> <CfgTextFieldCell span={4} onUpdate={onUpdate} element={element} isNumber={true} label='Radius (m)' validate={validatePositiveInt} fieldName={FIELD_GEO_RADIUS} cydata={CFG_ELEM_GEO_RADIUS} /> </Grid> </> ); case ELEMENT_TYPE_POA_CELL: return ( Loading @@ -697,6 +775,29 @@ const TypeRelatedFormFields = ({ onUpdate, element }) => { element={element} prefixes={[PREFIX_TERM_LINK]} /> <Grid> <CfgTextFieldCell span={8} icon='location_on' onIconClick={onEditLocation} onUpdate={onUpdate} element={element} validate={validateLocation} label='Location Coordinates' fieldName={FIELD_GEO_LOCATION} cydata={CFG_ELEM_GEO_LOCATION} /> <CfgTextFieldCell span={4} onUpdate={onUpdate} element={element} isNumber={true} label='Radius (m)' validate={validateNumber} fieldName={FIELD_GEO_RADIUS} cydata={CFG_ELEM_GEO_RADIUS} /> </Grid> <CfgTextFieldCell onUpdate={onUpdate} element={element} Loading @@ -708,15 +809,84 @@ const TypeRelatedFormFields = ({ onUpdate, element }) => { </> ); case ELEMENT_TYPE_UE: return ( <> <NCGroups onUpdate={onUpdate} element={element} prefixes={[PREFIX_LINK]} /> <Grid> <CfgTextFieldCell span={12} icon='location_on' onIconClick={onEditLocation} onUpdate={onUpdate} element={element} validate={validateLocation} label='Location Coordinates' fieldName={FIELD_GEO_LOCATION} cydata={CFG_ELEM_GEO_LOCATION} /> <CfgTextFieldCell span={12} icon='location_on' onIconClick={onEditPath} onUpdate={onUpdate} element={element} validate={validateGeoPath} label='Path Coordinates' fieldName={FIELD_GEO_PATH} cydata={CFG_ELEM_GEO_PATH} /> <GridCell span={6} style={{ paddingTop: 16 }}> <IDSelect label='End-of-Path Mode' span={12} options={EOP_MODES} onChange={elem => onUpdate(FIELD_GEO_EOP_MODE, elem.target.value, null)} value={eopMode} disabled={false} cydata={CFG_ELEM_GEO_EOP_MODE} /> </GridCell> <CfgTextFieldCell span={6} onUpdate={onUpdate} element={element} validate={validateNumber} isNumber={true} label='Velocity (m/s)' fieldName={FIELD_GEO_VELOCITY} cydata={CFG_ELEM_GEO_VELOCITY} /> </Grid> </> ); case ELEMENT_TYPE_DC: case ELEMENT_TYPE_EDGE: case ELEMENT_TYPE_FOG: return ( <> <NCGroups onUpdate={onUpdate} element={element} prefixes={[PREFIX_LINK]} /> <Grid> <CfgTextFieldCell span={12} icon='location_on' onIconClick={onEditLocation} onUpdate={onUpdate} element={element} validate={validateLocation} label='Location Coordinates' fieldName={FIELD_GEO_LOCATION} cydata={CFG_ELEM_GEO_LOCATION} /> </Grid> </> ); case ELEMENT_TYPE_UE_APP: return ( Loading Loading @@ -1236,6 +1406,16 @@ export class CfgNetworkElementContainer extends Component { this.props.cfgElemUpdate(elem); } onEditLocation() { var elem = updateObject({}, this.props.configuredElement); this.props.onEditLocation(elem); } onEditPath() { var elem = updateObject({}, this.props.configuredElement); this.props.onEditPath(elem); } render() { const element = this.props.configuredElement; return ( Loading Loading @@ -1282,9 +1462,9 @@ export class CfgNetworkElementContainer extends Component { <TypeRelatedFormFields element={element} onUpdate={(name, val, err) => { this.onUpdateElement(name, val, err); }} onUpdate={(name, val, err) => this.onUpdateElement(name, val, err)} onEditLocation={() => this.onEditLocation()} onEditPath={() => this.onEditPath()} /> <div Loading Loading @@ -1315,10 +1495,10 @@ const styles = { height: '100%' }, block: { marginBottom: 10 marginBottom: 0 }, field: { marginBottom: 10 marginBottom: 0 }, button: { color: 'white' Loading
js-apps/meep-frontend/src/js/containers/cfg/cfg-page-container.js +67 −19 Original line number Diff line number Diff line Loading @@ -20,6 +20,8 @@ import React, { Component } from 'react'; import * as YAML from 'yamljs'; import { Grid, GridCell, GridInner } from '@rmwc/grid'; import { Elevation } from '@rmwc/elevation'; import IDSelect from '../../components/helper-components/id-select'; import IDCMap from '../idc-map'; import IDCVis from '../idc-vis'; import CfgNetworkElementContainer from './cfg-network-element-container'; import CfgPageScenarioButtons from './cfg-page-scenario-buttons'; Loading @@ -45,7 +47,8 @@ import { } from '../../state/cfg'; import { uiChangeCurrentDialog uiChangeCurrentDialog, uiCfgChangeView } from '../../state/ui'; import { Loading @@ -53,6 +56,9 @@ import { CFG_STATE_LOADED, CFG_STATE_NEW, CFG_STATE_IDLE, CFG_VIEW_NETWORK, CFG_VIEW_MAP, CFG_VIEW_TYPE, PAGE_CONFIGURE, ELEMENT_TYPE_SCENARIO, IDC_DIALOG_OPEN_SCENARIO, Loading Loading @@ -115,7 +121,9 @@ class CfgPageContainer extends Component { // EDIT onEditElement(element) { if (element !== null) { if (!this.props.configuredElement || (element.id !== this.props.configuredElement.id)) { this.props.cfgElemEdit(element); } } else { this.props.cfgElemClear(); } Loading @@ -129,10 +137,7 @@ class CfgPageContainer extends Component { } // Add/update element in scenario if ( this.props.cfg.elementConfiguration.configurationMode === CFG_ELEM_MODE_NEW ) { if (this.props.cfg.elementConfiguration.configurationMode === CFG_ELEM_MODE_NEW) { this.props.newScenarioElem(element, true); } else { this.props.updateScenarioElem(element); Loading Loading @@ -173,6 +178,24 @@ class CfgPageContainer extends Component { this.props.cfgElemClear(); } // Edit Location onEditLocation() { this.toggleCfgView(); } // Edit Path onEditPath() { this.toggleCfgView(); } toggleCfgView() { if (this.props.cfgView === CFG_VIEW_NETWORK) { this.props.changeView(CFG_VIEW_MAP); } else { this.props.changeView(CFG_VIEW_NETWORK); } } findIndexByKeyValue(_array, key, value) { for (var i = 0; i < _array.length; i++) { if (getElemFieldVal(_array[i], key) === value) { Loading Loading @@ -585,13 +608,26 @@ class CfgPageContainer extends Component { style={styles.headline} > <GridInner> <GridCell align={'middle'} span={4}> <IDSelect label="View" span={2} options={[CFG_VIEW_NETWORK, CFG_VIEW_MAP]} onChange={(e) => this.props.changeView(e.target.value)} value={this.props.cfgView} disabled={false} cydata={CFG_VIEW_TYPE} /> <GridCell align={'middle'} style={{ height: '100%'}} span={3}> <GridInner style={{ marginLeft: 10, height: '100%', borderLeft: '2px solid #e4e4e4'}}> <GridCell align={'middle'} style={{ marginLeft: 20}} span={12}> <HeadlineBar titleLabel="Scenario" scenarioName={this.props.scenarioName} /> </GridCell> <GridCell align={'middle'} span={8}> </GridInner> </GridCell> <GridCell align={'middle'} span={7}> <GridInner align={'right'}> <GridCell span={12}> <CfgPageScenarioButtons Loading Loading @@ -629,12 +665,20 @@ class CfgPageContainer extends Component { <GridCell span={8}> <Elevation className="component-style" z={2}> <div style={{ padding: 10, height: '70vh' }}> {this.props.cfgView === CFG_VIEW_NETWORK && ( <IDCVis type={TYPE_CFG} width='100%' height='100%' onEditElement={elem => this.onEditElement(elem)} /> )} {this.props.cfgView === CFG_VIEW_MAP && ( <IDCMap type={TYPE_CFG} onEditElement={elem => this.onEditElement(elem)} /> )} </div> </Elevation> </GridCell> Loading @@ -647,6 +691,8 @@ class CfgPageContainer extends Component { onDeleteElement={elem => this.onDeleteElement(elem)} onApplyCloneElement={elem => this.onApplyCloneElement(elem)} onCancelElement={() => this.onCancelElement()} onEditLocation={elem => this.onEditLocation(elem)} onEditPath={elem => this.onEditPath(elem)} /> </Elevation> </GridCell> Loading Loading @@ -695,6 +741,7 @@ const mapStateToProps = state => { return { cfg: state.cfg, cfgState: state.cfg.state, cfgView: state.ui.cfgView, configuredElement: state.cfg.elementConfiguration.configuredElement, table: state.cfg.table, selectedElements: state.cfg.table.selected, Loading @@ -715,7 +762,8 @@ const mapDispatchToProps = dispatch => { changeCurrentDialog: type => dispatch(uiChangeCurrentDialog(type)), changeScenarioList: scenarios => dispatch(cfgChangeScenarioList(scenarios)), changeState: s => dispatch(cfgChangeState(s)), changeScenario: scenario => dispatch(cfgChangeScenario(scenario)) changeScenario: scenario => dispatch(cfgChangeScenario(scenario)), changeView: view => dispatch(uiCfgChangeView(view)) }; }; Loading