diff --git a/application/src/components/services/ServiceRow.tsx b/application/src/components/services/ServiceRow.tsx
index 313f79e..fd9324c 100644
--- a/application/src/components/services/ServiceRow.tsx
+++ b/application/src/components/services/ServiceRow.tsx
@@ -56,7 +56,12 @@ export const ServiceRow = ({
-
+
{
+export const UptimeBar = ({ uptime, status, serviceId, interval = 60 }: UptimeBarProps) => {
const { theme } = useTheme();
const [historyItems, setHistoryItems] = useState([]);
// Fetch real uptime history data if serviceId is provided with improved caching and error handling
const { data: uptimeData, isLoading, error, isFetching, refetch } = useQuery({
queryKey: ['uptimeHistory', serviceId],
- queryFn: () => serviceId ? uptimeService.getUptimeHistory(serviceId, 20) : Promise.resolve([]),
+ queryFn: () => serviceId ? uptimeService.getUptimeHistory(serviceId, 50) : Promise.resolve([]),
enabled: !!serviceId,
refetchInterval: 30000, // Refresh every 30 seconds
staleTime: 15000, // Consider data fresh for 15 seconds
@@ -36,10 +36,45 @@ export const UptimeBar = ({ uptime, status, serviceId }: UptimeBarProps) => {
retryDelay: (attemptIndex) => Math.min(1000 * 2 ** attemptIndex, 10000), // Exponential backoff with max 10s
});
+ // Filter uptime data to respect the service interval
+ const filterUptimeDataByInterval = (data: UptimeData[], intervalSeconds: number): UptimeData[] => {
+ if (!data || data.length === 0) return [];
+
+ // 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
+
+ // Include the most recent record first
+ if (sortedData.length > 0) {
+ filtered.push(sortedData[0]);
+ lastIncludedTime = new Date(sortedData[0].timestamp).getTime();
+ }
+
+ // 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;
+ };
+
// Update history items when data changes
useEffect(() => {
if (uptimeData && uptimeData.length > 0) {
- setHistoryItems(uptimeData);
+ // 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
const statusValue = (status === "up" || status === "down" || status === "warning" || status === "paused")
@@ -49,13 +84,13 @@ export const UptimeBar = ({ uptime, status, serviceId }: UptimeBarProps) => {
const placeholderHistory: UptimeData[] = Array(20).fill(null).map((_, index) => ({
id: `placeholder-${index}`,
serviceId: serviceId || "",
- timestamp: new Date().toISOString(),
+ timestamp: new Date(Date.now() - (index * interval * 1000)).toISOString(),
status: statusValue as "up" | "down" | "warning" | "paused",
responseTime: 0
}));
setHistoryItems(placeholderHistory);
}
- }, [uptimeData, serviceId, status]);
+ }, [uptimeData, serviceId, status, interval]);
// Get appropriate color classes for each status type
const getStatusColor = (itemStatus: string) => {
@@ -153,13 +188,19 @@ export const UptimeBar = ({ uptime, status, serviceId }: UptimeBarProps) => {
(status === "up" || status === "down" || status === "warning" || status === "paused") ?
status as "up" | "down" | "warning" | "paused" : "paused";
- const paddingItems: UptimeData[] = Array(20 - displayItems.length).fill(null).map((_, index) => ({
- id: `padding-${index}`,
- serviceId: serviceId || "",
- timestamp: new Date().toISOString(),
- status: lastStatus,
- responseTime: 0
- }));
+ // Generate padding items with proper time spacing
+ const paddingItems: UptimeData[] = Array(20 - displayItems.length).fill(null).map((_, index) => {
+ const baseTime = lastItem ? new Date(lastItem.timestamp).getTime() : Date.now();
+ const timeOffset = (index + 1) * interval * 1000; // Respect the interval
+
+ return {
+ id: `padding-${index}`,
+ serviceId: serviceId || "",
+ timestamp: new Date(baseTime - timeOffset).toISOString(),
+ status: lastStatus,
+ responseTime: 0
+ };
+ });
displayItems.push(...paddingItems);
}
@@ -201,10 +242,10 @@ export const UptimeBar = ({ uptime, status, serviceId }: UptimeBarProps) => {
{Math.round(uptime)}% uptime
- Last 20 checks
+ Last 20 checks
);
-}
+}
\ No newline at end of file