mirror of
https://github.com/ansible/awx.git
synced 2026-01-11 10:00:01 -03:30
Merge pull request #8780 from mabashian/7879-notif-copy-search
Add support for notification template copy and advanced search Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
This commit is contained in:
commit
a5e54c3858
@ -34,7 +34,7 @@ function CopyButton({
|
||||
<>
|
||||
<Tooltip content={helperText.tooltip} position="top">
|
||||
<Button
|
||||
isDisabled={isDisabled}
|
||||
isDisabled={isLoading || isDisabled}
|
||||
aria-label={i18n._(t`Copy`)}
|
||||
variant="plain"
|
||||
onClick={copyItemToAPI}
|
||||
|
||||
@ -187,7 +187,7 @@ function NotificationList({
|
||||
key: 'description__icontains',
|
||||
},
|
||||
{
|
||||
name: i18n._(t`Type`),
|
||||
name: i18n._(t`Notification type`),
|
||||
key: 'or__notification_type',
|
||||
options: [
|
||||
['email', i18n._(t`Email`)],
|
||||
|
||||
@ -29,27 +29,41 @@ function NotificationTemplatesList({ i18n }) {
|
||||
const addUrl = `${match.url}/add`;
|
||||
|
||||
const {
|
||||
result: { templates, count, actions },
|
||||
result: {
|
||||
templates,
|
||||
count,
|
||||
actions,
|
||||
relatedSearchableKeys,
|
||||
searchableKeys,
|
||||
},
|
||||
error: contentError,
|
||||
isLoading: isTemplatesLoading,
|
||||
request: fetchTemplates,
|
||||
} = useRequest(
|
||||
useCallback(async () => {
|
||||
const params = parseQueryString(QS_CONFIG, location.search);
|
||||
const responses = await Promise.all([
|
||||
const [response, actionsResponse] = await Promise.all([
|
||||
NotificationTemplatesAPI.read(params),
|
||||
NotificationTemplatesAPI.readOptions(),
|
||||
]);
|
||||
return {
|
||||
templates: responses[0].data.results,
|
||||
count: responses[0].data.count,
|
||||
actions: responses[1].data.actions,
|
||||
templates: response.data.results,
|
||||
count: response.data.count,
|
||||
actions: actionsResponse.data.actions,
|
||||
relatedSearchableKeys: (
|
||||
actionsResponse.data?.related_search_fields || []
|
||||
).map(val => val.slice(0, -8)),
|
||||
searchableKeys: Object.keys(
|
||||
actionsResponse.data.actions?.GET || {}
|
||||
).filter(key => actionsResponse.data.actions?.GET[key].filterable),
|
||||
};
|
||||
}, [location]),
|
||||
{
|
||||
templates: [],
|
||||
count: 0,
|
||||
actions: {},
|
||||
relatedSearchableKeys: [],
|
||||
searchableKeys: [],
|
||||
}
|
||||
);
|
||||
|
||||
@ -109,7 +123,7 @@ function NotificationTemplatesList({ i18n }) {
|
||||
key: 'description__icontains',
|
||||
},
|
||||
{
|
||||
name: i18n._(t`Type`),
|
||||
name: i18n._(t`Notification type`),
|
||||
key: 'or__notification_type',
|
||||
options: [
|
||||
['email', i18n._(t`Email`)],
|
||||
@ -125,14 +139,16 @@ function NotificationTemplatesList({ i18n }) {
|
||||
],
|
||||
},
|
||||
{
|
||||
name: i18n._(t`Created By (Username)`),
|
||||
name: i18n._(t`Created by (username)`),
|
||||
key: 'created_by__username__icontains',
|
||||
},
|
||||
{
|
||||
name: i18n._(t`Modified By (Username)`),
|
||||
name: i18n._(t`Modified by (username)`),
|
||||
key: 'modified_by__username__icontains',
|
||||
},
|
||||
]}
|
||||
toolbarSearchableKeys={searchableKeys}
|
||||
toolbarRelatedSearchableKeys={relatedSearchableKeys}
|
||||
toolbarSortColumns={[
|
||||
{
|
||||
name: i18n._(t`Name`),
|
||||
@ -166,6 +182,7 @@ function NotificationTemplatesList({ i18n }) {
|
||||
renderItem={template => (
|
||||
<NotificationTemplateListItem
|
||||
key={template.id}
|
||||
fetchTemplates={fetchTemplates}
|
||||
template={template}
|
||||
detailUrl={`${match.url}/${template.id}`}
|
||||
isSelected={selected.some(row => row.id === template.id)}
|
||||
|
||||
@ -14,9 +14,11 @@ import {
|
||||
Tooltip,
|
||||
} from '@patternfly/react-core';
|
||||
import { PencilAltIcon, BellIcon } from '@patternfly/react-icons';
|
||||
import { timeOfDay } from '../../../util/dates';
|
||||
import { NotificationTemplatesAPI, NotificationsAPI } from '../../../api';
|
||||
import DataListCell from '../../../components/DataListCell';
|
||||
import StatusLabel from '../../../components/StatusLabel';
|
||||
import CopyButton from '../../../components/CopyButton';
|
||||
import useRequest from '../../../util/useRequest';
|
||||
import { NOTIFICATION_TYPES } from '../constants';
|
||||
|
||||
@ -24,7 +26,7 @@ const DataListAction = styled(_DataListAction)`
|
||||
align-items: center;
|
||||
display: grid;
|
||||
grid-gap: 16px;
|
||||
grid-template-columns: 40px 40px;
|
||||
grid-template-columns: repeat(3, 40px);
|
||||
`;
|
||||
|
||||
const NUM_RETRIES = 25;
|
||||
@ -33,6 +35,7 @@ const RETRY_TIMEOUT = 5000;
|
||||
function NotificationTemplateListItem({
|
||||
template,
|
||||
detailUrl,
|
||||
fetchTemplates,
|
||||
isSelected,
|
||||
onSelect,
|
||||
i18n,
|
||||
@ -42,6 +45,22 @@ function NotificationTemplateListItem({
|
||||
? recentNotifications[0]?.status
|
||||
: null;
|
||||
const [status, setStatus] = useState(latestStatus);
|
||||
const [isCopyDisabled, setIsCopyDisabled] = useState(false);
|
||||
|
||||
const copyTemplate = useCallback(async () => {
|
||||
await NotificationTemplatesAPI.copy(template.id, {
|
||||
name: `${template.name} @ ${timeOfDay()}`,
|
||||
});
|
||||
await fetchTemplates();
|
||||
}, [template.id, template.name, fetchTemplates]);
|
||||
|
||||
const handleCopyStart = useCallback(() => {
|
||||
setIsCopyDisabled(true);
|
||||
}, []);
|
||||
|
||||
const handleCopyFinish = useCallback(() => {
|
||||
setIsCopyDisabled(false);
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
setStatus(latestStatus);
|
||||
@ -114,7 +133,7 @@ function NotificationTemplateListItem({
|
||||
aria-label={i18n._(t`Test Notification`)}
|
||||
variant="plain"
|
||||
onClick={sendTestNotification}
|
||||
disabled={isLoading}
|
||||
isDisabled={isLoading || status === 'running'}
|
||||
>
|
||||
<BellIcon />
|
||||
</Button>
|
||||
@ -136,6 +155,18 @@ 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.`),
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</DataListAction>
|
||||
</DataListItemRow>
|
||||
</DataListItem>
|
||||
|
||||
@ -13,6 +13,7 @@ const template = {
|
||||
summary_fields: {
|
||||
user_capabilities: {
|
||||
edit: true,
|
||||
copy: true,
|
||||
},
|
||||
recent_notifications: [
|
||||
{
|
||||
@ -63,4 +64,56 @@ describe('<NotificationTemplateListItem />', () => {
|
||||
.text()
|
||||
).toEqual('Running');
|
||||
});
|
||||
|
||||
test('should call api to copy inventory', async () => {
|
||||
NotificationTemplatesAPI.copy.mockResolvedValue();
|
||||
|
||||
const wrapper = mountWithContexts(
|
||||
<NotificationTemplateListItem
|
||||
template={template}
|
||||
detailUrl="/notification_templates/3/detail"
|
||||
/>
|
||||
);
|
||||
|
||||
await act(async () =>
|
||||
wrapper.find('Button[aria-label="Copy"]').prop('onClick')()
|
||||
);
|
||||
expect(NotificationTemplatesAPI.copy).toHaveBeenCalled();
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
|
||||
test('should render proper alert modal on copy error', async () => {
|
||||
NotificationTemplatesAPI.copy.mockRejectedValue(new Error());
|
||||
|
||||
const wrapper = mountWithContexts(
|
||||
<NotificationTemplateListItem
|
||||
template={template}
|
||||
detailUrl="/notification_templates/3/detail"
|
||||
/>
|
||||
);
|
||||
await act(async () =>
|
||||
wrapper.find('Button[aria-label="Copy"]').prop('onClick')()
|
||||
);
|
||||
wrapper.update();
|
||||
expect(wrapper.find('Modal').prop('isOpen')).toBe(true);
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
|
||||
test('should not render copy button', async () => {
|
||||
const wrapper = mountWithContexts(
|
||||
<NotificationTemplateListItem
|
||||
template={{
|
||||
...template,
|
||||
summary_fields: {
|
||||
user_capabilities: {
|
||||
copy: false,
|
||||
edit: false,
|
||||
},
|
||||
},
|
||||
}}
|
||||
detailUrl="/notification_templates/3/detail"
|
||||
/>
|
||||
);
|
||||
expect(wrapper.find('CopyButton').length).toBe(0);
|
||||
});
|
||||
});
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user