mirror of
https://github.com/ansible/awx.git
synced 2026-05-21 07:47:44 -02:30
Adds blanket error handling to visualizer save process
This commit is contained in:
@@ -1,17 +1,21 @@
|
||||
import React, { useEffect, useReducer } from 'react';
|
||||
import React, { useCallback, useEffect, useReducer } from 'react';
|
||||
import { useHistory } from 'react-router-dom';
|
||||
import { withI18n } from '@lingui/react';
|
||||
import styled from 'styled-components';
|
||||
import { shape } from 'prop-types';
|
||||
import { t } from '@lingui/macro';
|
||||
import {
|
||||
WorkflowDispatchContext,
|
||||
WorkflowStateContext,
|
||||
} from '../../../contexts/Workflow';
|
||||
import { getAddedAndRemoved } from '../../../util/lists';
|
||||
import AlertModal from '../../../components/AlertModal';
|
||||
import ErrorDetail from '../../../components/ErrorDetail';
|
||||
import { layoutGraph } from '../../../components/Workflow/WorkflowUtils';
|
||||
import ContentError from '../../../components/ContentError';
|
||||
import ContentLoading from '../../../components/ContentLoading';
|
||||
import workflowReducer from '../../../components/Workflow/workflowReducer';
|
||||
import useRequest, { useDismissableError } from '../../../util/useRequest';
|
||||
import { DeleteAllNodesModal, UnsavedChangesModal } from './Modals';
|
||||
import {
|
||||
LinkAddModal,
|
||||
@@ -246,7 +250,49 @@ function Visualizer({ template, i18n }) {
|
||||
return disassociateNodeRequests;
|
||||
};
|
||||
|
||||
const generateLinkMapAndNewLinks = originalLinkMap => {
|
||||
useEffect(() => {
|
||||
async function fetchData() {
|
||||
try {
|
||||
const workflowNodes = await fetchWorkflowNodes(template.id);
|
||||
dispatch({
|
||||
type: 'GENERATE_NODES_AND_LINKS',
|
||||
nodes: workflowNodes,
|
||||
i18n,
|
||||
});
|
||||
} catch (error) {
|
||||
dispatch({ type: 'SET_CONTENT_ERROR', value: error });
|
||||
} finally {
|
||||
dispatch({ type: 'SET_IS_LOADING', value: false });
|
||||
}
|
||||
}
|
||||
fetchData();
|
||||
}, [template.id, i18n]);
|
||||
|
||||
// Update positions of nodes/links
|
||||
useEffect(() => {
|
||||
if (nodes) {
|
||||
const newNodePositions = {};
|
||||
const nonDeletedNodes = nodes.filter(node => !node.isDeleted);
|
||||
const g = layoutGraph(nonDeletedNodes, links);
|
||||
|
||||
g.nodes().forEach(node => {
|
||||
newNodePositions[node] = g.node(node);
|
||||
});
|
||||
|
||||
dispatch({ type: 'SET_NODE_POSITIONS', value: newNodePositions });
|
||||
}
|
||||
}, [links, nodes]);
|
||||
|
||||
const { error: saveVisualizerError, request: saveVisualizer } = useRequest(
|
||||
useCallback(async () => {
|
||||
const nodeRequests = [];
|
||||
const approvalTemplateRequests = [];
|
||||
const originalLinkMap = {};
|
||||
const deletedNodeIds = [];
|
||||
const associateCredentialRequests = [];
|
||||
const disassociateCredentialRequests = [];
|
||||
|
||||
const generateLinkMapAndNewLinks = () => {
|
||||
const linkMap = {};
|
||||
const newLinks = [];
|
||||
|
||||
@@ -294,13 +340,6 @@ function Visualizer({ template, i18n }) {
|
||||
return [linkMap, newLinks];
|
||||
};
|
||||
|
||||
const handleVisualizerSave = async () => {
|
||||
const nodeRequests = [];
|
||||
const approvalTemplateRequests = [];
|
||||
const originalLinkMap = {};
|
||||
const deletedNodeIds = [];
|
||||
const associateCredentialRequests = [];
|
||||
const disassociateCredentialRequests = [];
|
||||
nodes.forEach(node => {
|
||||
// node with id=1 is the artificial start node
|
||||
if (node.id === 1) {
|
||||
@@ -326,7 +365,9 @@ function Visualizer({ template, i18n }) {
|
||||
WorkflowJobTemplateNodesAPI.destroy(node.originalNodeObject.id)
|
||||
);
|
||||
} else if (!node.isDeleted && !node.originalNodeObject) {
|
||||
if (node.fullUnifiedJobTemplate.type === 'workflow_approval_template') {
|
||||
if (
|
||||
node.fullUnifiedJobTemplate.type === 'workflow_approval_template'
|
||||
) {
|
||||
nodeRequests.push(
|
||||
WorkflowJobTemplatesAPI.createNode(template.id, {}).then(
|
||||
({ data }) => {
|
||||
@@ -338,11 +379,14 @@ function Visualizer({ template, i18n }) {
|
||||
always_nodes: [],
|
||||
};
|
||||
approvalTemplateRequests.push(
|
||||
WorkflowJobTemplateNodesAPI.createApprovalTemplate(data.id, {
|
||||
WorkflowJobTemplateNodesAPI.createApprovalTemplate(
|
||||
data.id,
|
||||
{
|
||||
name: node.fullUnifiedJobTemplate.name,
|
||||
description: node.fullUnifiedJobTemplate.description,
|
||||
timeout: node.fullUnifiedJobTemplate.timeout,
|
||||
})
|
||||
}
|
||||
)
|
||||
);
|
||||
}
|
||||
)
|
||||
@@ -385,14 +429,17 @@ function Visualizer({ template, i18n }) {
|
||||
);
|
||||
}
|
||||
} else if (node.isEdited) {
|
||||
if (node.fullUnifiedJobTemplate.type === 'workflow_approval_template') {
|
||||
if (
|
||||
node.fullUnifiedJobTemplate.type === 'workflow_approval_template'
|
||||
) {
|
||||
if (
|
||||
node.originalNodeObject.summary_fields.unified_job_template
|
||||
.unified_job_type === 'workflow_approval'
|
||||
) {
|
||||
approvalTemplateRequests.push(
|
||||
WorkflowApprovalTemplatesAPI.update(
|
||||
node.originalNodeObject.summary_fields.unified_job_template.id,
|
||||
node.originalNodeObject.summary_fields.unified_job_template
|
||||
.id,
|
||||
{
|
||||
name: node.fullUnifiedJobTemplate.name,
|
||||
description: node.fullUnifiedJobTemplate.description,
|
||||
@@ -418,9 +465,7 @@ function Visualizer({ template, i18n }) {
|
||||
...node.promptValues,
|
||||
inventory: node.promptValues?.inventory?.id || null,
|
||||
unified_job_template: node.fullUnifiedJobTemplate.id,
|
||||
})
|
||||
);
|
||||
|
||||
}).then(() => {
|
||||
const {
|
||||
added: addedCredentials,
|
||||
removed: removedCredentials,
|
||||
@@ -452,6 +497,8 @@ function Visualizer({ template, i18n }) {
|
||||
)
|
||||
);
|
||||
}
|
||||
})
|
||||
);
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -470,40 +517,14 @@ function Visualizer({ template, i18n }) {
|
||||
await Promise.all(associateCredentialRequests);
|
||||
|
||||
history.push(`/templates/workflow_job_template/${template.id}/details`);
|
||||
};
|
||||
}, [links, nodes, history, template.id]),
|
||||
{}
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
async function fetchData() {
|
||||
try {
|
||||
const workflowNodes = await fetchWorkflowNodes(template.id);
|
||||
dispatch({
|
||||
type: 'GENERATE_NODES_AND_LINKS',
|
||||
nodes: workflowNodes,
|
||||
i18n,
|
||||
});
|
||||
} catch (error) {
|
||||
dispatch({ type: 'SET_CONTENT_ERROR', value: error });
|
||||
} finally {
|
||||
dispatch({ type: 'SET_IS_LOADING', value: false });
|
||||
}
|
||||
}
|
||||
fetchData();
|
||||
}, [template.id, i18n]);
|
||||
|
||||
// Update positions of nodes/links
|
||||
useEffect(() => {
|
||||
if (nodes) {
|
||||
const newNodePositions = {};
|
||||
const nonDeletedNodes = nodes.filter(node => !node.isDeleted);
|
||||
const g = layoutGraph(nonDeletedNodes, links);
|
||||
|
||||
g.nodes().forEach(node => {
|
||||
newNodePositions[node] = g.node(node);
|
||||
});
|
||||
|
||||
dispatch({ type: 'SET_NODE_POSITIONS', value: newNodePositions });
|
||||
}
|
||||
}, [links, nodes]);
|
||||
const {
|
||||
error: nodeRequestError,
|
||||
dismissError: dismissNodeRequestError,
|
||||
} = useDismissableError(saveVisualizerError);
|
||||
|
||||
if (isLoading) {
|
||||
return (
|
||||
@@ -529,7 +550,7 @@ function Visualizer({ template, i18n }) {
|
||||
<Wrapper>
|
||||
<VisualizerToolbar
|
||||
onClose={handleVisualizerClose}
|
||||
onSave={handleVisualizerSave}
|
||||
onSave={() => saveVisualizer(nodes)}
|
||||
hasUnsavedChanges={unsavedChanges}
|
||||
template={template}
|
||||
readOnly={readOnly}
|
||||
@@ -553,11 +574,22 @@ function Visualizer({ template, i18n }) {
|
||||
`/templates/workflow_job_template/${template.id}/details`
|
||||
)
|
||||
}
|
||||
onSaveAndExit={() => handleVisualizerSave()}
|
||||
onSaveAndExit={() => saveVisualizer(nodes)}
|
||||
/>
|
||||
)}
|
||||
{showDeleteAllNodesModal && <DeleteAllNodesModal />}
|
||||
{nodeToView && <NodeViewModal readOnly={readOnly} />}
|
||||
{nodeRequestError && (
|
||||
<AlertModal
|
||||
isOpen
|
||||
variant="error"
|
||||
title={i18n._(t`Error!`)}
|
||||
onClose={dismissNodeRequestError}
|
||||
>
|
||||
{i18n._(t`There was an error saving the workflow.`)}
|
||||
<ErrorDetail error={nodeRequestError} />
|
||||
</AlertModal>
|
||||
)}
|
||||
</WorkflowDispatchContext.Provider>
|
||||
</WorkflowStateContext.Provider>
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user