adds more filters to dashboard chart

This commit is contained in:
Alex Corey
2021-06-03 15:10:21 -04:00
parent 8adb53b5a8
commit 1537b84ec8
3 changed files with 129 additions and 54 deletions

View File

@@ -25,6 +25,12 @@ import LineChart from './shared/LineChart';
import Count from './shared/Count'; import Count from './shared/Count';
import TemplateList from '../../components/TemplateList'; import TemplateList from '../../components/TemplateList';
const StatusSelect = styled(Select)`
&& {
--pf-c-select__toggle--MinWidth: 165px;
}
`;
const Counts = styled.div` const Counts = styled.div`
display: grid; display: grid;
grid-template-columns: repeat(6, 1fr); grid-template-columns: repeat(6, 1fr);
@@ -57,8 +63,10 @@ const GraphCardActions = styled(CardActions)`
function Dashboard() { function Dashboard() {
const [isPeriodDropdownOpen, setIsPeriodDropdownOpen] = useState(false); const [isPeriodDropdownOpen, setIsPeriodDropdownOpen] = useState(false);
const [isJobTypeDropdownOpen, setIsJobTypeDropdownOpen] = useState(false); const [isJobTypeDropdownOpen, setIsJobTypeDropdownOpen] = useState(false);
const [isJobStatusDropdownOpen, setIsJobStatusDropdownOpen] = useState(false);
const [periodSelection, setPeriodSelection] = useState('month'); const [periodSelection, setPeriodSelection] = useState('month');
const [jobTypeSelection, setJobTypeSelection] = useState('all'); const [jobTypeSelection, setJobTypeSelection] = useState('all');
const [jobStatusSelection, setJobStatusSelection] = useState('all');
const [activeTabId, setActiveTabId] = useState(0); const [activeTabId, setActiveTabId] = useState(0);
const { const {
@@ -196,6 +204,9 @@ function Dashboard() {
<SelectOption key="week" value="week"> <SelectOption key="week" value="week">
{t`Past week`} {t`Past week`}
</SelectOption> </SelectOption>
<SelectOption key="day" value="day">
{t`Past 24 hours`}
</SelectOption>
</Select> </Select>
<Select <Select
variant={SelectVariant.single} variant={SelectVariant.single}
@@ -222,10 +233,37 @@ function Dashboard() {
{t`Playbook run`} {t`Playbook run`}
</SelectOption> </SelectOption>
</Select> </Select>
<StatusSelect
variant={SelectVariant.single}
placeholderText={t`Select status`}
aria-label={t`Select status`}
className="jobStatusSelect"
onToggle={setIsJobStatusDropdownOpen}
onSelect={(event, selection) => {
setIsJobStatusDropdownOpen(false);
setJobStatusSelection(selection);
}}
selections={jobStatusSelection}
isOpen={isJobStatusDropdownOpen}
>
<SelectOption
key="all"
value="all"
>{t`All jobs`}</SelectOption>
<SelectOption
key="successful"
value="successful"
>{t`Successful jobs`}</SelectOption>
<SelectOption
key="failed"
value="failed"
>{t`Failed jobs`}</SelectOption>
</StatusSelect>
</GraphCardActions> </GraphCardActions>
</GraphCardHeader> </GraphCardHeader>
<CardBody> <CardBody>
<LineChart <LineChart
jobStatus={jobStatusSelection}
height={390} height={390}
id="d3-line-chart-root" id="d3-line-chart-root"
data={jobGraphData} data={jobGraphData}

View File

@@ -53,4 +53,34 @@ describe('<Dashboard />', () => {
period: 'month', period: 'month',
}); });
}); });
test('should render all three line chart filters with correct number of options', async () => {
expect(pageWrapper.find('Select[variant="single"]')).toHaveLength(3);
await act(async () => {
pageWrapper
.find('Select[placeholderText="Select job type"]')
.prop('onToggle')(true);
});
pageWrapper.update();
expect(pageWrapper.find('SelectOption')).toHaveLength(4);
await act(async () => {
pageWrapper
.find('Select[placeholderText="Select job type"]')
.prop('onToggle')(false);
pageWrapper
.find('Select[placeholderText="Select period"]')
.prop('onToggle')(true);
});
pageWrapper.update();
expect(pageWrapper.find('SelectOption')).toHaveLength(4);
await act(async () => {
pageWrapper
.find('Select[placeholderText="Select period"]')
.prop('onToggle')(false);
pageWrapper
.find('Select[placeholderText="Select status"]')
.prop('onToggle')(true);
});
pageWrapper.update();
expect(pageWrapper.find('SelectOption')).toHaveLength(3);
});
}); });

View File

@@ -7,7 +7,7 @@ import { PageContextConsumer } from '@patternfly/react-core';
import ChartTooltip from './ChartTooltip'; import ChartTooltip from './ChartTooltip';
function LineChart({ id, data, height, pageContext }) { function LineChart({ id, data, height, pageContext, jobStatus }) {
const { isNavOpen } = pageContext; const { isNavOpen } = pageContext;
// Methods // Methods
@@ -197,61 +197,68 @@ function LineChart({ id, data, height, pageContext }) {
vertical.transition().style('opacity', 0); vertical.transition().style('opacity', 0);
}; };
// Add the successLine path.
svg
.append('path')
.data([formattedData])
.attr('class', 'line')
.style('fill', 'none')
.style('stroke', () => colors(1))
.attr('stroke-width', 2)
.attr('d', successLine)
.call(transition);
// Add the failLine path.
svg
.append('path')
.data([formattedData])
.attr('class', 'line')
.style('fill', 'none')
.style('stroke', () => colors(0))
.attr('stroke-width', 2)
.attr('d', failLine)
.call(transition);
const dateFormat = d3.timeFormat('%-m-%-d'); const dateFormat = d3.timeFormat('%-m-%-d');
// create our successLine circles if (jobStatus !== 'failed') {
svg // Add the success line path.
.selectAll('dot') svg
.data(formattedData) .append('path')
.enter() .data([formattedData])
.append('circle') .attr('class', 'line')
.attr('r', 3) .style('fill', 'none')
.style('stroke', () => colors(1)) .style('stroke', () => colors(1))
.style('fill', () => colors(1)) .attr('stroke-width', 2)
.attr('cx', d => x(d.DATE)) .attr('d', successLine)
.attr('cy', d => y(d.RAN)) .call(transition);
.attr('id', d => `success-dot-${dateFormat(d.DATE)}`)
.on('mouseover', handleMouseOver) // create our success line circles
.on('mousemove', handleMouseMove)
.on('mouseout', handleMouseOut); svg
// create our failLine circles .selectAll('dot')
svg .data(formattedData)
.selectAll('dot') .enter()
.data(formattedData) .append('circle')
.enter() .attr('r', 3)
.append('circle') .style('stroke', () => colors(1))
.attr('r', 3) .style('fill', () => colors(1))
.style('stroke', () => colors(0)) .attr('cx', d => x(d.DATE))
.style('fill', () => colors(0)) .attr('cy', d => y(d.RAN))
.attr('cx', d => x(d.DATE)) .attr('id', d => `success-dot-${dateFormat(d.DATE)}`)
.attr('cy', d => y(d.FAIL)) .on('mouseover', handleMouseOver)
.attr('id', d => `fail-dot-${dateFormat(d.DATE)}`) .on('mousemove', handleMouseMove)
.on('mouseover', handleMouseOver) .on('mouseout', handleMouseOut);
.on('mousemove', handleMouseMove) }
.on('mouseout', handleMouseOut);
}, [data, height, id]); if (jobStatus !== 'successful') {
// Add the failed line path.
svg
.append('path')
.data([formattedData])
.attr('class', 'line')
.style('fill', 'none')
.style('stroke', () => colors(0))
.attr('stroke-width', 2)
.attr('d', failLine)
.call(transition);
// create our failed line circles
svg
.selectAll('dot')
.data(formattedData)
.enter()
.append('circle')
.attr('r', 3)
.style('stroke', () => colors(0))
.style('fill', () => colors(0))
.attr('cx', d => x(d.DATE))
.attr('cy', d => y(d.FAIL))
.attr('id', d => `fail-dot-${dateFormat(d.DATE)}`)
.on('mouseover', handleMouseOver)
.on('mousemove', handleMouseMove)
.on('mouseout', handleMouseOut);
}
}, [data, height, id, jobStatus]);
useEffect(() => { useEffect(() => {
draw(); draw();