class DashboardChart extends BaseChart {
constructor(el, options) {
super(el, { ...options, chartType: "line" });
this.init();
}
get data() {
return [this.options.processed, this.options.failed];
}
get datasets() {
return [
{
label: this.options.processedLabel,
data: this.data[0],
borderColor: this.colors.success,
backgroundColor: this.colors.success,
borderWidth: 2,
pointRadius: 2,
},
{
label: this.options.failedLabel,
data: this.data[1],
borderColor: this.colors.failure,
backgroundColor: this.colors.failure,
borderWidth: 2,
pointRadius: 2,
},
];
}
get chartOptions() {
return {
...super.chartOptions,
aspectRatio: 4,
scales: {
...super.chartOptions.scales,
x: {
...super.chartOptions.scales.x,
ticks: {
...super.chartOptions.scales.x.ticks,
callback: function (value, index, ticks) {
// Remove the year from the date string
return this.getLabelForValue(value).split("-").slice(1).join("-");
},
},
},
y: {
...super.chartOptions.scales.y,
beginAtZero: true,
},
},
};
}
}
class RealtimeChart extends DashboardChart {
constructor(el, options) {
super(el, options);
let d = parseInt(localStorage.sidekiqTimeInterval) || 5000;
if (d < 2000) { d = 2000; }
this.delay = d
this.startPolling();
document.addEventListener("interval:update", this.handleUpdate.bind(this));
}
async startPolling() {
// Fetch initial values so we can show diffs moving forward
this.stats = await this.fetchStats();
this._interval = setInterval(this.poll.bind(this), this.delay);
}
async poll() {
const stats = await this.fetchStats();
const processed = stats.sidekiq.processed - this.stats.sidekiq.processed;
const failed = stats.sidekiq.failed - this.stats.sidekiq.failed;
this.chart.data.labels.shift();
this.chart.data.datasets[0].data.shift();
this.chart.data.datasets[1].data.shift();
this.chart.data.labels.push(new Date().toUTCString().split(" ")[4]);
this.chart.data.datasets[0].data.push(processed);
this.chart.data.datasets[1].data.push(failed);
this.chart.update();
updateStatsSummary(this.stats.sidekiq);
updateRedisStats(this.stats.redis);
updateFooterUTCTime(this.stats.server_utc_time);
pulseBeacon();
this.stats = stats;
}
async fetchStats() {
const response = await fetch(this.options.updateUrl);
return await response.json();
}
handleUpdate(e) {
this.delay = parseInt(e.detail);
clearInterval(this._interval);
this.startPolling();
}
registerLegend(el) {
this.legend = el;
}
renderLegend(dp) {
this.legend.innerHTML = `
${dp[0].dataset.label}: ${dp[0].formattedValue}
${dp[1].dataset.label}: ${dp[1].formattedValue}
${dp[0].label}
`;
}
renderCursor(dp) {
if (this.cursorX != dp[0].label) {
this.cursorX = dp[0].label;
this.update()
}
}
get chartOptions() {
return {
...super.chartOptions,
scales: {
...super.chartOptions.scales,
x: {
...super.chartOptions.scales.x,
display: false,
},
},
plugins: {
...super.chartOptions.plugins,
tooltip: {
...super.chartOptions.plugins.tooltip,
enabled: false,
external: (context) => {
const dp = context.tooltip.dataPoints;
if (dp && dp.length == 2 && this.legend) {
this.renderLegend(dp);
this.renderCursor(dp);
}
},
},
annotation: {
annotations: {
...super.chartOptions.plugins.annotation.annotations,
cursor: this.cursorX && {
type: "line",
borderColor: "rgba(0, 0, 0, 0.3)",
xMin: this.cursorX,
xMax: this.cursorX,
borderWidth: 1,
},
},
},
},
};
}
}