diff options
author | Vsevolod Stakhov <vsevolod@highsecure.ru> | 2017-01-31 15:48:57 +0000 |
---|---|---|
committer | Vsevolod Stakhov <vsevolod@highsecure.ru> | 2017-01-31 15:48:57 +0000 |
commit | 977c7309f8438796c3baaf09291cf3ece2916899 (patch) | |
tree | 9d5a16b67551d7d2daccbe61f0e2c9a80d88a11d /interface/js | |
parent | c7bfdbfcd187cf08fa1023770a67420a64203391 (diff) | |
download | rspamd-977c7309f8438796c3baaf09291cf3ece2916899.tar.gz rspamd-977c7309f8438796c3baaf09291cf3ece2916899.zip |
[WebUI] Add graph tab
Diffstat (limited to 'interface/js')
-rw-r--r-- | interface/js/app/graph.js | 195 | ||||
-rw-r--r-- | interface/js/app/rspamd.js | 252 | ||||
-rw-r--r-- | interface/js/app/stats.js | 98 |
3 files changed, 300 insertions, 245 deletions
diff --git a/interface/js/app/graph.js b/interface/js/app/graph.js new file mode 100644 index 000000000..2d5341446 --- /dev/null +++ b/interface/js/app/graph.js @@ -0,0 +1,195 @@ +/* + The MIT License (MIT) + + Copyright (C) 2017 Vsevolod Stakhov <vsevolod@highsecure.ru> + Copyright (C) 2017 Alexander Moisseev + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. + */ + +define(['jquery', 'd3evolution', 'humanize'], +function($, D3Evolution) { + var rrd_pie_config = { + header: {}, + size: { + canvasWidth: 400, + canvasHeight: 180, + pieInnerRadius: "20%", + pieOuterRadius: "80%" + }, + labels: { + outer: { + format: "none" + }, + inner: { + hideWhenLessThanPercentage: 8 + }, + }, + misc: { + pieCenterOffset: { + x: -120, + y: 10, + }, + gradient: { + enabled: true, + }, + }, + }; + + var graph_options = { + title: "Rspamd throughput", + width: 1060, + height: 370, + yAxisLabel: "Message rate, msg/s", + + legend: { + space: 140, + entries: [{ + label: "Rejected", + color: "#FF0000" + }, { + label: "Temporary rejected", + color: "#BF8040" + }, { + label: "Subject rewrited", + color: "#FF6600" + }, { + label: "Probable spam", + color: "#FFAD00" + }, { + label: "Greylisted", + color: "#436EEE" + }, { + label: "Clean", + color: "#66CC00" + }] + } + }; + + function initGraph() { + // Get selectors' current state + function getSelector(id) { + var e = document.getElementById(id); + return e.options[e.selectedIndex].value; + } + var graph = new D3Evolution("graph", $.extend({}, graph_options, { + type: getSelector("selType"), + interpolate: getSelector("selInterpolate"), + convert: getSelector("selConvert"), + })); + $("#selConvert").change(function () { + graph.convert(this.value); + }); + $("#selType").change(function () { + graph.type(this.value); + }); + $("#selInterpolate").change(function () { + graph.interpolate(this.value); + }); + + return graph; + } + + function getRrdSummary(json) { + var xExtents = d3.extent(d3.merge(json), function (d) { return d.x; }); + var timeInterval = xExtents[1] - xExtents[0]; + + return json.map(function (curr, i) { + var avg = d3.mean(curr, function (d) { return d.y; }); + var yExtents = d3.extent(curr, function (d) { return d.y; }); + + return { + label: graph_options.legend.entries[i].label, + value: avg && (avg * timeInterval) ^ 0, + min: yExtents[0], + avg: avg && avg.toFixed(6), + max: yExtents[1], + last: curr[curr.length - 1].y, + color: graph_options.legend.entries[i].color, + }; + }, []); + } + + function drawRrdTable(data) { + $('#rrd-table').DataTable({ + destroy: true, + paging: false, + searching: false, + info: false, + data: data, + columns: [ + { data: "label", title: "Action" }, + { data: "value", title: "Messages", defaultContent: "" }, + { data: "min", title: "Minimum, msg/s", defaultContent: "" }, + { data: "avg", title: "Average, msg/s", defaultContent: "" }, + { data: "max", title: "Maximum, msg/s", defaultContent: "" }, + { data: "last", title: "Last, msg/s" }, + ], + + "fnRowCallback": function (nRow, aData) { + $(nRow).css("color", aData.color); + } + }); + } + + var interface = {}; + + interface.draw = function(rspamd, graphs, checked_server, type) { + if (graphs.graph === undefined) { + graphs.graph = initGraph(); + } + + if (type === undefined) { + function getSelector(id) { + var e = document.getElementById(id); + return e.options[e.selectedIndex].value; + } + type = getSelector("selData"); + } + + $.ajax({ + dataType: 'json', + type: 'GET', + url: 'graph', + jsonp: false, + data: { + "type": type + }, + beforeSend: function (xhr) { + xhr.setRequestHeader('Password', rspamd.getPassword()); + }, + success: function (data) { + var rrd_summary = getRrdSummary(data); + graphs.graph.data(data); + graphs.rrd_pie = rspamd.drawPie(graphs.rrd_pie, + "rrd-pie", + rrd_summary, + rrd_pie_config); + drawRrdTable(rrd_summary); + }, + error: function (jqXHR, textStatus, errorThrown) { + rspamd.alertMessage('alert-error', 'Cannot receive throughput data: ' + + textStatus + ' ' + jqXHR.status + ' ' + errorThrown); + } + }); + }; + + + return interface; +}); diff --git a/interface/js/app/rspamd.js b/interface/js/app/rspamd.js index 800ad20fe..a7d3f4156 100644 --- a/interface/js/app/rspamd.js +++ b/interface/js/app/rspamd.js @@ -22,8 +22,8 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -define(['jquery', 'visibility', 'bootstrap'], - function ($, D3Evolution, d3pie, visibility, DataTable) { +define(['jquery', 'd3pie', 'visibility', 'bootstrap'], + function ($, d3pie, visibility, DataTable) { // begin var graphs = {}; var tables = {}; @@ -94,13 +94,18 @@ define(['jquery', 'visibility', 'bootstrap'], }); break; case "#throughput_nav": - getGraphData(selData); + require(['app/graph'], function(graph) { + graph.draw(interface, graphs, checked_server, selData); + }); + var autoRefresh = { hourly: 60000, daily: 300000 }; timer_id.throughput = Visibility.every(autoRefresh[selData] || 3600000, function () { - getGraphData(selData); + require(['app/graph'], function(graph) { + graph.draw(interface, graphs, checked_server, selData); + }); }); break; case "#configuration_nav": @@ -172,15 +177,6 @@ define(['jquery', 'visibility', 'bootstrap'], selData = this.value; tabClick("#throughput_nav"); }); - $("#selConvert").change(function () { - graph.convert(this.value); - }); - $("#selType").change(function () { - graph.type(this.value); - }); - $("#selInterpolate").change(function () { - graph.interpolate(this.value); - }); $.ajaxSetup({ timeout: 2000, jsonp: false @@ -389,6 +385,98 @@ define(['jquery', 'visibility', 'bootstrap'], }); }; + interface.drawPie = function(obj, id, data, conf) { + if (obj) { + obj.updateProp("data.content", + data.filter(function (elt) { + return elt.value > 0; + }) + ); + } else { + obj = new d3pie(id, + $.extend({}, { + "header": { + "title": { + "text": "Rspamd filter stats", + "fontSize": 24, + "font": "open sans" + }, + "subtitle": { + "color": "#999999", + "fontSize": 12, + "font": "open sans" + }, + "titleSubtitlePadding": 9 + }, + "footer": { + "color": "#999999", + "fontSize": 10, + "font": "open sans", + "location": "bottom-left" + }, + "size": { + "canvasWidth": 600, + "canvasHeight": 400, + "pieInnerRadius": "20%", + "pieOuterRadius": "85%" + }, + "data": { + //"sortOrder": "value-desc", + "content": data.filter(function (elt) { + return elt.value > 0; + }) + }, + "labels": { + "outer": { + "hideWhenLessThanPercentage": 1, + "pieDistance": 30 + }, + "inner": { + "hideWhenLessThanPercentage": 4 + }, + "mainLabel": { + "fontSize": 14 + }, + "percentage": { + "color": "#eeeeee", + "fontSize": 14, + "decimalPlaces": 0 + }, + "lines": { + "enabled": true + }, + "truncation": { + "enabled": true + } + }, + "tooltips": { + "enabled": true, + "type": "placeholder", + "string": "{label}: {value}, {percentage}%" + }, + "effects": { + "pullOutSegmentOnClick": { + "effect": "back", + "speed": 400, + "size": 8 + }, + "load": { + "effect": "none" + } + }, + "misc": { + "gradient": { + "enabled": true, + "percentage": 100 + } + } + }, conf)); + } + return obj; + }; + + interface.getPassword = getPassword; + return interface; // @alert popover @@ -500,145 +588,7 @@ define(['jquery', 'visibility', 'bootstrap'], $('#modalBody form').hide(); }); - var rrd_pie_config = { - header: {}, - size: { - canvasWidth: 400, - canvasHeight: 180, - pieInnerRadius: "20%", - pieOuterRadius: "80%" - }, - labels: { - outer: { - format: "none" - }, - inner: { - hideWhenLessThanPercentage: 8 - }, - }, - misc: { - pieCenterOffset: { - x: -120, - y: 10, - }, - gradient: { - enabled: true, - }, - }, - }; - var graph_options = { - title: "Rspamd throughput", - width: 1060, - height: 370, - yAxisLabel: "Message rate, msg/s", - - legend: { - space: 140, - entries: [{ - label: "Rejected", - color: "#FF0000" - }, { - label: "Temporary rejected", - color: "#BF8040" - }, { - label: "Subject rewrited", - color: "#FF6600" - }, { - label: "Probable spam", - color: "#FFAD00" - }, { - label: "Greylisted", - color: "#436EEE" - }, { - label: "Clean", - color: "#66CC00" - }] - } - }; - - function initGraph() { - // Get selectors' current state - function getSelector(id) { - var e = document.getElementById(id); - return e.options[e.selectedIndex].value; - } - - selData = getSelector("selData"); - - graph = new D3Evolution("graph", $.extend({}, graph_options, { - type: getSelector("selType"), - interpolate: getSelector("selInterpolate"), - convert: getSelector("selConvert"), - })); - } - - function getRrdSummary(json) { - var xExtents = d3.extent(d3.merge(json), function (d) { return d.x; }); - var timeInterval = xExtents[1] - xExtents[0]; - - return json.map(function (curr, i) { - var avg = d3.mean(curr, function (d) { return d.y; }); - var yExtents = d3.extent(curr, function (d) { return d.y; }); - - return { - label: graph_options.legend.entries[i].label, - value: avg && (avg * timeInterval) ^ 0, - min: yExtents[0], - avg: avg && avg.toFixed(6), - max: yExtents[1], - last: curr[curr.length - 1].y, - color: graph_options.legend.entries[i].color, - }; - }, []); - } - - function drawRrdTable(data) { - $('#rrd-table').DataTable({ - destroy: true, - paging: false, - searching: false, - info: false, - data: data, - columns: [ - { data: "label", title: "Action" }, - { data: "value", title: "Messages", defaultContent: "" }, - { data: "min", title: "Minimum, msg/s", defaultContent: "" }, - { data: "avg", title: "Average, msg/s", defaultContent: "" }, - { data: "max", title: "Maximum, msg/s", defaultContent: "" }, - { data: "last", title: "Last, msg/s" }, - ], - - "fnRowCallback": function (nRow, aData) { - $(nRow).css("color", aData.color); - } - }); - } - - function getGraphData(type) { - $.ajax({ - dataType: 'json', - type: 'GET', - url: 'graph', - jsonp: false, - data: { - "type": type - }, - beforeSend: function (xhr) { - xhr.setRequestHeader('Password', getPassword()); - }, - success: function (data) { - const rrd_summary = getRrdSummary(data); - graph.data(data); - rrd_pie = drawPie(rrd_pie, "rrd-pie", rrd_summary, rrd_pie_config); - drawRrdTable(rrd_summary); - }, - error: function (jqXHR, textStatus, errorThrown) { - alertMessage('alert-error', 'Cannot receive throughput data: ' + - textStatus + ' ' + jqXHR.status + ' ' + errorThrown); - } - }); - } // @get history log // function getChart() { diff --git a/interface/js/app/stats.js b/interface/js/app/stats.js index 51e13b385..e2ce33d0f 100644 --- a/interface/js/app/stats.js +++ b/interface/js/app/stats.js @@ -139,7 +139,7 @@ function($, d3pie, Humanize) { $(widgets).show(); } - function getChart(pie, checked_server) { + function getChart(rspamd, pie, checked_server) { var creds = JSON.parse(sessionStorage.getItem('Credentials')); if (creds && creds[checked_server]) { var data = creds[checked_server].data; @@ -169,100 +169,10 @@ function($, d3pie, Humanize) { "data" : data.reject, "value" : data.reject } ]; - return drawPie(pie, "chart", new_data); - } - } - function drawPie(obj, id, data, conf) { - if (obj) { - obj.updateProp("data.content", - data.filter(function (elt) { - return elt.value > 0; - }) - ); - } else { - obj = new d3pie(id, - $.extend({}, { - "header": { - "title": { - "text": "Rspamd filter stats", - "fontSize": 24, - "font": "open sans" - }, - "subtitle": { - "color": "#999999", - "fontSize": 12, - "font": "open sans" - }, - "titleSubtitlePadding": 9 - }, - "footer": { - "color": "#999999", - "fontSize": 10, - "font": "open sans", - "location": "bottom-left" - }, - "size": { - "canvasWidth": 600, - "canvasHeight": 400, - "pieInnerRadius": "20%", - "pieOuterRadius": "85%" - }, - "data": { - //"sortOrder": "value-desc", - "content": data.filter(function (elt) { - return elt.value > 0; - }) - }, - "labels": { - "outer": { - "hideWhenLessThanPercentage": 1, - "pieDistance": 30 - }, - "inner": { - "hideWhenLessThanPercentage": 4 - }, - "mainLabel": { - "fontSize": 14 - }, - "percentage": { - "color": "#eeeeee", - "fontSize": 14, - "decimalPlaces": 0 - }, - "lines": { - "enabled": true - }, - "truncation": { - "enabled": true - } - }, - "tooltips": { - "enabled": true, - "type": "placeholder", - "string": "{label}: {value}, {percentage}%" - }, - "effects": { - "pullOutSegmentOnClick": { - "effect": "back", - "speed": 400, - "size": 8 - }, - "load": { - "effect": "none" - } - }, - "misc": { - "gradient": { - "enabled": true, - "percentage": 100 - } - } - }, conf)); + return rspamd.drawPie(pie, "chart", new_data); } - return obj; } - // Public API var interface = { statWidgets: function(rspamd, graphs, checked_server) { @@ -311,7 +221,7 @@ function($, d3pie, Humanize) { }); sessionStorage.setItem("Credentials", JSON.stringify(to_Credentials)); displayStatWidgets(checked_server); - graphs.chart = getChart(graphs.chart, checked_server); + graphs.chart = getChart(rspamd, graphs.chart, checked_server); }, function (serv, jqXHR, textStatus, errorThrown) { var alert_status = serv.name + '_alerted'; @@ -327,4 +237,4 @@ function($, d3pie, Humanize) { return interface; } -);
\ No newline at end of file +); |