Merge pull request #4251 from AlexSCorey/JTLaunchButton

Add Launch Button to Job Template Details

Reviewed-by: https://github.com/softwarefactory-project-zuul[bot]
This commit is contained in:
softwarefactory-project-zuul[bot]
2019-07-09 20:58:46 +00:00
committed by GitHub
4 changed files with 75 additions and 47 deletions

View File

@@ -1,9 +1,6 @@
import React, { Fragment } from 'react'; import React, { Fragment } from 'react';
import { withRouter } from 'react-router-dom'; import { withRouter } from 'react-router-dom';
import { number } from 'prop-types'; import { number } from 'prop-types';
import { Button, Tooltip } from '@patternfly/react-core';
import { RocketIcon } from '@patternfly/react-icons';
import styled from 'styled-components';
import { withI18n } from '@lingui/react'; import { withI18n } from '@lingui/react';
import { t } from '@lingui/macro'; import { t } from '@lingui/macro';
@@ -11,15 +8,6 @@ import AlertModal from '@components/AlertModal';
import ErrorDetail from '@components/ErrorDetail'; import ErrorDetail from '@components/ErrorDetail';
import { JobTemplatesAPI } from '@api'; import { JobTemplatesAPI } from '@api';
const StyledLaunchButton = styled(Button)`
padding: 5px 8px;
&:hover {
background-color: #0066cc;
color: white;
}
`;
class LaunchButton extends React.Component { class LaunchButton extends React.Component {
static propTypes = { static propTypes = {
templateId: number.isRequired, templateId: number.isRequired,
@@ -65,20 +53,10 @@ class LaunchButton extends React.Component {
render() { render() {
const { launchError, promptError } = this.state; const { launchError, promptError } = this.state;
const { i18n } = this.props; const { i18n, children } = this.props;
return ( return (
<Fragment> <Fragment>
<Tooltip content={i18n._(t`Launch Job`)} position="top"> {children(this.handleLaunch)}
<div>
<StyledLaunchButton
variant="plain"
aria-label={i18n._(t`Launch`)}
onClick={this.handleLaunch}
>
<RocketIcon />
</StyledLaunchButton>
</div>
</Tooltip>
<AlertModal <AlertModal
isOpen={launchError} isOpen={launchError}
variant="danger" variant="danger"

View File

@@ -13,9 +13,14 @@ describe('LaunchButton', () => {
can_start_without_user_input: true, can_start_without_user_input: true,
}, },
}); });
const children = handleLaunch => (
<button type="submit" onClick={handleLaunch} />
);
test('renders the expected content', () => { test('renders the expected content', () => {
const wrapper = mountWithContexts(<LaunchButton templateId={1} />); const wrapper = mountWithContexts(
<LaunchButton templateId={1}>{children}</LaunchButton>
);
expect(wrapper).toHaveLength(1); expect(wrapper).toHaveLength(1);
}); });
test('redirects to details after successful launch', async done => { test('redirects to details after successful launch', async done => {
@@ -27,15 +32,18 @@ describe('LaunchButton', () => {
id: 9000, id: 9000,
}, },
}); });
const wrapper = mountWithContexts(<LaunchButton templateId={1} />, { const wrapper = mountWithContexts(
context: { <LaunchButton templateId={1}>{children}</LaunchButton>,
router: { history }, {
}, context: {
}); router: { history },
const launchButton = wrapper.find('LaunchButton__StyledLaunchButton'); },
launchButton.simulate('click'); }
await sleep(0); );
const button = wrapper.find('button');
button.prop('onClick')();
expect(JobTemplatesAPI.readLaunch).toHaveBeenCalledWith(1); expect(JobTemplatesAPI.readLaunch).toHaveBeenCalledWith(1);
await sleep(0);
expect(JobTemplatesAPI.launch).toHaveBeenCalledWith(1); expect(JobTemplatesAPI.launch).toHaveBeenCalledWith(1);
expect(history.push).toHaveBeenCalledWith('/jobs/9000/details'); expect(history.push).toHaveBeenCalledWith('/jobs/9000/details');
done(); done();
@@ -53,9 +61,11 @@ describe('LaunchButton', () => {
}, },
}) })
); );
const wrapper = mountWithContexts(<LaunchButton templateId={1} />); const wrapper = mountWithContexts(
const launchButton = wrapper.find('LaunchButton__StyledLaunchButton'); <LaunchButton templateId={1}>{children}</LaunchButton>
launchButton.simulate('click'); );
const button = wrapper.find('button');
button.prop('onClick')();
await waitForElement( await waitForElement(
wrapper, wrapper,
'Modal.at-c-alertModal--danger', 'Modal.at-c-alertModal--danger',

View File

@@ -13,6 +13,7 @@ import styled from 'styled-components';
import { t } from '@lingui/macro'; import { t } from '@lingui/macro';
import ContentError from '@components/ContentError'; import ContentError from '@components/ContentError';
import LaunchButton from '@components/LaunchButton';
import ContentLoading from '@components/ContentLoading'; import ContentLoading from '@components/ContentLoading';
import { ChipGroup, Chip } from '@components/Chip'; import { ChipGroup, Chip } from '@components/Chip';
import { DetailList, Detail } from '@components/DetailList'; import { DetailList, Detail } from '@components/DetailList';
@@ -83,9 +84,11 @@ class JobTemplateDetail extends Component {
verbosity, verbosity,
}, },
hasTemplateLoading, hasTemplateLoading,
template,
i18n, i18n,
match, match,
} = this.props; } = this.props;
const canLaunch = summary_fields.user_capabilities.start;
const { instanceGroups, hasContentLoading, contentError } = this.state; const { instanceGroups, hasContentLoading, contentError } = this.state;
const verbosityOptions = [ const verbosityOptions = [
{ verbosity: 0, details: i18n._(t`0 (Normal)`) }, { verbosity: 0, details: i18n._(t`0 (Normal)`) },
@@ -286,14 +289,25 @@ class JobTemplateDetail extends Component {
{i18n._(t`Edit`)} {i18n._(t`Edit`)}
</Button> </Button>
)} )}
<Button {canLaunch && (
variant="secondary" <LaunchButton
component={Link} variant="secondary"
to="/templates" component={Link}
aria-label={i18n._(t`Launch`)} to="/templates"
> templateId={template.id}
{i18n._(t`Launch`)} aria-label={i18n._(t`Launch`)}
</Button> >
{handleLaunch => (
<Button
variant="secondary"
type="submit"
onClick={handleLaunch}
>
{i18n._(t`Launch`)}
</Button>
)}
</LaunchButton>
)}
<Button <Button
variant="secondary" variant="secondary"
component={Link} component={Link}

