Merge pull request #41 from ansible/devel

Rebase
This commit is contained in:
Sean Sullivan
2021-02-15 14:23:29 -06:00
committed by GitHub
10 changed files with 101 additions and 87 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -133,7 +133,7 @@ def main():
existing_settings = module.get_endpoint('settings/all')['json'] existing_settings = module.get_endpoint('settings/all')['json']
# Begin a json response # Begin a json response
json_response = {'changed': False, 'old_values': {}} json_output = {'changed': False, 'old_values': {}, 'new_values': {}}
# Check any of the settings to see if anything needs to be updated # Check any of the settings to see if anything needs to be updated
needs_update = False needs_update = False
@@ -141,18 +141,29 @@ def main():
if a_setting not in existing_settings or existing_settings[a_setting] != new_settings[a_setting]: if a_setting not in existing_settings or existing_settings[a_setting] != new_settings[a_setting]:
# At least one thing is different so we need to patch # At least one thing is different so we need to patch
needs_update = True needs_update = True
json_response['old_values'][a_setting] = existing_settings[a_setting] json_output['old_values'][a_setting] = existing_settings[a_setting]
json_output['new_values'][a_setting] = new_settings[a_setting]
if module._diff:
json_output['diff'] = {
'before': json_output['old_values'],
'after': json_output['new_values']
}
# If nothing needs an update we can simply exit with the response (as not changed) # If nothing needs an update we can simply exit with the response (as not changed)
if not needs_update: if not needs_update:
module.exit_json(**json_response) module.exit_json(**json_output)
if module.check_mode and module._diff:
json_output['changed'] = True
module.exit_json(**json_output)
# Make the call to update the settings # Make the call to update the settings
response = module.patch_endpoint('settings/all', **{'data': new_settings}) response = module.patch_endpoint('settings/all', **{'data': new_settings})
if response['status_code'] == 200: if response['status_code'] == 200:
# Set the changed response to True # Set the changed response to True
json_response['changed'] = True json_output['changed'] = True
# To deal with the old style values we need to return 'value' in the response # To deal with the old style values we need to return 'value' in the response
new_values = {} new_values = {}
@@ -161,11 +172,11 @@ def main():
# If we were using a name we will just add a value of a string, otherwise we will return an array in values # If we were using a name we will just add a value of a string, otherwise we will return an array in values
if name is not None: if name is not None:
json_response['value'] = new_values[name] json_output['value'] = new_values[name]
else: else:
json_response['values'] = new_values json_output['values'] = new_values
module.exit_json(**json_response) module.exit_json(**json_output)
elif 'json' in response and '__all__' in response['json']: elif 'json' in response and '__all__' in response['json']:
module.fail_json(msg=response['json']['__all__']) module.fail_json(msg=response['json']['__all__'])
else: else: