Merge pull request #9439 from mabashian/9410-workflow-node-disable-jt

Disable job templates in node modal that are missing inv or project

Reviewed-by: Mat Wilson <mawilson@redhat.com>
             https://github.com/one-t
This commit is contained in:
softwarefactory-project-zuul[bot] 2021-03-09 19:41:18 +00:00 committed by GitHub
commit 5bdf9a108c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 138 additions and 16 deletions

View File

@ -1,5 +1,6 @@
import React from 'react';
import PropTypes from 'prop-types';
import styled from 'styled-components';
import {
DataListItem,
DataListItemRow,
@ -9,6 +10,14 @@ import {
} from '@patternfly/react-core';
import DataListCell from '../DataListCell';
const Label = styled.label`
${({ isDisabled }) =>
isDisabled &&
`
opacity: 0.5;
`}
`;
const CheckboxListItem = ({
isDisabled = false,
isRadio = false,
@ -32,7 +41,7 @@ const CheckboxListItem = ({
aria-label={`check-action-item-${itemId}`}
aria-labelledby={`check-action-item-${itemId}`}
checked={isSelected}
disabled={isDisabled}
isDisabled={isDisabled}
id={`selected-${itemId}`}
isChecked={isSelected}
name={name}
@ -42,13 +51,14 @@ const CheckboxListItem = ({
<DataListItemCells
dataListCells={[
<DataListCell key="name">
<label
<Label
id={`check-action-item-${itemId}`}
htmlFor={`selected-${itemId}`}
className="check-action-item"
isDisabled={isDisabled}
>
<b>{label}</b>
</label>
</Label>
</DataListCell>,
]}
/>

View File

@ -94,6 +94,7 @@ const mockJobTemplate = {
},
related: { webhook_receiver: '' },
inventory: 1,
project: 5,
};
describe('NodeModal', () => {

View File

@ -3,6 +3,7 @@ import { useLocation } from 'react-router-dom';
import { withI18n } from '@lingui/react';
import { t } from '@lingui/macro';
import { func, shape } from 'prop-types';
import { Tooltip } from '@patternfly/react-core';
import { JobTemplatesAPI } from '../../../../../../api';
import { getQSConfig, parseQueryString } from '../../../../../../util/qs';
import useRequest from '../../../../../../util/useRequest';
@ -56,26 +57,56 @@ function JobTemplatesList({ i18n, nodeResource, onUpdateNodeResource }) {
fetchJobTemplates();
}, [fetchJobTemplates]);
const onSelectRow = row => {
if (
row.project &&
row.project !== null &&
((row.inventory && row.inventory !== null) || row.ask_inventory_on_launch)
) {
onUpdateNodeResource(row);
}
};
return (
<PaginatedDataList
contentError={error}
hasContentLoading={isLoading}
itemCount={count}
items={jobTemplates}
onRowClick={row => onUpdateNodeResource(row)}
onRowClick={row => onSelectRow(row)}
qsConfig={QS_CONFIG}
renderItem={item => (
<CheckboxListItem
isSelected={!!(nodeResource && nodeResource.id === item.id)}
itemId={item.id}
key={item.id}
name={item.name}
label={item.name}
onSelect={() => onUpdateNodeResource(item)}
onDeselect={() => onUpdateNodeResource(null)}
isRadio
/>
)}
renderItem={item => {
const isDisabled =
!item.project ||
item.project === null ||
((!item.inventory || item.inventory === null) &&
!item.ask_inventory_on_launch);
const listItem = (
<CheckboxListItem
isDisabled={isDisabled}
isSelected={!!(nodeResource && nodeResource.id === item.id)}
itemId={item.id}
key={`${item.id}-listItem`}
name={item.name}
label={item.name}
onSelect={() => onSelectRow(item)}
onDeselect={() => onUpdateNodeResource(null)}
isRadio
/>
);
return isDisabled ? (
<Tooltip
key={`${item.id}-tooltip`}
content={i18n._(
t`Job Templates with a missing inventory or project cannot be selected when creating or editing nodes`
)}
>
{listItem}
</Tooltip>
) : (
listItem
);
}}
renderToolbar={props => <DataListToolbar {...props} fillWidth />}
showPageSizeOptions={false}
toolbarSearchColumns={[

View File

@ -16,6 +16,7 @@ const onUpdateNodeResource = jest.fn();
describe('JobTemplatesList', () => {
let wrapper;
afterEach(() => {
jest.clearAllMocks();
wrapper.unmount();
});
test('Row selected when nodeResource id matches row id and clicking new row makes expected callback', async () => {
@ -28,12 +29,16 @@ describe('JobTemplatesList', () => {
name: 'Test Job Template',
type: 'job_template',
url: '/api/v2/job_templates/1',
inventory: 1,
project: 2,
},
{
id: 2,
name: 'Test Job Template 2',
type: 'job_template',
url: '/api/v2/job_templates/2',
inventory: 1,
project: 2,
},
],
},
@ -60,10 +65,18 @@ describe('JobTemplatesList', () => {
wrapper.find('CheckboxListItem[name="Test Job Template"]').props()
.isSelected
).toBe(true);
expect(
wrapper.find('CheckboxListItem[name="Test Job Template"]').props()
.isDisabled
).toBe(false);
expect(
wrapper.find('CheckboxListItem[name="Test Job Template 2"]').props()
.isSelected
).toBe(false);
expect(
wrapper.find('CheckboxListItem[name="Test Job Template 2"]').props()
.isDisabled
).toBe(false);
wrapper
.find('CheckboxListItem[name="Test Job Template 2"]')
.simulate('click');
@ -72,8 +85,75 @@ describe('JobTemplatesList', () => {
name: 'Test Job Template 2',
type: 'job_template',
url: '/api/v2/job_templates/2',
inventory: 1,
project: 2,
});
});
test('Row disabled when job template missing inventory or project', async () => {
JobTemplatesAPI.read.mockResolvedValueOnce({
data: {
count: 2,
results: [
{
id: 1,
name: 'Test Job Template',
type: 'job_template',
url: '/api/v2/job_templates/1',
inventory: 1,
project: null,
ask_inventory_on_launch: false,
},
{
id: 2,
name: 'Test Job Template 2',
type: 'job_template',
url: '/api/v2/job_templates/2',
inventory: null,
project: 2,
ask_inventory_on_launch: false,
},
],
},
});
JobTemplatesAPI.readOptions.mockResolvedValue({
data: {
actions: {
GET: {},
POST: {},
},
related_search_fields: [],
},
});
await act(async () => {
wrapper = mountWithContexts(
<JobTemplatesList
nodeResource={nodeResource}
onUpdateNodeResource={onUpdateNodeResource}
/>
);
});
wrapper.update();
expect(
wrapper.find('CheckboxListItem[name="Test Job Template"]').props()
.isSelected
).toBe(true);
expect(
wrapper.find('CheckboxListItem[name="Test Job Template"]').props()
.isDisabled
).toBe(true);
expect(
wrapper.find('CheckboxListItem[name="Test Job Template 2"]').props()
.isSelected
).toBe(false);
expect(
wrapper.find('CheckboxListItem[name="Test Job Template 2"]').props()
.isDisabled
).toBe(true);
wrapper
.find('CheckboxListItem[name="Test Job Template 2"]')
.simulate('click');
expect(onUpdateNodeResource).not.toHaveBeenCalled();
});
test('Error shown when read() request errors', async () => {
JobTemplatesAPI.read.mockRejectedValue(new Error());
JobTemplatesAPI.readOptions.mockResolvedValue({