1import React, { FC } from 'react';
2import { ScrapePool, getColor } from './target';
3import { Collapse, Table, Badge } from 'reactstrap';
4import styles from './ScrapePoolPanel.module.css';
5import { Target } from './target';
6import EndpointLink from './EndpointLink';
7import TargetLabels from './TargetLabels';
8import { now } from 'moment';
9import { useLocalStorage } from '../../hooks/useLocalStorage';
10import { ToggleMoreLess } from '../../components/ToggleMoreLess';
11import { formatRelative, humanizeDuration } from '../../utils';
12
13interface PanelProps {
14  scrapePool: string;
15  targetGroup: ScrapePool;
16}
17
18export const columns = ['Endpoint', 'State', 'Labels', 'Last Scrape', 'Scrape Duration', 'Error'];
19
20const ScrapePoolPanel: FC<PanelProps> = ({ scrapePool, targetGroup }) => {
21  const [{ expanded }, setOptions] = useLocalStorage(`targets-${scrapePool}-expanded`, { expanded: true });
22  const modifier = targetGroup.upCount < targetGroup.targets.length ? 'danger' : 'normal';
23  const id = `pool-${scrapePool}`;
24  const anchorProps = {
25    href: `#${id}`,
26    id,
27  };
28
29  return (
30    <div className={styles.container}>
31      <ToggleMoreLess event={(): void => setOptions({ expanded: !expanded })} showMore={expanded}>
32        <a className={styles[modifier]} {...anchorProps}>
33          {`${scrapePool} (${targetGroup.upCount}/${targetGroup.targets.length} up)`}
34        </a>
35      </ToggleMoreLess>
36      <Collapse isOpen={expanded}>
37        <Table className={styles.table} size="sm" bordered hover striped>
38          <thead>
39            <tr key="header">
40              {columns.map((column) => (
41                <th key={column}>{column}</th>
42              ))}
43            </tr>
44          </thead>
45          <tbody>
46            {targetGroup.targets.map((target: Target, idx: number) => {
47              const {
48                discoveredLabels,
49                labels,
50                scrapePool,
51                scrapeUrl,
52                globalUrl,
53                lastError,
54                lastScrape,
55                lastScrapeDuration,
56                health,
57              } = target;
58              const color = getColor(health);
59
60              return (
61                <tr key={scrapeUrl}>
62                  <td className={styles.endpoint}>
63                    <EndpointLink endpoint={scrapeUrl} globalUrl={globalUrl} />
64                  </td>
65                  <td className={styles.state}>
66                    <Badge color={color}>{health.toUpperCase()}</Badge>
67                  </td>
68                  <td className={styles.labels}>
69                    <TargetLabels discoveredLabels={discoveredLabels} labels={labels} scrapePool={scrapePool} idx={idx} />
70                  </td>
71                  <td className={styles['last-scrape']}>{formatRelative(lastScrape, now())}</td>
72                  <td className={styles['scrape-duration']}>{humanizeDuration(lastScrapeDuration * 1000)}</td>
73                  <td className={styles.errors}>{lastError ? <Badge color={color}>{lastError}</Badge> : null}</td>
74                </tr>
75              );
76            })}
77          </tbody>
78        </Table>
79      </Collapse>
80    </div>
81  );
82};
83
84export default ScrapePoolPanel;
85