Commit f830489b authored by Dmytro Bogatov's avatar Dmytro Bogatov 💕

Rerender data tables on plot zoom.

parent 0aa0d49c
......@@ -13,6 +13,7 @@ import "bootstrap"
declare var source: string;
declare var type: number;
declare var min: number;
declare var max: number;
......
......@@ -55,4 +55,10 @@ export class Constants {
* of 5 minutes and sums of user actions will be displayed per interval.
*/
static USER_ACTIONS_AGGREGATION_INTERVAL : number = 30;
/**
* The interval in milliseconds that defines a default time frame of data
* on metric pages.
*/
static METRIC_PAGE_DATA_PREVIEW : number = 2 * 60 * 60 * 1000;
}
......@@ -10,8 +10,12 @@ import "../../vendor/jquery.flot.time.js";
import "../../vendor/jquery.flot.selection.js";
import "../../vendor/jquery.flot.threshold.js";
import "../../vendor/jquery.flot.tooltip.js";
import { Constants } from "../constants";
declare var start: number;
declare var end: number;
/**
* Represents set of procedures for rendering metric page.
*
......@@ -23,6 +27,7 @@ export abstract class MetricPage<T extends Metric<DataPoint>> {
protected metric: T;
protected dataTablesRendered: boolean = false;
protected dataTable : DataTables.DataTable;
/**
* Minimal theoretical value for data series.
......@@ -50,10 +55,21 @@ export abstract class MetricPage<T extends Metric<DataPoint>> {
protected minData: number;
protected maxData: number;
protected start: Date = null;
protected end: Date = null;
constructor(min: number, max: number) {
this.max = max;
this.min = min;
if (start > 0) {
this.start = new Date(start);
}
if (end > 0) {
this.end = new Date(end);
}
window.setTimeout(async () => {
await this.metric.loadData(60 * 60 * 24 * 3); // 3 days
......@@ -84,7 +100,7 @@ export abstract class MetricPage<T extends Metric<DataPoint>> {
* @memberOf MetricPage
*/
private renderPlot(): void {
var plot: any = $.plot(
$("#metric-detailed-plot"),
this.formattedData,
......@@ -113,17 +129,46 @@ export abstract class MetricPage<T extends Metric<DataPoint>> {
// don't fire event on the overview to prevent eternal loop
overview.setSelection(ranges, true);
this.renderTable(true, new Date(ranges.xaxis.from), new Date(ranges.xaxis.to));
}));
$("#metric-overview-plot").bind("plotselected", <any>((event, ranges) => {
plot.setSelection(ranges);
}));
// if latest data point is more than 2 hours ago
// select recent 2 hours in plot
if (new Date().getTime() - this.minData > 2 * 60 * 60 * 1000) {
let from = new Date().getTime() - 2 * 60 * 60 * 1000;
plot.setSelection({ xaxis: { from: from, to: this.maxData }, yaxis: { from: 0, to: 0 } });
if (this.start != null) {
let from = Math.min(
Math.max(
this.start.getTime(),
this.minData
),
this.maxData)
;
let to =
this.end == null ?
Math.min(
this.maxData,
this.start.getTime() + Constants.METRIC_PAGE_DATA_PREVIEW
) :
Math.max(
Math.min(
this.end.getTime(),
this.maxData
),
this.minData)
;
plot.setSelection({ xaxis: { from: from, to: to }, yaxis: { from: 0, to: 0 } });
} else {
// if latest data point is more than 2 hours ago
// select recent 2 hours in plot
if (new Date().getTime() - this.minData > Constants.METRIC_PAGE_DATA_PREVIEW) {
let from = new Date().getTime() - Constants.METRIC_PAGE_DATA_PREVIEW;
plot.setSelection({ xaxis: { from: from, to: this.maxData }, yaxis: { from: 0, to: 0 } });
}
}
}
......@@ -135,7 +180,19 @@ export abstract class MetricPage<T extends Metric<DataPoint>> {
*
* @memberOf MetricPage
*/
protected abstract renderTable(): void;
/**
* Renders data tables in the UI.
* Does not load the data.
*
* @protected
* @abstract
* @param {boolean} redraw if data table has to be force-redrawn; implies non-null values of start and end;
* @param {Date} start start date for filter
* @param {Date} end end date for filter
* @memberof MetricPage
*/
protected abstract renderTable(redraw: boolean, start: Date, end: Date): void;
/**
* Renders numeric values in the UI.
......@@ -160,10 +217,10 @@ export abstract class MetricPage<T extends Metric<DataPoint>> {
*/
public render(): void {
this.configurePlot()
this.configurePlot()
this.renderPlot();
this.renderValues();
this.renderTable();
this.renderTable(false, null, null);
}
}
......@@ -106,9 +106,13 @@ export class CpuLoadMetricPage extends MetricPage<Metric<CpuLoadDataPoint>> {
};
};
protected renderTable(): void {
protected renderTable(redraw: boolean, start: Date, end: Date): void {
if (!this.dataTablesRendered) {
if (!this.dataTablesRendered || redraw) {
if (this.dataTablesRendered) {
this.dataTable.destroy();
}
let header = `
<tr>
......@@ -124,6 +128,17 @@ export class CpuLoadMetricPage extends MetricPage<Metric<CpuLoadDataPoint>> {
this.metric
.data
.map(dp => <CpuLoadDataPoint>dp)
.filter((value, index, array) => {
if (start != null && value.timestamp < start) {
return false;
}
if (end != null && value.timestamp > end) {
return false;
}
return true;
})
.map(
dp => `
<tr>
......@@ -135,7 +150,7 @@ export class CpuLoadMetricPage extends MetricPage<Metric<CpuLoadDataPoint>> {
.join()
);
$('#metric-data').DataTable({
this.dataTable = $('#metric-data').DataTable({
"order": [[0, "desc"]],
lengthChange: false,
searching: false,
......
......@@ -111,9 +111,13 @@ export class HealthMetricPage extends MetricPage<Metric<HealthDataPoint>> {
};
};
protected renderTable(): void {
protected renderTable(redraw: boolean, start: Date, end: Date): void {
if (!this.dataTablesRendered) {
if (!this.dataTablesRendered || redraw) {
if (this.dataTablesRendered) {
this.dataTable.destroy();
}
let header = `
<tr>
......@@ -130,6 +134,17 @@ export class HealthMetricPage extends MetricPage<Metric<HealthDataPoint>> {
this.metric
.data
.map(dp => <HealthDataPoint>dp)
.filter((value, index, array) => {
if (start != null && value.timestamp < start) {
return false;
}
if (end != null && value.timestamp > end) {
return false;
}
return true;
})
.map(
dp => `
<tr>
......@@ -160,7 +175,7 @@ export class HealthMetricPage extends MetricPage<Metric<HealthDataPoint>> {
.join()
);
$('#metric-data').DataTable({
this.dataTable = $('#metric-data').DataTable({
"order": [[0, "desc"]],
lengthChange: false,
searching: false,
......@@ -173,8 +188,8 @@ export class HealthMetricPage extends MetricPage<Metric<HealthDataPoint>> {
'showDetails',
(e: CustomEvent) => {
let data : any[] = e.detail.data;
let timestamp : Date = e.detail.timestamp;
let data: any[] = e.detail.data;
let timestamp: Date = e.detail.timestamp;
let code = `
<div
......@@ -211,17 +226,17 @@ export class HealthMetricPage extends MetricPage<Metric<HealthDataPoint>> {
</thead>
<tbody>
${
data
.sortByProperty(el => el.Source)
.map(el => `
data
.sortByProperty(el => el.Source)
.map(el => `
<tr>
<th>${el.Type}</th>
<th>${el.Source}</th>
<th>${el.Label}</th>
</tr>
`)
.join("")
}
.join("")
}
</tbody>
</table>
</div>
......
......@@ -149,9 +149,13 @@ export class PingMetricPage extends MetricPage<Metric<PingDataPoint>> {
};
};
protected renderTable(): void {
protected renderTable(redraw: boolean, start: Date, end: Date): void {
if (!this.dataTablesRendered) {
if (!this.dataTablesRendered || redraw) {
if (this.dataTablesRendered) {
this.dataTable.destroy();
}
let header = `
<tr>
......@@ -168,6 +172,17 @@ export class PingMetricPage extends MetricPage<Metric<PingDataPoint>> {
this.metric
.data
.map(dp => <PingDataPoint>dp)
.filter((value, index, array) => {
if (start != null && value.timestamp < start) {
return false;
}
if (end != null && value.timestamp > end) {
return false;
}
return true;
})
.map(
dp => `
<tr>
......@@ -180,7 +195,7 @@ export class PingMetricPage extends MetricPage<Metric<PingDataPoint>> {
.join()
);
$('#metric-data').DataTable({
this.dataTable = $('#metric-data').DataTable({
"order": [[0, "desc"]],
lengthChange: false,
searching: false,
......
......@@ -154,9 +154,13 @@ export class UserActionMetricPage extends MetricPage<Metric<UserActionDataPoint>
};
};
protected renderTable(): void {
protected renderTable(redraw: boolean, start: Date, end: Date): void {
if (!this.dataTablesRendered) {
if (!this.dataTablesRendered || redraw) {
if (this.dataTablesRendered) {
this.dataTable.destroy();
}
let header = `
<tr>
......@@ -173,6 +177,17 @@ export class UserActionMetricPage extends MetricPage<Metric<UserActionDataPoint>
this.metric
.data
.map(dp => <UserActionDataPoint>dp)
.filter((value, index, array) => {
if (start != null && value.timestamp < start) {
return false;
}
if (end != null && value.timestamp > end) {
return false;
}
return true;
})
.map(
dp => `
<tr>
......@@ -185,7 +200,7 @@ export class UserActionMetricPage extends MetricPage<Metric<UserActionDataPoint>
.join()
);
$('#metric-data').DataTable({
this.dataTable = $('#metric-data').DataTable({
"order": [[0, "desc"]],
lengthChange: false,
searching: false,
......
......@@ -65,8 +65,8 @@ namespace StatusMonitor.Web.Controllers.View
return View(model);
}
[Route("Home/Metric/{type}/{source}")]
public async Task<IActionResult> Metric(string type, string source)
[Route("Home/Metric/{type}/{source}/{start?}/{end?}")]
public async Task<IActionResult> Metric(string type, string source, string start = null, string end = null)
{
Metrics metricType;
......@@ -79,6 +79,41 @@ namespace StatusMonitor.Web.Controllers.View
return BadRequest("Bad type. Needs to be one of Metrics type.");
}
if (start != null)
{
try
{
DateTime.SpecifyKind(new DateTime(1970, 1, 1), DateTimeKind.Utc).AddMilliseconds(Convert.ToInt64(start));
}
catch (System.Exception)
{
return BadRequest("Bad start date. Needs to be the number of milliseconds since Epoch.");
}
}
if (end != null)
{
try
{
DateTime.SpecifyKind(new DateTime(1970, 1, 1), DateTimeKind.Utc).AddMilliseconds(Convert.ToInt64(end));
}
catch (System.Exception)
{
return BadRequest("Bad end date. Needs to be the number of milliseconds since Epoch.");
}
}
if (start != null && end != null)
{
if (
DateTime.SpecifyKind(new DateTime(1970, 1, 1), DateTimeKind.Utc).AddMilliseconds(Convert.ToInt64(start)) >=
DateTime.SpecifyKind(new DateTime(1970, 1, 1), DateTimeKind.Utc).AddMilliseconds(Convert.ToInt64(end))
)
{
return BadRequest("Bad dates. End date needs to be greater than the start date.");
}
}
var model = await _metricService.GetMetricsAsync(metricType, source);
if (model.Count() == 0)
......@@ -107,6 +142,9 @@ namespace StatusMonitor.Web.Controllers.View
ViewBag.Uptime = await _uptime.ComputeUptimeAsync(source);
}
ViewBag.Start = start ?? 0.ToString();
ViewBag.End = end ?? 0.ToString();
return View(model.First());
}
......
......@@ -186,8 +186,12 @@
<script>
var source = "@Model.Source";
var type = @Model.Type;
var min = @ViewData["Min"];
var max = @ViewData["Max"];
var start = @ViewData["Start"];
var end = @ViewData["End"];
</script>
<environment names="Development">
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment