diff --git a/awx/ui_next/src/screens/Dashboard/Dashboard.jsx b/awx/ui_next/src/screens/Dashboard/Dashboard.jsx
index f8772f5185..950451cbe4 100644
--- a/awx/ui_next/src/screens/Dashboard/Dashboard.jsx
+++ b/awx/ui_next/src/screens/Dashboard/Dashboard.jsx
@@ -25,6 +25,12 @@ import LineChart from './shared/LineChart';
import Count from './shared/Count';
import TemplateList from '../../components/TemplateList';
+const StatusSelect = styled(Select)`
+ && {
+ --pf-c-select__toggle--MinWidth: 165px;
+ }
+`;
+
const Counts = styled.div`
display: grid;
grid-template-columns: repeat(6, 1fr);
@@ -57,8 +63,10 @@ const GraphCardActions = styled(CardActions)`
function Dashboard() {
const [isPeriodDropdownOpen, setIsPeriodDropdownOpen] = useState(false);
const [isJobTypeDropdownOpen, setIsJobTypeDropdownOpen] = useState(false);
+ const [isJobStatusDropdownOpen, setIsJobStatusDropdownOpen] = useState(false);
const [periodSelection, setPeriodSelection] = useState('month');
const [jobTypeSelection, setJobTypeSelection] = useState('all');
+ const [jobStatusSelection, setJobStatusSelection] = useState('all');
const [activeTabId, setActiveTabId] = useState(0);
const {
@@ -196,6 +204,9 @@ function Dashboard() {
{t`Past week`}
+
+ {t`Past 24 hours`}
+
+ {
+ setIsJobStatusDropdownOpen(false);
+ setJobStatusSelection(selection);
+ }}
+ selections={jobStatusSelection}
+ isOpen={isJobStatusDropdownOpen}
+ >
+ {t`All jobs`}
+ {t`Successful jobs`}
+ {t`Failed jobs`}
+
', () => {
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);
+ });
});
diff --git a/awx/ui_next/src/screens/Dashboard/shared/LineChart.jsx b/awx/ui_next/src/screens/Dashboard/shared/LineChart.jsx
index ddf9d62458..5b84973059 100644
--- a/awx/ui_next/src/screens/Dashboard/shared/LineChart.jsx
+++ b/awx/ui_next/src/screens/Dashboard/shared/LineChart.jsx
@@ -7,7 +7,7 @@ import { PageContextConsumer } from '@patternfly/react-core';
import ChartTooltip from './ChartTooltip';
-function LineChart({ id, data, height, pageContext }) {
+function LineChart({ id, data, height, pageContext, jobStatus }) {
const { isNavOpen } = pageContext;
// Methods
@@ -197,61 +197,68 @@ function LineChart({ id, data, height, pageContext }) {
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');
- // create our successLine circles
- svg
- .selectAll('dot')
- .data(formattedData)
- .enter()
- .append('circle')
- .attr('r', 3)
- .style('stroke', () => colors(1))
- .style('fill', () => colors(1))
- .attr('cx', d => x(d.DATE))
- .attr('cy', d => y(d.RAN))
- .attr('id', d => `success-dot-${dateFormat(d.DATE)}`)
- .on('mouseover', handleMouseOver)
- .on('mousemove', handleMouseMove)
- .on('mouseout', handleMouseOut);
- // create our failLine 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]);
+ if (jobStatus !== 'failed') {
+ // Add the success line 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);
+
+ // create our success line circles
+
+ svg
+ .selectAll('dot')
+ .data(formattedData)
+ .enter()
+ .append('circle')
+ .attr('r', 3)
+ .style('stroke', () => colors(1))
+ .style('fill', () => colors(1))
+ .attr('cx', d => x(d.DATE))
+ .attr('cy', d => y(d.RAN))
+ .attr('id', d => `success-dot-${dateFormat(d.DATE)}`)
+ .on('mouseover', handleMouseOver)
+ .on('mousemove', handleMouseMove)
+ .on('mouseout', handleMouseOut);
+ }
+
+ 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(() => {
draw();