import { Box, Card, Flex, H3, Skeleton, styled, Text } from '@traefiklabs/faency' import { Chart as ChartJs, ArcElement, Tooltip } from 'chart.js' import { ReactNode, useEffect, useMemo, useState } from 'react' import { Doughnut } from 'react-chartjs-2' import { FaArrowRightLong } from 'react-icons/fa6' import { Link as RouterLink, useNavigate } from 'react-router-dom' import Status, { colorByStatus, StatusType } from './Status' import { capitalizeFirstLetter } from 'utils/string' ChartJs.register(ArcElement, Tooltip) const Link = styled(RouterLink, { textDecoration: 'none', '&:hover': { textDecoration: 'none', }, }) type StatsCardType = { children: ReactNode } const StatsCard = ({ children, ...props }: StatsCardType) => ( {children} ) export type TraefikResourceStatsType = { title?: string errors: number total: number warnings: number } export type TraefikResourceStatsCardProps = TraefikResourceStatsType & { linkTo: string } export type DataType = { datasets: { backgroundColor: string[] data: (string | number)[] }[] labels?: string[] } const getPercent = (total: number, value: number) => (total > 0 ? ((value * 100) / total).toFixed(0) : 0) const STATS_ATTRIBUTES: { status: StatusType; label: string }[] = [ { status: 'enabled', label: 'success', }, { status: 'warning', label: 'warnings', }, { status: 'disabled', label: 'errors', }, ] const CustomLegend = ({ status, label, count, total, linkTo, }: { status: StatusType label: string count: number total: number linkTo: string }) => { return ( {capitalizeFirstLetter(label)} {getPercent(total, count)}% {count} ) } const TraefikResourceStatsCard = ({ title, errors, total, warnings, linkTo }: TraefikResourceStatsCardProps) => { const navigate = useNavigate() const defaultData = { datasets: [ { backgroundColor: [colorByStatus.enabled], data: [1], }, ], } const [data, setData] = useState(defaultData) const counts = useMemo( () => ({ success: total - (errors + warnings), warnings, errors, }), [errors, total, warnings], ) useEffect(() => { if (counts.success + counts.warnings + counts.errors === 0) { setData(defaultData) return } const newData = { datasets: [ { backgroundColor: [colorByStatus.enabled, colorByStatus.warning, colorByStatus.error], data: [counts.success, counts.warnings, counts.errors], }, ], labels: ['Success', 'Warnings', 'Errors'], } setData(newData) // eslint-disable-next-line react-hooks/exhaustive-deps }, [errors, warnings, total, counts]) const options = { animation: { duration: 1000, }, plugins: { legend: { display: false, }, }, tooltips: { enabled: true, }, maintainAspectRatio: false, onClick: (_, activeEl) => { navigate(`${linkTo}?status=${STATS_ATTRIBUTES[activeEl[0].index].status}`) }, } if (!errors && !total && !warnings) return null return ( {title && ( {title && (

{title}

Explore
)}
)} {STATS_ATTRIBUTES.map((i) => ( ))}
) } export const StatsCardSkeleton = () => { return ( ) } export default TraefikResourceStatsCard