mirror of
https://github.com/ansible/awx.git
synced 2026-01-11 18:09:57 -03:30
Adds toast to detail view and fixes non-disabled action button on list view
This commit is contained in:
parent
1fca505b61
commit
93ea8a0919
@ -91,7 +91,10 @@ function WorkflowApproval({ setBreadcrumb }) {
|
||||
/>
|
||||
{workflowApproval && (
|
||||
<Route path="/workflow_approvals/:id/details">
|
||||
<WorkflowApprovalDetail workflowApproval={workflowApproval} />
|
||||
<WorkflowApprovalDetail
|
||||
fetchWorkflowApproval={fetchWorkflowApproval}
|
||||
workflowApproval={workflowApproval}
|
||||
/>
|
||||
</Route>
|
||||
)}
|
||||
<Route key="not-found" path="*">
|
||||
|
||||
@ -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 <ContentError error={fetchWorkflowJobError} />;
|
||||
}
|
||||
|
||||
const showDeleteButton =
|
||||
workflowApproval.status !== 'pending' &&
|
||||
workflowApproval.summary_fields?.user_capabilities?.delete;
|
||||
return (
|
||||
<CardBody>
|
||||
<DetailList gutter="sm">
|
||||
@ -289,31 +305,35 @@ function WorkflowApprovalDetail({ workflowApproval }) {
|
||||
<WorkflowApprovalButton
|
||||
workflowApproval={workflowApproval}
|
||||
isDetailView
|
||||
onHandleToast={handleToast}
|
||||
/>
|
||||
<WorkflowDenyButton
|
||||
workflowApproval={workflowApproval}
|
||||
isDetailView
|
||||
onHandleToast={handleToast}
|
||||
/>
|
||||
<JobCancelButton
|
||||
title={t`Cancel Workflow`}
|
||||
job={workflowApproval.summary_fields.source_workflow_job}
|
||||
job={{
|
||||
...workflowApproval.summary_fields.source_workflow_job,
|
||||
type: 'workflow_job',
|
||||
}}
|
||||
buttonText={t`Cancel Workflow`}
|
||||
cancelationMessage={t`This will cancel all subsequent nodes in this workflow.
|
||||
`}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
{workflowApproval.status !== 'pending' &&
|
||||
workflowApproval.summary_fields?.user_capabilities?.delete && (
|
||||
<DeleteButton
|
||||
name={workflowApproval.name}
|
||||
modalTitle={t`Delete Workflow Approval`}
|
||||
onConfirm={deleteWorkflowApproval}
|
||||
isDisabled={isLoading}
|
||||
>
|
||||
{t`Delete`}
|
||||
</DeleteButton>
|
||||
)}
|
||||
{showDeleteButton && (
|
||||
<DeleteButton
|
||||
name={workflowApproval.name}
|
||||
modalTitle={t`Delete Workflow Approval`}
|
||||
onConfirm={deleteWorkflowApproval}
|
||||
isDisabled={isLoading}
|
||||
>
|
||||
{t`Delete`}
|
||||
</DeleteButton>
|
||||
)}
|
||||
</CardActionsRow>
|
||||
{deleteError && (
|
||||
<AlertModal
|
||||
@ -326,6 +346,7 @@ function WorkflowApprovalDetail({ workflowApproval }) {
|
||||
<ErrorDetail error={deleteError} />
|
||||
</AlertModal>
|
||||
)}
|
||||
<Toast {...toastProps} />
|
||||
</CardBody>
|
||||
);
|
||||
}
|
||||
|
||||
@ -515,7 +515,10 @@ describe('<WorkflowApprovalDetail />', () => {
|
||||
let wrapper;
|
||||
await act(async () => {
|
||||
wrapper = mountWithContexts(
|
||||
<WorkflowApprovalDetail workflowApproval={workflowApproval} />
|
||||
<WorkflowApprovalDetail
|
||||
workflowApproval={workflowApproval}
|
||||
fetchWorkflowApproval={jest.fn()}
|
||||
/>
|
||||
);
|
||||
});
|
||||
waitForElement(wrapper, 'WorkflowApprovalDetail', (el) => el.length > 0);
|
||||
@ -548,7 +551,10 @@ describe('<WorkflowApprovalDetail />', () => {
|
||||
let wrapper;
|
||||
await act(async () => {
|
||||
wrapper = mountWithContexts(
|
||||
<WorkflowApprovalDetail workflowApproval={workflowApproval} />
|
||||
<WorkflowApprovalDetail
|
||||
workflowApproval={workflowApproval}
|
||||
fetchWorkflowApproval={jest.fn()}
|
||||
/>
|
||||
);
|
||||
});
|
||||
waitForElement(wrapper, 'WorkflowApprovalDetail', (el) => el.length > 0);
|
||||
|
||||
@ -100,7 +100,10 @@ function WorkflowApprovalListItem({
|
||||
<JobCancelButton
|
||||
title={t`Cancel Workflow`}
|
||||
showIconButton
|
||||
job={workflowApproval.summary_fields.source_workflow_job}
|
||||
job={{
|
||||
...workflowApproval.summary_fields.source_workflow_job,
|
||||
type: 'workflow_job',
|
||||
}}
|
||||
buttonText={t`Cancel Workflow`}
|
||||
isDisabled={hasBeenActedOn}
|
||||
tooltip={
|
||||
|
||||
@ -9,9 +9,15 @@ import AlertModal from 'components/AlertModal';
|
||||
import ErrorDetail from 'components/ErrorDetail';
|
||||
import { getStatus } from './WorkflowApprovalUtils';
|
||||
|
||||
function WorkflowApprovalButton({ isDetailView, workflowApproval }) {
|
||||
function WorkflowApprovalButton({
|
||||
isDetailView,
|
||||
workflowApproval,
|
||||
onHandleToast,
|
||||
}) {
|
||||
const { id } = workflowApproval;
|
||||
const hasBeenActedOn = workflowApproval.status === 'successful';
|
||||
const hasBeenActedOn =
|
||||
Object.keys(workflowApproval.summary_fields.approved_or_denied_by || {})
|
||||
.length > 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 } =
|
||||
|
||||
@ -18,7 +18,10 @@ describe('<WorkflowApprovalButton/> shallow mount', () => {
|
||||
|
||||
test('initially render successfully', () => {
|
||||
wrapper = shallowWithContexts(
|
||||
<WorkflowApprovalButton workflowApproval={mockApprovalList[0]} />
|
||||
<WorkflowApprovalButton
|
||||
workflowApproval={mockApprovalList[0]}
|
||||
onHandleToast={jest.fn()}
|
||||
/>
|
||||
);
|
||||
|
||||
expect(wrapper.find('WorkflowApprovalButton')).toHaveLength(1);
|
||||
@ -39,7 +42,10 @@ describe('<WorkflowApprovalButton/>, full mount', () => {
|
||||
|
||||
test('should be disabled', () => {
|
||||
wrapper = mountWithContexts(
|
||||
<WorkflowApprovalButton workflowApproval={mockApprovalList[2]} />
|
||||
<WorkflowApprovalButton
|
||||
workflowApproval={mockApprovalList[2]}
|
||||
onHandleToast={jest.fn()}
|
||||
/>
|
||||
);
|
||||
expect(wrapper.find(approveButton)).toHaveLength(1);
|
||||
expect(wrapper.find(approveButton).prop('isDisabled')).toBe(true);
|
||||
@ -47,7 +53,10 @@ describe('<WorkflowApprovalButton/>, full mount', () => {
|
||||
test('should handle approve', async () => {
|
||||
act(() => {
|
||||
wrapper = mountWithContexts(
|
||||
<WorkflowApprovalButton workflowApproval={mockApprovalList[0]} />
|
||||
<WorkflowApprovalButton
|
||||
workflowApproval={mockApprovalList[0]}
|
||||
onHandleToast={jest.fn()}
|
||||
/>
|
||||
);
|
||||
});
|
||||
await act(() => wrapper.find(approveButton).prop('onClick')());
|
||||
|
||||
@ -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 } =
|
||||
|
||||
@ -39,7 +39,10 @@ describe('<WorkflowDenyButton/>, full mount', () => {
|
||||
|
||||
test('should be disabled', () => {
|
||||
wrapper = mountWithContexts(
|
||||
<WorkflowDenyButton workflowApproval={mockApprovalList[1]} />
|
||||
<WorkflowDenyButton
|
||||
workflowApproval={mockApprovalList[2]}
|
||||
onHandleToast={jest.fn()}
|
||||
/>
|
||||
);
|
||||
expect(wrapper.find(denyButton)).toHaveLength(1);
|
||||
expect(wrapper.find(denyButton).prop('isDisabled')).toBe(true);
|
||||
@ -48,7 +51,10 @@ describe('<WorkflowDenyButton/>, full mount', () => {
|
||||
test('should handle deny', async () => {
|
||||
act(() => {
|
||||
wrapper = mountWithContexts(
|
||||
<WorkflowDenyButton workflowApproval={mockApprovalList[0]} />
|
||||
<WorkflowDenyButton
|
||||
workflowApproval={mockApprovalList[0]}
|
||||
onHandleToast={jest.fn()}
|
||||
/>
|
||||
);
|
||||
});
|
||||
await act(() => wrapper.find(denyButton).prop('onClick')());
|
||||
@ -70,7 +76,10 @@ describe('<WorkflowDenyButton/>, full mount', () => {
|
||||
);
|
||||
act(() => {
|
||||
wrapper = mountWithContexts(
|
||||
<WorkflowDenyButton workflowApproval={mockApprovalList[0]} />
|
||||
<WorkflowDenyButton
|
||||
workflowApproval={mockApprovalList[0]}
|
||||
onHandleToast={jest.fn()}
|
||||
/>
|
||||
);
|
||||
});
|
||||
await act(() => wrapper.find(denyButton).prop('onClick')());
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user