mirror of
https://github.com/ansible/awx.git
synced 2026-02-18 19:50:05 -03:30
Adds sparkline to templates list
This commit is contained in:
@@ -353,7 +353,7 @@ function projectsListController (
|
|||||||
};
|
};
|
||||||
|
|
||||||
function buildTooltips (project) {
|
function buildTooltips (project) {
|
||||||
project.statusIcon = getStatusIcon(project);
|
project.statusIcon = getJobStatusIcon(project);
|
||||||
project.statusTip = getStatusTooltip(project);
|
project.statusTip = getStatusTooltip(project);
|
||||||
project.scm_update_tooltip = vm.strings.get('update.GET_LATEST');
|
project.scm_update_tooltip = vm.strings.get('update.GET_LATEST');
|
||||||
project.scm_update_disabled = false;
|
project.scm_update_disabled = false;
|
||||||
@@ -408,7 +408,7 @@ function projectsListController (
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
function getStatusIcon (project) {
|
function getJobStatusIcon (project) {
|
||||||
let icon = 'none';
|
let icon = 'none';
|
||||||
switch (project.status) {
|
switch (project.status) {
|
||||||
case 'n/a':
|
case 'n/a':
|
||||||
|
|||||||
128
awx/ui_next/src/components/Sparkline/JobStatusIcon.jsx
Normal file
128
awx/ui_next/src/components/Sparkline/JobStatusIcon.jsx
Normal file
@@ -0,0 +1,128 @@
|
|||||||
|
import React, { Fragment } from 'react';
|
||||||
|
import { node, object, string } from 'prop-types';
|
||||||
|
import { Link } from 'react-router-dom';
|
||||||
|
import styled, { keyframes } from 'styled-components';
|
||||||
|
import { Tooltip } from '@patternfly/react-core';
|
||||||
|
|
||||||
|
const Pulse = keyframes`
|
||||||
|
from {
|
||||||
|
-webkit-transform:scale(1);
|
||||||
|
}
|
||||||
|
to {
|
||||||
|
-webkit-transform:scale(0);
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
const Wrapper = styled.div`
|
||||||
|
width: 14px;
|
||||||
|
height: 14px;
|
||||||
|
`;
|
||||||
|
|
||||||
|
const RunningJob = styled(Wrapper)`
|
||||||
|
background-color: #5cb85c;
|
||||||
|
padding-right: 0px;
|
||||||
|
text-shadow:
|
||||||
|
-1px -1px 0 #ffffff,
|
||||||
|
1px -1px 0 #ffffff,
|
||||||
|
-1px 1px 0 #ffffff,
|
||||||
|
1px 1px 0 #ffffff;
|
||||||
|
animation: ${Pulse} 1.5s linear infinite alternate;
|
||||||
|
`;
|
||||||
|
|
||||||
|
const WaitingJob = styled(Wrapper)`
|
||||||
|
border: 1px solid #d7d7d7;
|
||||||
|
`;
|
||||||
|
|
||||||
|
const FinishedJob = styled(Wrapper)`
|
||||||
|
flex: 0 1 auto;
|
||||||
|
> * {
|
||||||
|
width: 14px;
|
||||||
|
height: 7px;
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
const SuccessfulTop = styled.div`
|
||||||
|
background-color: #5cb85c;
|
||||||
|
`;
|
||||||
|
|
||||||
|
const SuccessfulBottom = styled.div`
|
||||||
|
border: 1px solid #b7b7b7;
|
||||||
|
border-top: 0;
|
||||||
|
background: #ffffff;
|
||||||
|
`;
|
||||||
|
|
||||||
|
const FailedTop = styled.div`
|
||||||
|
border: 1px solid #b7b7b7;
|
||||||
|
border-bottom: 0;
|
||||||
|
background: #ffffff;
|
||||||
|
`;
|
||||||
|
|
||||||
|
const FailedBottom = styled.div`
|
||||||
|
background-color: #D9534F;
|
||||||
|
`;
|
||||||
|
|
||||||
|
const JobStatusIcon = ({ job, link, tooltip, ...props }) => {
|
||||||
|
let Icon = (
|
||||||
|
<Fragment>
|
||||||
|
{ job.status === 'running' && <RunningJob /> }
|
||||||
|
{ (job.status === 'new'
|
||||||
|
|| job.status === 'pending'
|
||||||
|
|| job.status === 'waiting')
|
||||||
|
&& <WaitingJob />
|
||||||
|
}
|
||||||
|
{ (job.status === 'failed'
|
||||||
|
|| job.status === 'error'
|
||||||
|
|| job.status === 'canceled')
|
||||||
|
&& (
|
||||||
|
<FinishedJob>
|
||||||
|
<FailedTop />
|
||||||
|
<FailedBottom />
|
||||||
|
</FinishedJob>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
{ job.status === 'successful' && (
|
||||||
|
<FinishedJob>
|
||||||
|
<SuccessfulTop />
|
||||||
|
<SuccessfulBottom />
|
||||||
|
</FinishedJob>
|
||||||
|
)}
|
||||||
|
</Fragment>
|
||||||
|
);
|
||||||
|
|
||||||
|
if (link) {
|
||||||
|
Icon = (
|
||||||
|
<Link to={link}>
|
||||||
|
{Icon}
|
||||||
|
</Link>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tooltip) {
|
||||||
|
return (
|
||||||
|
<div {...props}>
|
||||||
|
<Tooltip position="top" content={tooltip}>
|
||||||
|
{Icon}
|
||||||
|
</Tooltip>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div {...props}>
|
||||||
|
{Icon}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
JobStatusIcon.propTypes = {
|
||||||
|
job: object.isRequired,
|
||||||
|
link: string,
|
||||||
|
tooltip: node
|
||||||
|
};
|
||||||
|
|
||||||
|
JobStatusIcon.defaultProps = {
|
||||||
|
link: null,
|
||||||
|
tooltip: null,
|
||||||
|
};
|
||||||
|
|
||||||
|
export default JobStatusIcon;
|
||||||
41
awx/ui_next/src/components/Sparkline/Sparkline.jsx
Normal file
41
awx/ui_next/src/components/Sparkline/Sparkline.jsx
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
import React, { Fragment } from 'react';
|
||||||
|
import { arrayOf, object } from 'prop-types';
|
||||||
|
import { withI18n } from '@lingui/react';
|
||||||
|
import { JobStatusIcon as _JobStatusIcon } from '@components/Sparkline';
|
||||||
|
import styled from 'styled-components';
|
||||||
|
import { t } from '@lingui/macro';
|
||||||
|
import { JOB_TYPE_URL_SEGMENTS } from '../../constants';
|
||||||
|
|
||||||
|
const JobStatusIcon = styled(props => <_JobStatusIcon {...props} />)`
|
||||||
|
margin-right: 5px;
|
||||||
|
`;
|
||||||
|
|
||||||
|
const Sparkline = ({ i18n, jobs }) => {
|
||||||
|
const generateTooltip = (job) => (
|
||||||
|
<Fragment>
|
||||||
|
<div>{i18n._(t`JOB ID:`)} {job.id}</div>
|
||||||
|
<div>{i18n._(t`STATUS:`)} {job.status.toUpperCase()}</div>
|
||||||
|
<div>{i18n._(t`FINISHED:`)} {job.finished}</div>
|
||||||
|
</Fragment>
|
||||||
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
|
(jobs.map(job => (
|
||||||
|
<JobStatusIcon
|
||||||
|
key={job.id}
|
||||||
|
job={job}
|
||||||
|
link={`/jobs/${JOB_TYPE_URL_SEGMENTS[job.type]}/${job.id}`}
|
||||||
|
tooltip={generateTooltip(job)}
|
||||||
|
/>
|
||||||
|
)))
|
||||||
|
)
|
||||||
|
};
|
||||||
|
|
||||||
|
Sparkline.propTypes = {
|
||||||
|
jobs: arrayOf(object),
|
||||||
|
};
|
||||||
|
Sparkline.defaultProps = {
|
||||||
|
jobs: [],
|
||||||
|
};
|
||||||
|
|
||||||
|
export default withI18n()(Sparkline);
|
||||||
2
awx/ui_next/src/components/Sparkline/index.js
Normal file
2
awx/ui_next/src/components/Sparkline/index.js
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
export { default as Sparkline } from './Sparkline';
|
||||||
|
export { default as JobStatusIcon } from './JobStatusIcon';
|
||||||
@@ -15,7 +15,7 @@ import RoutedTabs from '@components/RoutedTabs';
|
|||||||
|
|
||||||
import JobDetail from './JobDetail';
|
import JobDetail from './JobDetail';
|
||||||
import JobOutput from './JobOutput';
|
import JobOutput from './JobOutput';
|
||||||
import { JOB_TYPE_URL_SEGMENTS } from './constants';
|
import { JOB_TYPE_URL_SEGMENTS } from '../../constants';
|
||||||
|
|
||||||
class Job extends Component {
|
class Job extends Component {
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ import {
|
|||||||
import DataListCell from '@components/DataListCell';
|
import DataListCell from '@components/DataListCell';
|
||||||
import VerticalSeparator from '@components/VerticalSeparator';
|
import VerticalSeparator from '@components/VerticalSeparator';
|
||||||
import { toTitleCase } from '@util/strings';
|
import { toTitleCase } from '@util/strings';
|
||||||
import { JOB_TYPE_URL_SEGMENTS } from '../constants';
|
import { JOB_TYPE_URL_SEGMENTS } from '../../../constants';
|
||||||
|
|
||||||
class JobListItem extends Component {
|
class JobListItem extends Component {
|
||||||
render() {
|
render() {
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import React, { Component } from 'react';
|
import React, { Component } from 'react';
|
||||||
import { Redirect } from 'react-router-dom';
|
import { Redirect } from 'react-router-dom';
|
||||||
import { UnifiedJobsAPI } from '@api';
|
import { UnifiedJobsAPI } from '@api';
|
||||||
import { JOB_TYPE_URL_SEGMENTS } from './constants';
|
import { JOB_TYPE_URL_SEGMENTS } from '../../constants';
|
||||||
|
|
||||||
class JobTypeRedirect extends Component {
|
class JobTypeRedirect extends Component {
|
||||||
static defaultProps = {
|
static defaultProps = {
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import Breadcrumbs from '@components/Breadcrumbs/Breadcrumbs';
|
|||||||
import Job from './Job';
|
import Job from './Job';
|
||||||
import JobTypeRedirect from './JobTypeRedirect';
|
import JobTypeRedirect from './JobTypeRedirect';
|
||||||
import JobList from './JobList/JobList';
|
import JobList from './JobList/JobList';
|
||||||
import { JOB_TYPE_URL_SEGMENTS } from './constants';
|
import { JOB_TYPE_URL_SEGMENTS } from '../../constants';
|
||||||
|
|
||||||
class Jobs extends Component {
|
class Jobs extends Component {
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ import styled from 'styled-components';
|
|||||||
import DataListCell from '@components/DataListCell';
|
import DataListCell from '@components/DataListCell';
|
||||||
import LaunchButton from '@components/LaunchButton';
|
import LaunchButton from '@components/LaunchButton';
|
||||||
import VerticalSeparator from '@components/VerticalSeparator';
|
import VerticalSeparator from '@components/VerticalSeparator';
|
||||||
|
import { Sparkline } from '@components/Sparkline';
|
||||||
import { toTitleCase } from '@util/strings';
|
import { toTitleCase } from '@util/strings';
|
||||||
|
|
||||||
const StyledButton = styled(PFButton)`
|
const StyledButton = styled(PFButton)`
|
||||||
@@ -56,6 +57,11 @@ class TemplateListItem extends Component {
|
|||||||
<DataListCell key="type">
|
<DataListCell key="type">
|
||||||
{toTitleCase(template.type)}
|
{toTitleCase(template.type)}
|
||||||
</DataListCell>,
|
</DataListCell>,
|
||||||
|
<DataListCell key="sparkline">
|
||||||
|
<Sparkline
|
||||||
|
jobs={template.summary_fields.recent_jobs}
|
||||||
|
/>
|
||||||
|
</DataListCell>,
|
||||||
<DataListCell lastcolumn="true" key="launch">
|
<DataListCell lastcolumn="true" key="launch">
|
||||||
{canLaunch && template.type === 'job_template' && (
|
{canLaunch && template.type === 'job_template' && (
|
||||||
<Tooltip content={i18n._(t`Launch`)} position="top">
|
<Tooltip content={i18n._(t`Launch`)} position="top">
|
||||||
|
|||||||
Reference in New Issue
Block a user