feat(cloudron): add tirreno package artifacts
- Add CloudronStack/output/CloudronPackages-Artifacts/tirreno/ directory and its contents - Includes package manifest, Dockerfile, source code, documentation, and build artifacts - Add tirreno-1761840148.tar.gz as a build artifact - Add tirreno-cloudron-package-1761841304.tar.gz as the Cloudron package - Include all necessary files for the tirreno Cloudron package This adds the complete tirreno Cloudron package artifacts to the repository.
This commit is contained in:
@@ -0,0 +1,210 @@
|
||||
import {BaseChart} from './BaseChart.js?v=2';
|
||||
import {COLOR_MAP} from '../utils/Constants.js?v=2';
|
||||
import {formatIntTimeUtc} from '../utils/Date.js?v=2';
|
||||
import {renderChartTooltipPart} from '../DataRenderers.js?v=2';
|
||||
|
||||
export class BaseBarChart extends BaseChart {
|
||||
getSeries() {
|
||||
return [
|
||||
this.getDaySeries(),
|
||||
{
|
||||
width: -1,
|
||||
paths: uPlot.paths.bars({size: [0.6, 100]}),
|
||||
points: {show: false},
|
||||
},
|
||||
this.getSingleSeries('Regular events', 'green'),
|
||||
this.getSingleSeries('Warning events', 'yellow'),
|
||||
this.getSingleSeries('Alert events', 'red'),
|
||||
];
|
||||
}
|
||||
|
||||
getSingleSeries(label, color) {
|
||||
return {
|
||||
label: label,
|
||||
width: -1,
|
||||
drawStyle: 1,
|
||||
fill: COLOR_MAP[color].main,
|
||||
stroke: COLOR_MAP[color].main,
|
||||
paths: uPlot.paths.bars({size: [0.6, 100]}),
|
||||
points: {show: false},
|
||||
};
|
||||
}
|
||||
|
||||
// dataset adaption for bands instead of regular bars
|
||||
getData(data) {
|
||||
let stacked = [data[0]];
|
||||
let sums = new Array(data[0].length).fill(0);
|
||||
|
||||
stacked.push(new Array(data[0].length).fill(0));
|
||||
|
||||
let maxLvl = data.length - 1;
|
||||
|
||||
for (let i = 1; i < data.length; i++) {
|
||||
let series = [];
|
||||
for (let j = 0; j < data[0].length; j++) {
|
||||
sums[j] += +data[i][j];
|
||||
series.push(sums[j]);
|
||||
}
|
||||
stacked.push(series);
|
||||
}
|
||||
|
||||
maxLvl = data.length;
|
||||
|
||||
for (let i = 0; i < data[0].length; i++) {
|
||||
let topMet = false;
|
||||
for (let j = maxLvl; j > 1; j--) {
|
||||
if (stacked[j][i] <= stacked[j-1][i] && !topMet) {
|
||||
stacked[j][i] = null;
|
||||
} else {
|
||||
topMet = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.data = stacked;
|
||||
|
||||
return stacked;
|
||||
}
|
||||
|
||||
stack(data, omit) {
|
||||
let data2 = [];
|
||||
let bands = [];
|
||||
let d0Len = data ? data[0].length : 0;
|
||||
let accum = Array(d0Len);
|
||||
|
||||
let i;
|
||||
|
||||
for (i = 0; i < d0Len; i++) {
|
||||
accum[i] = 0;
|
||||
}
|
||||
|
||||
let el;
|
||||
|
||||
for (i = 1; i < data.length; i++) {
|
||||
el = data[i];
|
||||
|
||||
if (!omit(i)) {
|
||||
el = el.map((v, j) => {
|
||||
let val = accum[j] + +v;
|
||||
accum[j] = val;
|
||||
|
||||
return val;
|
||||
});
|
||||
}
|
||||
|
||||
data2.push(el);
|
||||
}
|
||||
|
||||
for (i = 1; i < data.length; i++) {
|
||||
!omit(i) && bands.push({
|
||||
series: [
|
||||
data.findIndex((s, j) => j > i && !omit(j)),
|
||||
i,
|
||||
],
|
||||
});
|
||||
}
|
||||
|
||||
bands = bands.filter(b => b.series[1] > -1);
|
||||
|
||||
return {
|
||||
data: [data[0]].concat(data2),
|
||||
bands,
|
||||
};
|
||||
}
|
||||
|
||||
getOptions(resolution = 'day', nullChar = '0') {
|
||||
const opts = super.getOptions(resolution, nullChar);
|
||||
|
||||
let stacked = this.stack(this.data, i => false);
|
||||
|
||||
opts.bands = stacked.bands;
|
||||
|
||||
opts.series.forEach((s, sIdx) => {
|
||||
if (s) {
|
||||
s.value = (u, v, si, i) => u.data[sIdx][i];
|
||||
|
||||
s.points = s.points || {};
|
||||
s.points.filter = (u, seriesIdx, show, gaps) => {
|
||||
if (show) {
|
||||
let pts = [];
|
||||
u.data[seriesIdx].forEach((v, i) => {
|
||||
v != null && pts.push(i);
|
||||
});
|
||||
return pts;
|
||||
}
|
||||
};
|
||||
}
|
||||
});
|
||||
|
||||
return opts;
|
||||
}
|
||||
|
||||
tooltipCursor(u, seriestt, opts, resolution, defaultVal) {
|
||||
const left = u.cursor.left;
|
||||
const idx = u.cursor.idx;
|
||||
const col = [];
|
||||
|
||||
if (opts && opts.cursorMemo) {
|
||||
opts.cursorMemo.set(left, top);
|
||||
}
|
||||
|
||||
seriestt.style.display = 'none';
|
||||
|
||||
if (left >= 0 && u.data) {
|
||||
let xVal = u.data[0][idx];
|
||||
|
||||
let maxLvl = u.data.length - 1;
|
||||
|
||||
for (let i = 0; i <= maxLvl; i++) {
|
||||
col.push(u.data[i][idx]);
|
||||
}
|
||||
|
||||
const vtp = (resolution === 'day') ? 'DAY' : ((resolution === 'hour') ? 'HOUR' : 'MINUTE');
|
||||
let ts = '';
|
||||
|
||||
if (Number.isInteger(xVal)) {
|
||||
const useTime = resolution === 'hour' || resolution === 'minute';
|
||||
ts = formatIntTimeUtc(xVal * 1000, useTime);
|
||||
}
|
||||
|
||||
let frag = document.createDocumentFragment();
|
||||
frag.appendChild(document.createTextNode(ts.replace(/\./g, '/')));
|
||||
|
||||
let prev = null;
|
||||
|
||||
let maxVal = 0;
|
||||
let maxIdx = 0;
|
||||
|
||||
for (let i = maxLvl; i >= 1; i--) {
|
||||
if (col[i] === null) {
|
||||
col[i] = 0;
|
||||
} else {
|
||||
if (maxVal < col[i]) {
|
||||
maxVal = col[i];
|
||||
maxIdx = i;
|
||||
}
|
||||
|
||||
if (prev !== null) {
|
||||
col[prev] -= col[i];
|
||||
}
|
||||
|
||||
prev = i;
|
||||
}
|
||||
}
|
||||
|
||||
for (let i = 2; i <= maxLvl; i++) {
|
||||
frag = this.extendTooltipFragment(i, null, col, defaultVal, u, frag);
|
||||
}
|
||||
|
||||
if (frag.children.length > 1) {
|
||||
seriestt.replaceChildren(frag);
|
||||
|
||||
seriestt.style.top = Math.round(u.valToPos(maxVal, u.series[maxIdx].scale)) + 'px';
|
||||
seriestt.style.left = Math.round(u.valToPos(xVal, vtp)) + 'px';
|
||||
seriestt.style.display = null;
|
||||
}
|
||||
}
|
||||
|
||||
return [seriestt, opts];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,380 @@
|
||||
import {Loader} from '../Loader.js?v=2';
|
||||
import {getQueryParams} from '../utils/DataSource.js?v=2';
|
||||
import {handleAjaxError} from '../utils/ErrorHandler.js?v=2';
|
||||
import {formatIntTimeUtc} from '../utils/Date.js?v=2';
|
||||
import {fireEvent} from '../utils/Event.js?v=2';
|
||||
import {renderChartTooltipPart} from '../DataRenderers.js?v=2';
|
||||
import {
|
||||
MAX_HOURS_CHART,
|
||||
MIN_HOURS_CHART,
|
||||
X_AXIS_SERIFS,
|
||||
} from '../utils/Constants.js?v=2';
|
||||
|
||||
export class BaseChart {
|
||||
constructor(chartParams) {
|
||||
this.config = chartParams;
|
||||
|
||||
this.cursLeft = -10;
|
||||
this.cursTop = -10;
|
||||
this.cursorMemo = {
|
||||
set: (left, top) => {
|
||||
this.cursLeft = left;
|
||||
this.cursTop = top;
|
||||
},
|
||||
get: () => ({
|
||||
left: this.cursLeft,
|
||||
top: this.cursTop,
|
||||
y: false,
|
||||
drag: {
|
||||
x: false,
|
||||
y: false
|
||||
}
|
||||
})
|
||||
};
|
||||
|
||||
this.timeLabelColor = '#d7e6e1';
|
||||
|
||||
this.loader = new Loader();
|
||||
|
||||
const loaderDiv = document.createElement('div');
|
||||
loaderDiv.id = 'loader';
|
||||
this.chartBlock.appendChild(loaderDiv);
|
||||
|
||||
this.chart = null;
|
||||
if (!this.config.sequential) {
|
||||
this.loadData();
|
||||
}
|
||||
|
||||
const onDateFilterChanged = this.onDateFilterChanged.bind(this);
|
||||
window.addEventListener('dateFilterChanged', onDateFilterChanged, false);
|
||||
}
|
||||
|
||||
onDateFilterChanged() {
|
||||
this.loadData();
|
||||
}
|
||||
|
||||
stopAnimation() {
|
||||
this.loaderBlock.classList.add('is-hidden');
|
||||
this.loader.stop();
|
||||
}
|
||||
|
||||
startLoader() {
|
||||
const el = document.createElement('p');
|
||||
el.className = 'text-loader';
|
||||
|
||||
this.loaderBlock.classList.remove('is-hidden');
|
||||
this.loaderBlock.replaceChildren(el);
|
||||
|
||||
const p = this.loaderBlock.querySelector('p');
|
||||
|
||||
this.loader.start(p);
|
||||
}
|
||||
|
||||
loadData() {
|
||||
if (!this.config.sequential) {
|
||||
this.startLoader();
|
||||
}
|
||||
|
||||
const token = document.head.querySelector('[name=\'csrf-token\'][content]').content;
|
||||
const params = this.config.getParams();
|
||||
const data = getQueryParams(params);
|
||||
|
||||
data['mode'] = params.mode;
|
||||
data['token'] = token;
|
||||
data['resolution'] = 'day';
|
||||
if (data['dateFrom']) {
|
||||
const diff = new Date(data['dateTo']) - new Date(data['dateFrom']);
|
||||
const hours = diff/(60 * 60 * 1000);
|
||||
if (hours <= MAX_HOURS_CHART && hours > MIN_HOURS_CHART) {
|
||||
data['resolution'] = 'hour';
|
||||
} else if (hours <= MIN_HOURS_CHART) {
|
||||
data['resolution'] = 'minute';
|
||||
}
|
||||
}
|
||||
|
||||
fireEvent('dateFilterChangedCaught');
|
||||
|
||||
$.ajax({
|
||||
url: '/admin/loadChart',
|
||||
type: 'get',
|
||||
data: data,
|
||||
success: (responseData, status) => this.onChartLoaded(responseData, status, data['resolution']),
|
||||
error: handleAjaxError,
|
||||
complete: function() {
|
||||
fireEvent('dateFilterChangedCompleted');
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
onChartLoaded(data, status, resolution) {
|
||||
if ('success' == status) {
|
||||
if (this.chart) {
|
||||
this.chart.destroy();
|
||||
}
|
||||
const prepData = this.getData(data);
|
||||
this.chart = new uPlot(this.getOptions(resolution), prepData, this.chartBlock);
|
||||
|
||||
this.stopAnimation();
|
||||
}
|
||||
}
|
||||
|
||||
seriesResolutionShift(series, resolution) {
|
||||
if (resolution === 'hour') {
|
||||
series[0].label = 'Hour';
|
||||
series[0].scale = 'HOUR';
|
||||
series[0].value = '{YYYY}-{MM}-{DD} {HH}:{mm}';
|
||||
} else if (resolution === 'minute') {
|
||||
series[0].label = 'Minute';
|
||||
series[0].scale = 'MINUTE';
|
||||
series[0].value = '{YYYY}-{MM}-{DD} {HH}:{mm}';
|
||||
}
|
||||
|
||||
return series;
|
||||
}
|
||||
|
||||
getDaySeries() {
|
||||
return {
|
||||
label: 'Day',
|
||||
scale: 'DAY',
|
||||
value: '{YYYY}-{MM}-{DD}'
|
||||
};
|
||||
}
|
||||
|
||||
getAxisConfig() {
|
||||
const xAxis = {
|
||||
scale: 'DAY',
|
||||
stroke: '#8180a0',
|
||||
grid: {
|
||||
width: 1 / devicePixelRatio,
|
||||
stroke: '#2b2a3d',
|
||||
},
|
||||
ticks: {
|
||||
width: 1 / devicePixelRatio,
|
||||
stroke: '#2b2a3d',
|
||||
},
|
||||
values: [
|
||||
//Copied from https://github.com/leeoniya/uPlot/tree/master/docs#axis--grid-opts
|
||||
// tick incr default year month day hour min sec mode
|
||||
[3600 * 24, '{DD}/{MM}', '\n{YYYY}', null, null, null, null, null, 1],
|
||||
],
|
||||
};
|
||||
const yAxis = {
|
||||
stroke: '#8180a0',
|
||||
values: (u, vals, space) => vals.map(v => this.formatKiloValue(u, v)),
|
||||
grid: {
|
||||
width: 1 / devicePixelRatio,
|
||||
stroke: '#2b2a3d',
|
||||
},
|
||||
ticks: {
|
||||
width: 1 / devicePixelRatio,
|
||||
stroke: '#2b2a3d',
|
||||
},
|
||||
};
|
||||
|
||||
return {
|
||||
x: xAxis,
|
||||
y: yAxis,
|
||||
};
|
||||
}
|
||||
|
||||
getData(data) {
|
||||
return data;
|
||||
}
|
||||
|
||||
getOptions(resolution = 'day', nullChar = '0') {
|
||||
const tooltipsPlugin = this.tooltipsPlugin({cursorMemo: this.cursorMemo}, resolution, nullChar);
|
||||
const axes = this.getAxisConfig();
|
||||
const series = this.seriesResolutionShift(this.getSeries(), resolution);
|
||||
const xAxis = this.xAxisResolutionShift(axes.x, resolution);
|
||||
const yAxis = axes.y;
|
||||
|
||||
const opts = {
|
||||
width: 995,
|
||||
height: 200,
|
||||
|
||||
tzDate: ts => uPlot.tzDate(new Date(ts * 1000), 'Etc/UTC'),
|
||||
series: series,
|
||||
|
||||
legend: {
|
||||
show: false
|
||||
},
|
||||
cursor: this.cursorMemo.get(),
|
||||
plugins: [tooltipsPlugin],
|
||||
scales: {
|
||||
x: {time: false},
|
||||
},
|
||||
axes: [
|
||||
xAxis,
|
||||
yAxis,
|
||||
]
|
||||
};
|
||||
|
||||
return opts;
|
||||
}
|
||||
|
||||
xAxisResolutionShift(xAxis, resolution) {
|
||||
if (resolution === 'hour') {
|
||||
xAxis.scale = 'HOUR';
|
||||
xAxis.values = [
|
||||
// tick incr default year month day hour min sec mode
|
||||
[3600, '{HH}:{mm}', '\n{DD}/{MM}/{YYYY}', null, '\n{DD}/{MM}', null, null, null, 1]
|
||||
];
|
||||
xAxis.space = function(self, axisIdx, scaleMin, scaleMax, plotDim) {
|
||||
let rangeHours = (scaleMax - scaleMin) / 3600;
|
||||
if (rangeHours > X_AXIS_SERIFS) rangeHours = X_AXIS_SERIFS;
|
||||
const pxPerHour = plotDim / rangeHours;
|
||||
|
||||
return pxPerHour;
|
||||
};
|
||||
} else if (resolution === 'minute') {
|
||||
xAxis.scale = 'MINUTE';
|
||||
xAxis.values = [
|
||||
// tick incr default year month day hour min sec mode
|
||||
[60, '{HH}:{mm}', '\n{DD}/{MM}/{YYYY}', null, '\n{DD}/{MM}', null, null, null, 1]
|
||||
];
|
||||
xAxis.space = function(self, axisIdx, scaleMin, scaleMax, plotDim) {
|
||||
let rangeMinutes = (scaleMax - scaleMin) / 60;
|
||||
if (rangeMinutes > X_AXIS_SERIFS) rangeMinutes = X_AXIS_SERIFS;
|
||||
const pxPerMinute = plotDim / rangeMinutes;
|
||||
|
||||
return pxPerMinute;
|
||||
};
|
||||
}
|
||||
|
||||
return xAxis;
|
||||
}
|
||||
|
||||
formatKiloValue(u, value) {
|
||||
if (value === 0) {
|
||||
return value;
|
||||
}
|
||||
if (value % 1000000 === 0) {
|
||||
return Math.round(value / 1000000) + 'M';
|
||||
}
|
||||
if (value % 1000 === 0) {
|
||||
return Math.round(value / 1000) + 'k';
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
get loaderBlock() {
|
||||
return document.getElementById('loader');
|
||||
}
|
||||
|
||||
get chartBlock() {
|
||||
return document.querySelector('.stat-chart:not(#session-stat)');
|
||||
}
|
||||
|
||||
tooltipsPlugin(opts, resolution = 'day', defaultVal = '0') {
|
||||
let self = this;
|
||||
let seriestt;
|
||||
|
||||
function init(u, options, data) {
|
||||
seriestt = self.tooltipInit(u, options, data);
|
||||
}
|
||||
|
||||
function setCursor(u) {
|
||||
[seriestt, opts] = self.tooltipCursor(u, seriestt, opts, resolution, defaultVal);
|
||||
}
|
||||
|
||||
return {
|
||||
hooks: {
|
||||
init,
|
||||
setCursor,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
tooltipCursor(u, seriestt, opts, resolution, defaultVal) {
|
||||
const left = u.cursor.left;
|
||||
const idx = u.cursor.idx;
|
||||
|
||||
if (opts && opts.cursorMemo) {
|
||||
opts.cursorMemo.set(left, top);
|
||||
}
|
||||
|
||||
seriestt.style.display = 'none';
|
||||
|
||||
if (left >= 0) {
|
||||
let xVal = u.data[0][idx];
|
||||
|
||||
const vtp = (resolution === 'day') ? 'DAY' : ((resolution === 'hour') ? 'HOUR' : 'MINUTE');
|
||||
let ts = '';
|
||||
|
||||
if (Number.isInteger(xVal)) {
|
||||
const useTime = resolution === 'hour' || resolution === 'minute';
|
||||
ts = formatIntTimeUtc(xVal * 1000, useTime);
|
||||
}
|
||||
|
||||
let frag = document.createDocumentFragment();
|
||||
frag.appendChild(renderChartTooltipPart(this.timeLabelColor, null, ts.replace(/\./g, '/')));
|
||||
|
||||
for (let i = 1; i <= 12; i++) {
|
||||
frag = this.extendTooltipFragment(i, idx, u.data, defaultVal, u, frag);
|
||||
}
|
||||
|
||||
if (frag.children.length > 1) {
|
||||
seriestt.replaceChildren(frag);
|
||||
|
||||
let val = null;
|
||||
let lvl = 1;
|
||||
|
||||
const lim = Math.min(u.data.length - 1, 12);
|
||||
|
||||
for (let i = 1; i <= lim; i++) {
|
||||
if (u.data[i][idx] > val) {
|
||||
val = u.data[i][idx];
|
||||
lvl = i;
|
||||
}
|
||||
}
|
||||
|
||||
val = (val !== null && val != undefined) ? val : defaultVal;
|
||||
|
||||
seriestt.style.top = Math.round(u.valToPos(val, u.series[lvl].scale)) + 'px';
|
||||
seriestt.style.left = Math.round(u.valToPos(xVal, vtp)) + 'px';
|
||||
seriestt.style.display = null;
|
||||
}
|
||||
}
|
||||
|
||||
return [seriestt, opts];
|
||||
}
|
||||
|
||||
tooltipInit(u, options, data) {
|
||||
let over = u.over;
|
||||
|
||||
let tt = document.createElement('div');
|
||||
tt.className = 'tooltipline';
|
||||
tt.textContent = '';
|
||||
tt.style.pointerEvents = 'none';
|
||||
tt.style.position = 'absolute';
|
||||
tt.style.background = 'rgba(0,0,0,1)';
|
||||
over.appendChild(tt);
|
||||
|
||||
over.addEventListener('mouseleave', () => {
|
||||
if (!u.cursor._lock) {
|
||||
tt.style.display = 'none';
|
||||
}
|
||||
});
|
||||
|
||||
over.addEventListener('mouseenter', () => {
|
||||
tt.style.display = u.data.length > 1 ? null : 'none';
|
||||
});
|
||||
|
||||
tt.style.display = (u.cursor.left < 0) ? 'none' : null;
|
||||
|
||||
return tt;
|
||||
}
|
||||
|
||||
extendTooltipFragment(lvl, idx, data, defaultVal, u, frag) {
|
||||
if (data.length > lvl) {
|
||||
let series = u.series[lvl];
|
||||
let val = (idx !== null) ? data[lvl][idx] : data[lvl];
|
||||
val = (val !== null && val != undefined) ? val : defaultVal;
|
||||
|
||||
frag.appendChild(document.createElement('br'));
|
||||
frag.appendChild(renderChartTooltipPart(series.stroke(), series.label, val));
|
||||
}
|
||||
|
||||
return frag;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
import {BaseChart} from './BaseChart.js?v=2';
|
||||
import {
|
||||
COLOR_MAP,
|
||||
X_AXIS_SERIFS,
|
||||
} from '../utils/Constants.js?v=2';
|
||||
|
||||
export class BaseLineChart extends BaseChart {
|
||||
getSeries() {
|
||||
return [
|
||||
this.getDaySeries(),
|
||||
this.getSingleSeries('Total events', 'green'),
|
||||
];
|
||||
}
|
||||
|
||||
getSingleSeries(label, color) {
|
||||
return {
|
||||
label: label,
|
||||
scale: 'EVENTS',
|
||||
value: (u, v) => Number(v.toFixed(0)).toLocaleString(),
|
||||
points: {
|
||||
space: 0,
|
||||
fill: COLOR_MAP[color].main,
|
||||
},
|
||||
stroke: COLOR_MAP[color].main,
|
||||
fill: COLOR_MAP[color].light,
|
||||
};
|
||||
}
|
||||
|
||||
getAxisConfig() {
|
||||
const axes = super.getAxisConfig();
|
||||
|
||||
axes.x.space = function(self, axisIdx, scaleMin, scaleMax, plotDim) {
|
||||
let rangeDays = (scaleMax - scaleMin) / 86400;
|
||||
if (rangeDays > X_AXIS_SERIFS) rangeDays = X_AXIS_SERIFS;
|
||||
const pxPerDay = plotDim / rangeDays;
|
||||
|
||||
return pxPerDay;
|
||||
};
|
||||
|
||||
axes.y.scale = 'EVENTS';
|
||||
axes.y.side = 3;
|
||||
axes.y.split = u => [
|
||||
u.series[1].min,
|
||||
u.series[1].max,
|
||||
];
|
||||
|
||||
return axes;
|
||||
}
|
||||
|
||||
getOptions(resolution = 'day') {
|
||||
return super.getOptions(resolution, '—');
|
||||
}
|
||||
|
||||
// invert lines order to keep originally first line on top layer
|
||||
seriesResolutionShift(series, resolution) {
|
||||
if (resolution === 'hour') {
|
||||
series[0].label = 'Hour';
|
||||
series[0].scale = 'HOUR';
|
||||
series[0].value = '{YYYY}-{MM}-{DD} {HH}:{mm}';
|
||||
} else if (resolution === 'minute') {
|
||||
series[0].label = 'Minute';
|
||||
series[0].scale = 'MINUTE';
|
||||
series[0].value = '{YYYY}-{MM}-{DD} {HH}:{mm}';
|
||||
}
|
||||
|
||||
const inverted = [series[0]].concat(series.slice(1).reverse());
|
||||
|
||||
return inverted;
|
||||
}
|
||||
|
||||
getData(data) {
|
||||
return [data[0]].concat(data.slice(1).reverse());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,137 @@
|
||||
import {Loader} from '../Loader.js?v=2';
|
||||
import {BaseChart} from './BaseChart.js?v=2';
|
||||
import {
|
||||
COLOR_LIGHT_GREEN,
|
||||
COLOR_GREEN,
|
||||
X_AXIS_SERIFS,
|
||||
} from '../utils/Constants.js?v=2';
|
||||
|
||||
export class BaseSparklineChart extends BaseChart {
|
||||
constructor(chartParams) {
|
||||
super(chartParams);
|
||||
|
||||
this.charts = null;
|
||||
|
||||
if (!this.loaders) {
|
||||
this.loaders = [];
|
||||
this.elems.forEach(el => {this.loaders[el] = new Loader();});
|
||||
}
|
||||
}
|
||||
|
||||
getOptions() {
|
||||
const tooltipsPlugin = this.tooltipsPlugin({cursorMemo: this.cursorMemo}, 'day', '0');
|
||||
return {
|
||||
width: 200,
|
||||
height: 30,
|
||||
pxAlign: false,
|
||||
cursor: {
|
||||
show: false
|
||||
},
|
||||
select: {
|
||||
show: false,
|
||||
},
|
||||
legend: {
|
||||
show: false,
|
||||
},
|
||||
scales: {
|
||||
x: {time: false},
|
||||
},
|
||||
axes: [
|
||||
{show: false},
|
||||
{show: false}
|
||||
],
|
||||
cursor: this.cursorMemo.get(),
|
||||
plugins: [tooltipsPlugin],
|
||||
series: [
|
||||
{
|
||||
label: 'Day',
|
||||
scale: 'DAY',
|
||||
value: '{YYYY}-{MM}-{DD}',
|
||||
stroke: '#8180a0',
|
||||
},
|
||||
{
|
||||
label: 'This week',
|
||||
stroke: COLOR_GREEN,
|
||||
fill: COLOR_LIGHT_GREEN,
|
||||
points: {show: false}
|
||||
},
|
||||
{
|
||||
label: 'Previous week',
|
||||
stroke: 'rgba(129,128,160,0.7)',
|
||||
fill: 'rgba(129,128,160,0.03)',
|
||||
points: {show: false}
|
||||
},
|
||||
],
|
||||
};
|
||||
}
|
||||
|
||||
onChartLoaded(data, status, resolution) {
|
||||
if ('success' == status) {
|
||||
data = this.getData(data);
|
||||
|
||||
this.stopLoader();
|
||||
|
||||
this.charts = [];
|
||||
|
||||
this.elems.forEach(el => {
|
||||
const lines = [data.time, data[el], data[el + 'Prev']];
|
||||
this.charts.push(new uPlot(this.getOptions(), lines, this.getChartBlock(el)));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
startLoader() {
|
||||
if (!this.loaders) {
|
||||
this.loaders = [];
|
||||
this.elems.forEach(el => this.loaders[el] = new Loader());
|
||||
}
|
||||
|
||||
this.elems.forEach(name => {
|
||||
const el = document.createElement('p');
|
||||
const block = this.getChartBlock(name);
|
||||
|
||||
block.classList.remove('is-hidden');
|
||||
block.replaceChildren(el);
|
||||
|
||||
const p = block.querySelector('p');
|
||||
|
||||
this.loaders[name].start(p);
|
||||
});
|
||||
}
|
||||
|
||||
stopLoader() {
|
||||
this.elems.forEach(el => {
|
||||
this.loaders[el].stop();
|
||||
this.getChartBlock(el).querySelector('p').classList.add('is-hidden');
|
||||
});
|
||||
}
|
||||
|
||||
getData(data) {
|
||||
return {
|
||||
'time': data[0],
|
||||
'totalDevices': data[1],
|
||||
'totalIps': data[2],
|
||||
'totalSessions': data[3],
|
||||
'totalEvents': data[4],
|
||||
'totalDevicesPrev': data[5],
|
||||
'totalIpsPrev': data[6],
|
||||
'totalSessionsPrev': data[7],
|
||||
'totalEventsPrev': data[8],
|
||||
};
|
||||
}
|
||||
|
||||
getChartBlock(cls) {
|
||||
return document.querySelector(`td.${cls} p.session-stat`);
|
||||
}
|
||||
|
||||
get chartBlocks() {
|
||||
const result = {};
|
||||
this.elems.forEach(el => {result[el] = this.getChartBlock(el);});
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
get elems() {
|
||||
return ['totalDevices', 'totalIps', 'totalSessions', 'totalEvents'];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
import {BaseLineChart} from './BaseLine.js?v=2';
|
||||
|
||||
export class BlacklistChart extends BaseLineChart {
|
||||
getSeries() {
|
||||
return [
|
||||
this.getDaySeries(),
|
||||
this.getSingleSeries('Blacklisted identities', 'red'),
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
import {BaseLineChart} from './BaseLine.js?v=2';
|
||||
|
||||
export class BotsChart extends BaseLineChart {
|
||||
getSeries() {
|
||||
return [
|
||||
this.getDaySeries(),
|
||||
this.getSingleSeries('Bots', 'red'),
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
import {BaseLineChart} from './BaseLine.js?v=2';
|
||||
|
||||
export class DomainsChart extends BaseLineChart {
|
||||
getSeries() {
|
||||
return [
|
||||
this.getDaySeries(),
|
||||
this.getSingleSeries('Total domains', 'green'),
|
||||
this.getSingleSeries('New domains', 'yellow'),
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
import {BaseLineChart} from './BaseLine.js?v=2';
|
||||
|
||||
export class EventsChart extends BaseLineChart {
|
||||
getSeries() {
|
||||
return [
|
||||
this.getDaySeries(),
|
||||
this.getSingleSeries('Regular events', 'green'),
|
||||
this.getSingleSeries('Warning events', 'yellow'),
|
||||
this.getSingleSeries('Alert events', 'red'),
|
||||
this.getSingleSeries('Unauthenticated events', 'purple'),
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
import {BaseLineChart} from './BaseLine.js?v=2';
|
||||
|
||||
export class IpsChart extends BaseLineChart {
|
||||
getSeries() {
|
||||
return [
|
||||
this.getDaySeries(),
|
||||
this.getSingleSeries('Residential', 'green'),
|
||||
this.getSingleSeries('Privacy', 'yellow'),
|
||||
this.getSingleSeries('Suspicious', 'red'),
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
import {BaseLineChart} from './BaseLine.js?v=2';
|
||||
|
||||
export class IspsChart extends BaseLineChart {
|
||||
getSeries() {
|
||||
return [
|
||||
this.getDaySeries(),
|
||||
this.getSingleSeries('Total ISPs', 'green'),
|
||||
this.getSingleSeries('New ISPs', 'yellow'),
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
import {BaseLineChart} from './BaseLine.js?v=2';
|
||||
|
||||
export class LogbookChart extends BaseLineChart {
|
||||
getSeries() {
|
||||
return [
|
||||
this.getDaySeries(),
|
||||
this.getSingleSeries('Success', 'green'),
|
||||
this.getSingleSeries('Validation issues', 'yellow'),
|
||||
this.getSingleSeries('Failed', 'red'),
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
import {BaseLineChart} from './BaseLine.js?v=2';
|
||||
|
||||
export class ResourcesChart extends BaseLineChart {
|
||||
getSeries() {
|
||||
return [
|
||||
this.getDaySeries(),
|
||||
this.getSingleSeries('200', 'green'),
|
||||
this.getSingleSeries('404', 'yellow'),
|
||||
this.getSingleSeries('403 & 500', 'red'),
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
import {BaseLineChart} from './BaseLine.js?v=2';
|
||||
|
||||
export class ReviewQueueChart extends BaseLineChart {
|
||||
getSeries() {
|
||||
return [
|
||||
this.getDaySeries(),
|
||||
this.getSingleSeries('Whitelisted', 'green'),
|
||||
this.getSingleSeries('In review', 'yellow'),
|
||||
this.getSingleSeries('Blacklisted', 'red'),
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
import {BaseLineChart} from './BaseLine.js?v=2';
|
||||
|
||||
export class UsersChart extends BaseLineChart {
|
||||
getSeries() {
|
||||
return [
|
||||
this.getDaySeries(),
|
||||
this.getSingleSeries('High trust', 'green'),
|
||||
this.getSingleSeries('Average trust', 'yellow'),
|
||||
this.getSingleSeries('In review', 'red'),
|
||||
];
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user