diff --git a/awx/ui_next/src/api/index.js b/awx/ui_next/src/api/index.js index c7dab6f76b..3c0d5e3237 100644 --- a/awx/ui_next/src/api/index.js +++ b/awx/ui_next/src/api/index.js @@ -17,6 +17,7 @@ import Jobs from './models/Jobs'; import Labels from './models/Labels'; import Me from './models/Me'; import NotificationTemplates from './models/NotificationTemplates'; +import Notifications from './models/Notifications'; import Organizations from './models/Organizations'; import ProjectUpdates from './models/ProjectUpdates'; import Projects from './models/Projects'; @@ -53,6 +54,7 @@ const JobsAPI = new Jobs(); const LabelsAPI = new Labels(); const MeAPI = new Me(); const NotificationTemplatesAPI = new NotificationTemplates(); +const NotificationsAPI = new Notifications(); const OrganizationsAPI = new Organizations(); const ProjectUpdatesAPI = new ProjectUpdates(); const ProjectsAPI = new Projects(); @@ -90,6 +92,7 @@ export { LabelsAPI, MeAPI, NotificationTemplatesAPI, + NotificationsAPI, OrganizationsAPI, ProjectUpdatesAPI, ProjectsAPI, diff --git a/awx/ui_next/src/api/models/Notifications.js b/awx/ui_next/src/api/models/Notifications.js new file mode 100644 index 0000000000..68405c0986 --- /dev/null +++ b/awx/ui_next/src/api/models/Notifications.js @@ -0,0 +1,10 @@ +import Base from '../Base'; + +class Notifications extends Base { + constructor(http) { + super(http); + this.baseUrl = '/api/v2/notifications/'; + } +} + +export default Notifications; diff --git a/awx/ui_next/src/components/StatusLabel/StatusLabel.jsx b/awx/ui_next/src/components/StatusLabel/StatusLabel.jsx index 0f2be56fdc..31917b9597 100644 --- a/awx/ui_next/src/components/StatusLabel/StatusLabel.jsx +++ b/awx/ui_next/src/components/StatusLabel/StatusLabel.jsx @@ -26,6 +26,7 @@ const RunningIcon = styled(SyncAltIcon)` const colors = { success: 'green', + successful: 'green', failed: 'red', error: 'red', running: 'blue', @@ -35,6 +36,7 @@ const colors = { }; const icons = { success: CheckCircleIcon, + successful: CheckCircleIcon, failed: ExclamationCircleIcon, error: ExclamationCircleIcon, running: RunningIcon, @@ -58,6 +60,7 @@ export default function StatusLabel({ status }) { StatusLabel.propTypes = { status: oneOf([ 'success', + 'successful', 'failed', 'error', 'running', diff --git a/awx/ui_next/src/screens/NotificationTemplate/NotificationTemplateList/NotificationTemplateListItem.jsx b/awx/ui_next/src/screens/NotificationTemplate/NotificationTemplateList/NotificationTemplateListItem.jsx index 0087e7f9a8..59d9fb748d 100644 --- a/awx/ui_next/src/screens/NotificationTemplate/NotificationTemplateList/NotificationTemplateListItem.jsx +++ b/awx/ui_next/src/screens/NotificationTemplate/NotificationTemplateList/NotificationTemplateListItem.jsx @@ -14,7 +14,7 @@ import { Tooltip, } from '@patternfly/react-core'; import { PencilAltIcon, BellIcon } from '@patternfly/react-icons'; -import { NotificationTemplatesAPI } from '../../../api'; +import { NotificationTemplatesAPI, NotificationsAPI } from '../../../api'; import DataListCell from '../../../components/DataListCell'; import StatusLabel from '../../../components/StatusLabel'; import useRequest from '../../../util/useRequest'; @@ -27,6 +27,9 @@ const DataListAction = styled(_DataListAction)` grid-template-columns: 40px 40px; `; +const NUM_RETRIES = 25; +const RETRY_TIMEOUT = 5000; + function NotificationTemplateListItem({ template, detailUrl, @@ -45,9 +48,29 @@ function NotificationTemplateListItem({ }, [latestStatus]); const { request: sendTestNotification, isLoading, error } = useRequest( - useCallback(() => { - NotificationTemplatesAPI.test(template.id); + useCallback(async () => { + const request = NotificationTemplatesAPI.test(template.id); setStatus('running'); + let retries = NUM_RETRIES; + const { + data: { notification: notificationId }, + } = await request; + + async function pollForStatusChange() { + const { data: notification } = await NotificationsAPI.readDetail( + notificationId + ); + if (notification.status !== 'pending') { + setStatus(notification.status); + return; + } + retries--; + if (retries > 0) { + setTimeout(pollForStatusChange, RETRY_TIMEOUT); + } + } + + setTimeout(pollForStatusChange, RETRY_TIMEOUT); }, [template.id]) ); diff --git a/awx/ui_next/src/screens/NotificationTemplate/NotificationTemplateList/NotificationTemplateListItem.test.jsx b/awx/ui_next/src/screens/NotificationTemplate/NotificationTemplateList/NotificationTemplateListItem.test.jsx index 5a4566779e..58878d3b96 100644 --- a/awx/ui_next/src/screens/NotificationTemplate/NotificationTemplateList/NotificationTemplateListItem.test.jsx +++ b/awx/ui_next/src/screens/NotificationTemplate/NotificationTemplateList/NotificationTemplateListItem.test.jsx @@ -39,7 +39,9 @@ describe('', () => { }); test('should send test notification', async () => { - NotificationTemplatesAPI.test.mockResolvedValue({}); + NotificationTemplatesAPI.test.mockResolvedValue({ + data: { notification: 1 }, + }); const wrapper = mountWithContexts(