mirror of
https://github.com/apache/superset.git
synced 2026-04-26 11:34:27 +00:00
Periodically update the slices in the dashboard (#374)
* Periodically update the slices in the dashboard * Make the refresh interval changeable * Add the button and the modal for the user to change the refresh interval * Don't use callback for refreshing * Randomize to prevent all widgets refreshing at the same time * Show the loading icon as an overlay when the slices refresh
This commit is contained in:
committed by
Maxime Beauchemin
parent
9a33557112
commit
d8a2b621d8
@@ -31,10 +31,11 @@ var Dashboard = function (dashboardData) {
|
||||
slice.render(true);
|
||||
});
|
||||
sliceObjects.push(slice);
|
||||
slice.render();
|
||||
}
|
||||
});
|
||||
this.slices = sliceObjects;
|
||||
this.refreshTimer = null;
|
||||
this.startPeriodicRender(0);
|
||||
},
|
||||
setFilter: function (slice_id, col, vals) {
|
||||
this.addFilter(slice_id, col, vals, false);
|
||||
@@ -57,6 +58,36 @@ var Dashboard = function (dashboardData) {
|
||||
// Returns a list of human readable active filters
|
||||
return JSON.stringify(this.filters, null, 4);
|
||||
},
|
||||
stopPeriodicRender: function () {
|
||||
if (this.refreshTimer) {
|
||||
clearTimeout(this.refreshTimer);
|
||||
this.refreshTimer = null;
|
||||
}
|
||||
},
|
||||
startPeriodicRender: function (interval) {
|
||||
this.stopPeriodicRender();
|
||||
var dash = this;
|
||||
var maxRandomDelay = Math.min(interval * 0.1, 5000);
|
||||
var refreshAll = function () {
|
||||
dash.slices.forEach(function (slice) {
|
||||
setTimeout(function () {
|
||||
slice.render(true);
|
||||
},
|
||||
//Randomize to prevent all widgets refreshing at the same time
|
||||
maxRandomDelay * Math.random());
|
||||
});
|
||||
};
|
||||
|
||||
var fetchAndRender = function () {
|
||||
refreshAll();
|
||||
if (interval > 0) {
|
||||
dash.refreshTimer = setTimeout(function () {
|
||||
fetchAndRender();
|
||||
}, interval);
|
||||
}
|
||||
};
|
||||
fetchAndRender();
|
||||
},
|
||||
refreshExcept: function (slice_id) {
|
||||
var immune = this.metadata.filter_immune_slice || [];
|
||||
this.slices.forEach(function (slice) {
|
||||
@@ -191,6 +222,10 @@ var Dashboard = function (dashboardData) {
|
||||
body: "The following global filters are currently applied:<br/>" + dashboard.readFilters()
|
||||
});
|
||||
});
|
||||
$("#refresh_dash_interval").on("change", function () {
|
||||
var interval = $(this).find('option:selected').val() * 1000;
|
||||
dashboard.startPeriodicRender(interval);
|
||||
});
|
||||
$('#refresh_dash').click(function () {
|
||||
dashboard.slices.forEach(function (slice) {
|
||||
slice.render(true);
|
||||
|
||||
@@ -314,8 +314,6 @@ var px = (function () {
|
||||
}
|
||||
this.force = force;
|
||||
token.find("img.loading").show();
|
||||
container.hide();
|
||||
container.html('');
|
||||
container.css('height', slice.height());
|
||||
dttm = 0;
|
||||
timer = setInterval(stopwatch, 10);
|
||||
@@ -325,9 +323,7 @@ var px = (function () {
|
||||
},
|
||||
resize: function () {
|
||||
token.find("img.loading").show();
|
||||
container.hide();
|
||||
container.css('height', slice.height());
|
||||
container.html('');
|
||||
this.viz.render();
|
||||
this.viz.resize();
|
||||
},
|
||||
|
||||
@@ -184,6 +184,7 @@ img.loading {
|
||||
.dashboard img.loading {
|
||||
width: 20px;
|
||||
margin: 5px;
|
||||
position: absolute;
|
||||
}
|
||||
img.viz-thumb-option {
|
||||
width: 100px;
|
||||
|
||||
@@ -16,6 +16,8 @@ function bigNumberVis(slice) {
|
||||
slice.error(error.responseText);
|
||||
return '';
|
||||
}
|
||||
div.html(''); //reset
|
||||
|
||||
var fd = payload.form_data;
|
||||
var json = payload.data;
|
||||
var color_range = [-1, 1];
|
||||
|
||||
@@ -20,116 +20,120 @@ function nvd3Vis(slice) {
|
||||
var colorKey = 'key';
|
||||
|
||||
nv.addGraph(function () {
|
||||
switch (viz_type) {
|
||||
case 'line':
|
||||
if (fd.show_brush) {
|
||||
chart = nv.models.lineWithFocusChart();
|
||||
chart.lines2.xScale(d3.time.scale.utc());
|
||||
chart.x2Axis
|
||||
.showMaxMin(fd.x_axis_showminmax)
|
||||
.staggerLabels(false);
|
||||
} else {
|
||||
chart = nv.models.lineChart();
|
||||
}
|
||||
// To alter the tooltip header
|
||||
// chart.interactiveLayer.tooltip.headerFormatter(function(){return '';});
|
||||
chart.xScale(d3.time.scale.utc());
|
||||
chart.interpolate(fd.line_interpolation);
|
||||
chart.xAxis
|
||||
.showMaxMin(fd.x_axis_showminmax)
|
||||
.staggerLabels(false);
|
||||
break;
|
||||
if (!chart) {
|
||||
switch (viz_type) {
|
||||
case 'line':
|
||||
if (fd.show_brush) {
|
||||
chart = nv.models.lineWithFocusChart();
|
||||
chart.lines2.xScale(d3.time.scale.utc());
|
||||
chart.x2Axis
|
||||
.showMaxMin(fd.x_axis_showminmax)
|
||||
.staggerLabels(false);
|
||||
} else {
|
||||
chart = nv.models.lineChart();
|
||||
}
|
||||
// To alter the tooltip header
|
||||
// chart.interactiveLayer.tooltip.headerFormatter(function(){return '';});
|
||||
chart.xScale(d3.time.scale.utc());
|
||||
chart.interpolate(fd.line_interpolation);
|
||||
chart.xAxis
|
||||
.showMaxMin(fd.x_axis_showminmax)
|
||||
.staggerLabels(false);
|
||||
break;
|
||||
|
||||
case 'bar':
|
||||
chart = nv.models.multiBarChart()
|
||||
.showControls(true)
|
||||
.groupSpacing(0.1);
|
||||
case 'bar':
|
||||
chart = nv.models.multiBarChart()
|
||||
.showControls(true)
|
||||
.groupSpacing(0.1);
|
||||
|
||||
chart.xAxis
|
||||
.showMaxMin(false)
|
||||
.staggerLabels(true);
|
||||
chart.xAxis
|
||||
.showMaxMin(false)
|
||||
.staggerLabels(true);
|
||||
|
||||
chart.stacked(fd.bar_stacked);
|
||||
break;
|
||||
chart.stacked(fd.bar_stacked);
|
||||
break;
|
||||
|
||||
case 'dist_bar':
|
||||
chart = nv.models.multiBarChart()
|
||||
.showControls(true) //Allow user to switch between 'Grouped' and 'Stacked' mode.
|
||||
.reduceXTicks(false)
|
||||
.rotateLabels(45)
|
||||
.groupSpacing(0.1); //Distance between each group of bars.
|
||||
case 'dist_bar':
|
||||
chart = nv.models.multiBarChart()
|
||||
.showControls(true) //Allow user to switch between 'Grouped' and 'Stacked' mode.
|
||||
.reduceXTicks(false)
|
||||
.rotateLabels(45)
|
||||
.groupSpacing(0.1); //Distance between each group of bars.
|
||||
|
||||
chart.xAxis
|
||||
.showMaxMin(false);
|
||||
chart.xAxis
|
||||
.showMaxMin(false);
|
||||
|
||||
chart.stacked(fd.bar_stacked);
|
||||
break;
|
||||
chart.stacked(fd.bar_stacked);
|
||||
break;
|
||||
|
||||
case 'pie':
|
||||
chart = nv.models.pieChart();
|
||||
colorKey = 'x';
|
||||
chart.valueFormat(f);
|
||||
if (fd.donut) {
|
||||
chart.donut(true);
|
||||
case 'pie':
|
||||
chart = nv.models.pieChart();
|
||||
colorKey = 'x';
|
||||
chart.valueFormat(f);
|
||||
if (fd.donut) {
|
||||
chart.donut(true);
|
||||
chart.labelsOutside(true);
|
||||
}
|
||||
chart.labelsOutside(true);
|
||||
}
|
||||
chart.labelsOutside(true);
|
||||
chart.cornerRadius(true);
|
||||
break;
|
||||
chart.cornerRadius(true);
|
||||
break;
|
||||
|
||||
case 'column':
|
||||
chart = nv.models.multiBarChart()
|
||||
.reduceXTicks(false)
|
||||
.rotateLabels(45);
|
||||
break;
|
||||
case 'column':
|
||||
chart = nv.models.multiBarChart()
|
||||
.reduceXTicks(false)
|
||||
.rotateLabels(45);
|
||||
break;
|
||||
|
||||
case 'compare':
|
||||
chart = nv.models.cumulativeLineChart();
|
||||
chart.xScale(d3.time.scale.utc());
|
||||
chart.xAxis
|
||||
.showMaxMin(false)
|
||||
.staggerLabels(true);
|
||||
break;
|
||||
case 'compare':
|
||||
chart = nv.models.cumulativeLineChart();
|
||||
chart.xScale(d3.time.scale.utc());
|
||||
chart.xAxis
|
||||
.showMaxMin(false)
|
||||
.staggerLabels(true);
|
||||
break;
|
||||
|
||||
case 'bubble':
|
||||
var row = function (col1, col2) {
|
||||
return "<tr><td>" + col1 + "</td><td>" + col2 + "</td></tr>";
|
||||
};
|
||||
chart = nv.models.scatterChart();
|
||||
chart.showDistX(true);
|
||||
chart.showDistY(true);
|
||||
chart.tooltip.contentGenerator(function (obj) {
|
||||
var p = obj.point;
|
||||
var s = "<table>";
|
||||
s += '<tr><td style="color:' + p.color + ';"><strong>' + p[fd.entity] + '</strong> (' + p.group + ')</td></tr>';
|
||||
s += row(fd.x, f(p.x));
|
||||
s += row(fd.y, f(p.y));
|
||||
s += row(fd.size, f(p.size));
|
||||
s += "</table>";
|
||||
return s;
|
||||
});
|
||||
chart.pointRange([5, fd.max_bubble_size * fd.max_bubble_size]);
|
||||
break;
|
||||
case 'bubble':
|
||||
var row = function (col1, col2) {
|
||||
return "<tr><td>" + col1 + "</td><td>" + col2 + "</td></tr>";
|
||||
};
|
||||
chart = nv.models.scatterChart();
|
||||
chart.showDistX(true);
|
||||
chart.showDistY(true);
|
||||
chart.tooltip.contentGenerator(function (obj) {
|
||||
var p = obj.point;
|
||||
var s = "<table>";
|
||||
s += '<tr><td style="color:' + p.color + ';"><strong>' + p[fd.entity] + '</strong> (' + p.group + ')</td></tr>';
|
||||
s += row(fd.x, f(p.x));
|
||||
s += row(fd.y, f(p.y));
|
||||
s += row(fd.size, f(p.size));
|
||||
s += "</table>";
|
||||
return s;
|
||||
});
|
||||
chart.pointRange([5, fd.max_bubble_size * fd.max_bubble_size]);
|
||||
break;
|
||||
|
||||
case 'area':
|
||||
chart = nv.models.stackedAreaChart();
|
||||
chart.style(fd.stacked_style);
|
||||
chart.xScale(d3.time.scale.utc());
|
||||
chart.xAxis
|
||||
.showMaxMin(false)
|
||||
.staggerLabels(true);
|
||||
break;
|
||||
case 'area':
|
||||
chart = nv.models.stackedAreaChart();
|
||||
chart.style(fd.stacked_style);
|
||||
chart.xScale(d3.time.scale.utc());
|
||||
chart.xAxis
|
||||
.showMaxMin(false)
|
||||
.staggerLabels(true);
|
||||
break;
|
||||
|
||||
case 'box_plot':
|
||||
colorKey = 'label';
|
||||
chart = nv.models.boxPlotChart();
|
||||
chart.x(function (d) { return d.label; });
|
||||
chart.staggerLabels(true);
|
||||
chart.maxBoxWidth(75); // prevent boxes from being incredibly wide
|
||||
break;
|
||||
case 'box_plot':
|
||||
colorKey = 'label';
|
||||
chart = nv.models.boxPlotChart();
|
||||
chart.x(function (d) {
|
||||
return d.label;
|
||||
});
|
||||
chart.staggerLabels(true);
|
||||
chart.maxBoxWidth(75); // prevent boxes from being incredibly wide
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new Error("Unrecognized visualization for nvd3" + viz_type);
|
||||
default:
|
||||
throw new Error("Unrecognized visualization for nvd3" + viz_type);
|
||||
}
|
||||
}
|
||||
|
||||
if ("showLegend" in chart && typeof fd.show_legend !== 'undefined') {
|
||||
@@ -197,8 +201,12 @@ function nvd3Vis(slice) {
|
||||
return px.color.category21(d[colorKey]);
|
||||
});
|
||||
|
||||
d3.select(slice.selector).html('');
|
||||
d3.select(slice.selector).append("svg")
|
||||
var svg = d3.select(slice.selector).select("svg");
|
||||
if (svg.empty()) {
|
||||
svg = d3.select(slice.selector).append("svg");
|
||||
}
|
||||
|
||||
svg
|
||||
.datum(payload.data)
|
||||
.transition().duration(500)
|
||||
.attr('height', height)
|
||||
|
||||
@@ -35,7 +35,7 @@ function tableVis(slice) {
|
||||
maxes[metrics[i]] = d3.max(col(metrics[i]));
|
||||
}
|
||||
|
||||
var table = d3.select(slice.selector).append('table')
|
||||
var table = d3.select(slice.selector).html('').append('table')
|
||||
.classed('dataframe dataframe table table-striped table-bordered table-condensed table-hover dataTable no-footer', true)
|
||||
.attr('width', '100%');
|
||||
|
||||
|
||||
@@ -37,6 +37,31 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal fade" id="refresh_modal" tabindex="-1" role="dialog">
|
||||
<div class="modal-dialog" role="document">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button>
|
||||
<h4 class="modal-title" id="myModalLabel">Refresh Interval</h4>
|
||||
<h6><strong>Choose how frequent should the dashboard refresh</strong></h6>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<select id="refresh_dash_interval" class="select2" style="margin-bottom: 5px;">
|
||||
<option value="0">Don't refresh</option>
|
||||
<option value="10">10 seconds</option>
|
||||
<option value="30">30 seconds</option>
|
||||
<option value="60">1 minute</option>
|
||||
<option value="300">5 minutes</option>
|
||||
</select><br>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-default" data-dismiss="modal">
|
||||
Close
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="title">
|
||||
<div class="row">
|
||||
@@ -52,6 +77,9 @@
|
||||
<button type="button" id="refresh_dash" class="btn btn-default" data-toggle="tooltip" title="Force refresh the whole dashboard">
|
||||
<i class="fa fa-refresh"></i>
|
||||
</button>
|
||||
<button type="button" id="refresh_dash_periodic" class="btn btn-default" data-toggle="modal" data-target="#refresh_modal">
|
||||
<i class="fa fa-clock-o" data-toggle="tooltip" title="Edit the dashboard's CSS"></i>
|
||||
</button>
|
||||
<button type="button" id="filters" class="btn btn-default" data-toggle="tooltip" title="View the list of active filters">
|
||||
<i class="fa fa-filter"></i>
|
||||
</button>
|
||||
|
||||
Reference in New Issue
Block a user