summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorJared Dillard <jdillard@netgate.com>2016-08-17 14:46:22 -0500
committerJared Dillard <jdillard@netgate.com>2016-08-17 14:46:31 -0500
commit9f33ec64330d0b50896772abd73156abbd762305 (patch)
treed5cb7f956dcba23f653bf5a182ca97b33707e5b2 /src
parent01c2735c0f18707559cca73df6b880b456a012d8 (diff)
downloadpfsense-9f33ec64330d0b50896772abd73156abbd762305.zip
pfsense-9f33ec64330d0b50896772abd73156abbd762305.tar.gz
change traffic graphs to d3
Diffstat (limited to 'src')
-rw-r--r--src/usr/local/www/css/pfSense-dark.css58
-rw-r--r--src/usr/local/www/css/pfSense.css63
-rw-r--r--src/usr/local/www/ifstats.php119
-rw-r--r--src/usr/local/www/js/traffic-graphs.js189
-rw-r--r--src/usr/local/www/status_graph.php292
-rw-r--r--src/usr/local/www/widgets/widgets/traffic_graphs.widget.php542
6 files changed, 1079 insertions, 184 deletions
diff --git a/src/usr/local/www/css/pfSense-dark.css b/src/usr/local/www/css/pfSense-dark.css
index e8e6606..7a7dfc8 100644
--- a/src/usr/local/www/css/pfSense-dark.css
+++ b/src/usr/local/www/css/pfSense-dark.css
@@ -5,17 +5,49 @@
* Copyright (c) 2016 Electric Sheep Fencing, LLC
* All rights reserved.
*
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
*
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgment:
+ * "This product includes software developed by the pfSense Project
+ * for use in the pfSense® software distribution. (http://www.pfsense.org/).
+ *
+ * 4. The names "pfSense" and "pfSense Project" must not be used to
+ * endorse or promote products derived from this software without
+ * prior written permission. For written permission, please contact
+ * coreteam@pfsense.org.
+ *
+ * 5. Products derived from this software may not be called "pfSense"
+ * nor may "pfSense" appear in their names without prior written
+ * permission of the Electric Sheep Fencing, LLC.
+ *
+ * 6. Redistributions of any form whatsoever must retain the following
+ * acknowledgment:
+ *
+ * "This product includes software developed by the pfSense Project
+ * for use in the pfSense software distribution (http://www.pfsense.org/).
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE pfSense PROJECT ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE pfSense PROJECT OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
*/
@import url("/css/pfSense.css");
@@ -486,6 +518,10 @@ textarea {
/* D3 Styles */
+.traffic-widget-chart:not(:last-child) {
+ border-bottom: 2px solid #303030;
+}
+
svg text {
fill: #FFFFFF !important;
}
@@ -499,13 +535,13 @@ g.nv-axis text, g.nv-legend text {
stroke: #616161 !important;
}
-#chart .nvtooltip > h3 {
+.d3-chart .nvtooltip > h3 {
background-color: rgba(66,66,66, 0.9);
border-bottom: 1px solid #616161;
color: #e0e0e0;
}
-#chart .nvtooltip {
+.d3-chart .nvtooltip {
background: rgba(97,97,97, 0.9);
color: #e0e0e0;
}
diff --git a/src/usr/local/www/css/pfSense.css b/src/usr/local/www/css/pfSense.css
index 24e86ad..b2535f2 100644
--- a/src/usr/local/www/css/pfSense.css
+++ b/src/usr/local/www/css/pfSense.css
@@ -5,17 +5,49 @@
* Copyright (c) 2016 Electric Sheep Fencing, LLC
* All rights reserved.
*
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
*
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgment:
+ * "This product includes software developed by the pfSense Project
+ * for use in the pfSense® software distribution. (http://www.pfsense.org/).
+ *
+ * 4. The names "pfSense" and "pfSense Project" must not be used to
+ * endorse or promote products derived from this software without
+ * prior written permission. For written permission, please contact
+ * coreteam@pfsense.org.
+ *
+ * 5. Products derived from this software may not be called "pfSense"
+ * nor may "pfSense" appear in their names without prior written
+ * permission of the Electric Sheep Fencing, LLC.
+ *
+ * 6. Redistributions of any form whatsoever must retain the following
+ * acknowledgment:
+ *
+ * "This product includes software developed by the pfSense Project
+ * for use in the pfSense software distribution (http://www.pfsense.org/).
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE pfSense PROJECT ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE pfSense PROJECT OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
*/
@import url("/vendor/bootstrap/css/bootstrap.min.css");
@@ -924,14 +956,23 @@ svg {
display: block;
}
-#chart, #chart svg {
+.d3-chart, .d3-chart svg {
margin: 0px;
padding: 10px 0;
height: 445px;
width: 100%;
}
-#chart .nvtooltip > h3 {
+.traffic-widget-chart, .traffic-widget-chart svg {
+ padding: 0;
+ height: 250px;
+}
+
+.traffic-widget-chart:not(:last-child) {
+ border-bottom: 2px solid #ccc;
+}
+
+.d3-chart .nvtooltip > h3 {
font-size: 14px;
}
diff --git a/src/usr/local/www/ifstats.php b/src/usr/local/www/ifstats.php
index f01eb25..f6dd1f4 100644
--- a/src/usr/local/www/ifstats.php
+++ b/src/usr/local/www/ifstats.php
@@ -1,22 +1,56 @@
<?php
/*
- * ifstats.php
+ ifstats.php
+*/
+/* ====================================================================
+ * Copyright (c) 2004-2015 Electric Sheep Fencing, LLC. All rights reserved.
*
- * part of pfSense (https://www.pfsense.org)
- * Copyright (c) 2004-2016 Electric Sheep Fencing, LLC
- * All rights reserved.
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
*
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgment:
+ * "This product includes software developed by the pfSense Project
+ * for use in the pfSense software distribution. (http://www.pfsense.org/).
+ *
+ * 4. The names "pfSense" and "pfSense Project" must not be used to
+ * endorse or promote products derived from this software without
+ * prior written permission. For written permission, please contact
+ * coreteam@pfsense.org.
+ *
+ * 5. Products derived from this software may not be called "pfSense"
+ * nor may "pfSense" appear in their names without prior written
+ * permission of the Electric Sheep Fencing, LLC.
+ *
+ * 6. Redistributions of any form whatsoever must retain the following
+ * acknowledgment:
+ *
+ * "This product includes software developed by the pfSense Project
+ * for use in the pfSense software distribution (http://www.pfsense.org/).
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE pfSense PROJECT ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE pfSense PROJECT OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * ====================================================================
*
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
*/
##|+PRIV
@@ -26,12 +60,65 @@
##|*MATCH=ifstats.php*
##|-PRIV
- require_once('guiconfig.inc');
- require_once("interfaces.inc");
+$nocsrf = true;
+
+require_once('guiconfig.inc');
+require_once("interfaces.inc");
+
+
+//overload the use of this page until the conversion of both traffic graphs have been completed
+if($_POST['if']) {
+
+ $ifs = $_POST['if'];
+
+ $ifarray = explode("|", $ifs);
+
+ $temp = gettimeofday();
+ $timing = (double)$temp["sec"] + (double)$temp["usec"] / 1000000.0;
+ $obj = [];
+ $count = 0;
+
+ foreach ($ifarray as $if) {
+
+ $realif = get_real_interface($if);
+
+ if (!$realif) {
+ $realif = $if; // Need for IPsec case interface.
+ }
+
+ $ifinfo = pfSense_get_interface_stats($realif);
+
+ $obj[$if] = [];
+
+ $obj[$if][0]['key'] = $if . "in";
+ $obj[$if][0]['values'] = array($timing, $ifinfo['inbytes']);
+
+ $obj[$if][1]['key'] = $if . "out";
+ $obj[$if][1]['values'] = array($timing, $ifinfo['outbytes']);
+/*
+ $obj[$count]['key'] = $if . "in";
+ $obj[$count]['name'] = $if . " (in)";
+ $obj[$count]['values'] = array($timing, $ifinfo['inbytes']);
+
+ $count++;
+
+ $obj[$count]['key'] = $if . "out";
+ $obj[$count]['name'] = $if . " (out)";
+ $obj[$count]['values'] = array($timing, $ifinfo['outbytes']);
+
+ $count++;
+*/
+ }
+
+ header('Content-Type: application/json');
+ echo json_encode($obj,JSON_PRETTY_PRINT|JSON_PARTIAL_OUTPUT_ON_ERROR|JSON_NUMERIC_CHECK);
+
+} else {
$if = $_GET['if'];
$realif = get_real_interface($if);
+
if (!$realif) {
$realif = $if; // Need for IPsec case interface.
}
@@ -48,4 +135,6 @@
echo "$timing|" . $ifinfo['inbytes'] . "|" . $ifinfo['outbytes'] . "\n";
+}
+
?>
diff --git a/src/usr/local/www/js/traffic-graphs.js b/src/usr/local/www/js/traffic-graphs.js
new file mode 100644
index 0000000..7229917
--- /dev/null
+++ b/src/usr/local/www/js/traffic-graphs.js
@@ -0,0 +1,189 @@
+function draw_graph(refreshInterval, then) {
+
+ d3.select("div[id^=nvtooltip-]").remove();
+ d3.select(".interface-label").remove();
+
+ var invert = localStorage.getItem('invert');
+ var size = localStorage.getItem('size');
+
+ startTime = 120 * refreshInterval;
+ then.setSeconds(then.getSeconds() - startTime);
+ var thenTime = then.getTime();
+
+ $.each( JSON.parse(localStorage.getItem('interfaces')), function( key, value ) {
+
+ latest[value + 'in'] = 0;
+ latest[value + 'out'] = 0;
+
+ var stepTime = thenTime;
+
+ //initialize first 120 graph points to zero
+ for (i = 1; i < 120; i++) {
+
+ stepTime = stepTime + (1000 * refreshInterval);
+
+ myData[value].forEach(function(entry) {
+ entry.values.push({
+ x: stepTime,
+ y: 0
+ });
+ });
+
+ }
+
+ nv.addGraph(function() {
+
+ charts[value] = nv.models.lineChart()
+ .useInteractiveGuideline(true)
+ .color(d3.scale.category20().range())
+ .rightAlignYAxis(true)
+ .margin({top: 0, left:25, bottom: 30, right: 45});
+
+ charts[value]
+ .x(function(d,i) { return d.x });
+
+ charts[value].xAxis
+ .tickFormat(function (d) {
+ return d3.time.format('%M:%S')(new Date(d));
+ });
+
+ //TODO change to localStorage.getItem('sizeLabel');
+ var sizeLabel = $( "#traffic-graph-size option:selected" ).text();
+
+ d3.select('#traffic-chart-' + value + ' svg')
+ .append("text")
+ .attr('class', 'interface-label')
+ .attr("x", 20)
+ .attr("y", 20)
+ .attr("font-size", 18)
+ .text(value);
+
+ charts[value].yAxis
+ .tickFormat(d3.format('.2s'))
+ .showMaxMin(false);
+
+ d3.select('#traffic-chart-' + value + ' svg')
+ .datum(myData[value])
+ .transition().duration(500)
+ .call(charts[value]);
+
+ nv.utils.windowResize(charts[value].update);
+
+ //custom tooltip contents
+ charts[value].interactiveLayer.tooltip.contentGenerator(function(data) {
+
+ var units = 'b/s';
+ console.log(localStorage.getItem('size'));
+ if(localStorage.getItem('size') === "1") {
+ units = 'B/s'
+ }
+
+ var content = '<h3>' + d3.time.format('%Y-%m-%d %H:%M:%S')(new Date(data.value)) + '</h3><table><tbody>';
+
+ for ( var v = 0; v < data.series.length; v++ ){
+
+ var rawValue = data.series[v].value;
+
+ if((invert === "true") && data.series[v].key.includes("(out)")) {
+ rawValue = 0 - rawValue;
+ }
+
+ var sValue = d3.formatPrefix(rawValue);
+
+ //TODO change unit based on unit size
+ var formattedVal = sValue.scale(rawValue).toFixed(2) + ' ' + sValue.symbol + units;
+
+ content += '<tr><td class="legend-color-guide"><div style="background-color: ' + data.series[v].color + '"></div></td><td>' + data.series[v].key + '</td><td class="value"><strong>' + formattedVal + '</strong></td></tr>';
+
+ }
+
+ content += '</tbody></table>';
+
+ return content;
+
+ });
+
+ return charts[value];
+ });
+
+ });
+
+ //only update the graphs when tab is active in window to save resources and prevent build up
+ updateIds = Visibility.every(refreshInterval * 1000, function(){
+
+ d3.json("ifstats.php")
+ .header("Content-Type", "application/x-www-form-urlencoded")
+ .post('if='+JSON.parse(localStorage.getItem('interfaces')).join('|'), function(error, json) { //TODO all ifs again
+
+ if (error) {
+
+ Visibility.stop(updateIds);
+ $(".traffic-widget-chart").remove();
+ $("#traffic-chart-error").show().html('<strong>Error</strong>: ' + error);
+ return console.warn(error);
+
+ }
+
+ if (json.error) {
+
+ Visibility.stop(updateIds);
+ $(".traffic-widget-chart").remove();
+ $("#traffic-chart-error").show().html('<strong>Error</strong>: ' + json.error);
+ return console.warn(json.error);
+
+ }
+
+ now = new Date(Date.now());
+
+ $.each(json, function( key, ifVals ) {
+
+ if(!myData[key][0].first) {
+
+ var trafficIn = ((ifVals[0].values[1] * size) - latest[ifVals[0].key]) / refreshInterval;
+ var trafficOut = ((ifVals[1].values[1] * size) - latest[ifVals[1].key]) / refreshInterval;
+
+ if((localStorage.getItem('invert') === "true")) {
+ trafficOut = 0 - trafficOut;
+ }
+
+ myData[key][0].values.push({
+ x: now.getTime(),
+ y: trafficIn
+ });
+
+ myData[key][1].values.push({
+ x: now.getTime(),
+ y: trafficOut
+ });
+
+ } else {
+ myData[key][0].values.push({
+ x: now.getTime(),
+ y: 0
+ });
+
+ myData[key][1].values.push({
+ x: now.getTime(),
+ y: 0
+ });
+ }
+
+ latest[ifVals[0].key] = ifVals[0].values[1] * size;
+ latest[ifVals[1].key] = ifVals[1].values[1] * size;
+
+ myData[key][0].first = false;
+ myData[key][1].first = false;
+
+
+ myData[key][0].values.shift();
+ myData[key][1].values.shift();
+
+ charts[key].update();
+
+ });
+
+ });
+
+ });
+
+} \ No newline at end of file
diff --git a/src/usr/local/www/status_graph.php b/src/usr/local/www/status_graph.php
index e79272a..638eaf2 100644
--- a/src/usr/local/www/status_graph.php
+++ b/src/usr/local/www/status_graph.php
@@ -10,17 +10,49 @@
* Copyright (c) 2003-2004 Manuel Kasper <mk@neon1.net>.
* All rights reserved.
*
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
*
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgment:
+ * "This product includes software developed by the pfSense Project
+ * for use in the pfSense® software distribution. (http://www.pfsense.org/).
+ *
+ * 4. The names "pfSense" and "pfSense Project" must not be used to
+ * endorse or promote products derived from this software without
+ * prior written permission. For written permission, please contact
+ * coreteam@pfsense.org.
+ *
+ * 5. Products derived from this software may not be called "pfSense"
+ * nor may "pfSense" appear in their names without prior written
+ * permission of the Electric Sheep Fencing, LLC.
+ *
+ * 6. Redistributions of any form whatsoever must retain the following
+ * acknowledgment:
+ *
+ * "This product includes software developed by the pfSense Project
+ * for use in the pfSense software distribution (http://www.pfsense.org/).
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE pfSense PROJECT ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE pfSense PROJECT OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
*/
##|+PRIV
@@ -36,18 +68,6 @@
require_once("guiconfig.inc");
require_once("ipsec.inc");
-if ($_POST['width']) {
- $width = $_POST['width'];
-} else {
- $width = "100%";
-}
-
-if ($_POST['height']) {
- $height = $_POST['height'];
-} else {
- $height = "200";
-}
-
// Get configured interface list
$ifdescrs = get_configured_interface_with_descr();
if (ipsec_enabled()) {
@@ -186,6 +206,226 @@ $form->add($section);
print $form;
?>
+
+<script src="/vendor/d3/d3.min.js"></script>
+<script src="/vendor/nvd3/nv.d3.js"></script>
+<script src="/vendor/visibility/visibility-1.2.3.min.js"></script>
+
+<link href="/vendor/nvd3/nv.d3.css" media="screen, projection" rel="stylesheet" type="text/css">
+
+<script type="text/javascript">
+
+//<![CDATA[
+events.push(function() {
+
+ var InterfaceString = "<?=$curif?>";
+
+ //store saved settings in a fresh localstorage
+ localStorage.clear();
+ localStorage.setItem('interfaces', JSON.stringify(InterfaceString.split("|"))); //TODO see if can be switched to interfaces
+ localStorage.setItem('interval', 1);
+ localStorage.setItem('invert', "true");
+ localStorage.setItem('size', 1);
+
+ window.charts = {};
+ window.myData = {};
+ window.updateIds = 0;
+ window.latest = [];
+ var refreshInterval = localStorage.getItem('interval');
+
+ //TODO make it fall on a second value so it increments better
+ var now = then = new Date(Date.now());
+
+ var nowTime = now.getTime();
+
+ $.each( JSON.parse(localStorage.getItem('interfaces')), function( key, value ) {
+
+ myData[value] = [];
+ updateIds = 0;
+
+ var itemIn = new Object();
+ var itemOut = new Object();
+
+ itemIn.key = value + " (in)";
+ if(localStorage.getItem('invert') === "true") { itemIn.area = true; }
+ itemIn.first = true;
+ itemIn.values = [{x: nowTime, y: 0}];
+ myData[value].push(itemIn);
+
+ itemOut.key = value + " (out)";
+ if(localStorage.getItem('invert') === "true") { itemOut.area = true; }
+ itemOut.first = true;
+ itemOut.values = [{x: nowTime, y: 0}];
+ myData[value].push(itemOut);
+
+ });
+
+ draw_graph(refreshInterval, then);
+
+ //re-draw graph when the page goes from inactive (in it's window) to active
+ Visibility.change(function (e, state) {
+ if(state === "visible") {
+
+ now = then = new Date(Date.now());
+
+ var nowTime = now.getTime();
+
+ $.each( JSON.parse(localStorage.getItem('interfaces')), function( key, value ) {
+
+ Visibility.stop(updateIds);
+
+ myData[value] = [];
+
+ var itemIn = new Object();
+ var itemOut = new Object();
+
+ itemIn.key = value + " (in)";
+ if(localStorage.getItem('invert') === "true") { itemIn.area = true; }
+ itemIn.first = true;
+ itemIn.values = [{x: nowTime, y: 0}];
+ myData[value].push(itemIn);
+
+ itemOut.key = value + " (out)";
+ if(localStorage.getItem('invert') === "true") { itemOut.area = true; }
+ itemOut.first = true;
+ itemOut.values = [{x: nowTime, y: 0}];
+ myData[value].push(itemOut);
+
+ });
+
+ draw_graph(refreshInterval, then);
+
+ }
+ });
+
+ // save new config defaults
+ $( '#traffic-graph-form' ).submit(function(event) {
+
+ var error = false;
+ $("#traffic-chart-error").hide();
+
+ var interfaces = $( "#traffic-graph-interfaces" ).val();
+ refreshInterval = parseInt($( "#traffic-graph-interval" ).val());
+ var invert = $( "#traffic-graph-invert" ).val();
+ var size = $( "#traffic-graph-size" ).val();
+
+ //TODO validate interfaces data and throw error
+
+ if(!Number.isInteger(refreshInterval) || refreshInterval < 1 || refreshInterval > 10) {
+ error = 'Refresh Interval is not a valid number between 1 and 10.';
+ }
+
+ if(invert != "true" && invert != "false") {
+
+ error = 'Invert is not a boolean of true or false.';
+
+ }
+
+ if(!error) {
+
+ var formData = {
+ 'traffic-graph-interfaces' : interfaces,
+ 'traffic-graph-interval' : refreshInterval,
+ 'traffic-graph-invert' : invert,
+ 'traffic-graph-size' : size
+ };
+
+ $.ajax({
+ type : 'POST',
+ url : '/widgets/widgets/traffic_graphs.widget.php',
+ data : formData,
+ dataType : 'json',
+ encode : true
+ })
+ .done(function(message) {
+
+ if(message.success) {
+
+ Visibility.stop(updateIds);
+
+ //remove all old graphs (divs/svgs)
+ $( ".traffic-widget-chart" ).remove();
+
+ localStorage.setItem('interfaces', JSON.stringify(interfaces));
+ localStorage.setItem('interval', refreshInterval);
+ localStorage.setItem('invert', invert);
+ localStorage.setItem('size', size);
+
+ //redraw graph with new settings
+ now = then = new Date(Date.now());
+
+ var freshData = [];
+
+ var nowTime = now.getTime();
+
+ $.each( interfaces, function( key, value ) {
+
+ //create new graphs (divs/svgs)
+ $("#widget-traffic_graphs_panel-body").append('<div id="traffic-chart-' + value + '" class="d3-chart traffic-widget-chart"><svg></svg></div>');
+
+ myData[value] = [];
+
+ var itemIn = new Object();
+ var itemOut = new Object();
+
+ itemIn.key = value + " (in)";
+ if(localStorage.getItem('invert') === "true") { itemIn.area = true; }
+ itemIn.first = true;
+ itemIn.values = [{x: nowTime, y: 0}];
+ myData[value].push(itemIn);
+
+ itemOut.key = value + " (out)";
+ if(localStorage.getItem('invert') === "true") { itemOut.area = true; }
+ itemOut.first = true;
+ itemOut.values = [{x: nowTime, y: 0}];
+ myData[value].push(itemOut);
+
+ });
+
+ draw_graph(refreshInterval, then);
+
+ $( "#traffic-graph-message" ).removeClass("text-danger").addClass("text-success");
+ $( "#traffic-graph-message" ).text(message.success);
+
+ setTimeout(function() {
+ $( "#traffic-graph-message" ).empty();
+ $( "#traffic-graph-message" ).removeClass("text-success");
+ }, 5000);
+
+ } else {
+
+ $( "#traffic-graph-message" ).addClass("text-danger");
+ $( "#traffic-graph-message" ).text(message.error);
+
+ console.warn(message.error);
+
+ }
+
+ })
+ .fail(function() {
+
+ console.warn( "The Traffic Graphs widget AJAX request failed." );
+
+ });
+
+ } else {
+
+ $( "#traffic-graph-message" ).addClass("text-danger");
+ $( "#traffic-graph-message" ).text(error);
+
+ console.warn(error);
+
+ }
+
+ event.preventDefault();
+ });
+
+});
+//]]>
+</script>
+
+<script src="/js/traffic-graphs.js"></script>
+
<script type="text/javascript">
//<![CDATA[
@@ -241,13 +481,9 @@ if (ipsec_enabled()) {
</div>
<div class="panel-body">
<div class="col-sm-6">
- <object data="graph.php?ifnum=<?=htmlspecialchars($curif);?>&amp;ifname=<?=rawurlencode($ifdescrs[htmlspecialchars($curif)]);?>">
- <param name="id" value="graph" />
- <param name="type" value="image/svg+xml" />
- <param name="width" value="<?=$width;?>" />
- <param name="height" value="<?=$height;?>" />
- <param name="pluginspage" value="http://www.adobe.com/svg/viewer/install/auto" />
- </object>
+ <div id="traffic-chart-<?=$curif?>" class="d3-chart traffic-widget-chart">
+ <svg></svg>
+ </div>
</div>
<div class="col-sm-6">
<table class="table table-striped table-condensed">
diff --git a/src/usr/local/www/widgets/widgets/traffic_graphs.widget.php b/src/usr/local/www/widgets/widgets/traffic_graphs.widget.php
index 4279c7b..843ee22 100644
--- a/src/usr/local/www/widgets/widgets/traffic_graphs.widget.php
+++ b/src/usr/local/www/widgets/widgets/traffic_graphs.widget.php
@@ -1,31 +1,74 @@
<?php
/*
- * traffic_graphs.widget.php
+ traffic_graphs.widget.php
+*/
+/* ====================================================================
+ * Copyright (c) 2004-2015 Electric Sheep Fencing, LLC. All rights reserved.
+ * Copyright (c) 2007 Scott Dale
+ * Copyright (c) 2004-2005 T. Lechat <dev@lechat.org>, Manuel Kasper <mk@neon1.net>
+ * and Jonathan Watt <jwatt@jwatt.org>.
*
- * part of pfSense (https://www.pfsense.org)
- * Copyright (c) 2004-2016 Electric Sheep Fencing, LLC
- * Copyright (c) 2007 Scott Dale
- * Copyright (c) 2004-2005 T. Lechat <dev@lechat.org>
- * Copyright (c) 2004-2005 Jonathan Watt <jwatt@jwatt.org>.
- * All rights reserved.
+ * Some or all of this file is based on the m0n0wall project which is
+ * Copyright (c) 2004 Manuel Kasper (BSD 2 clause)
*
- * originally part of m0n0wall (http://m0n0.ch/wall)
- * Copyright (c) 2003-2004 Manuel Kasper <mk@neon1.net>.
- * All rights reserved.
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
*
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgment:
+ * "This product includes software developed by the pfSense Project
+ * for use in the pfSense software distribution. (http://www.pfsense.org/).
+ *
+ * 4. The names "pfSense" and "pfSense Project" must not be used to
+ * endorse or promote products derived from this software without
+ * prior written permission. For written permission, please contact
+ * coreteam@pfsense.org.
+ *
+ * 5. Products derived from this software may not be called "pfSense"
+ * nor may "pfSense" appear in their names without prior written
+ * permission of the Electric Sheep Fencing, LLC.
+ *
+ * 6. Redistributions of any form whatsoever must retain the following
+ * acknowledgment:
+ *
+ * "This product includes software developed by the pfSense Project
+ * for use in the pfSense software distribution (http://www.pfsense.org/).
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE pfSense PROJECT ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE pfSense PROJECT OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * ====================================================================
*
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
*/
+/* TODOs */
+//re-use on Status > traffic graphs
+//figure out why there is a missing datapoint at the start
+//name things/variables better
+//apply css change to Status > Monitoring
+//show interface name and latest in/out in upper left
+//add stacked overall graph?
+ //also show pie graph of lastest precentages of total? (split 50/50 on width)
+ //make this an option?
+
$nocsrf = true;
require_once("guiconfig.inc");
@@ -33,141 +76,402 @@ require_once("pfsense-utils.inc");
require_once("ipsec.inc");
require_once("functions.inc");
-$first_time = false;
+$ifdescrs = get_configured_interface_with_descr();
-if (!is_array($user_settings["widgets"]["trafficgraphs"])) {
- $first_time = true;
- $user_settings["widgets"]["trafficgraphs"] = array();
+if (ipsec_enabled()) {
+ $ifdescrs['enc0'] = "IPsec";
}
-$a_config = &$user_settings["widgets"]["trafficgraphs"];
+//there are no traffic graph widget defaults in config yet. so set them, but don't write the config
+if (!is_array($config["widgets"]["trafficgraphs"])) {
-if (!is_array($a_config["shown"])) {
- $a_config["shown"] = array();
-}
+ $config["widgets"]["trafficgraphs"] = array();
+ $config["widgets"]["trafficgraphs"]["refreshinterval"] = 1;
+ $config["widgets"]["trafficgraphs"]["invert"] = "true";
+ $config["widgets"]["trafficgraphs"]["size"] = 1;
+ $config["widgets"]["trafficgraphs"]["shown"] = array();
+ $config["widgets"]["trafficgraphs"]["shown"]["item"] = array();
+
+ foreach($ifdescrs as $ifname => $ifdescr) {
+
+ $ifinfo = get_interface_info($ifname);
+
+ if ($ifinfo['status'] != "down") {
+ $config["widgets"]["trafficgraphs"]["shown"]["item"][] = $ifname;
+ }
+
+ }
+
+ //TODO silently write to config? (use a config message about saving defaults)
-if (!is_array($a_config["shown"]["item"])) {
- $a_config["shown"]["item"] = array();
}
-$ifdescrs = get_configured_interface_with_descr();
+if(!isset($config["widgets"]["trafficgraphs"]["size"])) {
+ $config["widgets"]["trafficgraphs"]["size"] = 1;
+}
-if (ipsec_enabled()) {
- $ifdescrs['enc0'] = "IPsec";
+if(!isset($config["widgets"]["trafficgraphs"]["invert"])) {
+ $config["widgets"]["trafficgraphs"]["invert"] = "true";
}
+$a_config = &$config["widgets"]["trafficgraphs"];
+
+// save new default config options that have been submitted
if ($_POST) {
- if (isset($_POST["refreshinterval"]) && is_numericint($_POST["refreshinterval"])) {
- $a_config["refreshinterval"] = $_POST["refreshinterval"];
- }
- if (isset($_POST["scale_type"])) {
- $a_config["scale_type"] = $_POST["scale_type"];
+ //TODO validate data and throw error
+ $a_config["shown"]["item"] = $_POST["traffic-graph-interfaces"];
+
+ // TODO check if between 1 and 10
+ if (isset($_POST["traffic-graph-interval"]) && is_numericint($_POST["traffic-graph-interval"])) {
+
+ $a_config["refreshinterval"] = $_POST["traffic-graph-interval"];
+
+ } else {
+
+ die('{ "error" : "Refresh Interval is not a valid number between 1 and 10." }');
+
}
- $a_config["shown"]["item"] = array();
+ if($_POST["traffic-graph-invert"] === "true" || $_POST["traffic-graph-invert"] === "false") {
+
+ $a_config["invert"] = $_POST["traffic-graph-invert"];
+
+ } else {
+
+ die('{ "error" : "Invert is not a boolean of true or false." }');
- foreach ($ifdescrs as $ifname => $ifdescr) {
- if (in_array($ifname, $_POST["shown"])) {
- $a_config["shown"]["item"][] = $ifname;
- }
}
- save_widget_settings($_SESSION['Username'], $user_settings["widgets"], gettext("Updated traffic graph settings via dashboard."));
- header("Location: /");
- exit(0);
-}
+ //TODO validate data and throw error
+ $a_config["size"] = $_POST["traffic-graph-size"];
-$shown = array();
+ write_config(gettext("Updated traffic graph settings via dashboard."));
-foreach ($a_config["shown"]["item"] as $if) {
- $shown[$if] = true;
-}
+ header('Content-Type: application/json');
-if ($first_time) {
- $keys = array_keys($ifdescrs);
- $shown[$keys[0]] = true;
-}
+ die('{ "success" : "The changes have been applied successfully." }');
-if (isset($a_config["refreshinterval"]) && is_numericint($a_config["refreshinterval"])) {
- $refreshinterval = $a_config["refreshinterval"];
-} else {
- $refreshinterval = 10;
}
-if (isset($a_config["scale_type"])) {
- $scale_type = $a_config["scale_type"];
-} else {
- $scale_type = "up";
-}
+$refreshinterval = $a_config["refreshinterval"];
+
+$ifsarray = [];
-$graphcounter = 0;
+foreach ($a_config["shown"]["item"] as $ifname) {
-foreach ($ifdescrs as $ifname => $ifdescr):
$ifinfo = get_interface_info($ifname);
- if ($shown[$ifname]) {
- $mingraphbutton = "inline";
- $showgraphbutton = "none";
- $graphdisplay = "inline";
- $interfacevalue = "show";
- $graphcounter++;
+
+ if ($ifinfo['status'] != "down") {
+ $ifsarray[] = $ifname;
} else {
- $mingraphbutton = "none";
- $showgraphbutton = "inline";
- $graphdisplay = "none";
- $interfacevalue = "hide";
+ //TODO throw error?
}
- if ($ifinfo['status'] != "down"):
+}
+
+$allifs = implode("|", $ifsarray);
+
?>
- <div style="display:<?=$graphdisplay?>">
- <object data="graph.php?ifnum=<?=$ifname?>&amp;ifname=<?=rawurlencode($ifdescr)?>&amp;timeint=<?=$refreshinterval?>&amp;initdelay=<?=$graphcounter * 2?>">
- <param name="id" value="graph" />
- <param name="type" value="image/svg+xml" />
- </object>
- </div>
-<?php endif; ?>
-<?php endforeach; ?>
+ <script src="/vendor/d3/d3.min.js"></script>
+ <script src="/vendor/nvd3/nv.d3.js"></script>
+ <script src="/vendor/visibility/visibility-1.2.3.min.js"></script>
+
+ <link href="/vendor/nvd3/nv.d3.css" media="screen, projection" rel="stylesheet" type="text/css">
+
+ <div id="traffic-chart-error" class="alert alert-danger" style="display: none;"></div>
+
+ <?php
+ foreach($a_config["shown"]["item"] as $ifname) {
+ echo '<div id="traffic-chart-' . $ifname . '" class="d3-chart traffic-widget-chart">';
+ echo ' <svg></svg>';
+ echo '</div>';
+ }
+ ?>
+
+ <script type="text/javascript">
+
+//<![CDATA[
+events.push(function() {
+
+ var InterfaceString = "<?=$allifs?>";
+
+ //store saved settings in a fresh localstorage
+ localStorage.clear();
+ localStorage.setItem('interfaces', JSON.stringify(InterfaceString.split("|"))); //TODO see if can be switched to interfaces
+ localStorage.setItem('interval', <?=$refreshinterval?>);
+ localStorage.setItem('invert', <?=$a_config["invert"]?>);
+ localStorage.setItem('size', <?=$a_config["size"]?>);
+
+ window.charts = {};
+ window.myData = {};
+ window.updateIds = 0;
+ window.latest = [];
+ var refreshInterval = localStorage.getItem('interval');
+
+ //TODO make it fall on a second value so it increments better
+ var now = then = new Date(Date.now());
+
+ var nowTime = now.getTime();
+
+ $.each( JSON.parse(localStorage.getItem('interfaces')), function( key, value ) {
+
+ myData[value] = [];
+ updateIds = 0;
+
+ var itemIn = new Object();
+ var itemOut = new Object();
+
+ itemIn.key = value + " (in)";
+ if(localStorage.getItem('invert') === "true") { itemIn.area = true; }
+ itemIn.first = true;
+ itemIn.values = [{x: nowTime, y: 0}];
+ myData[value].push(itemIn);
+
+ itemOut.key = value + " (out)";
+ if(localStorage.getItem('invert') === "true") { itemOut.area = true; }
+ itemOut.first = true;
+ itemOut.values = [{x: nowTime, y: 0}];
+ myData[value].push(itemOut);
+
+ });
+
+ draw_graph(refreshInterval, then);
+
+ //re-draw graph when the page goes from inactive (in it's window) to active
+ Visibility.change(function (e, state) {
+ if(state === "visible") {
+
+ now = then = new Date(Date.now());
+
+ var nowTime = now.getTime();
+
+ $.each( JSON.parse(localStorage.getItem('interfaces')), function( key, value ) {
+
+ Visibility.stop(updateIds);
+
+ myData[value] = [];
+
+ var itemIn = new Object();
+ var itemOut = new Object();
+
+ itemIn.key = value + " (in)";
+ if(localStorage.getItem('invert') === "true") { itemIn.area = true; }
+ itemIn.first = true;
+ itemIn.values = [{x: nowTime, y: 0}];
+ myData[value].push(itemIn);
+
+ itemOut.key = value + " (out)";
+ if(localStorage.getItem('invert') === "true") { itemOut.area = true; }
+ itemOut.first = true;
+ itemOut.values = [{x: nowTime, y: 0}];
+ myData[value].push(itemOut);
+
+ });
+
+ draw_graph(refreshInterval, then);
+
+ }
+ });
+
+ // save new config defaults
+ $( '#traffic-graph-form' ).submit(function(event) {
+
+ var error = false;
+ $("#traffic-chart-error").hide();
+
+ var interfaces = $( "#traffic-graph-interfaces" ).val();
+ refreshInterval = parseInt($( "#traffic-graph-interval" ).val());
+ var invert = $( "#traffic-graph-invert" ).val();
+ var size = $( "#traffic-graph-size" ).val();
+
+ //TODO validate interfaces data and throw error
+
+ if(!Number.isInteger(refreshInterval) || refreshInterval < 1 || refreshInterval > 10) {
+ error = 'Refresh Interval is not a valid number between 1 and 10.';
+ }
+
+ if(invert != "true" && invert != "false") {
+
+ error = 'Invert is not a boolean of true or false.';
+
+ }
+
+ if(!error) {
+
+ var formData = {
+ 'traffic-graph-interfaces' : interfaces,
+ 'traffic-graph-interval' : refreshInterval,
+ 'traffic-graph-invert' : invert,
+ 'traffic-graph-size' : size
+ };
+
+ $.ajax({
+ type : 'POST',
+ url : '/widgets/widgets/traffic_graphs.widget.php',
+ data : formData,
+ dataType : 'json',
+ encode : true
+ })
+ .done(function(message) {
+
+ if(message.success) {
+
+ Visibility.stop(updateIds);
+
+ //remove all old graphs (divs/svgs)
+ $( ".traffic-widget-chart" ).remove();
+
+ localStorage.setItem('interfaces', JSON.stringify(interfaces));
+ localStorage.setItem('interval', refreshInterval);
+ localStorage.setItem('invert', invert);
+ localStorage.setItem('size', size);
+
+ //redraw graph with new settings
+ now = then = new Date(Date.now());
+
+ var freshData = [];
+
+ var nowTime = now.getTime();
+
+ $.each( interfaces, function( key, value ) {
+
+ //create new graphs (divs/svgs)
+ $("#widget-traffic_graphs_panel-body").append('<div id="traffic-chart-' + value + '" class="d3-chart traffic-widget-chart"><svg></svg></div>');
+
+ myData[value] = [];
+
+ var itemIn = new Object();
+ var itemOut = new Object();
+
+ itemIn.key = value + " (in)";
+ if(localStorage.getItem('invert') === "true") { itemIn.area = true; }
+ itemIn.first = true;
+ itemIn.values = [{x: nowTime, y: 0}];
+ myData[value].push(itemIn);
+
+ itemOut.key = value + " (out)";
+ if(localStorage.getItem('invert') === "true") { itemOut.area = true; }
+ itemOut.first = true;
+ itemOut.values = [{x: nowTime, y: 0}];
+ myData[value].push(itemOut);
+
+ });
+
+ draw_graph(refreshInterval, then);
+
+ $( "#traffic-graph-message" ).removeClass("text-danger").addClass("text-success");
+ $( "#traffic-graph-message" ).text(message.success);
+
+ setTimeout(function() {
+ $( "#traffic-graph-message" ).empty();
+ $( "#traffic-graph-message" ).removeClass("text-success");
+ }, 5000);
+
+ } else {
+
+ $( "#traffic-graph-message" ).addClass("text-danger");
+ $( "#traffic-graph-message" ).text(message.error);
+
+ console.warn(message.error);
+
+ }
+
+ })
+ .fail(function() {
+
+ console.warn( "The Traffic Graphs widget AJAX request failed." );
+
+ });
+
+ } else {
+
+ $( "#traffic-graph-message" ).addClass("text-danger");
+ $( "#traffic-graph-message" ).text(error);
+
+ console.warn(error);
+
+ }
+
+ event.preventDefault();
+ });
+
+});
+//]]>
+</script>
+
+<script src="/js/traffic-graphs.js"></script>
<!-- close the body we're wrapped in and add a configuration-panel -->
-</div><div id="widget-<?=$widgetname?>_panel-footer" class="panel-footer collapse">
-
-<form action="/widgets/widgets/traffic_graphs.widget.php" method="post" class="form-horizontal">
- <div class="form-group">
- <label for="scale_type_up" class="col-sm-3 control-label"><?=gettext('Show graphs')?></label>
- <div class="col-sm-6 checkbox">
-<?php foreach ($ifdescrs as $ifname => $ifdescr): ?>
- <label>
- <input type="checkbox" name="shown[<?= $ifname?>]" value="<?=$ifname?>" <?= ($shown[$ifname]) ? "checked":""?> />
- <?=$ifdescr?>
- </label>
-<?php endforeach; ?>
+</div>
+
+<div id="widget-<?=$widgetname?>_panel-footer" class="panel-footer collapse">
+
+ <form id="traffic-graph-form" action="/widgets/widgets/traffic_graphs.widget.php" method="post" class="form-horizontal">
+ <div class="form-group">
+ <label for="traffic-graph-interfaces" class="col-sm-3 control-label"><?=gettext('Show graphs')?></label>
+ <div class="col-sm-9">
+ <select name="traffic-graph-interfaces[]" id="traffic-graph-interfaces" multiple>
+ <?php
+ foreach ($ifdescrs as $ifname => $ifdescr) {
+
+ $if_shown = "";
+ if (in_array($ifname, $a_config["shown"]["item"])) { $if_shown = " selected"; };
+ echo '<option value="' . $ifname . '"' . $if_shown . '>' . $ifdescr . "</option>\n";
+
+ }
+ ?>
+ </select>
+ </div>
</div>
- </div>
- <div class="form-group">
- <label for="scale_type_up" class="col-sm-3 control-label"><?=gettext('Default Autoscale')?></label>
- <div class="col-sm-6 checkbox">
- <label>
- <input name="scale_type" type="radio" id="scale_type_up" value="up" <?=($config["widgets"]["trafficgraphs"]["scale_type"]=="up" ? '' : 'checked')?> />
- <?=gettext('Up')?>
- </label>
- <label>
- <input name="scale_type" type="radio" id="scale_type_follow" value="follow" <?=($config["widgets"]["trafficgraphs"]["scale_type"]=="follow" ? 'checked' : '')?> />
- <?=gettext('Follow')?>
- </label>
+
+ <div class="form-group">
+ <label for="traffic-graph-interval" class="col-sm-3 control-label"><?=gettext('Refresh Interval')?></label>
+ <div class="col-sm-9">
+ <input type="number" id="traffic-graph-interval" name="traffic-graph-interval" value="<?=$refreshinterval?>" min="1" max="10" class="form-control" />
+ </div>
+ </div>
+
+ <div class="form-group">
+ <label for="traffic-graph-invert" class="col-sm-3 control-label"><?=gettext('Inverse')?></label>
+ <div class="col-sm-9">
+ <select class="form-control" id="traffic-graph-invert" name="traffic-graph-invert">
+ <?php
+ if($a_config["invert"] === "true") {
+ echo '<option value="true" selected>On</option>';
+ echo '<option value="false">Off</option>';
+ } else {
+ echo '<option value="true">On</option>';
+ echo '<option value="false" selected>Off</option>';
+ }
+ ?>
+ </select>
+ </div>
</div>
- </div>
- <div class="form-group">
- <label for="refreshinterval" class="col-sm-3 control-label"><?=gettext('Refresh Interval')?></label>
- <div class="col-sm-6">
- <input type="number" id="refreshinterval" name="refreshinterval" value="<?=$refreshinterval?>" min="1" max="30" class="form-control" />
+ <div class="form-group">
+ <label for="traffic-graph-size" class="col-sm-3 control-label"><?=gettext('Unit Size')?></label>
+ <div class="col-sm-9">
+ <select class="form-control" id="traffic-graph-size" name="traffic-graph-size">
+ <?php
+ if($a_config["size"] === "8") {
+ echo '<option value="8" selected>Bits</option>';
+ echo '<option value="1">Bytes</option>';
+ } else {
+ echo '<option value="8">Bits</option>';
+ echo '<option value="1" selected>Bytes</option>';
+ }
+ ?>
+ </select>
+ </div>
</div>
- </div>
- <div class="form-group">
- <div class="col-sm-offset-3 col-sm-6">
- <button type="submit" class="btn btn-primary"><i class="fa fa-save icon-embed-btn"></i><?=gettext('Save')?></button>
+ <div class="form-group">
+ <div class="col-sm-3 text-right">
+ <button type="submit" class="btn btn-primary"><i class="fa fa-save icon-embed-btn"></i><?=gettext('Save')?></button>
+ </div>
+ <div class="col-sm-9">
+ <div id="traffic-graph-message"></div>
+ </div>
</div>
- </div>
-</form>
+ </form>
OpenPOWER on IntegriCloud