mirror of
https://github.com/prometheus/prometheus.git
synced 2025-03-05 20:59:13 -08:00
Feature: Add collapse/expand all button to target page for react ui (#8486)
* Feature: Add collapse/expand all button to target page for react ui Signed-off-by: Dustin Hooten <dustinhooten@gmail.com> * update local storage key to prevent bad state Signed-off-by: Dustin Hooten <dustinhooten@gmail.com> * PR feedback Signed-off-by: Dustin Hooten <dustinhooten@gmail.com> * split big state object into smaller ones Signed-off-by: Dustin Hooten <dustinhooten@gmail.com> * fix duplication typo Signed-off-by: Dustin Hooten <dustinhooten@gmail.com>
This commit is contained in:
parent
c0c36b1155
commit
0d8db52954
|
@ -5,12 +5,23 @@ import Filter, { FilterData, FilterProps } from './Filter';
|
||||||
import sinon, { SinonSpy } from 'sinon';
|
import sinon, { SinonSpy } from 'sinon';
|
||||||
|
|
||||||
describe('Filter', () => {
|
describe('Filter', () => {
|
||||||
const initialState: FilterData = { showHealthy: true, showUnhealthy: true };
|
const initialExpanded = {
|
||||||
|
scrapePool1: true,
|
||||||
|
scrapePool2: true,
|
||||||
|
};
|
||||||
|
let setExpaned: SinonSpy;
|
||||||
|
const initialState: FilterData = {
|
||||||
|
showHealthy: true,
|
||||||
|
showUnhealthy: true,
|
||||||
|
};
|
||||||
let setFilter: SinonSpy;
|
let setFilter: SinonSpy;
|
||||||
let filterWrapper: ShallowWrapper<FilterProps, Readonly<{}>, Component<{}, {}, Component>>;
|
let filterWrapper: ShallowWrapper<FilterProps, Readonly<{}>, Component<{}, {}, Component>>;
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
setFilter = sinon.spy();
|
setFilter = sinon.spy();
|
||||||
filterWrapper = shallow(<Filter filter={initialState} setFilter={setFilter} />);
|
setExpaned = sinon.spy();
|
||||||
|
filterWrapper = shallow(
|
||||||
|
<Filter filter={initialState} setFilter={setFilter} expanded={initialExpanded} setExpanded={setExpaned} />
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('renders a button group', () => {
|
it('renders a button group', () => {
|
||||||
|
@ -29,6 +40,12 @@ describe('Filter', () => {
|
||||||
expect(btn.prop('color')).toBe('primary');
|
expect(btn.prop('color')).toBe('primary');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('renders an expansion filter button that is inactive', () => {
|
||||||
|
const btn = filterWrapper.find(Button).filterWhere((btn): boolean => btn.hasClass('expansion'));
|
||||||
|
expect(btn.prop('active')).toBe(false);
|
||||||
|
expect(btn.prop('color')).toBe('primary');
|
||||||
|
});
|
||||||
|
|
||||||
it('renders an all filter button which shows all targets', () => {
|
it('renders an all filter button which shows all targets', () => {
|
||||||
const btn = filterWrapper.find(Button).filterWhere((btn): boolean => btn.hasClass('all'));
|
const btn = filterWrapper.find(Button).filterWhere((btn): boolean => btn.hasClass('all'));
|
||||||
btn.simulate('click');
|
btn.simulate('click');
|
||||||
|
@ -40,6 +57,46 @@ describe('Filter', () => {
|
||||||
const btn = filterWrapper.find(Button).filterWhere((btn): boolean => btn.hasClass('unhealthy'));
|
const btn = filterWrapper.find(Button).filterWhere((btn): boolean => btn.hasClass('unhealthy'));
|
||||||
btn.simulate('click');
|
btn.simulate('click');
|
||||||
expect(setFilter.calledOnce).toBe(true);
|
expect(setFilter.calledOnce).toBe(true);
|
||||||
expect(setFilter.getCall(0).args[0]).toEqual({ showHealthy: false, showUnhealthy: true });
|
expect(setFilter.getCall(0).args[0]).toEqual({
|
||||||
|
showHealthy: false,
|
||||||
|
showUnhealthy: true,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('Expansion filter', () => {
|
||||||
|
[
|
||||||
|
{
|
||||||
|
name: 'expanded => collapsed',
|
||||||
|
initial: initialExpanded,
|
||||||
|
final: { scrapePool1: false, scrapePool2: false },
|
||||||
|
text: 'Collapse All',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'collapsed => expanded',
|
||||||
|
initial: { scrapePool1: false, scrapePool2: false },
|
||||||
|
final: initialExpanded,
|
||||||
|
text: 'Expand All',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'some expanded => expanded',
|
||||||
|
initial: { scrapePool1: true, scrapePool2: false },
|
||||||
|
final: initialExpanded,
|
||||||
|
text: 'Expand All',
|
||||||
|
},
|
||||||
|
].forEach(({ name, text, initial, final }) => {
|
||||||
|
it(`filters targets ${name}`, (): void => {
|
||||||
|
const filter = { ...initialState };
|
||||||
|
const filterCallback = sinon.spy();
|
||||||
|
const expandedCallback = sinon.spy();
|
||||||
|
const filterW = shallow(
|
||||||
|
<Filter filter={filter} setFilter={filterCallback} expanded={initial} setExpanded={expandedCallback} />
|
||||||
|
);
|
||||||
|
const btn = filterW.find(Button).filterWhere((btn): boolean => btn.hasClass('expansion'));
|
||||||
|
expect(btn.children().text()).toEqual(text);
|
||||||
|
btn.simulate('click');
|
||||||
|
expect(expandedCallback.calledOnce).toBe(true);
|
||||||
|
expect(expandedCallback.getCall(0).args[0]).toEqual(final);
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -7,13 +7,28 @@ export interface FilterData {
|
||||||
showUnhealthy: boolean;
|
showUnhealthy: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface Expanded {
|
||||||
|
[scrapePool: string]: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
export interface FilterProps {
|
export interface FilterProps {
|
||||||
filter: FilterData;
|
filter: FilterData;
|
||||||
setFilter: Dispatch<SetStateAction<FilterData>>;
|
setFilter: Dispatch<SetStateAction<FilterData>>;
|
||||||
|
expanded: Expanded;
|
||||||
|
setExpanded: Dispatch<SetStateAction<Expanded>>;
|
||||||
}
|
}
|
||||||
|
|
||||||
const Filter: FC<FilterProps> = ({ filter, setFilter }) => {
|
const Filter: FC<FilterProps> = ({ filter, setFilter, expanded, setExpanded }) => {
|
||||||
const { showHealthy } = filter;
|
const { showHealthy } = filter;
|
||||||
|
const allExpanded = Object.values(expanded).every((v: boolean): boolean => v);
|
||||||
|
const mapExpansion = (next: boolean): Expanded =>
|
||||||
|
Object.keys(expanded).reduce(
|
||||||
|
(acc: { [scrapePool: string]: boolean }, scrapePool: string) => ({
|
||||||
|
...acc,
|
||||||
|
[scrapePool]: next,
|
||||||
|
}),
|
||||||
|
{}
|
||||||
|
);
|
||||||
const btnProps = {
|
const btnProps = {
|
||||||
all: {
|
all: {
|
||||||
active: showHealthy,
|
active: showHealthy,
|
||||||
|
@ -27,11 +42,18 @@ const Filter: FC<FilterProps> = ({ filter, setFilter }) => {
|
||||||
color: 'primary',
|
color: 'primary',
|
||||||
onClick: (): void => setFilter({ ...filter, showHealthy: false }),
|
onClick: (): void => setFilter({ ...filter, showHealthy: false }),
|
||||||
},
|
},
|
||||||
|
expansionState: {
|
||||||
|
active: false,
|
||||||
|
className: `expansion ${styles.btn}`,
|
||||||
|
color: 'primary',
|
||||||
|
onClick: (): void => setExpanded(mapExpansion(!allExpanded)),
|
||||||
|
},
|
||||||
};
|
};
|
||||||
return (
|
return (
|
||||||
<ButtonGroup>
|
<ButtonGroup>
|
||||||
<Button {...btnProps.all}>All</Button>
|
<Button {...btnProps.all}>All</Button>
|
||||||
<Button {...btnProps.unhealthy}>Unhealthy</Button>
|
<Button {...btnProps.unhealthy}>Unhealthy</Button>
|
||||||
|
<Button {...btnProps.expansionState}>{allExpanded ? 'Collapse All' : 'Expand All'}</Button>
|
||||||
</ButtonGroup>
|
</ButtonGroup>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
@ -10,10 +10,6 @@ import { FetchMock } from 'jest-fetch-mock/types';
|
||||||
import { PathPrefixContext } from '../../contexts/PathPrefixContext';
|
import { PathPrefixContext } from '../../contexts/PathPrefixContext';
|
||||||
|
|
||||||
describe('ScrapePoolList', () => {
|
describe('ScrapePoolList', () => {
|
||||||
const defaultProps = {
|
|
||||||
filter: { showHealthy: true, showUnhealthy: true },
|
|
||||||
};
|
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
fetchMock.resetMocks();
|
fetchMock.resetMocks();
|
||||||
});
|
});
|
||||||
|
@ -38,7 +34,7 @@ describe('ScrapePoolList', () => {
|
||||||
await act(async () => {
|
await act(async () => {
|
||||||
scrapePoolList = mount(
|
scrapePoolList = mount(
|
||||||
<PathPrefixContext.Provider value="/path/prefix">
|
<PathPrefixContext.Provider value="/path/prefix">
|
||||||
<ScrapePoolList {...defaultProps} />
|
<ScrapePoolList />
|
||||||
</PathPrefixContext.Provider>
|
</PathPrefixContext.Provider>
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
@ -55,27 +51,6 @@ describe('ScrapePoolList', () => {
|
||||||
expect(panel).toHaveLength(1);
|
expect(panel).toHaveLength(1);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('filters by health', async () => {
|
|
||||||
const props = {
|
|
||||||
...defaultProps,
|
|
||||||
filter: { showHealthy: false, showUnhealthy: true },
|
|
||||||
};
|
|
||||||
await act(async () => {
|
|
||||||
scrapePoolList = mount(
|
|
||||||
<PathPrefixContext.Provider value="/path/prefix">
|
|
||||||
<ScrapePoolList {...props} />
|
|
||||||
</PathPrefixContext.Provider>
|
|
||||||
);
|
|
||||||
});
|
|
||||||
scrapePoolList.update();
|
|
||||||
expect(mock).toHaveBeenCalledWith('/path/prefix/api/v1/targets?state=active', {
|
|
||||||
cache: 'no-store',
|
|
||||||
credentials: 'same-origin',
|
|
||||||
});
|
|
||||||
const panels = scrapePoolList.find(ScrapePoolPanel);
|
|
||||||
expect(panels).toHaveLength(0);
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('when an error is returned', () => {
|
describe('when an error is returned', () => {
|
||||||
|
@ -86,7 +61,7 @@ describe('ScrapePoolList', () => {
|
||||||
await act(async () => {
|
await act(async () => {
|
||||||
scrapePoolList = mount(
|
scrapePoolList = mount(
|
||||||
<PathPrefixContext.Provider value="/path/prefix">
|
<PathPrefixContext.Provider value="/path/prefix">
|
||||||
<ScrapePoolList {...defaultProps} />
|
<ScrapePoolList />
|
||||||
</PathPrefixContext.Provider>
|
</PathPrefixContext.Provider>
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,29 +1,53 @@
|
||||||
import React, { FC } from 'react';
|
import React, { FC } from 'react';
|
||||||
import { FilterData } from './Filter';
|
import Filter, { Expanded, FilterData } from './Filter';
|
||||||
import { useFetch } from '../../hooks/useFetch';
|
import { useFetch } from '../../hooks/useFetch';
|
||||||
import { groupTargets, Target } from './target';
|
import { groupTargets, Target } from './target';
|
||||||
import ScrapePoolPanel from './ScrapePoolPanel';
|
import ScrapePoolPanel from './ScrapePoolPanel';
|
||||||
import { withStatusIndicator } from '../../components/withStatusIndicator';
|
import { withStatusIndicator } from '../../components/withStatusIndicator';
|
||||||
import { usePathPrefix } from '../../contexts/PathPrefixContext';
|
import { usePathPrefix } from '../../contexts/PathPrefixContext';
|
||||||
import { API_PATH } from '../../constants/constants';
|
import { API_PATH } from '../../constants/constants';
|
||||||
|
import { useLocalStorage } from '../../hooks/useLocalStorage';
|
||||||
|
|
||||||
interface ScrapePoolListProps {
|
interface ScrapePoolListProps {
|
||||||
filter: FilterData;
|
|
||||||
activeTargets: Target[];
|
activeTargets: Target[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export const ScrapePoolContent: FC<ScrapePoolListProps> = ({ filter, activeTargets }) => {
|
export const ScrapePoolContent: FC<ScrapePoolListProps> = ({ activeTargets }) => {
|
||||||
const targetGroups = groupTargets(activeTargets);
|
const targetGroups = groupTargets(activeTargets);
|
||||||
|
const initialFilter: FilterData = {
|
||||||
|
showHealthy: true,
|
||||||
|
showUnhealthy: true,
|
||||||
|
};
|
||||||
|
const [filter, setFilter] = useLocalStorage('targets-page-filter', initialFilter);
|
||||||
|
|
||||||
|
const initialExpanded: Expanded = Object.keys(targetGroups).reduce(
|
||||||
|
(acc: { [scrapePool: string]: boolean }, scrapePool: string) => ({
|
||||||
|
...acc,
|
||||||
|
[scrapePool]: true,
|
||||||
|
}),
|
||||||
|
{}
|
||||||
|
);
|
||||||
|
const [expanded, setExpanded] = useLocalStorage('targets-page-expansion-state', initialExpanded);
|
||||||
|
|
||||||
const { showHealthy, showUnhealthy } = filter;
|
const { showHealthy, showUnhealthy } = filter;
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{Object.keys(targetGroups).reduce<JSX.Element[]>((panels, scrapePool) => {
|
<Filter filter={filter} setFilter={setFilter} expanded={expanded} setExpanded={setExpanded} />
|
||||||
|
{Object.keys(targetGroups)
|
||||||
|
.filter(scrapePool => {
|
||||||
const targetGroup = targetGroups[scrapePool];
|
const targetGroup = targetGroups[scrapePool];
|
||||||
const isHealthy = targetGroup.upCount === targetGroup.targets.length;
|
const isHealthy = targetGroup.upCount === targetGroup.targets.length;
|
||||||
return (isHealthy && showHealthy) || (!isHealthy && showUnhealthy)
|
return (isHealthy && showHealthy) || (!isHealthy && showUnhealthy);
|
||||||
? [...panels, <ScrapePoolPanel key={scrapePool} scrapePool={scrapePool} targetGroup={targetGroup} />]
|
})
|
||||||
: panels;
|
.map<JSX.Element>(scrapePool => (
|
||||||
}, [])}
|
<ScrapePoolPanel
|
||||||
|
key={scrapePool}
|
||||||
|
scrapePool={scrapePool}
|
||||||
|
targetGroup={targetGroups[scrapePool]}
|
||||||
|
expanded={expanded[scrapePool]}
|
||||||
|
toggleExpanded={(): void => setExpanded({ ...expanded, [scrapePool]: !expanded[scrapePool] })}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -31,7 +55,7 @@ ScrapePoolContent.displayName = 'ScrapePoolContent';
|
||||||
|
|
||||||
const ScrapePoolListWithStatusIndicator = withStatusIndicator(ScrapePoolContent);
|
const ScrapePoolListWithStatusIndicator = withStatusIndicator(ScrapePoolContent);
|
||||||
|
|
||||||
const ScrapePoolList: FC<{ filter: FilterData }> = ({ filter }) => {
|
const ScrapePoolList: FC = () => {
|
||||||
const pathPrefix = usePathPrefix();
|
const pathPrefix = usePathPrefix();
|
||||||
const { response, error, isLoading } = useFetch<ScrapePoolListProps>(`${pathPrefix}/${API_PATH}/targets?state=active`);
|
const { response, error, isLoading } = useFetch<ScrapePoolListProps>(`${pathPrefix}/${API_PATH}/targets?state=active`);
|
||||||
const { status: responseStatus } = response;
|
const { status: responseStatus } = response;
|
||||||
|
@ -39,7 +63,6 @@ const ScrapePoolList: FC<{ filter: FilterData }> = ({ filter }) => {
|
||||||
return (
|
return (
|
||||||
<ScrapePoolListWithStatusIndicator
|
<ScrapePoolListWithStatusIndicator
|
||||||
{...response.data}
|
{...response.data}
|
||||||
filter={filter}
|
|
||||||
error={badResponse ? new Error(responseStatus) : error}
|
error={badResponse ? new Error(responseStatus) : error}
|
||||||
isLoading={isLoading}
|
isLoading={isLoading}
|
||||||
componentTitle="Targets information"
|
componentTitle="Targets information"
|
||||||
|
|
|
@ -6,11 +6,14 @@ import { Button, Collapse, Table, Badge } from 'reactstrap';
|
||||||
import { Target, getColor } from './target';
|
import { Target, getColor } from './target';
|
||||||
import EndpointLink from './EndpointLink';
|
import EndpointLink from './EndpointLink';
|
||||||
import TargetLabels from './TargetLabels';
|
import TargetLabels from './TargetLabels';
|
||||||
|
import sinon from 'sinon';
|
||||||
|
|
||||||
describe('ScrapePoolPanel', () => {
|
describe('ScrapePoolPanel', () => {
|
||||||
const defaultProps = {
|
const defaultProps = {
|
||||||
scrapePool: 'blackbox',
|
scrapePool: 'blackbox',
|
||||||
targetGroup: targetGroups.blackbox,
|
targetGroup: targetGroups.blackbox,
|
||||||
|
expanded: true,
|
||||||
|
toggleExpanded: sinon.spy(),
|
||||||
};
|
};
|
||||||
const scrapePoolPanel = shallow(<ScrapePoolPanel {...defaultProps} />);
|
const scrapePoolPanel = shallow(<ScrapePoolPanel {...defaultProps} />);
|
||||||
|
|
||||||
|
@ -31,6 +34,7 @@ describe('ScrapePoolPanel', () => {
|
||||||
|
|
||||||
it('renders an anchor with up count and normal color if upCount == targetsCount', () => {
|
it('renders an anchor with up count and normal color if upCount == targetsCount', () => {
|
||||||
const props = {
|
const props = {
|
||||||
|
...defaultProps,
|
||||||
scrapePool: 'prometheus',
|
scrapePool: 'prometheus',
|
||||||
targetGroup: targetGroups.prometheus,
|
targetGroup: targetGroups.prometheus,
|
||||||
};
|
};
|
||||||
|
@ -45,8 +49,10 @@ describe('ScrapePoolPanel', () => {
|
||||||
|
|
||||||
it('renders a show more btn if collapsed', () => {
|
it('renders a show more btn if collapsed', () => {
|
||||||
const props = {
|
const props = {
|
||||||
|
...defaultProps,
|
||||||
scrapePool: 'prometheus',
|
scrapePool: 'prometheus',
|
||||||
targetGroup: targetGroups.prometheus,
|
targetGroup: targetGroups.prometheus,
|
||||||
|
toggleExpanded: sinon.spy(),
|
||||||
};
|
};
|
||||||
const div = document.createElement('div');
|
const div = document.createElement('div');
|
||||||
div.id = `series-labels-prometheus-0`;
|
div.id = `series-labels-prometheus-0`;
|
||||||
|
@ -55,8 +61,7 @@ describe('ScrapePoolPanel', () => {
|
||||||
|
|
||||||
const btn = scrapePoolPanel.find(Button);
|
const btn = scrapePoolPanel.find(Button);
|
||||||
btn.simulate('click');
|
btn.simulate('click');
|
||||||
const collapse = scrapePoolPanel.find(Collapse);
|
expect(props.toggleExpanded.calledOnce).toBe(true);
|
||||||
expect(collapse.prop('isOpen')).toBe(false);
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -6,19 +6,19 @@ import { Target } from './target';
|
||||||
import EndpointLink from './EndpointLink';
|
import EndpointLink from './EndpointLink';
|
||||||
import TargetLabels from './TargetLabels';
|
import TargetLabels from './TargetLabels';
|
||||||
import { now } from 'moment';
|
import { now } from 'moment';
|
||||||
import { useLocalStorage } from '../../hooks/useLocalStorage';
|
|
||||||
import { ToggleMoreLess } from '../../components/ToggleMoreLess';
|
import { ToggleMoreLess } from '../../components/ToggleMoreLess';
|
||||||
import { formatRelative, humanizeDuration } from '../../utils';
|
import { formatRelative, humanizeDuration } from '../../utils';
|
||||||
|
|
||||||
interface PanelProps {
|
interface PanelProps {
|
||||||
scrapePool: string;
|
scrapePool: string;
|
||||||
targetGroup: ScrapePool;
|
targetGroup: ScrapePool;
|
||||||
|
expanded: boolean;
|
||||||
|
toggleExpanded: () => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const columns = ['Endpoint', 'State', 'Labels', 'Last Scrape', 'Scrape Duration', 'Error'];
|
export const columns = ['Endpoint', 'State', 'Labels', 'Last Scrape', 'Scrape Duration', 'Error'];
|
||||||
|
|
||||||
const ScrapePoolPanel: FC<PanelProps> = ({ scrapePool, targetGroup }) => {
|
const ScrapePoolPanel: FC<PanelProps> = ({ scrapePool, targetGroup, expanded, toggleExpanded }) => {
|
||||||
const [{ expanded }, setOptions] = useLocalStorage(`targets-${scrapePool}-expanded`, { expanded: true });
|
|
||||||
const modifier = targetGroup.upCount < targetGroup.targets.length ? 'danger' : 'normal';
|
const modifier = targetGroup.upCount < targetGroup.targets.length ? 'danger' : 'normal';
|
||||||
const id = `pool-${scrapePool}`;
|
const id = `pool-${scrapePool}`;
|
||||||
const anchorProps = {
|
const anchorProps = {
|
||||||
|
@ -28,7 +28,7 @@ const ScrapePoolPanel: FC<PanelProps> = ({ scrapePool, targetGroup }) => {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={styles.container}>
|
<div className={styles.container}>
|
||||||
<ToggleMoreLess event={(): void => setOptions({ expanded: !expanded })} showMore={expanded}>
|
<ToggleMoreLess event={toggleExpanded} showMore={expanded}>
|
||||||
<a className={styles[modifier]} {...anchorProps}>
|
<a className={styles[modifier]} {...anchorProps}>
|
||||||
{`${scrapePool} (${targetGroup.upCount}/${targetGroup.targets.length} up)`}
|
{`${scrapePool} (${targetGroup.upCount}/${targetGroup.targets.length} up)`}
|
||||||
</a>
|
</a>
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { shallow } from 'enzyme';
|
import { shallow } from 'enzyme';
|
||||||
import Targets from './Targets';
|
import Targets from './Targets';
|
||||||
import Filter from './Filter';
|
|
||||||
import ScrapePoolList from './ScrapePoolList';
|
import ScrapePoolList from './ScrapePoolList';
|
||||||
|
|
||||||
describe('Targets', () => {
|
describe('Targets', () => {
|
||||||
|
@ -19,14 +18,8 @@ describe('Targets', () => {
|
||||||
expect(h2).toHaveLength(1);
|
expect(h2).toHaveLength(1);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
it('renders a filter', () => {
|
|
||||||
const filter = targets.find(Filter);
|
|
||||||
expect(filter).toHaveLength(1);
|
|
||||||
expect(filter.prop('filter')).toEqual({ showHealthy: true, showUnhealthy: true });
|
|
||||||
});
|
|
||||||
it('renders a scrape pool list', () => {
|
it('renders a scrape pool list', () => {
|
||||||
const scrapePoolList = targets.find(ScrapePoolList);
|
const scrapePoolList = targets.find(ScrapePoolList);
|
||||||
expect(scrapePoolList).toHaveLength(1);
|
expect(scrapePoolList).toHaveLength(1);
|
||||||
expect(scrapePoolList.prop('filter')).toEqual({ showHealthy: true, showUnhealthy: true });
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,22 +1,12 @@
|
||||||
import React, { FC } from 'react';
|
import React, { FC } from 'react';
|
||||||
import { RouteComponentProps } from '@reach/router';
|
import { RouteComponentProps } from '@reach/router';
|
||||||
import Filter from './Filter';
|
|
||||||
import ScrapePoolList from './ScrapePoolList';
|
import ScrapePoolList from './ScrapePoolList';
|
||||||
import { useLocalStorage } from '../../hooks/useLocalStorage';
|
|
||||||
import { usePathPrefix } from '../../contexts/PathPrefixContext';
|
|
||||||
import { API_PATH } from '../../constants/constants';
|
|
||||||
|
|
||||||
const Targets: FC<RouteComponentProps> = () => {
|
const Targets: FC<RouteComponentProps> = () => {
|
||||||
const pathPrefix = usePathPrefix();
|
|
||||||
const [filter, setFilter] = useLocalStorage('targets-page-filter', { showHealthy: true, showUnhealthy: true });
|
|
||||||
const filterProps = { filter, setFilter };
|
|
||||||
const scrapePoolListProps = { filter, pathPrefix, API_PATH };
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<h2>Targets</h2>
|
<h2>Targets</h2>
|
||||||
<Filter {...filterProps} />
|
<ScrapePoolList />
|
||||||
<ScrapePoolList {...scrapePoolListProps} />
|
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in a new issue