mirror of
https://github.com/9technologygroup/patchmon.net.git
synced 2025-11-13 02:17:05 +00:00
Added Package trends over time graph XD
This commit is contained in:
@@ -130,15 +130,20 @@ async function createDefaultDashboardPreferences(userId, userRole = "user") {
|
||||
requiredPermission: "can_view_packages",
|
||||
order: 13,
|
||||
},
|
||||
{
|
||||
cardId: "packageTrends",
|
||||
requiredPermission: "can_view_packages",
|
||||
order: 14,
|
||||
},
|
||||
{
|
||||
cardId: "recentUsers",
|
||||
requiredPermission: "can_view_users",
|
||||
order: 14,
|
||||
order: 15,
|
||||
},
|
||||
{
|
||||
cardId: "quickStats",
|
||||
requiredPermission: "can_view_dashboard",
|
||||
order: 15,
|
||||
order: 16,
|
||||
},
|
||||
];
|
||||
|
||||
@@ -341,19 +346,26 @@ router.get("/defaults", authenticateToken, async (_req, res) => {
|
||||
enabled: true,
|
||||
order: 13,
|
||||
},
|
||||
{
|
||||
cardId: "packageTrends",
|
||||
title: "Package Trends",
|
||||
icon: "TrendingUp",
|
||||
enabled: true,
|
||||
order: 14,
|
||||
},
|
||||
{
|
||||
cardId: "recentUsers",
|
||||
title: "Recent Users Logged in",
|
||||
icon: "Users",
|
||||
enabled: true,
|
||||
order: 14,
|
||||
order: 15,
|
||||
},
|
||||
{
|
||||
cardId: "quickStats",
|
||||
title: "Quick Stats",
|
||||
icon: "TrendingUp",
|
||||
enabled: true,
|
||||
order: 15,
|
||||
order: 16,
|
||||
},
|
||||
];
|
||||
|
||||
|
||||
@@ -475,4 +475,132 @@ router.get(
|
||||
},
|
||||
);
|
||||
|
||||
// Get package trends over time
|
||||
router.get(
|
||||
"/package-trends",
|
||||
authenticateToken,
|
||||
requireViewHosts,
|
||||
async (req, res) => {
|
||||
try {
|
||||
const { days = 30, hostId } = req.query;
|
||||
const daysInt = parseInt(days);
|
||||
|
||||
// Calculate date range
|
||||
const endDate = new Date();
|
||||
const startDate = new Date();
|
||||
startDate.setDate(endDate.getDate() - daysInt);
|
||||
|
||||
// Build where clause
|
||||
const whereClause = {
|
||||
timestamp: {
|
||||
gte: startDate,
|
||||
lte: endDate,
|
||||
},
|
||||
};
|
||||
|
||||
// Add host filter if specified
|
||||
if (hostId && hostId !== "all" && hostId !== "undefined") {
|
||||
whereClause.host_id = hostId;
|
||||
}
|
||||
|
||||
// Get all update history records in the date range
|
||||
const trendsData = await prisma.update_history.findMany({
|
||||
where: whereClause,
|
||||
select: {
|
||||
timestamp: true,
|
||||
packages_count: true,
|
||||
security_count: true,
|
||||
total_packages: true,
|
||||
},
|
||||
orderBy: {
|
||||
timestamp: "asc",
|
||||
},
|
||||
});
|
||||
|
||||
// Process data to show actual values (no averaging)
|
||||
const processedData = trendsData
|
||||
.filter((record) => record.total_packages !== null) // Only include records with valid data
|
||||
.map((record) => {
|
||||
const date = new Date(record.timestamp);
|
||||
let timeKey;
|
||||
|
||||
if (daysInt <= 1) {
|
||||
// For hourly view, use exact timestamp
|
||||
timeKey = date.toISOString().substring(0, 16); // YYYY-MM-DDTHH:MM
|
||||
} else {
|
||||
// For daily view, group by day
|
||||
timeKey = date.toISOString().split("T")[0]; // YYYY-MM-DD
|
||||
}
|
||||
|
||||
return {
|
||||
timeKey,
|
||||
total_packages: record.total_packages,
|
||||
packages_count: record.packages_count || 0,
|
||||
security_count: record.security_count || 0,
|
||||
};
|
||||
})
|
||||
.sort((a, b) => a.timeKey.localeCompare(b.timeKey)); // Sort by time
|
||||
|
||||
// Get hosts list for dropdown (always fetch for dropdown functionality)
|
||||
const hostsList = await prisma.hosts.findMany({
|
||||
select: {
|
||||
id: true,
|
||||
friendly_name: true,
|
||||
hostname: true,
|
||||
},
|
||||
orderBy: {
|
||||
friendly_name: "asc",
|
||||
},
|
||||
});
|
||||
|
||||
// Format data for chart
|
||||
const chartData = {
|
||||
labels: [],
|
||||
datasets: [
|
||||
{
|
||||
label: "Total Packages",
|
||||
data: [],
|
||||
borderColor: "#3B82F6", // Blue
|
||||
backgroundColor: "rgba(59, 130, 246, 0.1)",
|
||||
tension: 0.4,
|
||||
hidden: true, // Hidden by default
|
||||
},
|
||||
{
|
||||
label: "Outdated Packages",
|
||||
data: [],
|
||||
borderColor: "#F59E0B", // Orange
|
||||
backgroundColor: "rgba(245, 158, 11, 0.1)",
|
||||
tension: 0.4,
|
||||
},
|
||||
{
|
||||
label: "Security Packages",
|
||||
data: [],
|
||||
borderColor: "#EF4444", // Red
|
||||
backgroundColor: "rgba(239, 68, 68, 0.1)",
|
||||
tension: 0.4,
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
// Process aggregated data
|
||||
processedData.forEach((item) => {
|
||||
chartData.labels.push(item.timeKey);
|
||||
chartData.datasets[0].data.push(item.total_packages);
|
||||
chartData.datasets[1].data.push(item.packages_count);
|
||||
chartData.datasets[2].data.push(item.security_count);
|
||||
});
|
||||
|
||||
res.json({
|
||||
chartData,
|
||||
hosts: hostsList,
|
||||
period: daysInt,
|
||||
hostId: hostId || "all",
|
||||
});
|
||||
} catch (error) {
|
||||
console.error("Error fetching package trends:", error);
|
||||
res.status(500).json({ error: "Failed to fetch package trends" });
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
module.exports = router;
|
||||
|
||||
@@ -674,11 +674,16 @@ async function getPermissionBasedPreferences(userRole) {
|
||||
requiredPermission: "can_view_packages",
|
||||
order: 13,
|
||||
},
|
||||
{ cardId: "recentUsers", requiredPermission: "can_view_users", order: 14 },
|
||||
{
|
||||
cardId: "packageTrends",
|
||||
requiredPermission: "can_view_packages",
|
||||
order: 14,
|
||||
},
|
||||
{ cardId: "recentUsers", requiredPermission: "can_view_users", order: 15 },
|
||||
{
|
||||
cardId: "quickStats",
|
||||
requiredPermission: "can_view_dashboard",
|
||||
order: 15,
|
||||
order: 16,
|
||||
},
|
||||
];
|
||||
|
||||
|
||||
Reference in New Issue
Block a user