Skip to content

Commit

Permalink
Fixes #37447 - Add rerun job error
Browse files Browse the repository at this point in the history
  • Loading branch information
kmalyjur authored and adamruzicka committed Aug 19, 2024
1 parent f237a8c commit f32a8bb
Show file tree
Hide file tree
Showing 4 changed files with 95 additions and 17 deletions.
96 changes: 80 additions & 16 deletions webpack/JobWizard/JobWizardPageRerun.js
Original file line number Diff line number Diff line change
@@ -1,16 +1,33 @@
import React, { useState, useEffect } from 'react';
import PropTypes from 'prop-types';
import React from 'react';
import URI from 'urijs';
import { Alert, Button, Divider, Skeleton } from '@patternfly/react-core';
import { useDispatch, useSelector } from 'react-redux';
import {
Alert,
Divider,
Skeleton,
Button,
Title,
EmptyState,
EmptyStateVariant,
EmptyStateIcon,
EmptyStateBody,
} from '@patternfly/react-core';
import { ExclamationCircleIcon } from '@patternfly/react-icons';
import { global_palette_red_200 as exclamationColor } from '@patternfly/react-tokens';
import { get } from 'foremanReact/redux/API';
import { sprintf, translate as __ } from 'foremanReact/common/I18n';
import PageLayout from 'foremanReact/routes/common/PageLayout/PageLayout';
import { STATUS } from 'foremanReact/constants';
import {
useForemanLocation,
useForemanOrganization,
} from 'foremanReact/Root/Context/ForemanContext';
import { translate as __, sprintf } from 'foremanReact/common/I18n';
import { useAPI } from 'foremanReact/common/hooks/API/APIHooks';
import { STATUS } from 'foremanReact/constants';
import PageLayout from 'foremanReact/routes/common/PageLayout/PageLayout';
import { JobWizard } from './JobWizard';
import {
selectRerunJobInvocationResponse,
selectRerunJobInvocationStatus,
} from './JobWizardSelectors';
import { JOB_API_KEY } from './JobWizardConstants';

