165 lines
6.6 KiB
JavaScript
165 lines
6.6 KiB
JavaScript
document.addEventListener('DOMContentLoaded', function () {
|
|
const CHART_COLORS = {
|
|
red: 'rgba(234, 67, 53, 0.8)',
|
|
orange: 'rgba(249, 171, 0, 0.8)',
|
|
green: 'rgba(52, 168, 83, 0.8)',
|
|
blue: 'rgba(26, 115, 232, 0.8)',
|
|
};
|
|
const CHART_BORDERS = {
|
|
red: 'rgb(234, 67, 53)',
|
|
orange: 'rgb(249, 171, 0)',
|
|
green: 'rgb(52, 168, 83)',
|
|
blue: 'rgb(26, 115, 232)',
|
|
};
|
|
|
|
const chartContexts = {
|
|
perWarehouse: document.getElementById('alertsPerWarehouseChart')?.getContext('2d'),
|
|
overTime: document.getElementById('alertsOverTimeChart')?.getContext('2d'),
|
|
status: document.getElementById('alertStatusChart')?.getContext('2d')
|
|
};
|
|
|
|
const charts = {};
|
|
|
|
function createOrUpdateChart(ctx, type, data, options) {
|
|
const chartId = ctx.canvas.id;
|
|
if (charts[chartId]) {
|
|
charts[chartId].data = data;
|
|
charts[chartId].options = options;
|
|
charts[chartId].update();
|
|
} else {
|
|
charts[chartId] = new Chart(ctx, { type, data, options });
|
|
}
|
|
}
|
|
|
|
function renderAlertsTable(alerts) {
|
|
const tableBody = document.getElementById('alerts-table-body');
|
|
if (!tableBody) return;
|
|
tableBody.innerHTML = ''; // Clear existing rows
|
|
|
|
if (!alerts || alerts.length === 0) {
|
|
tableBody.innerHTML = '<tr><td colspan="10" class="text-center text-muted">No active alerts found.</td></tr>';
|
|
return;
|
|
}
|
|
|
|
alerts.forEach(alert => {
|
|
const statusBadge = getStatusBadge(alert.status);
|
|
const row = `
|
|
<tr>
|
|
<td><span class="fw-bold">${alert.alert_id}</span></td>
|
|
<td>${new Date(alert.timestamp).toLocaleString()}</td>
|
|
<td>${alert.warehouse_name}</td>
|
|
<td>${alert.slot_name}</td>
|
|
<td>${alert.node_name}</td>
|
|
<td>${alert.metric_name}</td>
|
|
<td><span class="fw-bold text-danger">${alert.actual_value}</span></td>
|
|
<td>${alert.threshold_value}</td>
|
|
<td><span class="badge ${statusBadge}">${alert.status}</span></td>
|
|
<td>
|
|
<button class="btn btn-sm btn-outline-secondary" title="Acknowledge"><i class="bi bi-check-circle"></i></button>
|
|
<button class="btn btn-sm btn-outline-secondary" title="Resolve"><i class="bi bi-patch-check"></i></button>
|
|
</td>
|
|
</tr>
|
|
`;
|
|
tableBody.insertAdjacentHTML('beforeend', row);
|
|
});
|
|
}
|
|
|
|
function getStatusBadge(status) {
|
|
switch (status) {
|
|
case 'active': return 'text-bg-danger';
|
|
case 'acknowledged': return 'text-bg-warning';
|
|
case 'resolved': return 'text-bg-success';
|
|
default: return 'text-bg-secondary';
|
|
}
|
|
}
|
|
|
|
function renderCharts(chartData) {
|
|
// Chart 1: Alerts per Warehouse (Bar)
|
|
if (chartContexts.perWarehouse && chartData.per_warehouse) {
|
|
const data = {
|
|
labels: chartData.per_warehouse.map(d => d.name),
|
|
datasets: [{
|
|
label: 'Alerts',
|
|
data: chartData.per_warehouse.map(d => d.alert_count),
|
|
backgroundColor: CHART_COLORS.blue,
|
|
borderColor: CHART_BORDERS.blue,
|
|
borderWidth: 1
|
|
}]
|
|
};
|
|
const options = {
|
|
responsive: true,
|
|
plugins: { legend: { display: false }, title: { display: true, text: 'Alerts per Warehouse' } },
|
|
scales: { y: { beginAtZero: true } }
|
|
};
|
|
createOrUpdateChart(chartContexts.perWarehouse, 'bar', data, options);
|
|
}
|
|
|
|
// Chart 2: Alerts over Time (Line)
|
|
if (chartContexts.overTime && chartData.over_time) {
|
|
const data = {
|
|
labels: chartData.over_time.map(d => d.alert_date),
|
|
datasets: [{
|
|
label: 'Alerts',
|
|
data: chartData.over_time.map(d => d.alert_count),
|
|
borderColor: CHART_COLORS.red,
|
|
backgroundColor: CHART_COLORS.red,
|
|
tension: 0.1,
|
|
fill: false
|
|
}]
|
|
};
|
|
const options = {
|
|
responsive: true,
|
|
plugins: { legend: { display: false }, title: { display: true, text: 'Alerts Over Last 7 Days' } },
|
|
scales: { y: { beginAtZero: true } }
|
|
};
|
|
createOrUpdateChart(chartContexts.overTime, 'line', data, options);
|
|
}
|
|
|
|
// Chart 3: Alert Status (Pie)
|
|
if (chartContexts.status && chartData.status_distribution) {
|
|
const data = {
|
|
labels: chartData.status_distribution.map(d => d.status),
|
|
datasets: [{
|
|
label: 'Alerts',
|
|
data: chartData.status_distribution.map(d => d.alert_count),
|
|
backgroundColor: [CHART_COLORS.red, CHART_COLORS.orange, CHART_COLORS.green],
|
|
borderColor: [CHART_BORDERS.red, CHART_BORDERS.orange, CHART_BORDERS.green],
|
|
borderWidth: 1
|
|
}]
|
|
};
|
|
const options = {
|
|
responsive: true,
|
|
plugins: {
|
|
legend: { position: 'top' },
|
|
title: { display: true, text: 'Alert Status Distribution' }
|
|
}
|
|
};
|
|
createOrUpdateChart(chartContexts.status, 'pie', data, options);
|
|
}
|
|
}
|
|
|
|
async function fetchData() {
|
|
const tableBody = document.getElementById('alerts-table-body');
|
|
try {
|
|
const response = await fetch('api/alerts-data.php');
|
|
if (!response.ok) {
|
|
throw new Error(`HTTP error! status: ${response.status}`);
|
|
}
|
|
const data = await response.json();
|
|
|
|
if (data.success) {
|
|
renderAlertsTable(data.alerts);
|
|
renderCharts(data.chart_data);
|
|
} else {
|
|
console.error('API Error:', data.error);
|
|
if(tableBody) tableBody.innerHTML = `<tr><td colspan="10" class="text-center text-danger">Failed to load data from API.</td></tr>`;
|
|
}
|
|
} catch (error) {
|
|
console.error('Fetch Error:', error);
|
|
if(tableBody) tableBody.innerHTML = `<tr><td colspan="10" class="text-center text-danger">Error fetching data. Check console for details.</td></tr>`;
|
|
}
|
|
}
|
|
|
|
fetchData();
|
|
// setInterval(fetchData, 30000); // Optional: Refresh every 30 seconds
|
|
}); |