View File

@@ -5,16 +5,30 @@ import {
DataListItemRow, DataListItemRow,
DataListItemCells, DataListItemCells,
DataListCheck, DataListCheck,
Tooltip,
Button as PFButton,
} from '@patternfly/react-core'; } from '@patternfly/react-core';
import { t } from '@lingui/macro';
import { withI18n } from '@lingui/react';
import { RocketIcon } from '@patternfly/react-icons';
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 { toTitleCase } from '@util/strings'; import { toTitleCase } from '@util/strings';
const StyledButton = styled(PFButton)`
padding: 5px 8px;
border: none;
&:hover {
background-color: #0066cc;
color: white;
}
`;
class TemplateListItem extends Component { class TemplateListItem extends Component {
render() { render() {
const { template, isSelected, onSelect } = this.props; const { i18n, template, isSelected, onSelect } = this.props;
const canLaunch = template.summary_fields.user_capabilities.start; const canLaunch = template.summary_fields.user_capabilities.start;
return ( return (
@@ -44,7 +58,19 @@ class TemplateListItem extends Component {
</DataListCell>, </DataListCell>,
<DataListCell lastcolumn="true" key="launch"> <DataListCell lastcolumn="true" key="launch">
{canLaunch && template.type === 'job_template' && ( {canLaunch && template.type === 'job_template' && (
<LaunchButton templateId={template.id} /> <Tooltip content={i18n._(t`Launch`)} position="top">
<LaunchButton
component={Link}
to="/templates"
templateId={template.id}
>
{handleLaunch => (
<StyledButton variant="plain" onClick={handleLaunch}>
<RocketIcon />
</StyledButton>
)}
</LaunchButton>
</Tooltip>
)} )}
</DataListCell>, </DataListCell>,
]} ]}
@@ -55,4 +81,4 @@ class TemplateListItem extends Component {
} }
} }
export { TemplateListItem as _TemplateListItem }; export { TemplateListItem as _TemplateListItem };
export default TemplateListItem; export default withI18n()(TemplateListItem);