Merge pull request #9287 from mabashian/7679-copy-inv-w-source

Disable inventory copy button when inventory has sources

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
This commit is contained in:
softwarefactory-project-zuul[bot] 2021-02-15 17:19:49 +00:00 committed by GitHub
commit 4e48118704
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 83 additions and 80 deletions

View File

@ -3,7 +3,7 @@ import { withI18n } from '@lingui/react';
import { t } from '@lingui/macro';
import PropTypes from 'prop-types';
import { Button, Tooltip } from '@patternfly/react-core';
import { Button } from '@patternfly/react-core';
import { CopyIcon } from '@patternfly/react-icons';
import useRequest, { useDismissableError } from '../../util/useRequest';
import AlertModal from '../AlertModal';
@ -15,7 +15,7 @@ function CopyButton({
isDisabled,
onCopyStart,
onCopyFinish,
helperText,
errorMessage,
i18n,
}) {
const { isLoading, error: copyError, request: copyItemToAPI } = useRequest(
@ -33,17 +33,15 @@ function CopyButton({
return (
<>
<Tooltip content={helperText.tooltip} position="top">
<Button
id={id}
isDisabled={isLoading || isDisabled}
aria-label={i18n._(t`Copy`)}
variant="plain"
onClick={copyItemToAPI}
>
<CopyIcon />
</Button>
</Tooltip>
<Button
id={id}
isDisabled={isLoading || isDisabled}
aria-label={i18n._(t`Copy`)}
variant="plain"
onClick={copyItemToAPI}
>
<CopyIcon />
</Button>
<AlertModal
aria-label={i18n._(t`Copy Error`)}
isOpen={error}
@ -51,7 +49,7 @@ function CopyButton({
title={i18n._(t`Error!`)}
onClose={dismissError}
>
{helperText.errorMessage}
{errorMessage}
<ErrorDetail error={error} />
</AlertModal>
</>
@ -62,10 +60,7 @@ CopyButton.propTypes = {
copyItem: PropTypes.func.isRequired,
onCopyStart: PropTypes.func.isRequired,
onCopyFinish: PropTypes.func.isRequired,
helperText: PropTypes.shape({
tooltip: PropTypes.string.isRequired,
errorMessage: PropTypes.string.isRequired,
}).isRequired,
errorMessage: PropTypes.string.isRequired,
isDisabled: PropTypes.bool,
};

View File

@ -1,36 +1,44 @@
import React from 'react';
import { act } from 'react-dom/test-utils';
import { mountWithContexts } from '../../../testUtils/enzymeHelpers';
import CopyButton from './CopyButton';
jest.mock('../../api');
let wrapper;
describe('<CopyButton/>', () => {
test('shold mount properly', () => {
const wrapper = mountWithContexts(
<CopyButton
onCopyStart={() => {}}
onCopyFinish={() => {}}
copyItem={() => {}}
helperText={{
tooltip: `Copy Template`,
errorMessage: `Failed to copy template.`,
}}
/>
);
afterEach(() => {
wrapper.unmount();
});
test('should mount properly', async () => {
await act(async () => {
wrapper = mountWithContexts(
<CopyButton
onCopyStart={() => {}}
onCopyFinish={() => {}}
copyItem={() => {}}
errorMessage="Failed to copy template."
/>
);
});
expect(wrapper.find('CopyButton').length).toBe(1);
});
test('should render proper tooltip', () => {
const wrapper = mountWithContexts(
<CopyButton
onCopyStart={() => {}}
onCopyFinish={() => {}}
copyItem={() => {}}
helperText={{
tooltip: `Copy Template`,
errorMessage: `Failed to copy template.`,
}}
/>
);
expect(wrapper.find('Tooltip').prop('content')).toBe('Copy Template');
test('should call the correct function on button click', async () => {
const copyItem = jest.fn();
await act(async () => {
wrapper = mountWithContexts(
<CopyButton
onCopyStart={() => {}}
onCopyFinish={() => {}}
copyItem={copyItem}
errorMessage="Failed to copy template."
/>
);
});
await act(async () => {
wrapper.find('button').simulate('click');
});
expect(copyItem).toHaveBeenCalledTimes(1);
});
});

View File

@ -14,7 +14,7 @@ export default function ActionItem({ column, tooltip, visible, children }) {
`}
>
<Tooltip content={tooltip} position="top">
{children}
<div>{children}</div>
</Tooltip>
</div>
);

View File

@ -12,7 +12,7 @@ describe('<ActionItem />', () => {
const tooltip = wrapper.find('Tooltip');
expect(tooltip.prop('content')).toEqual('a tooltip');
expect(tooltip.prop('children')).toEqual('foo');
expect(tooltip.prop('children')).toEqual(<div>foo</div>);
});
test('should render null if not visible', async () => {

View File

@ -177,13 +177,13 @@ function TemplateListItem({
<PencilAltIcon />
</Button>
</ActionItem>
<ActionItem visible={template.summary_fields.user_capabilities.copy}>
<ActionItem
tooltip={i18n._(t`Copy Template`)}
visible={template.summary_fields.user_capabilities.copy}
>
<CopyButton
id={`template-action-copy-${template.id}`}
helperText={{
errorMessage: i18n._(t`Failed to copy template.`),
tooltip: i18n._(t`Copy Template`),
}}
errorMessage={i18n._(t`Failed to copy template.`)}
isDisabled={isDisabled}
onCopyStart={handleCopyStart}
onCopyFinish={handleCopyFinish}

View File

@ -72,16 +72,16 @@ function CredentialListItem({
<PencilAltIcon />
</Button>
</ActionItem>
<ActionItem visible={credential.summary_fields.user_capabilities.copy}>
<ActionItem
tooltip={i18n._(t`Copy Credential`)}
visible={credential.summary_fields.user_capabilities.copy}
>
<CopyButton
isDisabled={isDisabled}
onCopyStart={handleCopyStart}
onCopyFinish={handleCopyFinish}
copyItem={copyCredential}
helperText={{
tooltip: i18n._(t`Copy Credential`),
errorMessage: i18n._(t`Failed to copy credential.`),
}}
errorMessage={i18n._(t`Failed to copy credential.`)}
/>
</ActionItem>
</ActionsTd>

View File

@ -28,7 +28,7 @@ function InventoryListItem({
isSelected: bool.isRequired,
onSelect: func.isRequired,
};
const [isDisabled, setIsDisabled] = useState(false);
const [isCopying, setIsCopying] = useState(false);
const copyInventory = useCallback(async () => {
await InventoriesAPI.copy(inventory.id, {
@ -38,11 +38,11 @@ function InventoryListItem({
}, [inventory.id, inventory.name, fetchInventories]);
const handleCopyStart = useCallback(() => {
setIsDisabled(true);
setIsCopying(true);
}, []);
const handleCopyFinish = useCallback(() => {
setIsDisabled(false);
setIsCopying(false);
}, []);
const labelId = `check-action-${inventory.id}`;
@ -115,7 +115,7 @@ function InventoryListItem({
tooltip={i18n._(t`Edit Inventory`)}
>
<Button
isDisabled={isDisabled}
isDisabled={isCopying}
aria-label={i18n._(t`Edit Inventory`)}
variant="plain"
component={Link}
@ -128,17 +128,18 @@ function InventoryListItem({
</ActionItem>
<ActionItem
visible={inventory.summary_fields.user_capabilities.copy}
tooltip={i18n._(t`Copy Inventory`)}
tooltip={
inventory.has_inventory_sources
? i18n._(t`Inventories with sources cannot be copied`)
: i18n._(t`Copy Inventory`)
}
>
<CopyButton
copyItem={copyInventory}
isDisabled={isDisabled}
isDisabled={isCopying || inventory.has_inventory_sources}
onCopyStart={handleCopyStart}
onCopyFinish={handleCopyFinish}
helperText={{
tooltip: i18n._(t`Copy Inventory`),
errorMessage: i18n._(t`Failed to copy inventory.`),
}}
errorMessage={i18n._(t`Failed to copy inventory.`)}
/>
</ActionItem>
</ActionsTd>

View File

@ -159,16 +159,15 @@ function NotificationTemplateListItem({
<div />
)}
{template.summary_fields.user_capabilities.copy && (
<CopyButton
copyItem={copyTemplate}
isCopyDisabled={isCopyDisabled}
onCopyStart={handleCopyStart}
onCopyFinish={handleCopyFinish}
helperText={{
tooltip: i18n._(t`Copy Notification Template`),
errorMessage: i18n._(t`Failed to copy template.`),
}}
/>
<Tooltip content={i18n._(t`Copy Notification Template`)}>
<CopyButton
copyItem={copyTemplate}
isCopyDisabled={isCopyDisabled}
onCopyStart={handleCopyStart}
onCopyFinish={handleCopyFinish}
errorMessage={i18n._(t`Failed to copy template.`)}
/>
</Tooltip>
)}
</DataListAction>
</DataListItemRow>

View File

@ -143,16 +143,16 @@ function ProjectListItem({
<PencilAltIcon />
</Button>
</ActionItem>
<ActionItem visible={project.summary_fields.user_capabilities.copy}>
<ActionItem
tooltip={i18n._(t`Copy Project`)}
visible={project.summary_fields.user_capabilities.copy}
>
<CopyButton
copyItem={copyProject}
isDisabled={isDisabled}
onCopyStart={handleCopyStart}
onCopyFinish={handleCopyFinish}
helperText={{
tooltip: i18n._(t`Copy Project`),
errorMessage: i18n._(t`Failed to copy project.`),
}}
errorMessage={i18n._(t`Failed to copy project.`)}
/>
</ActionItem>
</ActionsTd>