diff --git a/awx/ui/src/screens/WorkflowApproval/WorkflowApproval.js b/awx/ui/src/screens/WorkflowApproval/WorkflowApproval.js
index 07de41eb43..ebd0b3ef04 100644
--- a/awx/ui/src/screens/WorkflowApproval/WorkflowApproval.js
+++ b/awx/ui/src/screens/WorkflowApproval/WorkflowApproval.js
@@ -91,7 +91,10 @@ function WorkflowApproval({ setBreadcrumb }) {
/>
{workflowApproval && (
-
+
)}
diff --git a/awx/ui/src/screens/WorkflowApproval/WorkflowApprovalDetail/WorkflowApprovalDetail.js b/awx/ui/src/screens/WorkflowApproval/WorkflowApprovalDetail/WorkflowApprovalDetail.js
index 7a68fd9986..75dd963b3a 100644
--- a/awx/ui/src/screens/WorkflowApproval/WorkflowApprovalDetail/WorkflowApprovalDetail.js
+++ b/awx/ui/src/screens/WorkflowApproval/WorkflowApprovalDetail/WorkflowApprovalDetail.js
@@ -1,5 +1,4 @@
import React, { useCallback, useEffect } from 'react';
-
import { t } from '@lingui/macro';
import { Link, useHistory, useParams } from 'react-router-dom';
import styled from 'styled-components';
@@ -27,6 +26,7 @@ import useRequest, { useDismissableError } from 'hooks/useRequest';
import { WorkflowApproval } from 'types';
import StatusLabel from 'components/StatusLabel';
import JobCancelButton from 'components/JobCancelButton';
+import useToast, { AlertVariant } from 'hooks/useToast';
import WorkflowApprovalButton from '../shared/WorkflowApprovalButton';
import WorkflowDenyButton from '../shared/WorkflowDenyButton';
import {
@@ -48,9 +48,11 @@ const WFDetailList = styled(DetailList)`
padding: 0px var(--pf-global--spacer--lg);
`;
-function WorkflowApprovalDetail({ workflowApproval }) {
+function WorkflowApprovalDetail({ workflowApproval, fetchWorkflowApproval }) {
const { id: workflowApprovalId } = useParams();
const history = useHistory();
+ const { addToast, Toast, toastProps } = useToast();
+
const {
request: deleteWorkflowApproval,
isLoading: isDeleteLoading,
@@ -102,6 +104,18 @@ function WorkflowApprovalDetail({ workflowApproval }) {
fetchWorkflowJob();
}, [fetchWorkflowJob]);
+ const handleToast = useCallback(
+ (id, title) => {
+ addToast({
+ id,
+ title,
+ variant: AlertVariant.success,
+ hasTimeout: true,
+ });
+ fetchWorkflowApproval();
+ },
+ [addToast, fetchWorkflowApproval]
+ );
const sourceWorkflowJob =
workflowApproval?.summary_fields?.source_workflow_job;
@@ -116,7 +130,9 @@ function WorkflowApprovalDetail({ workflowApproval }) {
if (fetchWorkflowJobError) {
return ;
}
-
+ const showDeleteButton =
+ workflowApproval.status !== 'pending' &&
+ workflowApproval.summary_fields?.user_capabilities?.delete;
return (
@@ -289,31 +305,35 @@ function WorkflowApprovalDetail({ workflowApproval }) {
>
)}
- {workflowApproval.status !== 'pending' &&
- workflowApproval.summary_fields?.user_capabilities?.delete && (
-
- {t`Delete`}
-
- )}
+ {showDeleteButton && (
+
+ {t`Delete`}
+
+ )}
{deleteError && (
)}
+
);
}
diff --git a/awx/ui/src/screens/WorkflowApproval/WorkflowApprovalDetail/WorkflowApprovalDetail.test.js b/awx/ui/src/screens/WorkflowApproval/WorkflowApprovalDetail/WorkflowApprovalDetail.test.js
index 6b46536a38..49aebfe5ec 100644
--- a/awx/ui/src/screens/WorkflowApproval/WorkflowApprovalDetail/WorkflowApprovalDetail.test.js
+++ b/awx/ui/src/screens/WorkflowApproval/WorkflowApprovalDetail/WorkflowApprovalDetail.test.js
@@ -515,7 +515,10 @@ describe('', () => {
let wrapper;
await act(async () => {
wrapper = mountWithContexts(
-
+
);
});
waitForElement(wrapper, 'WorkflowApprovalDetail', (el) => el.length > 0);
@@ -548,7 +551,10 @@ describe('', () => {
let wrapper;
await act(async () => {
wrapper = mountWithContexts(
-
+
);
});
waitForElement(wrapper, 'WorkflowApprovalDetail', (el) => el.length > 0);
diff --git a/awx/ui/src/screens/WorkflowApproval/WorkflowApprovalList/WorkflowApprovalListItem.js b/awx/ui/src/screens/WorkflowApproval/WorkflowApprovalList/WorkflowApprovalListItem.js
index b72f5fb446..c369747c6a 100644
--- a/awx/ui/src/screens/WorkflowApproval/WorkflowApprovalList/WorkflowApprovalListItem.js
+++ b/awx/ui/src/screens/WorkflowApproval/WorkflowApprovalList/WorkflowApprovalListItem.js
@@ -100,7 +100,10 @@ function WorkflowApprovalListItem({
0 || workflowApproval.status === 'canceled';
const { error: approveApprovalError, request: approveWorkflowApprovals } =
useRequest(
useCallback(async () => WorkflowApprovalsAPI.approve(id), [id]),
@@ -20,6 +26,7 @@ function WorkflowApprovalButton({ isDetailView, workflowApproval }) {
const handleApprove = async () => {
await approveWorkflowApprovals();
+ onHandleToast(workflowApproval.id, t`Successfully Approved`);
};
const { error: approveError, dismissError: dismissApproveError } =
diff --git a/awx/ui/src/screens/WorkflowApproval/shared/WorkflowApprovalButton.test.js b/awx/ui/src/screens/WorkflowApproval/shared/WorkflowApprovalButton.test.js
index f1f7989ffc..3cc2564c0d 100644
--- a/awx/ui/src/screens/WorkflowApproval/shared/WorkflowApprovalButton.test.js
+++ b/awx/ui/src/screens/WorkflowApproval/shared/WorkflowApprovalButton.test.js
@@ -18,7 +18,10 @@ describe(' shallow mount', () => {
test('initially render successfully', () => {
wrapper = shallowWithContexts(
-
+
);
expect(wrapper.find('WorkflowApprovalButton')).toHaveLength(1);
@@ -39,7 +42,10 @@ describe(', full mount', () => {
test('should be disabled', () => {
wrapper = mountWithContexts(
-
+
);
expect(wrapper.find(approveButton)).toHaveLength(1);
expect(wrapper.find(approveButton).prop('isDisabled')).toBe(true);
@@ -47,7 +53,10 @@ describe(', full mount', () => {
test('should handle approve', async () => {
act(() => {
wrapper = mountWithContexts(
-
+
);
});
await act(() => wrapper.find(approveButton).prop('onClick')());
diff --git a/awx/ui/src/screens/WorkflowApproval/shared/WorkflowDenyButton.js b/awx/ui/src/screens/WorkflowApproval/shared/WorkflowDenyButton.js
index b0546f6726..3399ec624d 100644
--- a/awx/ui/src/screens/WorkflowApproval/shared/WorkflowDenyButton.js
+++ b/awx/ui/src/screens/WorkflowApproval/shared/WorkflowDenyButton.js
@@ -9,10 +9,12 @@ import AlertModal from 'components/AlertModal';
import ErrorDetail from 'components/ErrorDetail';
import { getStatus } from './WorkflowApprovalUtils';
-function WorkflowDenyButton({ isDetailView, workflowApproval }) {
- const hasBeenActedOn = workflowApproval.status === 'failed';
- const { id } = workflowApproval;
+function WorkflowDenyButton({ isDetailView, workflowApproval, onHandleToast }) {
+ const hasBeenActedOn =
+ Object.keys(workflowApproval.summary_fields.approved_or_denied_by || {})
+ .length > 0 || workflowApproval.status === 'canceled';
+ const { id } = workflowApproval;
const { error: denyApprovalError, request: denyWorkflowApprovals } =
useRequest(
useCallback(async () => WorkflowApprovalsAPI.deny(id), [id]),
@@ -21,6 +23,7 @@ function WorkflowDenyButton({ isDetailView, workflowApproval }) {
const handleDeny = async () => {
await denyWorkflowApprovals();
+ onHandleToast(workflowApproval.id, t`Successfully Denied`);
};
const { error: denyError, dismissError: dismissDenyError } =
diff --git a/awx/ui/src/screens/WorkflowApproval/shared/WorkflowDenyButton.test.js b/awx/ui/src/screens/WorkflowApproval/shared/WorkflowDenyButton.test.js
index ebfef860c4..af00c5403a 100644
--- a/awx/ui/src/screens/WorkflowApproval/shared/WorkflowDenyButton.test.js
+++ b/awx/ui/src/screens/WorkflowApproval/shared/WorkflowDenyButton.test.js
@@ -39,7 +39,10 @@ describe(', full mount', () => {
test('should be disabled', () => {
wrapper = mountWithContexts(
-
+
);
expect(wrapper.find(denyButton)).toHaveLength(1);
expect(wrapper.find(denyButton).prop('isDisabled')).toBe(true);
@@ -48,7 +51,10 @@ describe(', full mount', () => {
test('should handle deny', async () => {
act(() => {
wrapper = mountWithContexts(
-
+
);
});
await act(() => wrapper.find(denyButton).prop('onClick')());
@@ -70,7 +76,10 @@ describe(', full mount', () => {
);
act(() => {
wrapper = mountWithContexts(
-
+
);
});
await act(() => wrapper.find(denyButton).prop('onClick')());