1
0
mirror of https://github.com/ansible/awx.git synced 2024-10-31 23:51:09 +03:00

Add close button to workflow tools/key

This commit is contained in:
mabashian 2020-01-22 12:05:32 -05:00
parent 5a1a47b7aa
commit e394d0a6f6
8 changed files with 56 additions and 20 deletions

View File

@ -2,18 +2,25 @@ import React from 'react';
import { withI18n } from '@lingui/react'; import { withI18n } from '@lingui/react';
import { t } from '@lingui/macro'; import { t } from '@lingui/macro';
import styled from 'styled-components'; import styled from 'styled-components';
import { ExclamationTriangleIcon, PauseIcon } from '@patternfly/react-icons'; import { func } from 'prop-types';
import {
ExclamationTriangleIcon,
PauseIcon,
TimesIcon,
} from '@patternfly/react-icons';
const Wrapper = styled.div` const Wrapper = styled.div`
background-color: white; background-color: white;
border: 1px solid #c7c7c7; border: 1px solid #c7c7c7;
margin-left: 20px; margin-left: 20px;
min-width: 100px; min-width: 100px;
position: relative;
`; `;
const Header = styled.div` const Header = styled.div`
border-bottom: 1px solid #c7c7c7; border-bottom: 1px solid #c7c7c7;
padding: 10px; padding: 10px;
position: relative;
`; `;
const Key = styled.ul` const Key = styled.ul`
@ -63,11 +70,19 @@ const AlwaysLink = styled(Link)`
background-color: #337ab7; background-color: #337ab7;
`; `;
function WorkflowKey({ i18n }) { const Close = styled(TimesIcon)`
cursor: pointer;
position: absolute;
right: 10px;
top: 15px;
`;
function WorkflowKey({ i18n, onClose }) {
return ( return (
<Wrapper> <Wrapper>
<Header> <Header>
<b>{i18n._(t`Key`)}</b> <b>{i18n._(t`Key`)}</b>
<Close onClick={onClose} />
</Header> </Header>
<Key> <Key>
<li> <li>
@ -113,4 +128,8 @@ function WorkflowKey({ i18n }) {
); );
} }
WorkflowKey.propTypes = {
onClose: func.isRequired,
};
export default withI18n()(WorkflowKey); export default withI18n()(WorkflowKey);

View File

@ -4,7 +4,7 @@ import WorkflowKey from './WorkflowKey';
describe('WorkflowKey', () => { describe('WorkflowKey', () => {
test('renders the expected content', () => { test('renders the expected content', () => {
const wrapper = mountWithContexts(<WorkflowKey />); const wrapper = mountWithContexts(<WorkflowKey onClose={() => {}} />);
expect(wrapper).toHaveLength(1); expect(wrapper).toHaveLength(1);
}); });
}); });

View File

@ -13,12 +13,14 @@ import {
HomeIcon, HomeIcon,
MinusIcon, MinusIcon,
PlusIcon, PlusIcon,
TimesIcon,
} from '@patternfly/react-icons'; } from '@patternfly/react-icons';
const Wrapper = styled.div` const Wrapper = styled.div`
background-color: white; background-color: white;
border: 1px solid #c7c7c7; border: 1px solid #c7c7c7;
height: 135px; height: 135px;
position: relative;
`; `;
const Header = styled.div` const Header = styled.div`
@ -42,8 +44,16 @@ const Tools = styled.div`
padding: 20px; padding: 20px;
`; `;
const Close = styled(TimesIcon)`
cursor: pointer;
position: absolute;
right: 10px;
top: 15px;
`;
function WorkflowTools({ function WorkflowTools({
i18n, i18n,
onClose,
onFitGraph, onFitGraph,
onPan, onPan,
onPanToMiddle, onPanToMiddle,
@ -70,6 +80,7 @@ function WorkflowTools({
<Wrapper> <Wrapper>
<Header> <Header>
<b>{i18n._(t`Tools`)}</b> <b>{i18n._(t`Tools`)}</b>
<Close onClick={onClose} />
</Header> </Header>
<Tools> <Tools>
<Tooltip <Tooltip
@ -123,6 +134,7 @@ function WorkflowTools({
} }
WorkflowTools.propTypes = { WorkflowTools.propTypes = {
onClose: func.isRequired,
onFitGraph: func.isRequired, onFitGraph: func.isRequired,
onPan: func.isRequired, onPan: func.isRequired,
onPanToMiddle: func.isRequired, onPanToMiddle: func.isRequired,

View File

@ -6,6 +6,7 @@ describe('WorkflowTools', () => {
test('renders the expected content', () => { test('renders the expected content', () => {
const wrapper = mountWithContexts( const wrapper = mountWithContexts(
<WorkflowTools <WorkflowTools
onClose={() => {}}
onFitGraph={() => {}} onFitGraph={() => {}}
onPan={() => {}} onPan={() => {}}
onPanToMiddle={() => {}} onPanToMiddle={() => {}}
@ -15,12 +16,14 @@ describe('WorkflowTools', () => {
); );
expect(wrapper).toHaveLength(1); expect(wrapper).toHaveLength(1);
}); });
test('clicking zoom buttons passes callback correctly updated scale', () => { test('clicking zoom/pan buttons passes callback correct values', () => {
const pan = jest.fn();
const zoomChange = jest.fn(); const zoomChange = jest.fn();
const wrapper = mountWithContexts( const wrapper = mountWithContexts(
<WorkflowTools <WorkflowTools
onClose={() => {}}
onFitGraph={() => {}} onFitGraph={() => {}}
onPan={() => {}} onPan={pan}
onPanToMiddle={() => {}} onPanToMiddle={() => {}}
onZoomChange={zoomChange} onZoomChange={zoomChange}
zoomPercentage={95.7} zoomPercentage={95.7}
@ -30,18 +33,6 @@ describe('WorkflowTools', () => {
expect(zoomChange).toHaveBeenCalledWith(1.1); expect(zoomChange).toHaveBeenCalledWith(1.1);
wrapper.find('MinusIcon').simulate('click'); wrapper.find('MinusIcon').simulate('click');
expect(zoomChange).toHaveBeenCalledWith(0.8); expect(zoomChange).toHaveBeenCalledWith(0.8);
});
test('clicking pan buttons passes callback correct string direction', () => {
const pan = jest.fn();
const wrapper = mountWithContexts(
<WorkflowTools
onFitGraph={() => {}}
onPan={pan}
onPanToMiddle={() => {}}
onZoomChange={() => {}}
zoomPercentage={100}
/>
);
wrapper.find('CaretLeftIcon').simulate('click'); wrapper.find('CaretLeftIcon').simulate('click');
expect(pan).toHaveBeenCalledWith('left'); expect(pan).toHaveBeenCalledWith('left');
wrapper.find('CaretUpIcon').simulate('click'); wrapper.find('CaretUpIcon').simulate('click');

View File

@ -211,6 +211,8 @@ function WorkflowOutput({ job, i18n }) {
links={graphLinks} links={graphLinks}
nodePositions={nodePositions} nodePositions={nodePositions}
nodes={graphNodes} nodes={graphNodes}
onUpdateShowKey={setShowKey}
onUpdateShowTools={setShowTools}
showKey={showKey} showKey={showKey}
showTools={showTools} showTools={showTools}
/> />

View File

@ -1,6 +1,6 @@
import React, { Fragment, useEffect, useRef, useState } from 'react'; import React, { Fragment, useEffect, useRef, useState } from 'react';
import * as d3 from 'd3'; import * as d3 from 'd3';
import { arrayOf, bool, shape } from 'prop-types'; import { arrayOf, bool, shape, func } from 'prop-types';
import { calcZoomAndFit, getZoomTranslate } from '@util/workflow'; import { calcZoomAndFit, getZoomTranslate } from '@util/workflow';
import { import {
WorkflowOutputLink, WorkflowOutputLink,
@ -18,6 +18,8 @@ function WorkflowOutputGraph({
links, links,
nodePositions, nodePositions,
nodes, nodes,
onUpdateShowKey,
onUpdateShowTools,
showKey, showKey,
showTools, showTools,
}) { }) {
@ -180,6 +182,7 @@ function WorkflowOutputGraph({
<div css="position: absolute; top: 75px;right: 20px;display: flex;"> <div css="position: absolute; top: 75px;right: 20px;display: flex;">
{showTools && ( {showTools && (
<WorkflowTools <WorkflowTools
onClose={() => onUpdateShowTools(false)}
onFitGraph={handleFitGraph} onFitGraph={handleFitGraph}
onPan={handlePan} onPan={handlePan}
onPanToMiddle={handlePanToMiddle} onPanToMiddle={handlePanToMiddle}
@ -187,7 +190,7 @@ function WorkflowOutputGraph({
zoomPercentage={zoomPercentage} zoomPercentage={zoomPercentage}
/> />
)} )}
{showKey && <WorkflowKey />} {showKey && <WorkflowKey onClose={() => onUpdateShowKey(false)} />}
</div> </div>
</Fragment> </Fragment>
); );
@ -197,6 +200,8 @@ WorkflowOutputGraph.propTypes = {
links: arrayOf(shape()).isRequired, links: arrayOf(shape()).isRequired,
nodePositions: shape().isRequired, nodePositions: shape().isRequired,
nodes: arrayOf(shape()).isRequired, nodes: arrayOf(shape()).isRequired,
onUpdateShowKey: func.isRequired,
onUpdateShowTools: func.isRequired,
showKey: bool.isRequired, showKey: bool.isRequired,
showTools: bool.isRequired, showTools: bool.isRequired,
}; };

View File

@ -825,6 +825,8 @@ function Visualizer({ history, template, i18n }) {
onEditNodeClick={startEditNode} onEditNodeClick={startEditNode}
onLinkEditClick={setLinkToEdit} onLinkEditClick={setLinkToEdit}
onStartAddLinkClick={selectSourceNodeForLinking} onStartAddLinkClick={selectSourceNodeForLinking}
onUpdateShowKey={setShowKey}
onUpdateShowTools={setShowTools}
onViewNodeClick={setNodeToView} onViewNodeClick={setNodeToView}
readOnly={!template.summary_fields.user_capabilities.edit} readOnly={!template.summary_fields.user_capabilities.edit}
showKey={showKey} showKey={showKey}

View File

@ -47,6 +47,8 @@ function VisualizerGraph({
onEditNodeClick, onEditNodeClick,
onLinkEditClick, onLinkEditClick,
onStartAddLinkClick, onStartAddLinkClick,
onUpdateShowKey,
onUpdateShowTools,
onViewNodeClick, onViewNodeClick,
readOnly, readOnly,
showKey, showKey,
@ -329,6 +331,7 @@ function VisualizerGraph({
<div css="position: absolute; top: 75px;right: 20px;display: flex;"> <div css="position: absolute; top: 75px;right: 20px;display: flex;">
{showTools && ( {showTools && (
<WorkflowTools <WorkflowTools
onClose={() => onUpdateShowTools(false)}
onFitGraph={handleFitGraph} onFitGraph={handleFitGraph}
onPan={handlePan} onPan={handlePan}
onPanToMiddle={handlePanToMiddle} onPanToMiddle={handlePanToMiddle}
@ -336,7 +339,7 @@ function VisualizerGraph({
zoomPercentage={zoomPercentage} zoomPercentage={zoomPercentage}
/> />
)} )}
{showKey && <WorkflowKey />} {showKey && <WorkflowKey onClose={() => onUpdateShowKey(false)} />}
</div> </div>
</> </>
); );
@ -356,6 +359,8 @@ VisualizerGraph.propTypes = {
onEditNodeClick: func.isRequired, onEditNodeClick: func.isRequired,
onLinkEditClick: func.isRequired, onLinkEditClick: func.isRequired,
onStartAddLinkClick: func.isRequired, onStartAddLinkClick: func.isRequired,
onUpdateShowKey: func.isRequired,
onUpdateShowTools: func.isRequired,
onViewNodeClick: func.isRequired, onViewNodeClick: func.isRequired,
readOnly: bool.isRequired, readOnly: bool.isRequired,
showKey: bool.isRequired, showKey: bool.isRequired,