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
commit c7bfc60be3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
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 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>

View File

@ -133,7 +133,7 @@ def main():
existing_settings = module.get_endpoint('settings/all')['json']
# 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
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]:
# At least one thing is different so we need to patch
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 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
response = module.patch_endpoint('settings/all', **{'data': new_settings})
if response['status_code'] == 200:
# 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
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 name is not None:
json_response['value'] = new_values[name]
json_output['value'] = new_values[name]
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']:
module.fail_json(msg=response['json']['__all__'])
else: