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}
| Scrape URL |
Health |
Discovered labels
|
Labels |
Last scrape
|
Scrape duration
|
Last error |
{children}
) : 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;