From eddb6e1faf9f02733562219aa002c24c368a0326 Mon Sep 17 00:00:00 2001 From: mabashian Date: Fri, 24 Jan 2020 11:24:46 -0500 Subject: [PATCH] Combines the two start node components into one. Removes use of document.getElementById in workflow components in favor of refs. --- .../Workflow/WorkflowStartNode.jsx} | 31 +++++++++------- .../Workflow/WorkflowStartNode.test.jsx | 36 +++++++++++++++++++ awx/ui_next/src/components/Workflow/index.js | 1 + .../WorkflowOutput/WorkflowOutputGraph.jsx | 14 ++++---- .../Job/WorkflowOutput/WorkflowOutputLink.jsx | 14 +++----- .../WorkflowOutputStartNode.jsx | 28 --------------- .../WorkflowOutputStartNode.test.jsx | 21 ----------- .../src/screens/Job/WorkflowOutput/index.js | 1 - .../VisualizerGraph.jsx | 15 ++++---- .../VisualizerLink.jsx | 14 +++----- .../VisualizerNode.jsx | 7 ++-- .../WorkflowJobTemplateVisualizer/index.js | 1 - 12 files changed, 82 insertions(+), 101 deletions(-) rename awx/ui_next/src/{screens/Template/WorkflowJobTemplateVisualizer/VisualizerStartNode.jsx => components/Workflow/WorkflowStartNode.jsx} (77%) create mode 100644 awx/ui_next/src/components/Workflow/WorkflowStartNode.test.jsx delete mode 100644 awx/ui_next/src/screens/Job/WorkflowOutput/WorkflowOutputStartNode.jsx delete mode 100644 awx/ui_next/src/screens/Job/WorkflowOutput/WorkflowOutputStartNode.test.jsx diff --git a/awx/ui_next/src/screens/Template/WorkflowJobTemplateVisualizer/VisualizerStartNode.jsx b/awx/ui_next/src/components/Workflow/WorkflowStartNode.jsx similarity index 77% rename from awx/ui_next/src/screens/Template/WorkflowJobTemplateVisualizer/VisualizerStartNode.jsx rename to awx/ui_next/src/components/Workflow/WorkflowStartNode.jsx index c54cb51799..a292ef1763 100644 --- a/awx/ui_next/src/screens/Template/WorkflowJobTemplateVisualizer/VisualizerStartNode.jsx +++ b/awx/ui_next/src/components/Workflow/WorkflowStartNode.jsx @@ -1,4 +1,4 @@ -import React, { useState } from 'react'; +import React, { useRef, useState } from 'react'; import styled from 'styled-components'; import { withI18n } from '@lingui/react'; import { t } from '@lingui/macro'; @@ -14,19 +14,19 @@ const StartG = styled.g` pointer-events: ${props => (props.ignorePointerEvents ? 'none' : 'auto')}; `; -function VisualizerStartNode({ +function WorkflowStartNode({ addingLink, i18n, nodePositions, onAddNodeClick, onUpdateHelpText, - readOnly, + showActionTooltip, }) { + const ref = useRef(null); const [hovering, setHovering] = useState(false); const handleNodeMouseEnter = () => { - const nodeEl = document.getElementById('node-1'); - nodeEl.parentNode.appendChild(nodeEl); + ref.current.parentNode.appendChild(ref.current); setHovering(true); }; @@ -36,6 +36,7 @@ function VisualizerStartNode({ ignorePointerEvents={addingLink} onMouseEnter={handleNodeMouseEnter} onMouseLeave={() => setHovering(false)} + ref={ref} transform={`translate(${nodePositions[1].x},0)`} > START - {!readOnly && hovering && ( + {showActionTooltip && hovering && ( {}, + onUpdateHelpText: () => {}, +}; + +export default withI18n()(WorkflowStartNode); diff --git a/awx/ui_next/src/components/Workflow/WorkflowStartNode.test.jsx b/awx/ui_next/src/components/Workflow/WorkflowStartNode.test.jsx new file mode 100644 index 0000000000..8bc7d733b3 --- /dev/null +++ b/awx/ui_next/src/components/Workflow/WorkflowStartNode.test.jsx @@ -0,0 +1,36 @@ +import React from 'react'; +import { mount } from 'enzyme'; +import WorkflowStartNode from './WorkflowStartNode'; + +const nodePositions = { + 1: { + x: 0, + y: 0, + }, +}; + +describe('WorkflowStartNode', () => { + test('mounts successfully', () => { + const wrapper = mount( + + + + ); + expect(wrapper).toHaveLength(1); + }); + test('tooltip shown on hover', () => { + const wrapper = mount( + + + + ); + expect(wrapper.find('WorkflowActionTooltip')).toHaveLength(0); + wrapper.find('WorkflowStartNode').simulate('mouseenter'); + expect(wrapper.find('WorkflowActionTooltip')).toHaveLength(1); + wrapper.find('WorkflowStartNode').simulate('mouseleave'); + expect(wrapper.find('WorkflowActionTooltip')).toHaveLength(0); + }); +}); diff --git a/awx/ui_next/src/components/Workflow/index.js b/awx/ui_next/src/components/Workflow/index.js index c0adfbe7c1..3dd45adb26 100644 --- a/awx/ui_next/src/components/Workflow/index.js +++ b/awx/ui_next/src/components/Workflow/index.js @@ -7,4 +7,5 @@ export { default as WorkflowKey } from './WorkflowKey'; export { default as WorkflowLinkHelp } from './WorkflowLinkHelp'; export { default as WorkflowNodeHelp } from './WorkflowNodeHelp'; export { default as WorkflowNodeTypeLetter } from './WorkflowNodeTypeLetter'; +export { default as WorkflowStartNode } from './WorkflowStartNode'; export { default as WorkflowTools } from './WorkflowTools'; diff --git a/awx/ui_next/src/screens/Job/WorkflowOutput/WorkflowOutputGraph.jsx b/awx/ui_next/src/screens/Job/WorkflowOutput/WorkflowOutputGraph.jsx index e053d7d346..0b65674907 100644 --- a/awx/ui_next/src/screens/Job/WorkflowOutput/WorkflowOutputGraph.jsx +++ b/awx/ui_next/src/screens/Job/WorkflowOutput/WorkflowOutputGraph.jsx @@ -8,13 +8,13 @@ import { import { WorkflowOutputLink, WorkflowOutputNode, - WorkflowOutputStartNode, } from '@screens/Job/WorkflowOutput'; import { WorkflowHelp, WorkflowKey, WorkflowLinkHelp, WorkflowNodeHelp, + WorkflowStartNode, WorkflowTools, } from '@components/Workflow'; @@ -75,8 +75,7 @@ function WorkflowOutputGraph({ }; const handlePanToMiddle = () => { - const svgElement = document.getElementById('workflow-svg'); - const svgBoundingClientRect = svgElement.getBoundingClientRect(); + const svgBoundingClientRect = svgRef.current.getBoundingClientRect(); d3.select(svgRef.current).call( zoomRef.transform, d3.zoomIdentity @@ -88,8 +87,7 @@ function WorkflowOutputGraph({ }; const handleZoomChange = newScale => { - const svgElement = document.getElementById('workflow-svg'); - const svgBoundingClientRect = svgElement.getBoundingClientRect(); + const svgBoundingClientRect = svgRef.current.getBoundingClientRect(); const currentScaleAndOffset = d3.zoomTransform( d3.select(svgRef.current).node() ); @@ -121,8 +119,7 @@ function WorkflowOutputGraph({ .node() .getBBox(); - const svgElement = document.getElementById('workflow-svg'); - const svgBoundingClientRect = svgElement.getBoundingClientRect(); + const svgBoundingClientRect = svgRef.current.getBoundingClientRect(); const [scaleToFit, yTranslate] = getScaleAndOffsetToFit( gBoundingClientRect, @@ -175,9 +172,10 @@ function WorkflowOutputGraph({ > {nodePositions && [ - , links.map(link => ( { - const linkEl = document.getElementById( - `link-${link.source.id}-${link.target.id}` - ); - linkEl.parentNode.appendChild(linkEl); + ref.current.parentNode.appendChild(ref.current); setHovering(true); }; const handleLinkMouseLeave = () => { - const linkEl = document.getElementById( - `link-${link.source.id}-${link.target.id}` - ); - linkEl.parentNode.prepend(linkEl); + ref.current.parentNode.prepend(ref.current); setHovering(null); }; @@ -46,6 +41,7 @@ function WorkflowOutputLink({ link, nodePositions, onUpdateLinkHelp }) { return ( - - {/* TODO: We need to be able to handle translated text here */} - - START - - - ); -} - -WorkflowOutputStartNode.propTypes = { - nodePositions: shape().isRequired, -}; - -export default WorkflowOutputStartNode; diff --git a/awx/ui_next/src/screens/Job/WorkflowOutput/WorkflowOutputStartNode.test.jsx b/awx/ui_next/src/screens/Job/WorkflowOutput/WorkflowOutputStartNode.test.jsx deleted file mode 100644 index 456c8aa19c..0000000000 --- a/awx/ui_next/src/screens/Job/WorkflowOutput/WorkflowOutputStartNode.test.jsx +++ /dev/null @@ -1,21 +0,0 @@ -import React from 'react'; -import { mount } from 'enzyme'; -import WorkflowOutputStartNode from './WorkflowOutputStartNode'; - -const nodePositions = { - 1: { - x: 0, - y: 0, - }, -}; - -describe('WorkflowOutputStartNode', () => { - test('mounts successfully', () => { - const wrapper = mount( - - - - ); - expect(wrapper).toHaveLength(1); - }); -}); diff --git a/awx/ui_next/src/screens/Job/WorkflowOutput/index.js b/awx/ui_next/src/screens/Job/WorkflowOutput/index.js index f3020d0679..879db49502 100644 --- a/awx/ui_next/src/screens/Job/WorkflowOutput/index.js +++ b/awx/ui_next/src/screens/Job/WorkflowOutput/index.js @@ -2,5 +2,4 @@ export { default as WorkflowOutput } from './WorkflowOutput'; export { default as WorkflowOutputGraph } from './WorkflowOutputGraph'; export { default as WorkflowOutputLink } from './WorkflowOutputLink'; export { default as WorkflowOutputNode } from './WorkflowOutputNode'; -export { default as WorkflowOutputStartNode } from './WorkflowOutputStartNode'; export { default as WorkflowOutputToolbar } from './WorkflowOutputToolbar'; diff --git a/awx/ui_next/src/screens/Template/WorkflowJobTemplateVisualizer/VisualizerGraph.jsx b/awx/ui_next/src/screens/Template/WorkflowJobTemplateVisualizer/VisualizerGraph.jsx index a37b022e14..9e613f506c 100644 --- a/awx/ui_next/src/screens/Template/WorkflowJobTemplateVisualizer/VisualizerGraph.jsx +++ b/awx/ui_next/src/screens/Template/WorkflowJobTemplateVisualizer/VisualizerGraph.jsx @@ -14,12 +14,12 @@ import { WorkflowKey, WorkflowLinkHelp, WorkflowNodeHelp, + WorkflowStartNode, WorkflowTools, } from '@components/Workflow'; import { VisualizerLink, VisualizerNode, - VisualizerStartNode, } from '@screens/Template/WorkflowJobTemplateVisualizer'; const PotentialLink = styled.polyline` @@ -148,8 +148,7 @@ function VisualizerGraph({ }; const handlePanToMiddle = () => { - const svgElement = document.getElementById('workflow-svg'); - const svgBoundingClientRect = svgElement.getBoundingClientRect(); + const svgBoundingClientRect = svgRef.current.getBoundingClientRect(); d3.select(svgRef.current).call( zoomRef.transform, d3.zoomIdentity @@ -161,8 +160,7 @@ function VisualizerGraph({ }; const handleZoomChange = newScale => { - const svgElement = document.getElementById('workflow-svg'); - const svgBoundingClientRect = svgElement.getBoundingClientRect(); + const svgBoundingClientRect = svgRef.current.getBoundingClientRect(); const currentScaleAndOffset = d3.zoomTransform( d3.select(svgRef.current).node() ); @@ -194,8 +192,7 @@ function VisualizerGraph({ .node() .getBBox(); - const svgElement = document.getElementById('workflow-svg'); - const svgBoundingClientRect = svgElement.getBoundingClientRect(); + const svgBoundingClientRect = svgRef.current.getBoundingClientRect(); const [scaleToFit, yTranslate] = getScaleAndOffsetToFit( gBoundingClientRect, @@ -276,12 +273,12 @@ function VisualizerGraph({ /> {nodePositions && [ - , links.map(link => { diff --git a/awx/ui_next/src/screens/Template/WorkflowJobTemplateVisualizer/VisualizerLink.jsx b/awx/ui_next/src/screens/Template/WorkflowJobTemplateVisualizer/VisualizerLink.jsx index 4a9fd852f1..b719189e9e 100644 --- a/awx/ui_next/src/screens/Template/WorkflowJobTemplateVisualizer/VisualizerLink.jsx +++ b/awx/ui_next/src/screens/Template/WorkflowJobTemplateVisualizer/VisualizerLink.jsx @@ -1,4 +1,4 @@ -import React, { useEffect, useState } from 'react'; +import React, { useEffect, useRef, useState } from 'react'; import styled from 'styled-components'; import { withI18n } from '@lingui/react'; import { t } from '@lingui/macro'; @@ -30,6 +30,7 @@ function VisualizerLink({ onUpdateLinkHelp, readOnly, }) { + const ref = useRef(null); const [hovering, setHovering] = useState(false); const [pathD, setPathD] = useState(); const [pathStroke, setPathStroke] = useState('#CCCCCC'); @@ -80,18 +81,12 @@ function VisualizerLink({ ]; const handleLinkMouseEnter = () => { - const linkEl = document.getElementById( - `link-${link.source.id}-${link.target.id}` - ); - linkEl.parentNode.appendChild(linkEl); + ref.current.parentNode.appendChild(ref.current); setHovering(true); }; const handleLinkMouseLeave = () => { - const linkEl = document.getElementById( - `link-${link.source.id}-${link.target.id}` - ); - linkEl.parentNode.prepend(linkEl); + ref.current.parentNode.prepend(ref.current); setHovering(null); }; @@ -120,6 +115,7 @@ function VisualizerLink({ ignorePointerEvents={addingLink} onMouseEnter={handleLinkMouseEnter} onMouseLeave={handleLinkMouseLeave} + ref={ref} > { - const nodeEl = document.getElementById(`node-${node.id}`); - nodeEl.parentNode.appendChild(nodeEl); + ref.current.parentNode.appendChild(ref.current); setHovering(true); if (addingLink) { onUpdateHelpText( @@ -168,6 +168,7 @@ function VisualizerNode({ noPointerEvents={isAddLinkSourceNode} onMouseEnter={handleNodeMouseEnter} onMouseLeave={handleNodeMouseLeave} + ref={ref} transform={`translate(${nodePositions[node.id].x},${nodePositions[node.id] .y - nodePositions[1].y})`} > diff --git a/awx/ui_next/src/screens/Template/WorkflowJobTemplateVisualizer/index.js b/awx/ui_next/src/screens/Template/WorkflowJobTemplateVisualizer/index.js index 9c3200ca48..0d7871e690 100644 --- a/awx/ui_next/src/screens/Template/WorkflowJobTemplateVisualizer/index.js +++ b/awx/ui_next/src/screens/Template/WorkflowJobTemplateVisualizer/index.js @@ -2,6 +2,5 @@ export { default as Visualizer } from './Visualizer'; export { default as VisualizerGraph } from './VisualizerGraph'; export { default as VisualizerLink } from './VisualizerLink'; export { default as VisualizerNode } from './VisualizerNode'; -export { default as VisualizerStartNode } from './VisualizerStartNode'; export { default as VisualizerStartScreen } from './VisualizerStartScreen'; export { default as VisualizerToolbar } from './VisualizerToolbar';