Merge pull request #9278 from AlexSCorey/PreLingUI-Upgrade-3

Fixes final files in preparation for lingui upgrade

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
This commit is contained in:
softwarefactory-project-zuul[bot]
2021-02-12 22:00:46 +00:00
committed by GitHub
4 changed files with 135 additions and 161 deletions

View File

@@ -1,4 +1,4 @@
import React, { Fragment } from 'react'; import React, { Fragment, useState } from 'react';
import { withRouter } from 'react-router-dom'; import { withRouter } from 'react-router-dom';
import { number, shape } from 'prop-types'; import { number, shape } from 'prop-types';
import { withI18n } from '@lingui/react'; import { withI18n } from '@lingui/react';
@@ -32,40 +32,12 @@ function canLaunchWithoutPrompt(launchData) {
); );
} }
class LaunchButton extends React.Component { function LaunchButton({ resource, i18n, children, history }) {
static propTypes = { const [showLaunchPrompt, setShowLaunchPrompt] = useState(false);
resource: shape({ const [launchConfig, setLaunchConfig] = useState(null);
id: number.isRequired, const [surveyConfig, setSurveyConfig] = useState(null);
}).isRequired, const [error, setError] = useState(null);
}; const handleLaunch = async () => {
constructor(props) {
super(props);
this.state = {
showLaunchPrompt: false,
launchConfig: null,
launchError: false,
surveyConfig: null,
};
this.handleLaunch = this.handleLaunch.bind(this);
this.launchWithParams = this.launchWithParams.bind(this);
this.handleRelaunch = this.handleRelaunch.bind(this);
this.handleLaunchErrorClose = this.handleLaunchErrorClose.bind(this);
this.handlePromptErrorClose = this.handlePromptErrorClose.bind(this);
}
handleLaunchErrorClose() {
this.setState({ launchError: null });
}
handlePromptErrorClose() {
this.setState({ showLaunchPrompt: false });
}
async handleLaunch() {
const { resource } = this.props;
const readLaunch = const readLaunch =
resource.type === 'workflow_job_template' resource.type === 'workflow_job_template'
? WorkflowJobTemplatesAPI.readLaunch(resource.id) ? WorkflowJobTemplatesAPI.readLaunch(resource.id)
@@ -75,33 +47,27 @@ class LaunchButton extends React.Component {
? WorkflowJobTemplatesAPI.readSurvey(resource.id) ? WorkflowJobTemplatesAPI.readSurvey(resource.id)
: JobTemplatesAPI.readSurvey(resource.id); : JobTemplatesAPI.readSurvey(resource.id);
try { try {
const { data: launchConfig } = await readLaunch; const { data: launch } = await readLaunch;
setLaunchConfig(launch);
let surveyConfig = null; if (launch.survey_enabled) {
if (launchConfig.survey_enabled) {
const { data } = await readSurvey; const { data } = await readSurvey;
surveyConfig = data; setSurveyConfig(data);
} }
if (canLaunchWithoutPrompt(launchConfig)) { if (canLaunchWithoutPrompt(launch)) {
this.launchWithParams({}); launchWithParams({});
} else { } else {
this.setState({ setShowLaunchPrompt(true);
showLaunchPrompt: true,
launchConfig,
surveyConfig,
});
} }
} catch (err) { } catch (err) {
this.setState({ launchError: err }); setError(err);
} }
} };
async launchWithParams(params) { const launchWithParams = async params => {
try { try {
const { history, resource } = this.props;
let jobPromise; let jobPromise;
if (resource.type === 'job_template') { if (resource.type === 'job_template') {
@@ -117,13 +83,11 @@ class LaunchButton extends React.Component {
const { data: job } = await jobPromise; const { data: job } = await jobPromise;
history.push(`/jobs/${job.id}/output`); history.push(`/jobs/${job.id}/output`);
} catch (launchError) { } catch (launchError) {
this.setState({ launchError }); setError(launchError);
} }
} };
async handleRelaunch() {
const { history, resource } = this.props;
const handleRelaunch = async () => {
let readRelaunch; let readRelaunch;
let relaunch; let relaunch;
@@ -145,6 +109,7 @@ class LaunchButton extends React.Component {
try { try {
const { data: relaunchConfig } = await readRelaunch; const { data: relaunchConfig } = await readRelaunch;
setLaunchConfig(relaunchConfig);
if ( if (
!relaunchConfig.passwords_needed_to_start || !relaunchConfig.passwords_needed_to_start ||
relaunchConfig.passwords_needed_to_start.length === 0 relaunchConfig.passwords_needed_to_start.length === 0
@@ -165,53 +130,47 @@ class LaunchButton extends React.Component {
const { data: job } = await relaunch; const { data: job } = await relaunch;
history.push(`/jobs/${job.id}/output`); history.push(`/jobs/${job.id}/output`);
} else { } else {
this.setState({ setShowLaunchPrompt(true);
showLaunchPrompt: true,
launchConfig: relaunchConfig,
});
} }
} catch (err) { } catch (err) {
this.setState({ launchError: err }); setError(err);
} }
} };
render() { return (
const { <Fragment>
launchError, {children({
showLaunchPrompt, handleLaunch,
launchConfig, handleRelaunch,
surveyConfig, })}
} = this.state; {error && (
const { resource, i18n, children } = this.props; <AlertModal
return ( isOpen={error}
<Fragment> variant="error"
{children({ title={i18n._(t`Error!`)}
handleLaunch: this.handleLaunch, onClose={() => setError(null)}
handleRelaunch: this.handleRelaunch, >
})} {i18n._(t`Failed to launch job.`)}
{launchError && ( <ErrorDetail error={error} />
<AlertModal </AlertModal>
isOpen={launchError} )}
variant="error" {showLaunchPrompt && (
title={i18n._(t`Error!`)} <LaunchPrompt
onClose={this.handleLaunchErrorClose} launchConfig={launchConfig}
> surveyConfig={surveyConfig}
{i18n._(t`Failed to launch job.`)} resource={resource}
<ErrorDetail error={launchError} /> onLaunch={launchWithParams}
</AlertModal> onCancel={() => setShowLaunchPrompt(false)}
)} />
{showLaunchPrompt && ( )}
<LaunchPrompt </Fragment>
launchConfig={launchConfig} );
surveyConfig={surveyConfig}
resource={resource}
onLaunch={this.launchWithParams}
onCancel={() => this.setState({ showLaunchPrompt: false })}
/>
)}
</Fragment>
);
}
} }
LaunchButton.propTypes = {
resource: shape({
id: number.isRequired,
}).isRequired,
};
export default withI18n()(withRouter(LaunchButton)); export default withI18n()(withRouter(LaunchButton));

View File

@@ -1,5 +1,6 @@
import React from 'react'; import React from 'react';
import { createMemoryHistory } from 'history'; import { createMemoryHistory } from 'history';
import { act } from 'react-dom/test-utils';
import { mountWithContexts } from '../../../testUtils/enzymeHelpers'; import { mountWithContexts } from '../../../testUtils/enzymeHelpers';
import { sleep } from '../../../testUtils/testUtils'; import { sleep } from '../../../testUtils/testUtils';
@@ -69,7 +70,7 @@ describe('LaunchButton', () => {
} }
); );
const button = wrapper.find('button'); const button = wrapper.find('button');
button.prop('onClick')(); await act(() => button.prop('onClick')());
expect(JobTemplatesAPI.readLaunch).toHaveBeenCalledWith(1); expect(JobTemplatesAPI.readLaunch).toHaveBeenCalledWith(1);
await sleep(0); await sleep(0);
expect(JobTemplatesAPI.launch).toHaveBeenCalledWith(1, {}); expect(JobTemplatesAPI.launch).toHaveBeenCalledWith(1, {});
@@ -106,7 +107,7 @@ describe('LaunchButton', () => {
} }
); );
const button = wrapper.find('button'); const button = wrapper.find('button');
button.prop('onClick')(); await act(() => button.prop('onClick')());
expect(WorkflowJobTemplatesAPI.readLaunch).toHaveBeenCalledWith(1); expect(WorkflowJobTemplatesAPI.readLaunch).toHaveBeenCalledWith(1);
await sleep(0); await sleep(0);
expect(WorkflowJobTemplatesAPI.launch).toHaveBeenCalledWith(1, {}); expect(WorkflowJobTemplatesAPI.launch).toHaveBeenCalledWith(1, {});
@@ -143,7 +144,7 @@ describe('LaunchButton', () => {
} }
); );
const button = wrapper.find('button'); const button = wrapper.find('button');
button.prop('onClick')(); await act(() => button.prop('onClick')());
expect(JobsAPI.readRelaunch).toHaveBeenCalledWith(1); expect(JobsAPI.readRelaunch).toHaveBeenCalledWith(1);
await sleep(0); await sleep(0);
expect(JobsAPI.relaunch).toHaveBeenCalledWith(1); expect(JobsAPI.relaunch).toHaveBeenCalledWith(1);
@@ -180,7 +181,7 @@ describe('LaunchButton', () => {
} }
); );
const button = wrapper.find('button'); const button = wrapper.find('button');
button.prop('onClick')(); await act(() => button.prop('onClick')());
expect(WorkflowJobsAPI.readRelaunch).toHaveBeenCalledWith(1); expect(WorkflowJobsAPI.readRelaunch).toHaveBeenCalledWith(1);
await sleep(0); await sleep(0);
expect(WorkflowJobsAPI.relaunch).toHaveBeenCalledWith(1); expect(WorkflowJobsAPI.relaunch).toHaveBeenCalledWith(1);
@@ -218,7 +219,7 @@ describe('LaunchButton', () => {
} }
); );
const button = wrapper.find('button'); const button = wrapper.find('button');
button.prop('onClick')(); await act(() => button.prop('onClick')());
expect(ProjectsAPI.readLaunchUpdate).toHaveBeenCalledWith(5); expect(ProjectsAPI.readLaunchUpdate).toHaveBeenCalledWith(5);
await sleep(0); await sleep(0);
expect(ProjectsAPI.launchUpdate).toHaveBeenCalledWith(5); expect(ProjectsAPI.launchUpdate).toHaveBeenCalledWith(5);
@@ -256,7 +257,7 @@ describe('LaunchButton', () => {
} }
); );
const button = wrapper.find('button'); const button = wrapper.find('button');
button.prop('onClick')(); await act(() => button.prop('onClick')());
expect(InventorySourcesAPI.readLaunchUpdate).toHaveBeenCalledWith(5); expect(InventorySourcesAPI.readLaunchUpdate).toHaveBeenCalledWith(5);
await sleep(0); await sleep(0);
expect(InventorySourcesAPI.launchUpdate).toHaveBeenCalledWith(5); expect(InventorySourcesAPI.launchUpdate).toHaveBeenCalledWith(5);
@@ -280,7 +281,7 @@ describe('LaunchButton', () => {
}) })
); );
expect(wrapper.find('Modal').length).toBe(0); expect(wrapper.find('Modal').length).toBe(0);
wrapper.find('button').prop('onClick')(); await act(() => wrapper.find('button').prop('onClick')());
await sleep(0); await sleep(0);
wrapper.update(); wrapper.update();
expect(wrapper.find('Modal').length).toBe(1); expect(wrapper.find('Modal').length).toBe(1);

