Styling Fixes

This commit is contained in:
ferreo 2024-07-29 16:08:29 +01:00
parent 4774f15f3f
commit cb46826770
2 changed files with 171 additions and 169 deletions

View File

@ -1,6 +1,11 @@
import React, { useState, useEffect } from 'react'; import React, { useState, useEffect } from 'react';
import { Card, CardContent, CardHeader, CardTitle } from '../ui/card'; import { Card, CardContent, CardHeader, CardTitle } from '../ui/card';
interface CountResponse {
lastUpdateTime: string;
counts: PackageStats;
}
interface PackageStats { interface PackageStats {
stale: number; stale: number;
missing: number; missing: number;
@ -18,16 +23,21 @@ const Home: React.FC = () => {
const fetchStats = async () => { const fetchStats = async () => {
try { try {
const response = await fetch('/api/counts'); const response = await fetch('/api/counts');
const data: PackageStats = await response.json(); const data: CountResponse = await response.json();
setStats(data); const counts = data.counts;
setLastUpdated(new Date().toLocaleString('en-GB', { setStats(counts);
const dt = new Date(data.lastUpdateTime);
const dateLocale = dt.toLocaleDateString(navigator.language, {
day: '2-digit', day: '2-digit',
month: '2-digit', month: '2-digit',
year: 'numeric', year: 'numeric',
});
const timeLocale = dt.toLocaleTimeString(navigator.language, {
hour: '2-digit', hour: '2-digit',
minute: '2-digit', minute: '2-digit'
second: '2-digit' });
}));
setLastUpdated(`${timeLocale} on ${dateLocale}`);
} catch (error) { } catch (error) {
console.error('Failed to fetch stats:', error); console.error('Failed to fetch stats:', error);
} }

View File

@ -38,17 +38,8 @@ interface Package {
}; };
} }
interface CountsData {
stale: number;
missing: number;
built: number;
error: number;
queued: number;
building: number;
}
const Packages: React.FC = () => { const Packages: React.FC = () => {
const { getParam } = useSearchParams(); const { getParam, setParam } = useSearchParams();
const [packages, setPackages] = useState<Package[]>([]); const [packages, setPackages] = useState<Package[]>([]);
const [totalCount, setTotalCount] = useState(0); const [totalCount, setTotalCount] = useState(0);
const [currentPage, setCurrentPage] = useState( const [currentPage, setCurrentPage] = useState(
@ -65,21 +56,12 @@ const Packages: React.FC = () => {
}, [isMobile]); }, [isMobile]);
useEffect(() => { useEffect(() => {
fetchTotalCount();
fetchPackages(); fetchPackages();
setParam("page", currentPage.toString());
setParam("search", search);
setParam("filter", filter);
}, [currentPage, search, filter, pageSize]); }, [currentPage, search, filter, pageSize]);
const fetchTotalCount = async () => {
try {
const response = await fetch("/api/counts");
const data: CountsData = await response.json();
const total = Object.values(data).reduce((acc, curr) => acc + curr, 0);
setTotalCount(total);
} catch (error) {
console.error("Error fetching total count:", error);
setTotalCount(0); // Set to 0 if there's an error
}
};
const fetchPackages = async () => { const fetchPackages = async () => {
setLoading(true); setLoading(true);
@ -89,8 +71,10 @@ const Packages: React.FC = () => {
`/api/packages?page=${currentPage}&pageSize=${pageSize}&search=${search}&filter=${filterParam}` `/api/packages?page=${currentPage}&pageSize=${pageSize}&search=${search}&filter=${filterParam}`
); );
const data = await response.json(); const data = await response.json();
setPackages(Object.values(data)); setTotalCount(data.total);
setPackages(Object.values(data.packages));
} catch (error) { } catch (error) {
setTotalCount(0);
console.error("Error fetching packages:", error); console.error("Error fetching packages:", error);
} finally { } finally {
setLoading(false); setLoading(false);
@ -98,13 +82,24 @@ const Packages: React.FC = () => {
}; };
const handleFilterChange = (value: string) => { const handleFilterChange = (value: string) => {
setFilter(value === "All" ? "" : value); const newFilter = value === "All" ? "" : value;
setFilter(newFilter);
setCurrentPage(1); setCurrentPage(1);
setParam("filter", newFilter);
setParam("page", "1");
}; };
const handleSearchChange = (e: React.ChangeEvent<HTMLInputElement>) => { const handleSearchChange = (e: React.ChangeEvent<HTMLInputElement>) => {
setSearch(e.target.value); const newSearch = e.target.value;
setSearch(newSearch);
setCurrentPage(1); setCurrentPage(1);
setParam("search", newSearch);
setParam("page", "1");
};
const handlePageChange = (page: number) => {
setCurrentPage(page);
setParam("page", page.toString());
}; };
const totalPages = Math.ceil(totalCount / pageSize); const totalPages = Math.ceil(totalCount / pageSize);
@ -145,154 +140,151 @@ const Packages: React.FC = () => {
</div> </div>
</div> </div>
{/* Table */} {/* Table */}
<div className="flex-grow overflow-hidden"> <div className="flex-grow overflow-hidden">
<div className="container mx-0 px-0 h-full"> <div className="container mx-0 px-0 h-full">
<div className="h-full"> <div className="h-full">
<Table className=""> <Table className="w-full">
<TableHeader className="top-0 bg-background z-10 hidden md:table-header-group"> <TableHeader className="top-0 bg-background z-10 hidden md:table-header-group">
<TableRow> <TableRow>
<TableHead className="w-1/2 text-left">Name</TableHead> <TableHead className="w-1/2 text-left">Name</TableHead>
<TableHead className="w-1/4 text-left">Version</TableHead> <TableHead className="w-1/4 text-left">Version</TableHead>
<TableHead className="w-1/4 text-left">Status</TableHead> <TableHead className="w-1/4 text-left">Status</TableHead>
</TableRow>
</TableHeader>
<TableBody>
{loading ? (
<TableRow>
<TableCell colSpan={3} className="text-center">
Loading...
</TableCell>
</TableRow>
) : (
packages.map((pkg) => {
const firstPackage = Object.values(pkg.Packages)[0];
return (
<TableRow
key={pkg.Name}
className="md:table-row border-b last:border-b-0"
>
<TableCell className="w-full md:w-1/2 py-2 md:py-4">
<div className="flex flex-col h-full md:h-auto">
<div className="flex justify-between items-start mb-2 md:mb-0">
<span className="font-medium truncate mr-2">{pkg.Name}</span>
<span className="text-sm md:hidden truncate">{firstPackage.Status}</span>
</div>
<div className="md:hidden text-sm text-muted-foreground text-center">
<span className="truncate">{firstPackage.Version}</span>
{firstPackage.NewVersion && (
<span className="truncate block"> {firstPackage.NewVersion}</span>
)}
</div>
</div>
</TableCell>
<TableCell className="hidden md:table-cell md:w-1/4 py-4 text-left">
<div className="flex flex-col">
<span className="truncate">{firstPackage.Version}</span>
{firstPackage.NewVersion && (
<span className="text-sm text-muted-foreground truncate">
{firstPackage.NewVersion}
</span>
)}
</div>
</TableCell>
<TableCell className="hidden md:table-cell md:w-1/4 py-2 md:py-4 text-left">
<span className="truncate">{firstPackage.Status}</span>
</TableCell>
</TableRow> </TableRow>
</TableHeader> );
<TableBody> })
{loading ? ( )}
<TableRow> </TableBody>
<TableCell colSpan={3} className="text-center"> </Table>
Loading... </div>
</TableCell> </div>
</TableRow> </div>
) : (
packages.map((pkg) => {
const firstPackage = Object.values(pkg.Packages)[0];
return (
<TableRow
key={pkg.Name}
className="flex justify-between flex-row md:table-row"
>
<TableCell className="w-full md:w-1/2 py-2 md:py-4">
<div className="flex flex-col justify-center">
<div className="font-medium truncate md:text-left flex flex-row justify-between">
<div className="flex w-1/2">{pkg.Name}</div>
<div className="md:hidden flex w/2">
{firstPackage.Status}
</div>
</div>
<div className="md:hidden text-sm text-muted-foreground truncate">
{firstPackage.Version}
{firstPackage.NewVersion && (
<> {firstPackage.NewVersion}</>
)}
</div>
</div>
</TableCell>
<TableCell className="hidden md:table-cell md:w-1/4 py-4 md:text-left">
<div className="flex flex-col">
<div className="text-foreground truncate">
{firstPackage.Version}
</div>
{firstPackage.NewVersion && (
<span className="text-sm text-muted-foreground truncate">
{firstPackage.NewVersion}
</span>
)}
</div>
</TableCell>
<TableCell className="hidden md:block md:w-1/4 py-2 md:py-4 text-right md:text-left">
{firstPackage.Status}
</TableCell>
</TableRow>
);
})
)}
</TableBody>
</Table>
</div>
</div>
</div>
{/* Sticky Footer with Pagination */} {/* Sticky Footer with Pagination */}
<div className="sticky bottom-0 w-full bg-background border-t border-border py-4"> <div className="sticky bottom-0 w-full bg-background border-t border-border py-4">
<div className="container mx-auto"> <div className="container mx-auto px-2">
<Pagination> <Pagination>
<PaginationContent> <PaginationContent className="flex flex-wrap justify-center items-center gap-1">
<PaginationItem> <PaginationItem>
<PaginationPrevious <PaginationPrevious
size="default" size="default"
onClick={() => onClick={() => handlePageChange(Math.max(currentPage - 1, 1))}
setCurrentPage((prev) => Math.max(prev - 1, 1)) />
} </PaginationItem>
/>
</PaginationItem>
{currentPage > 1 && ( {currentPage > 2 && (
<PaginationItem> <PaginationItem className="hidden sm:inline-block">
<PaginationLink <PaginationLink size="default" onClick={() => handlePageChange(1)}>
size="default" 1
onClick={() => setCurrentPage(1)} </PaginationLink>
> </PaginationItem>
1 )}
</PaginationLink>
</PaginationItem>
)}
{currentPage > 3 && <PaginationEllipsis />} {currentPage > 3 && (
<PaginationItem className="hidden sm:inline-flex items-center">
<PaginationEllipsis />
</PaginationItem>
)}
{currentPage > 2 && ( {currentPage > 1 && (
<PaginationItem> <PaginationItem>
<PaginationLink <PaginationLink
size="default" size="default"
onClick={() => setCurrentPage(currentPage - 1)} onClick={() => handlePageChange(currentPage - 1)}
> >
{currentPage - 1} {currentPage - 1}
</PaginationLink> </PaginationLink>
</PaginationItem> </PaginationItem>
)} )}
<PaginationItem> <PaginationItem>
<PaginationLink size="default" isActive> <PaginationLink size="default" isActive>
{currentPage} {currentPage}
</PaginationLink> </PaginationLink>
</PaginationItem> </PaginationItem>
{currentPage < totalPages - 1 && ( {currentPage < totalPages && (
<PaginationItem> <PaginationItem>
<PaginationLink <PaginationLink
size="default" size="default"
onClick={() => setCurrentPage(currentPage + 1)} onClick={() => handlePageChange(currentPage + 1)}
> >
{currentPage + 1} {currentPage + 1}
</PaginationLink> </PaginationLink>
</PaginationItem> </PaginationItem>
)} )}
{currentPage < totalPages - 2 && <PaginationEllipsis />} {currentPage < totalPages - 2 && (
<PaginationItem className="hidden sm:inline-flex items-center">
<PaginationEllipsis />
</PaginationItem>
)}
{currentPage < totalPages && ( {currentPage < totalPages - 1 && (
<PaginationItem> <PaginationItem className="hidden sm:inline-block">
<PaginationLink <PaginationLink
size="default" size="default"
onClick={() => setCurrentPage(totalPages)} onClick={() => handlePageChange(totalPages)}
> >
{totalPages} {totalPages}
</PaginationLink> </PaginationLink>
</PaginationItem> </PaginationItem>
)} )}
<PaginationItem> <PaginationItem>
<PaginationNext <PaginationNext
size="default" size="default"
onClick={() => onClick={() => handlePageChange(Math.min(currentPage + 1, totalPages))}
setCurrentPage((prev) => Math.min(prev + 1, totalPages)) />
} </PaginationItem>
/> </PaginationContent>
</PaginationItem> </Pagination>
</PaginationContent> </div>
</Pagination> </div>
</div>
</div>
</div> </div>
); );
}; };