You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@spot.apache.org by ev...@apache.org on 2017/01/25 18:36:57 UTC
[45/49] incubator-spot git commit: Ingest summary supporting 3 use
cases, Netflow, DNS and Proxy
Ingest summary supporting 3 use cases, Netflow, DNS and Proxy
Project: http://git-wip-us.apache.org/repos/asf/incubator-spot/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-spot/commit/46470640
Tree: http://git-wip-us.apache.org/repos/asf/incubator-spot/tree/46470640
Diff: http://git-wip-us.apache.org/repos/asf/incubator-spot/diff/46470640
Branch: refs/heads/master
Commit: 46470640ef882297df1109d4f3484f017cf63d95
Parents: f0619ae
Author: Diego Ortiz Huerta <di...@intel.com>
Authored: Mon Dec 12 10:08:56 2016 -0800
Committer: Everardo Lopez Sandoval (Intel) <el...@elopezsa-mac02.ra.intel.com>
Committed: Fri Jan 20 17:01:02 2017 -0800
----------------------------------------------------------------------
.../ui/flow/js/constants/NetflowConstants.js | 1 -
spot-oa/ui/ingest-summary.html | 37 +-
.../js/components/IngestSummaryPanel.react.js | 418 +++++++++----------
spot-oa/ui/js/components/OptionPicker.react.js | 43 ++
spot-oa/ui/js/constants/SpotConstants.js | 10 +-
spot-oa/ui/js/ingest-summary.js | 66 +--
spot-oa/ui/js/stores/IngestSummaryStore.js | 107 +++--
spot-oa/ui/package.json | 2 +-
8 files changed, 378 insertions(+), 306 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-spot/blob/46470640/spot-oa/ui/flow/js/constants/NetflowConstants.js
----------------------------------------------------------------------
diff --git a/spot-oa/ui/flow/js/constants/NetflowConstants.js b/spot-oa/ui/flow/js/constants/NetflowConstants.js
index c0fc7a8..4de19e1 100755
--- a/spot-oa/ui/flow/js/constants/NetflowConstants.js
+++ b/spot-oa/ui/flow/js/constants/NetflowConstants.js
@@ -5,7 +5,6 @@ var NetflowConstants = {
API_VISUAL_DETAILS: '../../data/flow/${date}/chord-${ip}.tsv',
API_COMMENTS: '../../data/flow/${date}/threats.csv',
API_INCIDENT_PROGRESSION: '../../data/flow/${date}/threat-dendro-${ip}.json',
- API_INGEST_SUMMARY: '../data/flow/ingest_summary/is_${year}${month}.csv',
API_IMPACT_ANALYSIS: '../../data/flow/${date}/stats-${ip}.json',
API_GLOBE_VIEW: '../../data/flow/${date}/globe-${ip}.json',
API_WORLD_110M: '../flow/world-110m.json',
http://git-wip-us.apache.org/repos/asf/incubator-spot/blob/46470640/spot-oa/ui/ingest-summary.html
----------------------------------------------------------------------
diff --git a/spot-oa/ui/ingest-summary.html b/spot-oa/ui/ingest-summary.html
index e694609..1c4a100 100755
--- a/spot-oa/ui/ingest-summary.html
+++ b/spot-oa/ui/ingest-summary.html
@@ -34,32 +34,43 @@
height: 100%;
}
- #spot-is-header {
+ .is-chart svg {
width: 100%;
- position: absolute;
- top: 0;
- left: 0;
- z-index: 2;
- height: auto;
+ height: 100%;
}
- #spot-is, #spot-is-summary {
- height: 100%;
+ .is-chart svg .header text {
+ text-anchor: middle;
+ fill: #82837e;
+ }
+
+ .is-chart svg .header text tspan.bold {
+ font-weight: bold;
}
- .axis {
+ .is-chart .axis {
shape-rendering: crispEdges;
}
- .axis path, .axis line {
+ .is-chart .axis path, .is-chart .axis line {
fill: none;
}
- rect.pane {
- cursor: e-resize;
- fill: none;
+ .is-chart .pipeline {
pointer-events: all;
}
+
+ .is-chart .pipeline.zoom-in {
+ cursor: zoom-in;
+ }
+
+ .is-chart .pipeline.zoom-out {
+ cursor: zoom-out;
+ }
+
+ .is-chart .pipeline.e-resize {
+ cursor: e-resize;
+ }
</style>
</head>
<body>
http://git-wip-us.apache.org/repos/asf/incubator-spot/blob/46470640/spot-oa/ui/js/components/IngestSummaryPanel.react.js
----------------------------------------------------------------------
diff --git a/spot-oa/ui/js/components/IngestSummaryPanel.react.js b/spot-oa/ui/js/components/IngestSummaryPanel.react.js
index cc951ad..06c83bd 100755
--- a/spot-oa/ui/js/components/IngestSummaryPanel.react.js
+++ b/spot-oa/ui/js/components/IngestSummaryPanel.react.js
@@ -3,234 +3,216 @@ const d3 = require('d3');
const React = require('react');
const ReactDOM = require('react-dom');
+const ContentLoaderMixin = require('./ContentLoaderMixin.react');
+const ChartMixin = require('./ChartMixin.react');
const DateUtils = require('../utils/DateUtils');
const InSumActions = require('../actions/InSumActions');
-const NetflowIngestSummaryStore = require('../../flow/js/stores/IngestSummaryStore');
-
-function initialDraw() {
- var rootNode, format, x, y, xAxis, yAxis, area, svg, rect, total, minDate, maxDate, maxFlows, numberFormat;
-
- rootNode = d3.select(ReactDOM.findDOMNode(this));
-
- // graph dimensions
- var m = [100, 50, 50, 80], // Margin
- w = $(rootNode.node()).width() - m[1] - m[3], // Width
- h = $(rootNode.node()).height() - m[0] - m[2]; // Height
-
- format = d3.time.format("%Y-%m-%d %H:%M");
-
- // Scales.
- x = d3.time.scale().range([0, w]); // get X function
- y = d3.scale.linear().range([h, 0]); // get Y function
- xAxis = d3.svg.axis().scale(x).orient("bottom"); // Get the X axis (Time)
- yAxis = d3.svg.axis().scale(y).orient("left"); // Get Y Axis (Netflows)
-
- // An area generator.
- area = d3.svg.area()
- .x(function (d) {
- return x(d.date);
- })
- .y0(h)
- .y1(function (d) {
- if (!isNaN(d.total))
- return y(d.total);
- else
- return y(0);
- });
+const IngestSummaryStore = require('../stores/IngestSummaryStore');
- rootNode.select('svg').remove();
-
- // define the Main SVG
- svg = rootNode.select('#' + this.props.id + '-summary').append("svg")
- .attr("width", w + m[1] + m[3])
- .attr("height", h + m[0] + m[2])
- .append("g")
- .attr("transform", "translate(" + m[3] + "," + m[0] + ")")
-
- // Append the clipPath to avoid the Area overlapping
- svg.append("clipPath")
- .attr("id", "clip")
- .append("rect")
- .attr("x", x(0))
- .attr("y", y(1))
- .attr("width", x(1) - x(0))
- .attr("height", y(0) - y(1));
-
- // Append the Y Axis group
- svg.append("g")
- .attr("class", "y axis");
-
- // Append the X axis group
- svg.append("g")
- .attr("class", "x axis")
- .attr("transform", "translate(0," + h + ")");
-
- // Append a pane rect, which will help us to add the zoom functionality
- rect = svg.append("rect")
- .attr("class", "pane")
- .attr("width", w)
- .attr("height", h);
-
- this.state.data.forEach(function (dataSet)
- {
- var a;
-
- a = [{date: minDate}];
- a.push.apply(a, dataSet);
- minDate = d3.min(a, function (d) { return d.date; });
- a[0] = {date: maxDate, flows: maxFlows};
- maxDate = d3.max(a, function (d) { return d.date; });
- maxFlows = d3.max(a, function (d) { return d.total; })
- });
-
- !minDate && (minDate = DateUtils.parseDate(NetflowIngestSummaryStore.getStartDate()));
- !maxDate && (maxDate = DateUtils.parseDate(NetflowIngestSummaryStore.getEndDate()));
-
- // bind the data to the X and Y generators
- x.domain([minDate, maxDate]);
- y.domain([0, maxFlows]);
-
- // Bind the data to our path element.
- svg.selectAll("path.area").data(this.state.data).enter().insert('path', 'g')
- .attr('class', 'area')
- .attr('clip-path', 'url(#clip)')
- .style('fill', '#0071c5')
- .attr('d', function (d) {
- return area(d);
- });
-
- //Add the pane rect the zoom behavior
- rect.call(d3.behavior.zoom().x(x)
- .scaleExtent([0.3, 2300]) // these are magic numbers to avoid the grap be zoomable in/out to the infinity
- .on("zoom", zoom.bind(this)));
-
- function draw () {
- var total, minDate, maxDate, numberFormat;
-
- svg.select("g.x.axis").call(xAxis);
- svg.select("g.y.axis").call(yAxis);
- svg.selectAll("path.area").attr("d", function (d) { return area(d); });
- numberFormat = d3.format(",d"); // number formatter (comma separated number i.e. 100,000,000)
-
- rootNode.select('#' + this.props.id + '-range').html("Seeing total flows <strong>from:</strong> " + x.domain().map(format).join(" <strong>to:</strong> "));
-
- //Calculate the total flows between the displayed date range
-
- total = 0;
- minDate = x.domain()[0];
- maxDate = x.domain()[1];
-
- // Go to the first millisecond on dates
- minDate.setSeconds(0);minDate.setMilliseconds(0);
- maxDate.setSeconds(59);maxDate.setMilliseconds(0);
-
- svg.selectAll("path.area").data().forEach(function (pathData)
- {
- pathData.forEach(function (record)
- {
- // Discard records outside displayed date range
- if (record.date >= minDate && record.date <= maxDate) {
- total += +record.total;
- }
- });
- });
-
- rootNode.select('#' + this.props.id + '-total').html("<strong>Total netflows in range:</strong> " + numberFormat(total));
- }
-
- /*
- Zoom event handler
- */
- function zoom() {
- if (d3.event.sourceEvent.type == "wheel") {
- if (d3.event.sourceEvent.wheelDelta < 0)
- rect.style("cursor", "zoom-out");
- else
- rect.style("cursor", "zoom-in");
- }
- else if (d3.event.sourceEvent.type == "mousemove") {
- rect.style("cursor", "e-resize");
- }
+const MARGIN = [80, 50, 50, 100];
+const TIME_FORMATER = d3.time.format('%Y-%m-%d %H:%M');
+const NUMBER_FORMATER = d3.format(',d');
- draw.call(this);
- }
+const IngestSummaryPanel = React.createClass({
+ mixins: [ContentLoaderMixin, ChartMixin],
+ buildChart() {
+ // Scales
+ this.xScale = d3.time.scale();
+ this.yScale = d3.scale.linear();
- draw.call(this);
-}
+ // Axis
+ this.xAxis = d3.svg.axis().scale(this.xScale).orient('bottom'); // Time
+ this.yAxis = d3.svg.axis().scale(this.yScale).orient('left'); // Totals
-var IngestSummaryPanel = React.createClass({
- propTypes: {
- id: React.PropTypes.string
- },
- getDefaultProperties: function () {
- return {
- id: 'spot-is'
- };
- },
- getInitialState: function ()
- {
- return {loading: true};
- },
- render:function()
- {
- var content;
-
- if (this.state.error)
- {
- content = (
- <div className="text-center text-danger">
- {this.state.error}
- </div>
- );
- }
- else if (this.state.loading)
- {
- content = (
- <div className="spot-loader">
- Loading <span className="spinner"></span>
- </div>
- );
- }
- else
- {
- content = (
- <div id={this.props.id} className="text-center">
- <div id={this.props.id + '-header'}>
- <p id={this.props.id + '-range'}></p>
- <p id={this.props.id + '-total'}></p>
- <p id={this.props.id + '-istructions'} className="small">** Zoom in/out using mouse wheel or two fingers in track pad <br /> ** Move across the x-axis by clicking anywhere in the graph and dragging to left or right</p>
- </div>
- <div id={this.props.id + '-summary'}></div>
- </div>
- );
- }
+ // An area generator.
+ this.area = d3.svg.area()
+ .x(d => this.xScale(d.date))
+ .y1(d => (isNaN(d.total) ? this.yScale(0) : this.yScale(d.total)));
- return (
- <div>{content}</div>
- )
- },
- componentDidMount: function()
- {
- NetflowIngestSummaryStore.addChangeDataListener(this._onChange);
- window.addEventListener('resize', this.buildGraph);
- },
- componentWillUnmount: function ()
- {
- NetflowIngestSummaryStore.removeChangeDataListener(this._onChange);
- window.removeEventListener('resize', this.buildGraph);
+ let d3svg = d3.select(this.svg);
+
+ const d3header = d3svg.append('g').attr('class', 'header');
+
+ d3header.append('text')
+ .attr('transform', 'translate(0,15)')
+ .html('Seeing data <tspan class="bold">from</tspan > <tspan class="min-date" /> <tspan class="bold"> to </tspan> <tspan class="max-date" />');
+
+ d3header.append('text')
+ .attr('transform', 'translate(0,30)')
+ .html('<tspan class="bold">Total</tspan> records ingested: <tspan class="total" />');
+
+ d3header.append('text')
+ .attr('transform', 'translate(0,45)')
+ .text('** Zoom in/out using mouse wheel or two fingers in track pad');
+ d3header.append('text')
+ .attr('transform', 'translate(0,60)')
+ .text('** ** Move across the x-axis by clicking anywhere in the graph and dragging to left or right');
+
+ this.updateLegends(this.state.minDate, this.state.maxDate, this.state.total);
+
+ this.canvas = d3svg.append('g')
+ .attr('transform', `translate(${MARGIN[3]},${MARGIN[0]})`);
+
+ // Append the clipPath to avoid drawing not seen data
+ this.clipRect = d3svg.append('defs')
+ .append('clipPath')
+ .attr('id', 'clip')
+ .append('rect')
+ .attr('x',0)
+ .attr('y', 0);
+
+ this.d3xAxis = this.canvas.append('g').attr('class', 'x axis');
+ this.d3yAxis = this.canvas.append('g').attr('class', 'y axis');
+ this.pipelineCanvas = this.canvas.append('g').attr('class', 'pipeline');
+
+ this.d3zoom = d3.behavior.zoom()
+ .scaleExtent([0.3, 2300]) // these are magic numbers to avoid the grap be zoomable in/out to the infinity
+ .on('zoom', this.zoom)
+
+ this.pipelineCanvas.call(this.d3zoom);
+
+ this.pipelineColor = d3.scale.category10().domain(Object.keys(IngestSummaryStore.PIPELINES));
+ },
+ draw() {
+ let $svg = $(this.svg);
+
+ this.width = $svg.width() - MARGIN[1] - MARGIN[3];
+ this.height = $svg.height() - MARGIN[0] - MARGIN[2];
+
+ d3.select(this.svg).select('.header').attr('transform', `translate(${this.width/2},0)`);
+
+ this.xScale.range([0, this.width]).domain([this.state.minDate, this.state.maxDate]);
+ this.yScale.range([this.height, 0]).domain([0, this.state.maxTotal]);
+
+ this.d3zoom.x(this.xScale)
+
+ this.area.y0(this.height);
+
+ this.clipRect
+ .attr('width', this.width)
+ .attr('height', this.height);
+
+ this.d3xAxis.attr('transform', `translate(0,${this.height})`);
+
+ this.drawPaths();
+ },
+ drawPaths() {
+ this.d3xAxis.call(this.xAxis);
+ this.d3yAxis.call(this.yAxis);
+
+ let total = 0;
+ const [minDate, maxDate] = this.xScale.domain();
+
+ // Go to the first millisecond on dates
+ minDate.setSeconds(0);minDate.setMilliseconds(0);
+ maxDate.setSeconds(59);maxDate.setMilliseconds(0);
+
+ const pipelineData = this.state.data.map(currentMonthData => {
+ // Filter records outside current date range
+ return currentMonthData.filter(record => {
+ const included = record.date>=minDate && record.date<=maxDate;
+
+ // Sum records included in range only
+ if (included) total += record.total;
+
+ return included;
+ });
+ }).filter(monthData => monthData.length>0); // Filter out empty months
+
+ this.drawPipeline(pipelineData);
+
+ this.updateLegends(minDate, maxDate, total);
+ },
+ drawPipeline(data) {
+ const pipelineSel = {};
+
+ pipelineSel.update = this.pipelineCanvas.selectAll('path.area').data(data);
+
+ pipelineSel.enter = pipelineSel.update.enter();
+ pipelineSel.exit = pipelineSel.update.exit();
+
+ pipelineSel.enter.append('path')
+ .attr('class', 'area')
+ .style('fill', this.pipelineColor(IngestSummaryStore.getPipeline()));
+
+ pipelineSel.update.attr('d', d => this.area(d));
+
+ pipelineSel.exit.remove();
+ },
+ updateLegends(minDate, maxDate, total) {
+ const minDateStr = TIME_FORMATER(minDate);
+ const maxDateStr = TIME_FORMATER(maxDate);
+ const totalStr = NUMBER_FORMATER(total);
+
+ const d3header = d3.select(this.svg).select('.header');
+
+ d3header.select('.min-date').text(minDateStr);
+ d3header.select('.max-date').text(maxDateStr);
+ d3header.select('.total').text(totalStr);
+ },
+ zoom() {
+ if (d3.event.sourceEvent.type == 'wheel') {
+ this.pipelineCanvas.classed('zoom-out', d3.event.sourceEvent.wheelDelta < 0);
+ this.pipelineCanvas.classed('zoom-in', d3.event.sourceEvent.wheelDelta >= 0);
+ this.pipelineCanvas.classed('e-resize', false);
+ }
+ else if (d3.event.sourceEvent.type == 'mousemove') {
+ this.pipelineCanvas.classed('e-resize', true);
+ this.pipelineCanvas.classed('zoom-out', false);
+ this.pipelineCanvas.classed('zoom-in', false);
+ }
+
+ this.drawPaths();
},
- componentDidUpdate: function ()
- {
- if (!this.state.loading && !this.state.error && this.state.data)
- {
- this.buildGraph();
+ componentDidMount() {
+ IngestSummaryStore.addChangeDataListener(this._onChange);
+ },
+ componentWillUnmount() {
+ IngestSummaryStore.removeChangeDataListener(this._onChange);
+ },
+ _onChange() {
+ const storeData = IngestSummaryStore.getData();
+
+ if (storeData.error) {
+ this.replaceState({error: storeData.error});
+ }
+ else if (!storeData.loading && storeData.data) {
+ this.replaceState(this._getStateFromData(storeData.data));
+ }
+ else {
+ this.replaceState({loading: storeData.loading});
+ }
+ },
+ _getStateFromData(data) {
+ let total, maxTotal, minDate, maxDate;
+
+ total = 0;
+ maxTotal = 0;
+ minDate = null;
+ maxDate = null;
+
+ data.forEach(function (monthData) {
+ monthData.forEach(function (record) {
+ minDate = d3.min([minDate, record.date]);
+ maxDate = d3.max([maxDate, record.date]);
+ maxTotal = d3.max([maxTotal, +record.total]);
+ total += +record.total;
+ });
+ });
+
+ !minDate && (minDate = DateUtils.parseDate(IngestSummaryStore.getStartDate()));
+ !maxDate && (maxDate = DateUtils.parseDate(IngestSummaryStore.getEndDate()));
+
+ return {
+ loading: false,
+ total,
+ maxTotal,
+ minDate,
+ maxDate,
+ data: data
+ };
}
- },
- buildGraph: initialDraw,
- _onChange: function () {
- this.replaceState(NetflowIngestSummaryStore.getData());
- }
});
module.exports = IngestSummaryPanel;
http://git-wip-us.apache.org/repos/asf/incubator-spot/blob/46470640/spot-oa/ui/js/components/OptionPicker.react.js
----------------------------------------------------------------------
diff --git a/spot-oa/ui/js/components/OptionPicker.react.js b/spot-oa/ui/js/components/OptionPicker.react.js
new file mode 100644
index 0000000..f8e748d
--- /dev/null
+++ b/spot-oa/ui/js/components/OptionPicker.react.js
@@ -0,0 +1,43 @@
+const React = require('react');
+
+const RadioPicker = React.createClass({
+ propTypes: {
+ id: React.PropTypes.string,
+ name: React.PropTypes.string,
+ options: React.PropTypes.arrayOf(React.PropTypes.string).isRequired,
+ value: React.PropTypes.string
+ },
+ getDefaultProps() {
+ return {
+ id: null,
+ name: null,
+ value: null
+ };
+ },
+ getInitialState() {
+ const state = {};
+
+ state.value = this.props.value || (this.props.options.length>0 ? this.props.options[0] : null);
+
+ return state;
+ },
+ render() {
+ const options = Object.keys(this.props.options).map(option => {
+ return <option value={option} selected={this.state.value==option}>
+ {this.props.options[option]}
+ </option>;
+ });
+
+ return <select id={this.props.id} className="form-control" name={this.props.name} onChange={this.onChange}>
+ {options}
+ </select>;
+ },
+ onChange(e) {
+ const value = e.target.value;
+ this.setState({value});
+
+ this.props.onChange && this.props.onChange(value);
+ }
+});
+
+module.exports = RadioPicker;
http://git-wip-us.apache.org/repos/asf/incubator-spot/blob/46470640/spot-oa/ui/js/constants/SpotConstants.js
----------------------------------------------------------------------
diff --git a/spot-oa/ui/js/constants/SpotConstants.js b/spot-oa/ui/js/constants/SpotConstants.js
index 35e23c4..e4a711d 100755
--- a/spot-oa/ui/js/constants/SpotConstants.js
+++ b/spot-oa/ui/js/constants/SpotConstants.js
@@ -1,4 +1,7 @@
-var SpotConstants = {
+const SpotConstants = {
+ PIPELINE_NETFLOW: 'flow',
+ PIPELINE_DNS: 'dns',
+ PIPELINE_PROXY: 'proxy',
// Search Actions
UPDATE_FILTER: 'UPDATE_FILTER',
UPDATE_DATE: 'UPDATE_DATE',
@@ -18,6 +21,7 @@ var SpotConstants = {
IMPACT_ANALYSIS_PANEL:'Impact Analysis',
GLOBE_VIEW_PANEL:'Map View | Globe',
TIMELINE_PANEL:'Timeline',
+ INGEST_SUMMARY_PANEL:'Ingest Summary',
// Edge Investigation
MAX_SUSPICIOUS_ROWS: 250,
RELOAD_SUSPICIOUS: 'RELOAD_SUSPICIOUS',
@@ -31,10 +35,10 @@ var SpotConstants = {
RELOAD_COMMENTS: 'RELOAD_COMMENTS',
SELECT_COMMENT: 'SELECT_COMMENT',
// INGEST SUMMARY
+ API_INGEST_SUMMARY: '../data/${pipeline}/ingest_summary/is_${year}${month}.csv',
+ RELOAD_INGEST_SUMMARY: 'RELOAD_INGEST_SUMMARY',
START_DATE: 'start-date',
END_DATE: 'end-date',
- // Ingest summary Actions
- RELOAD_INGEST_SUMMARY: 'RELOAD_INGEST_SUMMARY',
// Server Paths
NOTEBOOKS_PATH: '/notebooks/ipynb'
};
http://git-wip-us.apache.org/repos/asf/incubator-spot/blob/46470640/spot-oa/ui/js/ingest-summary.js
----------------------------------------------------------------------
diff --git a/spot-oa/ui/js/ingest-summary.js b/spot-oa/ui/js/ingest-summary.js
index c42ed41..04f2872 100755
--- a/spot-oa/ui/js/ingest-summary.js
+++ b/spot-oa/ui/js/ingest-summary.js
@@ -3,12 +3,14 @@ const ReactDOM = require('react-dom');
const SpotActions = require('./actions/SpotActions');
const InSumActions = require('./actions/InSumActions');
+const IngestSummaryStore = require('./stores/IngestSummaryStore');
const SpotConstants = require('./constants/SpotConstants');
const SpotUtils = require('./utils/SpotUtils');
const DateUtils = require('./utils/DateUtils');
// Build and Render Toolbar
const DateInput = require('./components/DateInput.react');
+const OptionPicker = require('./components/OptionPicker.react');
// Find out period
var startDate, endDate, today;
@@ -41,32 +43,48 @@ if (endDate < startDate)
endDate = today;
}
+const PIPELINES = IngestSummaryStore.PIPELINES;
+const DEFAULT_PIPELINE = Object.keys(PIPELINES)[0];
+
+const loadPipeline = function loadPipeline(pipeline) {
+ IngestSummaryStore.setPipeline(pipeline);
+ InSumActions.reloadSummary();
+}
+
ReactDOM.render(
- (
<form className="form-inline">
- <div className="form-group">
- <label htmlFor="startDatePicker">Period:</label>
- <div className="input-group input-group-xs">
- <div className="input-group-addon">
- <span className="glyphicon glyphicon-calendar" aria-hidden="true"></span>
- </div>
- <DateInput id="startDatePicker" name={SpotConstants.START_DATE} value={startDate}/>
+ <div className="form-group">
+ <label htmlFor="pipeline-picker">Source: </label>
+ <div className="input-group input-group-xs">
+ <OptionPicker
+ id="pipeline-picker"
+ options={PIPELINES}
+ value={DEFAULT_PIPELINE}
+ onChange={loadPipeline} />
+ </div>
+ </div>
+ <div className="form-group">
+ <label htmlFor="startDatePicker">Period:</label>
+ <div className="input-group input-group-xs">
+ <div className="input-group-addon">
+ <span className="glyphicon glyphicon-calendar" aria-hidden="true"></span>
+ </div>
+ <DateInput id="startDatePicker" name={SpotConstants.START_DATE} value={startDate}/>
+ </div>
</div>
- </div>
- <div className="form-group">
- <label htmlFor="endDatePicker"> - </label>
- <div className="input-group input-group-xs">
- <DateInput id="endDatePicker" name={SpotConstants.END_DATE} value={endDate} />
- <div className="input-group-btn">
- <button className="btn btn-default" type="button" title="Reload" onClick={InSumActions.reloadSummary}>
- <span className="glyphicon glyphicon-repeat" aria-hidden="true"></span>
- </button>
- </div>
+ <div className="form-group">
+ <label htmlFor="endDatePicker"> - </label>
+ <div className="input-group input-group-xs">
+ <DateInput id="endDatePicker" name={SpotConstants.END_DATE} value={endDate} />
+ <div className="input-group-btn">
+ <button className="btn btn-default" type="button" title="Reload" onClick={InSumActions.reloadSummary}>
+ <span className="glyphicon glyphicon-repeat" aria-hidden="true"></span>
+ </button>
+ </div>
+ </div>
</div>
- </div>
- </form>
- ),
- document.getElementById('nav_form')
+ </form>,
+ document.getElementById('nav_form')
);
// Build and Render Edge Investigation's panels
@@ -79,7 +97,7 @@ ReactDOM.render(
<div id="spot-content">
<PanelRow maximized>
<Panel title="Ingest Summary" container header={false} className="col-md-12">
- <IngestSummaryPanel id="spot-is" />
+ <IngestSummaryPanel className="is-chart" />
</Panel>
</PanelRow>
</div>,
@@ -91,4 +109,4 @@ SpotActions.setDate(startDate, SpotConstants.START_DATE);
SpotActions.setDate(endDate, SpotConstants.END_DATE);
// Load data
-InSumActions.reloadSummary();
+loadPipeline(DEFAULT_PIPELINE);
http://git-wip-us.apache.org/repos/asf/incubator-spot/blob/46470640/spot-oa/ui/js/stores/IngestSummaryStore.js
----------------------------------------------------------------------
diff --git a/spot-oa/ui/js/stores/IngestSummaryStore.js b/spot-oa/ui/js/stores/IngestSummaryStore.js
index 9e4ccb5..ca8a439 100755
--- a/spot-oa/ui/js/stores/IngestSummaryStore.js
+++ b/spot-oa/ui/js/stores/IngestSummaryStore.js
@@ -1,34 +1,55 @@
-var assign = require('object-assign');
-var d3 = require('d3');
-
-var SpotDispatcher = require('../../../js/dispatchers/SpotDispatcher');
-var SpotConstants = require('../../../js/constants/SpotConstants');
-var NetflowConstants = require('../constants/NetflowConstants');
-var DateUtils = require('../../../js/utils/DateUtils');
-var RestStore = require('../../../js/stores/RestStore');
-
-var START_DATE_FILTER = NetflowConstants.START_DATE;
-var END_DATE_FILTER = NetflowConstants.END_DATE;
-var CURRENT_DATE_FILTER = 'current_date';
-
-var requestQueue = [];
-var requestErrors = [];
-
-var IngestSummaryStore = assign(new RestStore(NetflowConstants.API_INGEST_SUMMARY), {
+const assign = require('object-assign');
+const d3 = require('d3');
+
+const SpotDispatcher = require('../dispatchers/SpotDispatcher');
+const SpotConstants = require('../constants/SpotConstants');
+const DateUtils = require('../utils/DateUtils');
+const RestStore = require('../stores/RestStore');
+
+const PIPELINE_FILTER = 'pipeline';
+const CURRENT_YEAR_FILTER = 'year';
+const CURRENT_MONTH_FILTER = 'month';
+
+const requestQueue = [];
+const requestErrors = [];
+
+const IngestSummaryStore = assign(new RestStore(SpotConstants.API_INGEST_SUMMARY), {
+ PIPELINES: {
+ [SpotConstants.PIPELINE_NETFLOW]: 'Netflow',
+ [SpotConstants.PIPELINE_DNS]: 'Dns',
+ [SpotConstants.PIPELINE_PROXY]: 'Proxy'
+ },
errorMessages: {
404: 'No details available'
},
- setStartDate: function (date) {
- this.setRestFilter(START_DATE_FILTER, date);
+ setStartDate(date) {
+ this._startDate = date;
+ },
+ getStartDate() {
+ return this._startDate;
+ },
+ setEndDate(date) {
+ this._endDate = date;
},
- getStartDate: function () {
- return this.getRestFilter(START_DATE_FILTER);
+ getEndDate() {
+ return this._endDate;
},
- setEndDate: function (date) {
- this.setRestFilter(END_DATE_FILTER, date);
+ setPipeline(pipeline) {
+ this.setRestFilter(PIPELINE_FILTER, pipeline);
},
- getEndDate: function () {
- return this.getRestFilter(END_DATE_FILTER);
+ getPipeline() {
+ return this.getRestFilter(PIPELINE_FILTER);
+ },
+ setCurrentDate(date) {
+ this.setRestFilter(CURRENT_YEAR_FILTER, date.getFullYear())
+
+ const month = date.getMonth() + 1 + "";
+ this.setRestFilter(CURRENT_MONTH_FILTER, month.length==1 ? `0${month}`:month);
+
+ this._currentDate = date;
+ },
+ getCurrentDate() {
+ return this._currentDate;
},
/**
* Start asking the server for CSV data to create the chart
@@ -36,8 +57,8 @@ var IngestSummaryStore = assign(new RestStore(NetflowConstants.API_INGEST_SUMMAR
requestSummary: function () {
var startDate, endDate, date, delta, startRequests, i, month;
- startDate = DateUtils.parseDate(this.getRestFilter(START_DATE_FILTER));
- endDate = DateUtils.parseDate(this.getRestFilter(END_DATE_FILTER));
+ startDate = DateUtils.parseDate(this.getStartDate());
+ endDate = DateUtils.parseDate(this.getEndDate());
// Find out how many request need to be made
delta = (endDate.getFullYear() - startDate.getFullYear()) * 12 + (endDate.getMonth() - startDate.getMonth());
@@ -58,17 +79,10 @@ var IngestSummaryStore = assign(new RestStore(NetflowConstants.API_INGEST_SUMMAR
startRequests && this.dequeue();
},
dequeue: function () {
- var date, year, month;
-
if (requestQueue.length == 0) return;
- date = requestQueue.shift();
- this.setRestFilter(CURRENT_DATE_FILTER, date);
- year = date.getFullYear();
- month = date.getMonth() + 1 + "";
- month = month.length == 1 ? "0" + month : month;
-
- this.setEndpoint(NetflowConstants.API_INGEST_SUMMARY.replace('${year}', year).replace('${month}', month));
+ const date = requestQueue.shift();
+ this.setCurrentDate(date);
this.reload();
},
@@ -91,10 +105,10 @@ var IngestSummaryStore = assign(new RestStore(NetflowConstants.API_INGEST_SUMMAR
requestErrors.push(data);
}
else if (data.data) {
- parse = d3.time.format("%Y-%m-%d %H:%M").parse; // Date formatting parser
- startDate = DateUtils.parseDate(this.getRestFilter(START_DATE_FILTER));
- endDate = DateUtils.parseDate(this.getRestFilter(END_DATE_FILTER));
- date = DateUtils.parseDate(this.getRestFilter(CURRENT_DATE_FILTER));
+ parse = d3.time.format("%Y-%m-%d %H:%M:%S%Z").parse; // Date formatting parser
+ startDate = DateUtils.parseDate(this.getStartDate());
+ endDate = DateUtils.parseDate(this.getEndDate());
+ date = DateUtils.parseDate(this.getCurrentDate());
if (date.getFullYear() == startDate.getFullYear() && date.getMonth() == startDate.getMonth()) {
dayFilter = startDate.getDate();
@@ -112,8 +126,8 @@ var IngestSummaryStore = assign(new RestStore(NetflowConstants.API_INGEST_SUMMAR
// Parse dates and numbers.
data.data.forEach(function (d) {
- d.date = parse(d.date);
- d.flows = +d.flows;
+ d.date = parse(`${d.date}:00-0000`);
+ d.total = +d.total;
});
// Sort the data by date ASC
@@ -122,13 +136,14 @@ var IngestSummaryStore = assign(new RestStore(NetflowConstants.API_INGEST_SUMMAR
});
if (!this._data.data) this._data.data = [];
+
this._data.data.push(data.data);
}
this._data.loading = requestQueue.length > 0;
if (!this._data.loading) {
- if (this._data.data.length==0) {
+ if (this._data.data && this._data.data.length==0) {
// Broadcast first found error
this._data = requestErrors[0];
}
@@ -144,15 +159,15 @@ SpotDispatcher.register(function (action) {
switch (action.actionType) {
case SpotConstants.UPDATE_DATE:
switch (action.name) {
- case NetflowConstants.START_DATE:
+ case SpotConstants.START_DATE:
IngestSummaryStore.setStartDate(action.date);
break;
- case NetflowConstants.END_DATE:
+ case SpotConstants.END_DATE:
IngestSummaryStore.setEndDate(action.date);
break;
}
break;
- case NetflowConstants.RELOAD_INGEST_SUMMARY:
+ case SpotConstants.RELOAD_INGEST_SUMMARY:
IngestSummaryStore.requestSummary();
break;
}
http://git-wip-us.apache.org/repos/asf/incubator-spot/blob/46470640/spot-oa/ui/package.json
----------------------------------------------------------------------
diff --git a/spot-oa/ui/package.json b/spot-oa/ui/package.json
index 724544d..3863c64 100644
--- a/spot-oa/ui/package.json
+++ b/spot-oa/ui/package.json
@@ -36,7 +36,7 @@
"scripts": {
"test": "jest",
"postinstall": "npm run build-all",
- "watch-ingest-summary": "watchify js/ingest-summary.js -o js/ingest-summary.bundle.min.js -v -d",
+ "watch-ingest-summary": "NODE_ENV=development watchify js/ingest-summary.js -o js/ingest-summary.bundle.min.js -v -d",
"build-all": "npm run build-flow && npm run build-dns && npm run build-proxy && npm run build-ingest-summary",
"build-flow": "cd flow/ && npm run build-all && cd ../",
"build-dns": "cd dns/ && npm run build-all && cd ../",