Fix: Uptime history timestamp and service ID

This commit is contained in:
Tola Leng
2025-06-19 15:23:48 +07:00
parent cca2338468
commit 549a3793a5
3 changed files with 63 additions and 65 deletions
@@ -14,100 +14,102 @@ interface UseUptimeDataProps {
export const useUptimeData = ({ serviceId, serviceType, status, interval }: UseUptimeDataProps) => {
const [historyItems, setHistoryItems] = useState<UptimeData[]>([]);
// Fetch real uptime history data if serviceId is provided with improved caching and error handling
// Fetch real uptime history data if serviceId is provided
const { data: uptimeData, isLoading, error, isFetching, refetch } = useQuery({
queryKey: ['uptimeHistory', serviceId, serviceType],
queryFn: () => serviceId ? uptimeService.getUptimeHistory(serviceId, 50, undefined, undefined, serviceType) : Promise.resolve([]),
queryFn: () => {
if (!serviceId) {
console.log('No serviceId provided, skipping fetch');
return Promise.resolve([]);
}
console.log(`Fetching uptime data for service ${serviceId} of type ${serviceType}`);
return uptimeService.getUptimeHistory(serviceId, 50, undefined, undefined, serviceType);
},
enabled: !!serviceId,
refetchInterval: 30000, // Refresh every 30 seconds
staleTime: 15000, // Consider data fresh for 15 seconds
placeholderData: (previousData) => previousData, // Show previous data while refetching
retry: 3, // Retry failed requests three times
retryDelay: (attemptIndex) => Math.min(1000 * 2 ** attemptIndex, 10000), // Exponential backoff with max 10s
refetchInterval: 30000,
staleTime: 15000,
placeholderData: (previousData) => previousData,
retry: 3,
retryDelay: (attemptIndex) => Math.min(1000 * 2 ** attemptIndex, 10000),
});
// Filter uptime data to respect the service interval
const filterUptimeDataByInterval = (data: UptimeData[], intervalSeconds: number): UptimeData[] => {
// Filter and process uptime data
const processUptimeData = (data: UptimeData[], intervalSeconds: number): UptimeData[] => {
if (!data || data.length === 0) return [];
console.log(`Processing ${data.length} uptime records for service ${serviceId}`);
// Sort data by timestamp (newest first)
const sortedData = [...data].sort((a, b) =>
new Date(b.timestamp).getTime() - new Date(a.timestamp).getTime()
);
const filtered: UptimeData[] = [];
let lastIncludedTime: number | null = null;
const intervalMs = intervalSeconds * 1000; // Convert to milliseconds
// Take the most recent 20 records to ensure we have enough data
const recentData = sortedData.slice(0, 20);
// Include the most recent record first
if (sortedData.length > 0) {
filtered.push(sortedData[0]);
lastIncludedTime = new Date(sortedData[0].timestamp).getTime();
}
console.log(`Using ${recentData.length} most recent records`);
// Filter subsequent records to maintain proper interval spacing
for (let i = 1; i < sortedData.length && filtered.length < 20; i++) {
const currentTime = new Date(sortedData[i].timestamp).getTime();
// Only include if enough time has passed since the last included record
if (lastIncludedTime && (lastIncludedTime - currentTime) >= intervalMs) {
filtered.push(sortedData[i]);
lastIncludedTime = currentTime;
}
}
return filtered;
return recentData;
};
// Update history items when data changes
useEffect(() => {
if (uptimeData && uptimeData.length > 0) {
// Filter data based on the service interval
const filteredData = filterUptimeDataByInterval(uptimeData, interval);
setHistoryItems(filteredData);
} else if (status === "paused" || (uptimeData && uptimeData.length === 0)) {
// For paused services with no history, or empty history data, show all as paused
console.log(`Received ${uptimeData.length} uptime records for service ${serviceId}`);
const processedData = processUptimeData(uptimeData, interval);
setHistoryItems(processedData);
} else if (!serviceId || (uptimeData && uptimeData.length === 0)) {
// Generate placeholder data when no real data is available
console.log(`No uptime data available for service ${serviceId}, generating placeholder`);
const statusValue = (status === "up" || status === "down" || status === "warning" || status === "paused")
? status
: "paused"; // Default to paused if not a valid status
: "paused";
const placeholderHistory: UptimeData[] = Array(20).fill(null).map((_, index) => ({
id: `placeholder-${index}`,
id: `placeholder-${serviceId}-${index}`,
serviceId: serviceId || "",
timestamp: new Date(Date.now() - (index * interval * 1000)).toISOString(),
status: statusValue as "up" | "down" | "warning" | "paused",
responseTime: 0
}));
setHistoryItems(placeholderHistory);
}
}, [uptimeData, serviceId, status, interval]);
// Ensure we always have 20 items by padding with the last known status
// Ensure we always have exactly 20 items for consistent display
const getDisplayItems = (): UptimeData[] => {
const displayItems = [...historyItems];
if (displayItems.length < 20) {
const lastItem = displayItems.length > 0 ? displayItems[displayItems.length - 1] : null;
const items = [...historyItems];
// If we have fewer than 20 items, pad with older placeholder data
if (items.length < 20) {
const lastItem = items.length > 0 ? items[items.length - 1] : null;
const lastStatus = lastItem ? lastItem.status :
(status === "up" || status === "down" || status === "warning" || status === "paused") ?
status as "up" | "down" | "warning" | "paused" : "paused";
// Generate padding items with proper time spacing
const paddingItems: UptimeData[] = Array(20 - displayItems.length).fill(null).map((_, index) => {
const paddingCount = 20 - items.length;
const paddingItems: UptimeData[] = Array(paddingCount).fill(null).map((_, index) => {
const baseTime = lastItem ? new Date(lastItem.timestamp).getTime() : Date.now();
const timeOffset = (index + 1) * interval * 1000; // Respect the interval
const timeOffset = (index + 1) * interval * 1000;
return {
id: `padding-${index}`,
id: `padding-${serviceId}-${index}`,
serviceId: serviceId || "",
timestamp: new Date(baseTime - timeOffset).toISOString(),
status: lastStatus,
responseTime: 0
};
});
displayItems.push(...paddingItems);
items.push(...paddingItems);
}
return displayItems.slice(0, 20);
// Return exactly 20 items, sorted by timestamp (newest first)
return items.slice(0, 20).sort((a, b) =>
new Date(b.timestamp).getTime() - new Date(a.timestamp).getTime()
);
};
return {
@@ -13,7 +13,7 @@ export const UptimeSummary = ({ uptime, interval }: UptimeSummaryProps) => {
{Math.round(uptime)}% uptime
</span>
<span className="text-xs text-muted-foreground">
Last 20 checks ({interval}s interval)
Last 20 checks
</span>
</div>
);