View File

@@ -123,6 +123,7 @@ function Lookup(props) {
</ChipGroup> </ChipGroup>
</ChipHolder> </ChipHolder>
</InputGroup> </InputGroup>
<Modal <Modal
variant="large" variant="large"
title={i18n._(t`Select ${header || i18n._(t`Items`)}`)} title={i18n._(t`Select ${header || i18n._(t`Items`)}`)}
@@ -138,7 +139,12 @@ function Lookup(props) {
> >
{i18n._(t`Select`)} {i18n._(t`Select`)}
</Button>, </Button>,
<Button key="cancel" variant="link" onClick={closeModal}> <Button
key="cancel"
variant="link"
onClick={closeModal}
aria-label={i18n._(t`Cancel lookup`)}
>
{i18n._(t`Cancel`)} {i18n._(t`Cancel`)}
</Button>, </Button>,
]} ]}

View File

@@ -1,6 +1,6 @@
import React, { Component, Fragment } from 'react'; import React, { Component, Fragment } from 'react';
import { withRouter } from 'react-router-dom'; import { withRouter } from 'react-router-dom';
import { withI18n } from '@lingui/react'; import { I18n } from '@lingui/react';
import { t } from '@lingui/macro'; import { t } from '@lingui/macro';
import styled from 'styled-components'; import styled from 'styled-components';
import { import {
@@ -578,7 +578,7 @@ class JobOutput extends Component {
} }
render() { render() {
const { job, i18n } = this.props; const { job } = this.props;
const { const {
contentError, contentError,
@@ -666,64 +666,72 @@ class JobOutput extends Component {
</CardBody> </CardBody>
{showCancelPrompt && {showCancelPrompt &&
['pending', 'waiting', 'running'].includes(jobStatus) && ( ['pending', 'waiting', 'running'].includes(jobStatus) && (
<AlertModal <I18n>
isOpen={showCancelPrompt} {({ i18n }) => (
variant="danger" <AlertModal
onClose={this.handleCancelClose} isOpen={showCancelPrompt}
title={i18n._(t`Cancel Job`)}
label={i18n._(t`Cancel Job`)}
actions={[
<Button
id="cancel-job-confirm-button"
key="delete"
variant="danger" variant="danger"
isDisabled={cancelInProgress} onClose={this.handleCancelClose}
aria-label={i18n._(t`Cancel job`)} title={i18n._(t`Cancel Job`)}
onClick={this.handleCancelConfirm} label={i18n._(t`Cancel Job`)}
actions={[
<Button
id="cancel-job-confirm-button"
key="delete"
variant="danger"
isDisabled={cancelInProgress}
aria-label={i18n._(t`Cancel job`)}
onClick={this.handleCancelConfirm}
>
{i18n._(t`Cancel job`)}
</Button>,
<Button
id="cancel-job-return-button"
key="cancel"
variant="secondary"
aria-label={i18n._(t`Return`)}
onClick={this.handleCancelClose}
>
{i18n._(t`Return`)}
</Button>,
]}
> >
{i18n._(t`Cancel job`)} {i18n._(
</Button>, t`Are you sure you want to submit the request to cancel this job?`
<Button )}
id="cancel-job-return-button" </AlertModal>
key="cancel"
variant="secondary"
aria-label={i18n._(t`Return`)}
onClick={this.handleCancelClose}
>
{i18n._(t`Return`)}
</Button>,
]}
>
{i18n._(
t`Are you sure you want to submit the request to cancel this job?`
)} )}
</AlertModal> </I18n>
)} )}
{cancelError && ( {cancelError && (
<> <I18n>
<AlertModal {({ i18n }) => (
isOpen={cancelError} <AlertModal
variant="danger" isOpen={cancelError}
onClose={() => this.setState({ cancelError: null })} variant="danger"
title={i18n._(t`Job Cancel Error`)} onClose={() => this.setState({ cancelError: null })}
label={i18n._(t`Job Cancel Error`)} title={i18n._(t`Job Cancel Error`)}
> label={i18n._(t`Job Cancel Error`)}
<ErrorDetail error={cancelError} /> >
</AlertModal> <ErrorDetail error={cancelError} />
</> </AlertModal>
)}
</I18n>
)} )}
{deletionError && ( {deletionError && (
<> <I18n>
<AlertModal {({ i18n }) => (
isOpen={deletionError} <AlertModal
variant="danger" isOpen={deletionError}
onClose={() => this.setState({ deletionError: null })} variant="danger"
title={i18n._(t`Job Delete Error`)} onClose={() => this.setState({ deletionError: null })}
label={i18n._(t`Job Delete Error`)} title={i18n._(t`Job Delete Error`)}
> label={i18n._(t`Job Delete Error`)}
<ErrorDetail error={deletionError} /> >
</AlertModal> <ErrorDetail error={deletionError} />
</> </AlertModal>
)}
</I18n>
)} )}
</Fragment> </Fragment>
); );
@@ -731,4 +739,4 @@ class JobOutput extends Component {
} }
export { JobOutput as _JobOutput }; export { JobOutput as _JobOutput };
export default withI18n()(withRouter(JobOutput)); export default withRouter(JobOutput);