const JobWizardPageRerun = ({
Expand All @@ -19,6 +36,7 @@ const JobWizardPageRerun = ({
},
location: { search },
}) => {
const dispatch = useDispatch();
const uri = new URI(search);
const { failed_only: failedOnly } = uri.search(true);
const { succeeded_only: succeededOnly } = uri.search(true);
Expand All @@ -28,11 +46,6 @@ const JobWizardPageRerun = ({
} else if (succeededOnly) {
queryParams = '&succeeded_only=1';
}
const { response, status } = useAPI(
'get',
`/ui_job_wizard/job_invocation?id=${id}${queryParams}`,
JOB_API_KEY
);
const title = __('Run job');
const breadcrumbOptions = {
breadcrumbItems: [
Expand All @@ -41,11 +54,55 @@ const JobWizardPageRerun = ({
],
};

const jobOrganization = response.job_organization;
const jobLocation = response.job_location;
const [errorMessage, setErrorMessage] = useState('');
const jobInvocationResponse = useSelector(selectRerunJobInvocationResponse);
const jobInvocationStatus = useSelector(selectRerunJobInvocationStatus);
const jobOrganization = jobInvocationResponse.job_organization;
const jobLocation = jobInvocationResponse.job_location;
const currentOrganization = useForemanOrganization();
const currentLocation = useForemanLocation();

const emptyStateLarge = (
<EmptyState variant={EmptyStateVariant.large}>
<EmptyStateIcon
icon={ExclamationCircleIcon}
color={exclamationColor.value}
/>
<Title ouiaId="job-wizard-empty-state-header" headingLevel="h4" size="lg">
{__('Unable to run job')}
</Title>
<EmptyStateBody>{sprintf(errorMessage)}</EmptyStateBody>
<Button
ouiaId="job-wizard-run-job-button"
component="a"
href="/job_invocations/new"
variant="primary"
>
{__('Create job')}
</Button>
</EmptyState>
);

useEffect(() => {
let isMounted = true;
if (id !== undefined) {
dispatch(
get({
key: JOB_API_KEY,
url: `/ui_job_wizard/job_invocation?id=${id}${queryParams}`,
handleError: ({ response }) => {
if (isMounted) {
setErrorMessage(response?.data?.error?.message);
}
},
})
);
}
return () => {
isMounted = false;
};
}, [dispatch, id, failedOnly, queryParams]);

return (
<PageLayout
header={title}
Expand All @@ -66,14 +123,16 @@ const JobWizardPageRerun = ({
<React.Fragment>
<Divider component="div" />
</React.Fragment>
{!status || status === STATUS.PENDING ? (
{jobInvocationStatus === STATUS.ERROR && emptyStateLarge}
{(!jobInvocationStatus || jobInvocationStatus === STATUS.PENDING) && (
<div style={{ height: '400px' }}>
<Skeleton
height="100%"
screenreaderText="Loading large rectangle contents"
/>
</div>
) : (
)}
{jobInvocationStatus === STATUS.RESOLVED && (
<React.Fragment>
{jobOrganization?.id !== currentOrganization?.id && (
<Alert
Expand Down Expand Up @@ -107,7 +166,12 @@ const JobWizardPageRerun = ({
)}
<Divider component="div" />
<JobWizard
rerunData={{ ...response?.job, inputs: response?.inputs } || null}
rerunData={
{
...jobInvocationResponse?.job,
inputs: jobInvocationResponse?.inputs,
} || null
}
/>
</React.Fragment>
)}
Expand Down
7 changes: 7 additions & 0 deletions webpack/JobWizard/JobWizardSelectors.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,15 @@ import {
JOB_TEMPLATE,
HOSTS_API,
JOB_INVOCATION,
JOB_API_KEY,
} from './JobWizardConstants';

export const selectRerunJobInvocationResponse = state =>
selectAPIResponse(state, JOB_API_KEY) || {};

export const selectRerunJobInvocationStatus = state =>
selectAPIStatus(state, JOB_API_KEY);

export const selectJobTemplatesStatus = state =>
selectAPIStatus(state, JOB_TEMPLATES);

Expand Down
6 changes: 6 additions & 0 deletions webpack/JobWizard/__tests__/fixtures.js
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,8 @@ export const jobCategories = ['Services', 'Ansible Commands', 'Puppet'];

export const testSetup = (selectors, api) => {
jest.spyOn(api, 'get');
jest.spyOn(selectors, 'selectRerunJobInvocationResponse');
jest.spyOn(selectors, 'selectRerunJobInvocationStatus');
jest.spyOn(selectors, 'selectJobTemplate');
jest.spyOn(selectors, 'selectJobTemplates');
jest.spyOn(selectors, 'selectJobCategories');
Expand All @@ -123,6 +125,10 @@ export const testSetup = (selectors, api) => {

jest.spyOn(selectors, 'selectTemplateInputs');
jest.spyOn(selectors, 'selectAdvancedTemplateInputs');
selectors.selectRerunJobInvocationResponse.mockImplementation(
() => jobInvocation
);
selectors.selectRerunJobInvocationStatus.mockImplementation(() => 'RESOLVED');
selectors.selectWithKatello.mockImplementation(() => true);
selectors.selectTemplateInputs.mockImplementation(
() => jobTemplateResponse.template_inputs
Expand Down
3 changes: 2 additions & 1 deletion webpack/JobWizard/steps/ReviewDetails/ReviewDetails.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,16 +14,17 @@ import {
jobInvocation,
} from '../../__tests__/fixtures';

jest.useFakeTimers();
const store = testSetup(selectors, api);
mockApi(api);
jest.spyOn(APIHooks, 'useAPI');
store.dispatch = jest.fn();
APIHooks.useAPI.mockImplementation((action, url) => {
if (url === '/ui_job_wizard/job_invocation?id=57') {
return { response: jobInvocation, status: 'RESOLVED' };
}
return {};
});
jest.useFakeTimers();

describe('ReviewDetails', () => {
it('should call goToStepByName function when StepButton is clicked', async () => {
Expand Down

0 comments on commit f32a8bb

Please sign in to comment.