import React, { Children, useEffect, useState } from 'react'; import { Target } from '@webapp/models/targets'; import { useAppDispatch, useAppSelector } from '@webapp/redux/hooks'; import { loadTargets, selectTargetsData, } from '@webapp/redux/reducers/serviceDiscovery'; import { formatDistance, parseISO } from 'date-fns'; import cx from 'classnames'; import Button from '@webapp/ui/Button'; import styles from './ServiceDiscovery.module.scss'; enum Status { healthy = 'healthy', info = 'info', error = 'error', } const ServiceDiscoveryApp = () => { const data = targetsToMap(useAppSelector(selectTargetsData)); const dispatch = useAppDispatch(); const [unavailableFilter, setUnavailableFilter] = useState(false); const [expandAll, setExpandAll] = useState(true); useEffect(() => { async function run() { await dispatch(loadTargets()); } run(); }, []); function getUpCount(targets: Target[]) { return targets.filter((t) => t.health === 'up').length; } return (

Targets

{Object.keys(data).length === 0 ? (
{'No pull-mode targets configured. See '} documentation {' for information on how to add targets.'}
) : ( Object.keys(data).map((job) => { const children = data[job].map((target) => { const targetElem = ( /* eslint-disable-next-line react/jsx-props-no-spreading */ ); if (unavailableFilter) { if (target.health !== 'up') { return targetElem; } return null; } return targetElem; }); return ( {children} ); }) )}
); }; const CollapsibleSection = ({ children, title, open }: ShamefulAny) => { return Children.count(children.filter((c: ShamefulAny) => c)) > 0 ? (
{title}
{children}
Scrape URL Health Discovered labels Labels Last scrape Scrape duration Last error
) : null; }; function formatDuration(input: string): string { const a = input.match(/[a-zA-Z]+$/); const b = a ? a[0] : ''; return `${parseFloat(input).toFixed(2)} ${b}`; } const TargetComponent = ({ discoveredLabels, labels, url, lastError, lastScrape, lastScrapeDuration, health, }: Target) => { return ( {url} {health} {Object.keys(discoveredLabels).map((key) => ( {`${key}=${discoveredLabels[key]}`} ))} {Object.keys(labels).map((key) => ( {`${key}=${labels[key]}`} ))} {formatDistance(parseISO(lastScrape), new Date())} ago {formatDuration(lastScrapeDuration)} {lastError || '-'} ); }; const Badge = ({ children, status }: { children: string; status: Status }) => { function getStatusClass(status: ShamefulAny) { switch (status) { case Status.healthy: return styles.healthy; case Status.info: return styles.info; case Status.error: return styles.error; default: return styles.info; } } return ( {children} ); }; type TargetRecord = Record; const targetsToMap: (state: Target[]) => TargetRecord = (state) => { const acc = state.reduce((acc: TargetRecord, next: Target) => { if (!acc[next.job]) { acc[next.job] = []; } acc[next.job].push(next); return acc; }, {} as TargetRecord); return acc; }; export default ServiceDiscoveryApp;