Loading js-apps/meep-frontend/package-lock.json +5 −0 Original line number Diff line number Diff line Loading @@ -14606,6 +14606,11 @@ } } }, "react-d3-axis": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/react-d3-axis/-/react-d3-axis-0.1.2.tgz", "integrity": "sha512-Id2C208SGcLcIfgrdl9ffgZKXtp3wELV7dC3HJVjim+J0IQiAaZo9APSnlvJE2kB90C7wJKlXdFI1bYPg7jytA==" }, "react-d3-graph": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/react-d3-graph/-/react-d3-graph-2.1.0.tgz", js-apps/meep-frontend/package.json +1 −0 Original line number Diff line number Diff line Loading @@ -52,6 +52,7 @@ "material-design-icons": "3.0.1", "prop-types": "15.6.2", "react": "^16.8.6", "react-d3-axis": "^0.1.2", "react-d3-graph": "^2.0.2", "react-dom": "^16.8.6", "react-iframe": "^1.5.0", Loading js-apps/meep-frontend/src/js/containers/dashboard-container.js +122 −121 Original line number Diff line number Diff line import _ from 'lodash'; import { connect } from 'react-redux'; import React, { Component, useState } from 'react'; import React, { Component } from 'react'; import { Grid, GridCell, GridInner } from '@rmwc/grid'; import { Grid, GridCell } from '@rmwc/grid'; import { Elevation } from '@rmwc/elevation'; import { Graph } from 'react-d3-graph'; import ReactDOM from 'react-dom'; // import ReactDOM from 'react-dom'; import { Button } from '@rmwc/button'; import { Checkbox } from '@rmwc/checkbox'; import { TextField, TextFieldHelperText } from '@rmwc/textfield'; import moment from 'moment'; import * as d3 from 'd3'; import axios from 'axios'; // import IDCAreaChart from './idc-area-chart'; import IDCLineChart from './idc-line-chart'; import IDCGraph from './idc-graph'; import IDCAppsView from './idc-apps-view'; import IDSelect from '../components/helper-components/id-select'; import { idlog } from '../util/functional'; import { getScenarioNodeChildren, isApp } from '../util/scenario-utils'; import { dataAccessorForType, dataSetterForType, isDataPointOfType } from '../util/metrics'; Loading @@ -42,15 +41,15 @@ import { } from '../meep-constants'; const VIEW_NAME_NONE = 'none'; const TIME_FORMAT = moment.HTML5_FMT.DATETIME_LOCAL_MS; function colorArray(dataLength) { const colorScale = d3.interpolateInferno; // Other possible color scales: // const colorScale = d3.interpolateMagma; // const colorScale = d3.interpolateCool; // const colorScale = d3.interpolateWarm; // const colorScale = d3.interpolateCubehelixDefault; // interpolateViridis // const colorScale = d3.interpolateCubehelixDefault; let colorArray = []; Loading @@ -68,41 +67,22 @@ function colorArray(dataLength) { const metricsBasePath = 'http://10.3.16.73:30008/v1'; const dataPointFromEpochDataPoints = destinations => sourceNodeId => dataAccessor => epochDataPoints => { if (!epochDataPoints.length) { return null; const buildSeriesFromEpoch = (series, epoch) => { epoch.data.forEach(p => { if (! series[p.dest]) { series[p.dest] = []; } let dp = { date: epochDataPoints[0].timestamp }; const avgForDest = dataPoints => acc => dest => { const hasSource = src => p => p.src === src; const hasDestination = dest => p => p.dest === dest; const dataPointsForDestSource = dataPoints .filter(hasSource(sourceNodeId)) .filter(hasDestination(dest)); const avg = d3.mean(dataPointsForDestSource, acc); return avg; }; destinations.forEach(dest => { dp[dest] = avgForDest(epochDataPoints)(dataAccessor)(dest) || 0; series[p.dest].push(p); }); return dp; return series; }; const notNull = x => x; const epochsToDataPoints = epochs => nb => destinations => dataAccessor => sourceNodeId => { const selectedEpochs = epochs.length ? epochs.slice(-nb) : []; if (selectedEpochs.length === 0) { console.log('epoch length is 0'); } const dataPoints = selectedEpochs.map(dataPointFromEpochDataPoints(destinations)(sourceNodeId)(dataAccessor)).filter(notNull); return dataPoints; const epochsToSeries = (epochs) => { let series = epochs.reduce((s, current) => { return buildSeriesFromEpoch(s, current); }, {}); return series; }; const ConfigurationView = (props) => { Loading @@ -116,7 +96,6 @@ const ConfigurationView = (props) => { onChange={(e) => { props.changeView1(e.target.value); }} // disabled={props.disabled} value={props.view1} /> </GridCell> Loading @@ -128,7 +107,6 @@ const ConfigurationView = (props) => { onChange={(e) => { props.changeView2(e.target.value); }} // disabled={props.disabled} value={props.view1} /> </GridCell> Loading @@ -140,7 +118,6 @@ const ConfigurationView = (props) => { onChange={(e) => { props.changeSourceNodeSelected(e.target.value); }} // disabled={props.disabled} value={props.sourceNodeSelected ? props.sourceNodeSelected.data.id : ''} /> </GridCell> Loading @@ -158,7 +135,6 @@ const ConfigurationView = (props) => { ); }; const DATA_CONFIGURATION = 'DATA_CONFIGURATION'; const MAIN_CONFIGURATION = 'MAIN_CONFIGURATION'; const buttonStyles = { Loading @@ -177,10 +153,11 @@ const ViewForName = ( apps, colorRange, width, height, min, max, data, series, startTime, mobilityEvents, dataPoints, dataAccessor, Loading Loading @@ -210,12 +187,13 @@ const ViewForName = ( width={width} height={600} data={data} series={series} startTime={startTime} dataAccessor={dataAccessor} dataType={dataType} selectedSource={selectedSource} colorForApp={colorForApp} onNodeClicked={(e) => { console.log('Node clicked is: ', e.node); changeSourceNodeSelected(e.node); }} displayEdgeLabels={displayEdgeLabels} Loading @@ -225,14 +203,14 @@ const ViewForName = ( return ( <IDCLineChart data={dataPoints} series={series} startTime={startTime} mobilityEvents={mobilityEvents} width={width} height={600} destinations={appIds} colorRange={colorRange} selectedSource={selectedSource} dataType={dataType} // Specify units // Specify label min={min} max={max} colorForApp={colorForApp} Loading @@ -242,14 +220,14 @@ const ViewForName = ( return ( <IDCLineChart data={dataPoints} series={series} startTime={startTime} mobilityEvents={mobilityEvents} width={width} height={600} destinations={appIds} colorRange={colorRange} selectedSource={selectedSource} dataType={dataType} // Specify units // Specify label min={min} max={max} colorForApp={colorForApp} Loading Loading @@ -297,9 +275,10 @@ const DashboardConfiguration = (props) => { ) : null; const backgroundColor = 'ffffff'; // props.configurationType ? '#e4e4e4' : 'ffffff'; return ( <div style={{border: '1px solid #e4e4e4', padding: 10, marginBottom: 10, backgroundColor: backgroundColor}}> <Elevation z={2} style={{padding: 10, marginBottom: 10}} > <Grid> <GridCell span={10}> </GridCell> Loading @@ -308,12 +287,36 @@ const DashboardConfiguration = (props) => { {buttonClose} </GridCell> </Grid> {configurationView} </div> </Elevation> ); }; const filterSeries = keys => filter => series => { let newSeries = {}; keys.forEach(key => { if (series[key]) { newSeries[key] = removeDuplicatePoints(series[key].filter(filter)); } }); return newSeries; }; const removeDuplicatePoints = sequence => { let timestampsMap = {}; let newSequence = []; sequence.forEach(p => { if (!timestampsMap[p.timestamp]) { timestampsMap[p.timestamp] = true; newSequence.push(p); } }); return newSequence; }; class DashboardContainer extends Component { constructor(props) { super(props); Loading Loading @@ -342,11 +345,19 @@ class DashboardContainer extends Component { } fetchMetrics() { return axios.get(`${metricsBasePath}/metrics?startTime=now-6s&stopTime=now`) const startTime = moment().utc().add(-7, 'seconds').format(TIME_FORMAT); const stopTime = moment().utc().add(-6, 'seconds').format(TIME_FORMAT); return axios.get(`${metricsBasePath}/metrics?startTime=${startTime}&stopTime=${stopTime}`) .then(res => { this.props.addMetricsEpoch(res.data.dataResponse || []); let epoch = { data: res.data.logResponse || [], startTime: startTime }; this.props.addMetricsEpoch(epoch); }).catch((e) => { console.log('Error while fetching metrics', e); idlog('Error while fetching metrics')(e); }); } Loading Loading @@ -378,27 +389,13 @@ class DashboardContainer extends Component { const appIds = apps.map(a => a.data.id); const appMap = apps.reduce((acc, app) => {acc[app.data.id] = app; return acc;}, {}); const colorRange = colorArray(appIds.length); const nbEpochs = 25; const selectedSource = this.props.sourceNodeSelected ? this.props.sourceNodeSelected.data.id : null; const showApps = this.props.showAppsView; const span = showApps ? 6 : 12; const colorForApp = apps.reduce((res, val, i) => { return {...res, [val.data.id]: colorRange[i]}; }, {}); let lastEpoch = this.props.epochs.length ? this.props.epochs.slice(-1)[0] : []; const hasValue = p => { const accessor = dataAccessorForType(p.dataType); if (! accessor(p)) { console.log(`No value for src ${p.src} and dest ${p.dest}`); } return accessor(p); }; lastEpoch = lastEpoch.filter(hasValue); const isDataOfType = type => dataPoint => dataPoint.dataType === type; const dataTypeForView = view => { Loading @@ -412,60 +409,60 @@ class DashboardContainer extends Component { } }; // Determine last 25 epochs // Determine first and last epochs const firstEpoch = this.props.epochs.length ? this.props.epochs[0] : { data: [], startTime: null }; let lastEpoch = this.props.epochs.length ? this.props.epochs.slice(-1)[0] : { data: [], startTime: null }; // Determine startTime of first epoch and endTime of last epoch // Create map of arrays of points, one array per source, indexed by source id // Pass that map to the views // Have each view consume that map const startTime = firstEpoch.data.length ? firstEpoch.startTime : null; const endTime = lastEpoch.data.length ? moment(lastEpoch.startTime).add(1, 'seconds').format(TIME_FORMAT) : null; const series = epochsToSeries(this.props.epochs, selectedSource); const withTypeAndSource = type => source => point => { return point.dataType === type && point.src === source; }; // For view 1 const view1DataType = dataTypeForView(this.state.view1Name); const view1Accessor = dataAccessorForType(view1DataType); const view1DataPoints = epochsToDataPoints(this.props.epochs)(nbEpochs)(appIds)(view1Accessor)(selectedSource); const data1 = lastEpoch.filter(isDataOfType(view1DataType)); const max1 = d3.max(data1, view1Accessor); const min1 = d3.min(data1, view1Accessor); const series1 = filterSeries(appIds)(withTypeAndSource(view1DataType)(selectedSource))(series); const lastEpochData1 = lastEpoch.data.filter(isDataOfType(view1DataType)); // For view2 const view2DataType = dataTypeForView(this.state.view2Name); const view2Accessor = dataAccessorForType(view2DataType); const view2DataPoints = epochsToDataPoints(this.props.epochs)(nbEpochs)(appIds)(view2Accessor)(selectedSource); const data2 = lastEpoch.filter(isDataOfType(view2DataType)); const series2 = filterSeries(appIds)(withTypeAndSource(view2DataType)(selectedSource))(series); const lastEpochData2 = lastEpoch.data.filter(isDataOfType(view2DataType)); const extractPointsOfType = type => epoch => epoch.filter(isDataPointOfType(type)); // Mobility events const extractPointsOfType = type => epoch => epoch.data.filter(isDataPointOfType(type)); const extractMobilityEvents = extractPointsOfType(MOBILITY_EVENT); const mobilityEvents = this.props.epochs.flatMap(extractMobilityEvents); if (mobilityEvents.length) { console.log('Some mobility events ...'); } data2.forEach((d) => { const dd = view1Accessor(d); if (!dd) { console.log(`Null data: ${dd}. `); // console.log('Some mobility events ...'); } }); const max2 = d3.max(data2, view2Accessor); const min2 = d3.min(data2, view2Accessor); const width = 700; const height = 600; let span1 = 6; let width1 = 700; let span2 = 6; let width2 = 700; if (this.state.view1Name === VIEW_NAME_NONE) { span1 = 0; width1 = 0; span2 = 12; width2 = 1200; width2 = 1400; } if (this.state.view2Name === VIEW_NAME_NONE) { span1 = 12; width1 = 1200; span2 = 0; width1 = 1400; width2 = 0; } Loading @@ -475,12 +472,11 @@ class DashboardContainer extends Component { colorRange={colorRange} width={width1} height={height} data={data1} data={lastEpochData1} series={series1} startTime={startTime} endTime={endTime} mobilityEvents={mobilityEvents} min={min1} max={max1} dataPoints={view1DataPoints} dataAccessor={view1Accessor} dataType={view1DataType} selectedSource={selectedSource} colorForApp={colorForApp} Loading @@ -496,12 +492,11 @@ class DashboardContainer extends Component { colorRange={colorRange} width={width2} height={height} data={data2} data={lastEpochData2} series={series2} startTime={startTime} endTime={endTime} mobilityEvents={mobilityEvents} min={min2} max={max2} dataPoints={view2DataPoints} dataAccessor={view2Accessor} dataType={view2DataType} selectedSource={selectedSource} colorForApp={colorForApp} Loading @@ -514,9 +509,7 @@ class DashboardContainer extends Component { return ( <> <Elevation z={4} style={{padding: 10}} > <DashboardConfiguration configurationType={this.state.configurationType} displayConfiguration={ Loading @@ -535,15 +528,23 @@ class DashboardContainer extends Component { /> <Grid> <GridCell span={span1} style={{marginLeft: -10}}> <GridCell span={span1} style={{paddingRight: 10}}> <Elevation z={2} style={{padding: 10}} > {view1} </Elevation> </GridCell> <GridCell span={span2} style={{marginLeft: -10}}> <GridCell span={span1} style={{marginLeft: -10, paddingLeft: 10}}> <Elevation z={2} style={{padding: 10}} > {view2} </Elevation> </GridCell> </Grid> </Elevation> </> ); Loading js-apps/meep-frontend/src/js/containers/exec/exec-page-container.js +17 −19 Original line number Diff line number Diff line Loading @@ -12,8 +12,6 @@ import React, { Component } from 'react'; import { Grid, GridCell, GridInner } from '@rmwc/grid'; import { Elevation } from '@rmwc/elevation'; import IDCVis from '../idc-vis'; import IDCGraph from '../idc-graph'; import IDCAreaChart from '../idc-area-chart'; import DashboardContainer from '../dashboard-container'; import ExecPageScenarioButtons from './exec-page-scenario-buttons'; Loading Loading @@ -268,7 +266,7 @@ class ExecPageContainer extends Component { <Grid style={{width: '100%'}}> <GridCell span={spanLeft}> {/* <Elevation className="component-style" z={2}> */} <div style={{padding: 10}}> <div> {this.props.experimental ? (<DashboardContainer showAppsView={true}/>) : (<IDCVis type={TYPE_EXEC} />)} </div> Loading js-apps/meep-frontend/src/js/containers/idc-apps-view.js +8 −27 Original line number Diff line number Diff line Loading @@ -7,9 +7,8 @@ * information of InterDigital Communications, Inc. */ import _ from 'lodash'; import { connect } from 'react-redux'; import React, { useState } from 'react'; import ReactDOM from 'react-dom'; import React from 'react'; // import ReactDOM from 'react-dom'; import * as d3 from 'd3'; import IDCNode from './idc-node.js'; Loading @@ -18,7 +17,7 @@ import { lineGeneratorNodes } from './graph-utils'; const edgesFromData = (data, dataAccessor, colorForApp, selectedSource) => { const edgesFromData = (data, colorForApp, selectedSource) => { const pings = data; let m = {}; _.each(pings, p => { Loading @@ -38,7 +37,7 @@ const edgesFromData = (data, dataAccessor, colorForApp, selectedSource) => { const apps = Object.keys(m); const edgesFromSource = dataAccessor => src => { const edgesFromSource = src => { const rowObject = m[src]; if (!rowObject) { return []; Loading @@ -46,23 +45,12 @@ const edgesFromData = (data, dataAccessor, colorForApp, selectedSource) => { const destinations = Object.keys(m[src]); const edgesFromDestinations = (dest) => { // To debug const dataFromPing = p => { if (dataAccessor(p)) { console.log('Bad value!'); } return dataAccessor(p); }; if (!d3.mean(rowObject[dest].pings, dataAccessor)) { console.log('Bad value!'); } return { src: src, dest: dest, count: rowObject[dest].pings.length, color: colorForApp[dest], avgData: d3.mean(rowObject[dest].pings, dataAccessor) avgData: d3.mean(rowObject[dest].pings, p => p.value) }; }; return _.map(destinations, edgesFromDestinations); Loading @@ -75,7 +63,7 @@ const edgesFromData = (data, dataAccessor, colorForApp, selectedSource) => { return true; } }; const edges = _.flatMap(apps.map(edgesFromSource(dataAccessor))).filter(outwardEdgesIfSourceSelected); const edges = _.flatMap(apps.map(edgesFromSource)).filter(outwardEdgesIfSourceSelected); return edges; }; Loading Loading @@ -121,7 +109,6 @@ const IDCAppsView = ( colorRange, selectedSource, data, dataAccessor, dataType, width, height, Loading @@ -131,18 +118,12 @@ const IDCAppsView = ( } ) => { const [positioningNeeded, setPositioningNeeded] = useState(true); //if (positioningNeeded) { // copyAttributesRecursive(data)(this.root); positionAppsCircle({apps: apps, height: height, width: width}); //setPositioningNeeded(false); //} const appsMap = {}; _.each(apps, a => appsMap[a.data.id] = a); const edges = edgesFromData(data.filter(dataAccessor), dataAccessor, colorForApp, selectedSource); const edges = edgesFromData(data.filter(p => p.value), colorForApp, selectedSource); const edgeLabel = edgeLabelForDataType(dataType); const edgeUnits = unitsForDataType(dataType); Loading Loading @@ -178,7 +159,7 @@ const IDCAppsView = ( xlinkHref={`#textPathDef${i}`} startOffset={'45%'} > {displayEdgeLabels ? `${edgeLabel} ${e.avgData.toFixed(2)} ${edgeUnits}` : null} {displayEdgeLabels ? `${edgeLabel} ${e.avgData.toFixed(0)} ${edgeUnits}` : null} </textPath> </text> ); Loading Loading
js-apps/meep-frontend/package-lock.json +5 −0 Original line number Diff line number Diff line Loading @@ -14606,6 +14606,11 @@ } } }, "react-d3-axis": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/react-d3-axis/-/react-d3-axis-0.1.2.tgz", "integrity": "sha512-Id2C208SGcLcIfgrdl9ffgZKXtp3wELV7dC3HJVjim+J0IQiAaZo9APSnlvJE2kB90C7wJKlXdFI1bYPg7jytA==" }, "react-d3-graph": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/react-d3-graph/-/react-d3-graph-2.1.0.tgz",
js-apps/meep-frontend/package.json +1 −0 Original line number Diff line number Diff line Loading @@ -52,6 +52,7 @@ "material-design-icons": "3.0.1", "prop-types": "15.6.2", "react": "^16.8.6", "react-d3-axis": "^0.1.2", "react-d3-graph": "^2.0.2", "react-dom": "^16.8.6", "react-iframe": "^1.5.0", Loading
js-apps/meep-frontend/src/js/containers/dashboard-container.js +122 −121 Original line number Diff line number Diff line import _ from 'lodash'; import { connect } from 'react-redux'; import React, { Component, useState } from 'react'; import React, { Component } from 'react'; import { Grid, GridCell, GridInner } from '@rmwc/grid'; import { Grid, GridCell } from '@rmwc/grid'; import { Elevation } from '@rmwc/elevation'; import { Graph } from 'react-d3-graph'; import ReactDOM from 'react-dom'; // import ReactDOM from 'react-dom'; import { Button } from '@rmwc/button'; import { Checkbox } from '@rmwc/checkbox'; import { TextField, TextFieldHelperText } from '@rmwc/textfield'; import moment from 'moment'; import * as d3 from 'd3'; import axios from 'axios'; // import IDCAreaChart from './idc-area-chart'; import IDCLineChart from './idc-line-chart'; import IDCGraph from './idc-graph'; import IDCAppsView from './idc-apps-view'; import IDSelect from '../components/helper-components/id-select'; import { idlog } from '../util/functional'; import { getScenarioNodeChildren, isApp } from '../util/scenario-utils'; import { dataAccessorForType, dataSetterForType, isDataPointOfType } from '../util/metrics'; Loading @@ -42,15 +41,15 @@ import { } from '../meep-constants'; const VIEW_NAME_NONE = 'none'; const TIME_FORMAT = moment.HTML5_FMT.DATETIME_LOCAL_MS; function colorArray(dataLength) { const colorScale = d3.interpolateInferno; // Other possible color scales: // const colorScale = d3.interpolateMagma; // const colorScale = d3.interpolateCool; // const colorScale = d3.interpolateWarm; // const colorScale = d3.interpolateCubehelixDefault; // interpolateViridis // const colorScale = d3.interpolateCubehelixDefault; let colorArray = []; Loading @@ -68,41 +67,22 @@ function colorArray(dataLength) { const metricsBasePath = 'http://10.3.16.73:30008/v1'; const dataPointFromEpochDataPoints = destinations => sourceNodeId => dataAccessor => epochDataPoints => { if (!epochDataPoints.length) { return null; const buildSeriesFromEpoch = (series, epoch) => { epoch.data.forEach(p => { if (! series[p.dest]) { series[p.dest] = []; } let dp = { date: epochDataPoints[0].timestamp }; const avgForDest = dataPoints => acc => dest => { const hasSource = src => p => p.src === src; const hasDestination = dest => p => p.dest === dest; const dataPointsForDestSource = dataPoints .filter(hasSource(sourceNodeId)) .filter(hasDestination(dest)); const avg = d3.mean(dataPointsForDestSource, acc); return avg; }; destinations.forEach(dest => { dp[dest] = avgForDest(epochDataPoints)(dataAccessor)(dest) || 0; series[p.dest].push(p); }); return dp; return series; }; const notNull = x => x; const epochsToDataPoints = epochs => nb => destinations => dataAccessor => sourceNodeId => { const selectedEpochs = epochs.length ? epochs.slice(-nb) : []; if (selectedEpochs.length === 0) { console.log('epoch length is 0'); } const dataPoints = selectedEpochs.map(dataPointFromEpochDataPoints(destinations)(sourceNodeId)(dataAccessor)).filter(notNull); return dataPoints; const epochsToSeries = (epochs) => { let series = epochs.reduce((s, current) => { return buildSeriesFromEpoch(s, current); }, {}); return series; }; const ConfigurationView = (props) => { Loading @@ -116,7 +96,6 @@ const ConfigurationView = (props) => { onChange={(e) => { props.changeView1(e.target.value); }} // disabled={props.disabled} value={props.view1} /> </GridCell> Loading @@ -128,7 +107,6 @@ const ConfigurationView = (props) => { onChange={(e) => { props.changeView2(e.target.value); }} // disabled={props.disabled} value={props.view1} /> </GridCell> Loading @@ -140,7 +118,6 @@ const ConfigurationView = (props) => { onChange={(e) => { props.changeSourceNodeSelected(e.target.value); }} // disabled={props.disabled} value={props.sourceNodeSelected ? props.sourceNodeSelected.data.id : ''} /> </GridCell> Loading @@ -158,7 +135,6 @@ const ConfigurationView = (props) => { ); }; const DATA_CONFIGURATION = 'DATA_CONFIGURATION'; const MAIN_CONFIGURATION = 'MAIN_CONFIGURATION'; const buttonStyles = { Loading @@ -177,10 +153,11 @@ const ViewForName = ( apps, colorRange, width, height, min, max, data, series, startTime, mobilityEvents, dataPoints, dataAccessor, Loading Loading @@ -210,12 +187,13 @@ const ViewForName = ( width={width} height={600} data={data} series={series} startTime={startTime} dataAccessor={dataAccessor} dataType={dataType} selectedSource={selectedSource} colorForApp={colorForApp} onNodeClicked={(e) => { console.log('Node clicked is: ', e.node); changeSourceNodeSelected(e.node); }} displayEdgeLabels={displayEdgeLabels} Loading @@ -225,14 +203,14 @@ const ViewForName = ( return ( <IDCLineChart data={dataPoints} series={series} startTime={startTime} mobilityEvents={mobilityEvents} width={width} height={600} destinations={appIds} colorRange={colorRange} selectedSource={selectedSource} dataType={dataType} // Specify units // Specify label min={min} max={max} colorForApp={colorForApp} Loading @@ -242,14 +220,14 @@ const ViewForName = ( return ( <IDCLineChart data={dataPoints} series={series} startTime={startTime} mobilityEvents={mobilityEvents} width={width} height={600} destinations={appIds} colorRange={colorRange} selectedSource={selectedSource} dataType={dataType} // Specify units // Specify label min={min} max={max} colorForApp={colorForApp} Loading Loading @@ -297,9 +275,10 @@ const DashboardConfiguration = (props) => { ) : null; const backgroundColor = 'ffffff'; // props.configurationType ? '#e4e4e4' : 'ffffff'; return ( <div style={{border: '1px solid #e4e4e4', padding: 10, marginBottom: 10, backgroundColor: backgroundColor}}> <Elevation z={2} style={{padding: 10, marginBottom: 10}} > <Grid> <GridCell span={10}> </GridCell> Loading @@ -308,12 +287,36 @@ const DashboardConfiguration = (props) => { {buttonClose} </GridCell> </Grid> {configurationView} </div> </Elevation> ); }; const filterSeries = keys => filter => series => { let newSeries = {}; keys.forEach(key => { if (series[key]) { newSeries[key] = removeDuplicatePoints(series[key].filter(filter)); } }); return newSeries; }; const removeDuplicatePoints = sequence => { let timestampsMap = {}; let newSequence = []; sequence.forEach(p => { if (!timestampsMap[p.timestamp]) { timestampsMap[p.timestamp] = true; newSequence.push(p); } }); return newSequence; }; class DashboardContainer extends Component { constructor(props) { super(props); Loading Loading @@ -342,11 +345,19 @@ class DashboardContainer extends Component { } fetchMetrics() { return axios.get(`${metricsBasePath}/metrics?startTime=now-6s&stopTime=now`) const startTime = moment().utc().add(-7, 'seconds').format(TIME_FORMAT); const stopTime = moment().utc().add(-6, 'seconds').format(TIME_FORMAT); return axios.get(`${metricsBasePath}/metrics?startTime=${startTime}&stopTime=${stopTime}`) .then(res => { this.props.addMetricsEpoch(res.data.dataResponse || []); let epoch = { data: res.data.logResponse || [], startTime: startTime }; this.props.addMetricsEpoch(epoch); }).catch((e) => { console.log('Error while fetching metrics', e); idlog('Error while fetching metrics')(e); }); } Loading Loading @@ -378,27 +389,13 @@ class DashboardContainer extends Component { const appIds = apps.map(a => a.data.id); const appMap = apps.reduce((acc, app) => {acc[app.data.id] = app; return acc;}, {}); const colorRange = colorArray(appIds.length); const nbEpochs = 25; const selectedSource = this.props.sourceNodeSelected ? this.props.sourceNodeSelected.data.id : null; const showApps = this.props.showAppsView; const span = showApps ? 6 : 12; const colorForApp = apps.reduce((res, val, i) => { return {...res, [val.data.id]: colorRange[i]}; }, {}); let lastEpoch = this.props.epochs.length ? this.props.epochs.slice(-1)[0] : []; const hasValue = p => { const accessor = dataAccessorForType(p.dataType); if (! accessor(p)) { console.log(`No value for src ${p.src} and dest ${p.dest}`); } return accessor(p); }; lastEpoch = lastEpoch.filter(hasValue); const isDataOfType = type => dataPoint => dataPoint.dataType === type; const dataTypeForView = view => { Loading @@ -412,60 +409,60 @@ class DashboardContainer extends Component { } }; // Determine last 25 epochs // Determine first and last epochs const firstEpoch = this.props.epochs.length ? this.props.epochs[0] : { data: [], startTime: null }; let lastEpoch = this.props.epochs.length ? this.props.epochs.slice(-1)[0] : { data: [], startTime: null }; // Determine startTime of first epoch and endTime of last epoch // Create map of arrays of points, one array per source, indexed by source id // Pass that map to the views // Have each view consume that map const startTime = firstEpoch.data.length ? firstEpoch.startTime : null; const endTime = lastEpoch.data.length ? moment(lastEpoch.startTime).add(1, 'seconds').format(TIME_FORMAT) : null; const series = epochsToSeries(this.props.epochs, selectedSource); const withTypeAndSource = type => source => point => { return point.dataType === type && point.src === source; }; // For view 1 const view1DataType = dataTypeForView(this.state.view1Name); const view1Accessor = dataAccessorForType(view1DataType); const view1DataPoints = epochsToDataPoints(this.props.epochs)(nbEpochs)(appIds)(view1Accessor)(selectedSource); const data1 = lastEpoch.filter(isDataOfType(view1DataType)); const max1 = d3.max(data1, view1Accessor); const min1 = d3.min(data1, view1Accessor); const series1 = filterSeries(appIds)(withTypeAndSource(view1DataType)(selectedSource))(series); const lastEpochData1 = lastEpoch.data.filter(isDataOfType(view1DataType)); // For view2 const view2DataType = dataTypeForView(this.state.view2Name); const view2Accessor = dataAccessorForType(view2DataType); const view2DataPoints = epochsToDataPoints(this.props.epochs)(nbEpochs)(appIds)(view2Accessor)(selectedSource); const data2 = lastEpoch.filter(isDataOfType(view2DataType)); const series2 = filterSeries(appIds)(withTypeAndSource(view2DataType)(selectedSource))(series); const lastEpochData2 = lastEpoch.data.filter(isDataOfType(view2DataType)); const extractPointsOfType = type => epoch => epoch.filter(isDataPointOfType(type)); // Mobility events const extractPointsOfType = type => epoch => epoch.data.filter(isDataPointOfType(type)); const extractMobilityEvents = extractPointsOfType(MOBILITY_EVENT); const mobilityEvents = this.props.epochs.flatMap(extractMobilityEvents); if (mobilityEvents.length) { console.log('Some mobility events ...'); } data2.forEach((d) => { const dd = view1Accessor(d); if (!dd) { console.log(`Null data: ${dd}. `); // console.log('Some mobility events ...'); } }); const max2 = d3.max(data2, view2Accessor); const min2 = d3.min(data2, view2Accessor); const width = 700; const height = 600; let span1 = 6; let width1 = 700; let span2 = 6; let width2 = 700; if (this.state.view1Name === VIEW_NAME_NONE) { span1 = 0; width1 = 0; span2 = 12; width2 = 1200; width2 = 1400; } if (this.state.view2Name === VIEW_NAME_NONE) { span1 = 12; width1 = 1200; span2 = 0; width1 = 1400; width2 = 0; } Loading @@ -475,12 +472,11 @@ class DashboardContainer extends Component { colorRange={colorRange} width={width1} height={height} data={data1} data={lastEpochData1} series={series1} startTime={startTime} endTime={endTime} mobilityEvents={mobilityEvents} min={min1} max={max1} dataPoints={view1DataPoints} dataAccessor={view1Accessor} dataType={view1DataType} selectedSource={selectedSource} colorForApp={colorForApp} Loading @@ -496,12 +492,11 @@ class DashboardContainer extends Component { colorRange={colorRange} width={width2} height={height} data={data2} data={lastEpochData2} series={series2} startTime={startTime} endTime={endTime} mobilityEvents={mobilityEvents} min={min2} max={max2} dataPoints={view2DataPoints} dataAccessor={view2Accessor} dataType={view2DataType} selectedSource={selectedSource} colorForApp={colorForApp} Loading @@ -514,9 +509,7 @@ class DashboardContainer extends Component { return ( <> <Elevation z={4} style={{padding: 10}} > <DashboardConfiguration configurationType={this.state.configurationType} displayConfiguration={ Loading @@ -535,15 +528,23 @@ class DashboardContainer extends Component { /> <Grid> <GridCell span={span1} style={{marginLeft: -10}}> <GridCell span={span1} style={{paddingRight: 10}}> <Elevation z={2} style={{padding: 10}} > {view1} </Elevation> </GridCell> <GridCell span={span2} style={{marginLeft: -10}}> <GridCell span={span1} style={{marginLeft: -10, paddingLeft: 10}}> <Elevation z={2} style={{padding: 10}} > {view2} </Elevation> </GridCell> </Grid> </Elevation> </> ); Loading
js-apps/meep-frontend/src/js/containers/exec/exec-page-container.js +17 −19 Original line number Diff line number Diff line Loading @@ -12,8 +12,6 @@ import React, { Component } from 'react'; import { Grid, GridCell, GridInner } from '@rmwc/grid'; import { Elevation } from '@rmwc/elevation'; import IDCVis from '../idc-vis'; import IDCGraph from '../idc-graph'; import IDCAreaChart from '../idc-area-chart'; import DashboardContainer from '../dashboard-container'; import ExecPageScenarioButtons from './exec-page-scenario-buttons'; Loading Loading @@ -268,7 +266,7 @@ class ExecPageContainer extends Component { <Grid style={{width: '100%'}}> <GridCell span={spanLeft}> {/* <Elevation className="component-style" z={2}> */} <div style={{padding: 10}}> <div> {this.props.experimental ? (<DashboardContainer showAppsView={true}/>) : (<IDCVis type={TYPE_EXEC} />)} </div> Loading
js-apps/meep-frontend/src/js/containers/idc-apps-view.js +8 −27 Original line number Diff line number Diff line Loading @@ -7,9 +7,8 @@ * information of InterDigital Communications, Inc. */ import _ from 'lodash'; import { connect } from 'react-redux'; import React, { useState } from 'react'; import ReactDOM from 'react-dom'; import React from 'react'; // import ReactDOM from 'react-dom'; import * as d3 from 'd3'; import IDCNode from './idc-node.js'; Loading @@ -18,7 +17,7 @@ import { lineGeneratorNodes } from './graph-utils'; const edgesFromData = (data, dataAccessor, colorForApp, selectedSource) => { const edgesFromData = (data, colorForApp, selectedSource) => { const pings = data; let m = {}; _.each(pings, p => { Loading @@ -38,7 +37,7 @@ const edgesFromData = (data, dataAccessor, colorForApp, selectedSource) => { const apps = Object.keys(m); const edgesFromSource = dataAccessor => src => { const edgesFromSource = src => { const rowObject = m[src]; if (!rowObject) { return []; Loading @@ -46,23 +45,12 @@ const edgesFromData = (data, dataAccessor, colorForApp, selectedSource) => { const destinations = Object.keys(m[src]); const edgesFromDestinations = (dest) => { // To debug const dataFromPing = p => { if (dataAccessor(p)) { console.log('Bad value!'); } return dataAccessor(p); }; if (!d3.mean(rowObject[dest].pings, dataAccessor)) { console.log('Bad value!'); } return { src: src, dest: dest, count: rowObject[dest].pings.length, color: colorForApp[dest], avgData: d3.mean(rowObject[dest].pings, dataAccessor) avgData: d3.mean(rowObject[dest].pings, p => p.value) }; }; return _.map(destinations, edgesFromDestinations); Loading @@ -75,7 +63,7 @@ const edgesFromData = (data, dataAccessor, colorForApp, selectedSource) => { return true; } }; const edges = _.flatMap(apps.map(edgesFromSource(dataAccessor))).filter(outwardEdgesIfSourceSelected); const edges = _.flatMap(apps.map(edgesFromSource)).filter(outwardEdgesIfSourceSelected); return edges; }; Loading Loading @@ -121,7 +109,6 @@ const IDCAppsView = ( colorRange, selectedSource, data, dataAccessor, dataType, width, height, Loading @@ -131,18 +118,12 @@ const IDCAppsView = ( } ) => { const [positioningNeeded, setPositioningNeeded] = useState(true); //if (positioningNeeded) { // copyAttributesRecursive(data)(this.root); positionAppsCircle({apps: apps, height: height, width: width}); //setPositioningNeeded(false); //} const appsMap = {}; _.each(apps, a => appsMap[a.data.id] = a); const edges = edgesFromData(data.filter(dataAccessor), dataAccessor, colorForApp, selectedSource); const edges = edgesFromData(data.filter(p => p.value), colorForApp, selectedSource); const edgeLabel = edgeLabelForDataType(dataType); const edgeUnits = unitsForDataType(dataType); Loading Loading @@ -178,7 +159,7 @@ const IDCAppsView = ( xlinkHref={`#textPathDef${i}`} startOffset={'45%'} > {displayEdgeLabels ? `${edgeLabel} ${e.avgData.toFixed(2)} ${edgeUnits}` : null} {displayEdgeLabels ? `${edgeLabel} ${e.avgData.toFixed(0)} ${edgeUnits}` : null} </textPath> </text> ); Loading