"use client"; import React, { useEffect, useState } from "react"; import DatePicker from 'react-datepicker'; import 'react-datepicker/dist/react-datepicker.css'; import ApplicationChart from "../../components/ApplicationChart"; interface DataModel { id: number; ct_type: number; disk_size: number; core_count: number; ram_size: number; verbose: string; os_type: string; os_version: string; hn: string; disableip6: string; ssh: string; tags: string; nsapp: string; created_at: string; method: string; pve_version: string; status: string; } const DataFetcher: React.FC = () => { const [data, setData] = useState([]); const [loading, setLoading] = useState(true); const [error, setError] = useState(null); const [searchQuery, setSearchQuery] = useState(''); const [startDate, setStartDate] = useState(null); const [endDate, setEndDate] = useState(null); const [sortConfig, setSortConfig] = useState<{ key: keyof DataModel | null, direction: 'ascending' | 'descending' }>({ key: 'id', direction: 'descending' }); const [itemsPerPage, setItemsPerPage] = useState(25); const [currentPage, setCurrentPage] = useState(1); const [interval, setIntervalTime] = useState(10); // Default interval 10 seconds const [reloadInterval, setReloadInterval] = useState(null); useEffect(() => { const fetchData = async () => { try { const response = await fetch("https://api.htl-braunau.at/data/json"); if (!response.ok) throw new Error("Failed to fetch data: ${response.statusText}"); const result: DataModel[] = await response.json(); setData(result); } catch (err) { setError((err as Error).message); } finally { setLoading(false); } }; fetchData(); }, []); const filteredData = data.filter(item => { const matchesSearchQuery = Object.values(item).some(value => value.toString().toLowerCase().includes(searchQuery.toLowerCase()) ); const itemDate = new Date(item.created_at); const matchesDateRange = (!startDate || itemDate >= startDate) && (!endDate || itemDate <= endDate); return matchesSearchQuery && matchesDateRange; }); const sortedData = React.useMemo(() => { let sortableData = [...filteredData]; if (sortConfig.key !== null) { sortableData.sort((a, b) => { if (sortConfig.key !== null && a[sortConfig.key] < b[sortConfig.key]) { return sortConfig.direction === 'ascending' ? -1 : 1; } if (sortConfig.key !== null && a[sortConfig.key] > b[sortConfig.key]) { return sortConfig.direction === 'ascending' ? 1 : -1; } return 0; }); } return sortableData; }, [filteredData, sortConfig]); const requestSort = (key: keyof DataModel | null) => { let direction: 'ascending' | 'descending' = 'ascending'; if (sortConfig.key === key && sortConfig.direction === 'ascending') { direction = 'descending'; } else if (sortConfig.key === key && sortConfig.direction === 'descending') { direction = 'ascending'; } else { direction = 'descending'; } setSortConfig({ key, direction }); }; interface SortConfig { key: keyof DataModel | null; direction: 'ascending' | 'descending'; } const formatDate = (dateString: string): string => { const date = new Date(dateString); const year = date.getFullYear(); const month = date.getMonth() + 1; const day = date.getDate(); const hours = String(date.getHours()).padStart(2, '0'); const minutes = String(date.getMinutes()).padStart(2, '0'); const timezoneOffset = dateString.slice(-6); return `${day}.${month}.${year} ${hours}:${minutes} ${timezoneOffset} GMT`; }; const handleItemsPerPageChange = (event: React.ChangeEvent) => { setItemsPerPage(Number(event.target.value)); setCurrentPage(1); }; const paginatedData = sortedData.slice((currentPage - 1) * itemsPerPage, currentPage * itemsPerPage); useEffect(() => { const storedInterval = localStorage.getItem('reloadInterval'); if (storedInterval) { setIntervalTime(Number(storedInterval)); } }, []); useEffect(() => { if (interval <= 10) { const newInterval = setInterval(() => { window.location.reload(); }, 10000); return () => clearInterval(newInterval); } else { const newInterval = setInterval(() => { window.location.reload(); }, interval * 1000); } }, [interval]); useEffect(() => { if (interval > 0) { localStorage.setItem('reloadInterval', interval.toString()); } else { localStorage.removeItem('reloadInterval'); } }, [interval]); if (loading) return

Loading...

; if (error) return

Error: {error}

; var installingCounts: number = 0; var failedCounts: number = 0; var doneCounts: number = 0 var unknownCounts: number = 0; data.forEach((item) => { if (item.status === "installing") { installingCounts += 1; } else if (item.status === "failed") { failedCounts += 1; } else if (item.status === "done") { doneCounts += 1; } else { unknownCounts += 1; } }); return (

Created LXCs

setSearchQuery(e.target.value)} className="p-2 border" />
setStartDate(date)} selectsStart startDate={startDate} endDate={endDate} placeholderText="Start date" className="p-2 border" />
setEndDate(date)} selectsEnd startDate={startDate} endDate={endDate} placeholderText="End date" className="p-2 border" />
setIntervalTime(Number(e.target.value))} className="p-2 border" placeholder="Interval (seconds)" />

{filteredData.length} results found

Status Legend: 🔄 installing {installingCounts} | ✔️ completetd {doneCounts} | ❌ failed {failedCounts} | ❓ unknown {unknownCounts}

{paginatedData.map((item, index) => ( ))}
requestSort('status')}>Status requestSort('nsapp')}>Application requestSort('os_type')}>OS requestSort('os_version')}>OS Version requestSort('disk_size')}>Disk Size requestSort('core_count')}>Core Count requestSort('ram_size')}>RAM Size requestSort('hn')}>Hostname requestSort('ssh')}>SSH requestSort('verbose')}>Verb requestSort('tags')}>Tags requestSort('method')}>Method requestSort('pve_version')}>PVE Version requestSort('created_at')}>Created At
{item.status === "done" ? ( "✔️" ) : item.status === "failed" ? ( "❌" ) : item.status === "installing" ? ( "🔄" ) : ( item.status )} {item.nsapp} {item.os_type} {item.os_version} {item.disk_size} {item.core_count} {item.ram_size} {item.hn} {item.ssh} {item.verbose} {item.tags.replace(/;/g, ' ')} {item.method} {item.pve_version} {formatDate(item.created_at)}
Page {currentPage}
); }; export default DataFetcher;