Fix: Server Historical Performance chart improvement

Fix: Improve sidebar collapse/expand performance
This commit is contained in:
Tola Leng
2025-07-19 15:23:28 +07:00
parent d40d5898c0
commit dc586dc15f
19 changed files with 1534 additions and 643 deletions
+116 -155
View File
@@ -7,7 +7,7 @@ export const serverService = {
const records = await pb.collection('servers').getFullList<Server>();
return records;
} catch (error) {
// console.error('Error fetching servers:', error);
console.error('Error fetching servers:', error);
throw error;
}
},
@@ -17,190 +17,151 @@ export const serverService = {
const record = await pb.collection('servers').getOne<Server>(serverId);
return record;
} catch (error) {
// console.error('Error fetching server:', error);
console.error('Error fetching server:', error);
throw error;
}
},
async getServerMetrics(serverId: string, timeRange?: string): Promise<any[]> {
try {
// console.log('serverService.getServerMetrics: Fetching metrics for serverId:', serverId, 'timeRange:', timeRange);
console.log('🔍 serverService.getServerMetrics: Starting with serverId:', serverId, 'timeRange:', timeRange);
// First, get the server to find the correct server_id for metrics
let server;
try {
server = await this.getServer(serverId);
// console.log('serverService.getServerMetrics: Found server:', server);
console.log('✅ serverService.getServerMetrics: Found server:', {
id: server.id,
server_id: server.server_id,
name: server.name
});
} catch (error) {
// console.log('serverService.getServerMetrics: Could not fetch server details:', error);
console.log('❌ serverService.getServerMetrics: Could not fetch server details:', error);
}
// Try multiple filter strategies to find data
let filter = '';
let metricsServerId = serverId;
// Strategy 1: Use server.server_id if available
if (server && server.server_id) {
metricsServerId = server.server_id;
filter = `server_id = "${metricsServerId}"`;
// console.log('serverService.getServerMetrics: Strategy 1 - Using server.server_id for metrics:', metricsServerId);
} else {
// Strategy 2: Use the serverId directly
filter = `server_id = "${serverId}"`;
// console.log('serverService.getServerMetrics: Strategy 2 - Using serverId directly for metrics:', serverId);
}
// Add agent_id filter if available in server data
if (server && server.agent_id) {
filter += ` && agent_id = "${server.agent_id}"`;
// console.log('serverService.getServerMetrics: Added agent_id filter:', server.agent_id);
}
// Add time range filter
if (timeRange) {
const now = new Date();
let cutoffTime;
switch (timeRange) {
case '60m':
cutoffTime = new Date(now.getTime() - (60 * 60 * 1000));
break;
case '1d':
cutoffTime = new Date(now.getTime() - (24 * 60 * 60 * 1000));
break;
case '7d':
cutoffTime = new Date(now.getTime() - (7 * 24 * 60 * 60 * 1000));
break;
case '1m':
cutoffTime = new Date(now.getTime() - (30 * 24 * 60 * 60 * 1000));
break;
case '3m':
cutoffTime = new Date(now.getTime() - (90 * 24 * 60 * 60 * 1000));
break;
default:
cutoffTime = new Date(now.getTime() - (24 * 60 * 60 * 1000));
}
const cutoffISO = cutoffTime.toISOString();
filter += ` && created >= "${cutoffISO}"`;
// console.log('serverService.getServerMetrics: Using time filter from:', cutoffISO, 'to now');
}
// console.log('serverService.getServerMetrics: Final filter:', filter);
// Fetch filtered records with proper sorting
let records = await pb.collection('server_metrics').getFullList({
filter: filter,
// Let's first check what data exists in the database for this server
console.log('🔍 Checking all records for this server...');
const allServerRecords = await pb.collection('server_metrics').getFullList({
filter: `server_id = "${serverId}" || server_id = "${server?.server_id}" || server_id = "${server?.id}"`,
sort: '-created',
requestKey: null
});
// console.log('serverService.getServerMetrics: Found', records.length, 'records with primary filter');
// If no records found with primary strategy, try fallback strategies
if (records.length === 0) {
// console.log('serverService.getServerMetrics: No records found, trying fallback strategies...');
// Fallback 1: Try without agent_id filter
let fallbackFilter = `server_id = "${metricsServerId}"`;
if (timeRange) {
const now = new Date();
let cutoffTime;
switch (timeRange) {
case '60m':
cutoffTime = new Date(now.getTime() - (60 * 60 * 1000));
break;
case '1d':
cutoffTime = new Date(now.getTime() - (24 * 60 * 60 * 1000));
break;
case '7d':
cutoffTime = new Date(now.getTime() - (7 * 24 * 60 * 60 * 1000));
break;
case '1m':
cutoffTime = new Date(now.getTime() - (30 * 24 * 60 * 60 * 1000));
break;
case '3m':
cutoffTime = new Date(now.getTime() - (90 * 24 * 60 * 60 * 1000));
break;
default:
cutoffTime = new Date(now.getTime() - (24 * 60 * 60 * 1000));
}
const cutoffISO = cutoffTime.toISOString();
fallbackFilter += ` && created >= "${cutoffISO}"`;
}
// console.log('serverService.getServerMetrics: Trying fallback filter without agent_id:', fallbackFilter);
records = await pb.collection('server_metrics').getFullList({
filter: fallbackFilter,
sort: '-created',
requestKey: null
console.log('📊 Found total records for server:', allServerRecords.length);
if (allServerRecords.length > 0) {
console.log('📅 Date range of all records:', {
newest: allServerRecords[0]?.created,
oldest: allServerRecords[allServerRecords.length - 1]?.created
});
// console.log('serverService.getServerMetrics: Fallback found', records.length, 'records');
// Fallback 2: Try with different server_id strategies
if (records.length === 0) {
const alternativeIds = [serverId, server?.server_id, server?.id].filter(Boolean);
// console.log('serverService.getServerMetrics: Trying alternative server IDs:', alternativeIds);
// Check last 5 records
console.log('🔄 Last 5 records timestamps:', allServerRecords.slice(0, 5).map(r => ({
created: r.created,
age_minutes: Math.round((new Date().getTime() - new Date(r.created).getTime()) / (1000 * 60))
})));
}
// Calculate time range for filtering
const now = new Date();
let cutoffTime;
if (timeRange === '60m') {
cutoffTime = new Date(now.getTime() - (60 * 60 * 1000)); // Exactly 60 minutes
console.log('⏰ 60m filter: Looking for records newer than:', cutoffTime.toISOString());
console.log('⏰ Current time:', now.toISOString());
console.log('⏰ Time difference in minutes:', Math.round((now.getTime() - cutoffTime.getTime()) / (1000 * 60)));
} else if (timeRange === '1d') {
cutoffTime = new Date(now.getTime() - (24 * 60 * 60 * 1000));
} else if (timeRange === '7d') {
cutoffTime = new Date(now.getTime() - (7 * 24 * 60 * 60 * 1000));
} else if (timeRange === '1m') {
cutoffTime = new Date(now.getTime() - (30 * 24 * 60 * 60 * 1000));
} else if (timeRange === '3m') {
cutoffTime = new Date(now.getTime() - (90 * 24 * 60 * 60 * 1000));
} else {
cutoffTime = new Date(now.getTime() - (24 * 60 * 60 * 1000));
}
// Try to get filtered records
const searchStrategies = [
server?.server_id,
serverId,
server?.id
].filter(Boolean);
let filteredRecords: any[] = [];
for (const strategy of searchStrategies) {
try {
const cutoffISO = cutoffTime.toISOString();
const filter = `server_id = "${strategy}" && created >= "${cutoffISO}"`;
for (const altId of alternativeIds) {
if (altId && altId !== metricsServerId) {
let altFilter = `server_id = "${altId}"`;
if (timeRange) {
const now = new Date();
let cutoffTime;
switch (timeRange) {
case '60m':
cutoffTime = new Date(now.getTime() - (60 * 60 * 1000));
break;
case '1d':
cutoffTime = new Date(now.getTime() - (24 * 60 * 60 * 1000));
break;
case '7d':
cutoffTime = new Date(now.getTime() - (7 * 24 * 60 * 60 * 1000));
break;
case '1m':
cutoffTime = new Date(now.getTime() - (30 * 24 * 60 * 60 * 1000));
break;
case '3m':
cutoffTime = new Date(now.getTime() - (90 * 24 * 60 * 60 * 1000));
break;
default:
cutoffTime = new Date(now.getTime() - (24 * 60 * 60 * 1000));
}
const cutoffISO = cutoffTime.toISOString();
altFilter += ` && created >= "${cutoffISO}"`;
}
console.log(`🔍 Trying filter: ${filter}`);
const records = await pb.collection('server_metrics').getFullList({
filter: filter,
sort: '-created',
requestKey: null
});
console.log(`📊 Strategy "${strategy}" found ${records.length} records within time range`);
if (records.length > 0) {
filteredRecords = records;
console.log('✅ Using records from strategy:', strategy);
break;
}
} catch (error) {
console.error(`❌ Error with strategy ${strategy}:`, error);
continue;
}
}
// If no filtered records found and it's 60m, let's see what we have in a larger window
if (filteredRecords.length === 0 && timeRange === '60m') {
console.log('⚠️ No records found in 60m window, checking last 24 hours...');
const last24h = new Date(now.getTime() - (24 * 60 * 60 * 1000));
for (const strategy of searchStrategies) {
try {
const filter = `server_id = "${strategy}" && created >= "${last24h.toISOString()}"`;
const records = await pb.collection('server_metrics').getFullList({
filter: filter,
sort: '-created',
requestKey: null
});
console.log(`📊 Last 24h check for "${strategy}": ${records.length} records`);
if (records.length > 0) {
console.log('📅 Sample record ages (minutes ago):', records.slice(0, 3).map(r =>
Math.round((now.getTime() - new Date(r.created).getTime()) / (1000 * 60))
));
// console.log('serverService.getServerMetrics: Trying alternative ID filter:', altFilter);
const altRecords = await pb.collection('server_metrics').getFullList({
filter: altFilter,
sort: '-created',
requestKey: null
});
if (altRecords.length > 0) {
// console.log('serverService.getServerMetrics: Alternative ID found', altRecords.length, 'records');
records = altRecords;
break;
}
// Return all recent records for 60m if we have any
filteredRecords = records;
break;
}
} catch (error) {
console.error(`❌ Error with 24h fallback for ${strategy}:`, error);
continue;
}
}
}
// console.log('serverService.getServerMetrics: Final result:', records.length, 'records found');
if (records.length > 0) {
// console.log('serverService.getServerMetrics: Sample record:', records[0]);
console.log('🎯 Final result:', filteredRecords.length, 'records found for', timeRange);
if (filteredRecords.length > 0) {
console.log('📅 Returned records age range (minutes ago):', {
newest: Math.round((now.getTime() - new Date(filteredRecords[0].created).getTime()) / (1000 * 60)),
oldest: Math.round((now.getTime() - new Date(filteredRecords[filteredRecords.length - 1].created).getTime()) / (1000 * 60))
});
}
return records;
return filteredRecords;
} catch (error) {
// console.error('Error fetching server metrics:', error);
console.error('❌ Error fetching server metrics:', error);
throw error;
}
},
@@ -0,0 +1,85 @@
import { pb } from "@/lib/pocketbase";
export interface ServerThreshold {
id: string;
name: string;
cpu_threshold: number;
ram_threshold: number;
disk_threshold: number;
network_threshold: number;
created: string;
updated: string;
}
export interface CreateUpdateServerThresholdData {
name: string;
cpu_threshold: number;
ram_threshold: number;
disk_threshold: number;
network_threshold: number;
}
export const serverThresholdService = {
async getServerThresholds(): Promise<ServerThreshold[]> {
try {
console.log("Fetching server threshold templates");
const response = await pb.collection('server_threshold_templates').getList(1, 50, {
sort: '-created',
});
console.log("Server threshold templates response:", response);
return response.items as unknown as ServerThreshold[];
} catch (error) {
console.error("Error fetching server threshold templates:", error);
throw error;
}
},
async getServerThreshold(id: string): Promise<ServerThreshold> {
try {
console.log(`Fetching server threshold template with id: ${id}`);
const response = await pb.collection('server_threshold_templates').getOne(id);
console.log("Server threshold template response:", response);
return response as unknown as ServerThreshold;
} catch (error) {
console.error(`Error fetching server threshold template with id ${id}:`, error);
throw error;
}
},
async createServerThreshold(data: CreateUpdateServerThresholdData): Promise<ServerThreshold> {
try {
console.log("Creating new server threshold template with data:", data);
const response = await pb.collection('server_threshold_templates').create(data);
console.log("Create server threshold template response:", response);
return response as unknown as ServerThreshold;
} catch (error) {
console.error("Error creating server threshold template:", error);
throw error;
}
},
async updateServerThreshold(id: string, data: Partial<CreateUpdateServerThresholdData>): Promise<ServerThreshold> {
try {
console.log(`Updating server threshold template with id: ${id}`, data);
const response = await pb.collection('server_threshold_templates').update(id, data);
console.log("Update server threshold template response:", response);
return response as unknown as ServerThreshold;
} catch (error) {
console.error(`Error updating server threshold template with id ${id}:`, error);
throw error;
}
},
async deleteServerThreshold(id: string): Promise<boolean> {
try {
console.log(`Deleting server threshold template with id: ${id}`);
await pb.collection('server_threshold_templates').delete(id);
console.log("Server threshold template deleted successfully");
return true;
} catch (error) {
console.error(`Error deleting server threshold template with id ${id}:`, error);
throw error;
}
}
};
+21 -20
View File
@@ -1,4 +1,5 @@
import { pb } from "@/lib/pocketbase";
export interface NotificationTemplate {
@@ -37,62 +38,62 @@ export interface CreateUpdateTemplateData {
export const templateService = {
async getTemplates(): Promise<NotificationTemplate[]> {
try {
console.log("Fetching notification templates");
const response = await pb.collection('notification_templates').getList(1, 50, {
console.log("Fetching server notification templates");
const response = await pb.collection('server_notification_templates').getList(1, 50, {
sort: '-created',
});
console.log("Templates response:", response);
console.log("Server templates response:", response);
return response.items as unknown as NotificationTemplate[];
} catch (error) {
console.error("Error fetching templates:", error);
console.error("Error fetching server templates:", error);
throw error;
}
},
async getTemplate(id: string): Promise<NotificationTemplate> {
try {
console.log(`Fetching template with id: ${id}`);
const response = await pb.collection('notification_templates').getOne(id);
console.log("Template response:", response);
console.log(`Fetching server template with id: ${id}`);
const response = await pb.collection('server_notification_templates').getOne(id);
console.log("Server template response:", response);
return response as unknown as NotificationTemplate;
} catch (error) {
console.error(`Error fetching template with id ${id}:`, error);
console.error(`Error fetching server template with id ${id}:`, error);
throw error;
}
},
async createTemplate(data: CreateUpdateTemplateData): Promise<NotificationTemplate> {
try {
console.log("Creating new template with data:", data);
const response = await pb.collection('notification_templates').create(data);
console.log("Create template response:", response);
console.log("Creating new server template with data:", data);
const response = await pb.collection('server_notification_templates').create(data);
console.log("Create server template response:", response);
return response as unknown as NotificationTemplate;
} catch (error) {
console.error("Error creating template:", error);
console.error("Error creating server template:", error);
throw error;
}
},
async updateTemplate(id: string, data: Partial<CreateUpdateTemplateData>): Promise<NotificationTemplate> {
try {
console.log(`Updating template with id: ${id}`, data);
const response = await pb.collection('notification_templates').update(id, data);
console.log("Update template response:", response);
console.log(`Updating server template with id: ${id}`, data);
const response = await pb.collection('server_notification_templates').update(id, data);
console.log("Update server template response:", response);
return response as unknown as NotificationTemplate;
} catch (error) {
console.error(`Error updating template with id ${id}:`, error);
console.error(`Error updating server template with id ${id}:`, error);
throw error;
}
},
async deleteTemplate(id: string): Promise<boolean> {
try {
console.log(`Deleting template with id: ${id}`);
await pb.collection('notification_templates').delete(id);
console.log("Template deleted successfully");
console.log(`Deleting server template with id: ${id}`);
await pb.collection('server_notification_templates').delete(id);
console.log("Server template deleted successfully");
return true;
} catch (error) {
console.error(`Error deleting template with id ${id}:`, error);
console.error(`Error deleting server template with id ${id}:`, error);
throw error;
}
}