diff --git a/awx/ui_next/src/components/Workflow/WorkflowNodeHelp.jsx b/awx/ui_next/src/components/Workflow/WorkflowNodeHelp.jsx
index ce25921463..355c29c7d6 100644
--- a/awx/ui_next/src/components/Workflow/WorkflowNodeHelp.jsx
+++ b/awx/ui_next/src/components/Workflow/WorkflowNodeHelp.jsx
@@ -1,7 +1,8 @@
-import React, { Fragment } from 'react';
+import React from 'react';
import { withI18n } from '@lingui/react';
-import { t } from '@lingui/macro';
+import { t, Trans } from '@lingui/macro';
import styled from 'styled-components';
+import { ExclamationTriangleIcon } from '@patternfly/react-icons';
import { shape } from 'prop-types';
import { secondsToHHMMSS } from '@util/dates';
@@ -18,11 +19,23 @@ const GridDL = styled.dl`
}
`;
+const ResourceDeleted = styled.p`
+ margin-bottom: ${props => (props.job ? '10px' : '0px')};
+`;
+
+const StyledExclamationTriangleIcon = styled(ExclamationTriangleIcon)`
+ color: #f0ad4d;
+ height: 20px;
+ margin-right: 10px;
+ width: 20px;
+`;
+
function WorkflowNodeHelp({ node, i18n }) {
let nodeType;
- if (node.unifiedJobTemplate) {
- const type =
- node.unifiedJobTemplate.unified_job_type || node.unifiedJobTemplate.type;
+ if (node.unifiedJobTemplate || node.job) {
+ const type = node.unifiedJobTemplate
+ ? node.unifiedJobTemplate.unified_job_type || node.unifiedJobTemplate.type
+ : node.job.type;
switch (type) {
case 'job_template':
case 'job':
@@ -97,43 +110,59 @@ function WorkflowNodeHelp({ node, i18n }) {
}
return (
-
-
- {node.unifiedJobTemplate && (
-
-
- {i18n._(t`Name`)}
-
- {node.unifiedJobTemplate.name}
-
- {i18n._(t`Type`)}
-
- {nodeType}
-
- )}
- {node.job && (
-
-
- {i18n._(t`Job Status`)}
-
- {jobStatus}
- {node.job.elapsed && (
-
-
- {i18n._(t`Elapsed`)}
-
-
- {secondsToHHMMSS(node.job.elapsed)}
-
-
- )}
-
- )}
-
+ <>
+ {!node.unifiedJobTemplate && (
+ <>
+
+
+
+ The resource associated with this node has been deleted.
+
+
+ >
+ )}
+ {node.job && (
+
+
+ {i18n._(t`Name`)}
+
+ {node.job.name}
+
+ {i18n._(t`Type`)}
+
+ {nodeType}
+
+ {i18n._(t`Job Status`)}
+
+ {jobStatus}
+ {node.job.elapsed && (
+ <>
+
+ {i18n._(t`Elapsed`)}
+
+
+ {secondsToHHMMSS(node.job.elapsed)}
+
+ >
+ )}
+
+ )}
+ {node.unifiedJobTemplate && !node.job && (
+
+
+ {i18n._(t`Name`)}
+
+ {node.unifiedJobTemplate.name}
+
+ {i18n._(t`Type`)}
+
+ {nodeType}
+
+ )}
{node.job && (
{i18n._(t`Click to view job details`)}
)}
-
+ >
);
}
diff --git a/awx/ui_next/src/components/Workflow/WorkflowNodeHelp.test.jsx b/awx/ui_next/src/components/Workflow/WorkflowNodeHelp.test.jsx
index 01e771a140..30980cf353 100644
--- a/awx/ui_next/src/components/Workflow/WorkflowNodeHelp.test.jsx
+++ b/awx/ui_next/src/components/Workflow/WorkflowNodeHelp.test.jsx
@@ -10,6 +10,7 @@ describe('WorkflowNodeHelp', () => {
test('renders the expected content for a completed job template job', () => {
const node = {
job: {
+ name: 'Foo Job Template',
elapsed: 9000,
status: 'successful',
},
diff --git a/awx/ui_next/src/components/Workflow/WorkflowNodeTypeLetter.jsx b/awx/ui_next/src/components/Workflow/WorkflowNodeTypeLetter.jsx
index 8abe9f4e77..5e01977d88 100644
--- a/awx/ui_next/src/components/Workflow/WorkflowNodeTypeLetter.jsx
+++ b/awx/ui_next/src/components/Workflow/WorkflowNodeTypeLetter.jsx
@@ -3,13 +3,15 @@ import styled from 'styled-components';
import { shape } from 'prop-types';
import { PauseIcon } from '@patternfly/react-icons';
-const NodeTypeLetter = styled.foreignObject`
+const NodeTypeLetter = styled.div`
background-color: #393f43;
border-radius: 50%;
color: white;
font-size: 10px;
line-height: 20px;
text-align: center;
+ height: 20px;
+ width: 20px;
`;
const CenteredPauseIcon = styled(PauseIcon)`
@@ -19,11 +21,14 @@ const CenteredPauseIcon = styled(PauseIcon)`
function WorkflowNodeTypeLetter({ node }) {
let nodeTypeLetter;
if (
- node.unifiedJobTemplate &&
- (node.unifiedJobTemplate.type || node.unifiedJobTemplate.unified_job_type)
+ (node.unifiedJobTemplate &&
+ (node.unifiedJobTemplate.type ||
+ node.unifiedJobTemplate.unified_job_type)) ||
+ (node.job && node.job.type)
) {
- const ujtType =
- node.unifiedJobTemplate.type || node.unifiedJobTemplate.unified_job_type;
+ const ujtType = node.unifiedJobTemplate
+ ? node.unifiedJobTemplate.type || node.unifiedJobTemplate.unified_job_type
+ : node.job.type;
switch (ujtType) {
case 'job_template':
case 'job':
@@ -51,9 +56,9 @@ function WorkflowNodeTypeLetter({ node }) {
}
return (
-
- {nodeTypeLetter}
-
+
+ {nodeTypeLetter}
+
);
}
diff --git a/awx/ui_next/src/screens/Job/WorkflowOutput/WorkflowOutputNode.jsx b/awx/ui_next/src/screens/Job/WorkflowOutput/WorkflowOutputNode.jsx
index e8fcf8f68c..48bcba9617 100644
--- a/awx/ui_next/src/screens/Job/WorkflowOutput/WorkflowOutputNode.jsx
+++ b/awx/ui_next/src/screens/Job/WorkflowOutput/WorkflowOutputNode.jsx
@@ -43,7 +43,7 @@ const Elapsed = styled.div`
}
`;
-const NodeContents = styled.foreignObject`
+const NodeContents = styled.div`
font-size: 13px;
padding: 0px 10px;
`;
@@ -98,29 +98,28 @@ function WorkflowOutputNode({ history, i18n, mouseEnter, mouseLeave, node }) {
strokeWidth="2px"
width={wfConstants.nodeW}
/>
-
- {node.job ? (
- <>
-
-
-
- {node.unifiedJobTemplate
- ? node.unifiedJobTemplate.name
- : i18n._(t`DELETED`)}
-
-
- {secondsToHHMMSS(node.job.elapsed)}
- >
- ) : (
-
- {node.unifiedJobTemplate
- ? node.unifiedJobTemplate.name
- : i18n._(t`DELETED`)}
-
- )}
-
-
- {node.unifiedJobTemplate && }
+
+
+ {node.job ? (
+ <>
+
+
+ {node.job.name}
+
+ {secondsToHHMMSS(node.job.elapsed)}
+ >
+ ) : (
+
+ {node.unifiedJobTemplate
+ ? node.unifiedJobTemplate.name
+ : i18n._(t`DELETED`)}
+
+ )}
+
+
+ {(node.unifiedJobTemplate || node.job) && (
+
+ )}
);
}
diff --git a/awx/ui_next/src/screens/Job/WorkflowOutput/WorkflowOutputNode.test.jsx b/awx/ui_next/src/screens/Job/WorkflowOutput/WorkflowOutputNode.test.jsx
index e819d079f3..198c01c3d1 100644
--- a/awx/ui_next/src/screens/Job/WorkflowOutput/WorkflowOutputNode.test.jsx
+++ b/awx/ui_next/src/screens/Job/WorkflowOutput/WorkflowOutputNode.test.jsx
@@ -24,7 +24,7 @@ const nodeWithoutJT = {
job: {
elapsed: 7,
id: 9000,
- name: 'Automation JT',
+ name: 'Automation JT 2',
status: 'successful',
type: 'job',
},
@@ -87,7 +87,7 @@ describe('WorkflowOutputNode', () => {
);
- expect(wrapper.contains(
DELETED
)).toEqual(true);
+ expect(wrapper.contains(Automation JT 2
)).toEqual(true);
expect(wrapper.find('WorkflowOutputNode__Elapsed').text()).toBe('00:00:07');
});
test('node contents displayed correctly when Job deleted', () => {
diff --git a/awx/ui_next/src/screens/Template/WorkflowJobTemplateVisualizer/VisualizerNode.jsx b/awx/ui_next/src/screens/Template/WorkflowJobTemplateVisualizer/VisualizerNode.jsx
index bd66921fad..7b7e6eeaab 100644
--- a/awx/ui_next/src/screens/Template/WorkflowJobTemplateVisualizer/VisualizerNode.jsx
+++ b/awx/ui_next/src/screens/Template/WorkflowJobTemplateVisualizer/VisualizerNode.jsx
@@ -26,7 +26,7 @@ const NodeG = styled.g`
cursor: ${props => (props.job ? 'pointer' : 'default')};
`;
-const NodeContents = styled.foreignObject`
+const NodeContents = styled.div`
font-size: 13px;
padding: 0px 10px;
background-color: ${props =>
@@ -183,25 +183,28 @@ function VisualizerNode({
? '#007ABC'
: '#93969A'
}
- strokeWidth="4px"
+ strokeWidth="2px"
width={wfConstants.nodeW}
/>
- updateNodeHelp(node),
onMouseLeave: () => updateNodeHelp(null),
})}
onClick={() => handleNodeClick()}
- width="180"
+ width="178"
+ x="1"
+ y="1"
>
-
- {node.unifiedJobTemplate
- ? node.unifiedJobTemplate.name
- : i18n._(t`DELETED`)}
-
-
+
+
+ {node.unifiedJobTemplate
+ ? node.unifiedJobTemplate.name
+ : i18n._(t`DELETED`)}
+
+
+
{node.unifiedJobTemplate && }
{hovering && !addingLink && (