feat: introduce style and behavior improvements

This commit is contained in:
kasia.oczkowska
2024-05-24 11:48:57 +01:00
committed by Ali BARIN
parent 737eb31776
commit f08dc25711
13 changed files with 116 additions and 53 deletions

View File

@@ -165,6 +165,7 @@ function ChooseAppAndEventSubstep(props) {
value={getOption(appOptions, step.appKey) || null} value={getOption(appOptions, step.appKey) || null}
onChange={onAppChange} onChange={onAppChange}
data-test="choose-app-autocomplete" data-test="choose-app-autocomplete"
componentsProps={{ popper: { className: 'nowheel' } }}
/> />
{step.appKey && ( {step.appKey && (
@@ -227,6 +228,7 @@ function ChooseAppAndEventSubstep(props) {
value={getOption(actionOrTriggerOptions, step.key) || null} value={getOption(actionOrTriggerOptions, step.key) || null}
onChange={onEventChange} onChange={onEventChange}
data-test="choose-event-autocomplete" data-test="choose-event-autocomplete"
componentsProps={{ popper: { className: 'nowheel' } }}
/> />
</Box> </Box>
)} )}

View File

@@ -240,6 +240,7 @@ function ChooseConnectionSubstep(props) {
onChange={handleChange} onChange={handleChange}
loading={isAppConnectionsLoading} loading={isAppConnectionsLoading}
data-test="choose-connection-autocomplete" data-test="choose-connection-autocomplete"
componentsProps={{ popper: { className: 'nowheel' } }}
/> />
<Button <Button

View File

@@ -32,9 +32,11 @@ function ControlledAutocomplete(props) {
...autocompleteProps ...autocompleteProps
} = props; } = props;
let dependsOnValues = []; let dependsOnValues = [];
if (dependsOn?.length) { if (dependsOn?.length) {
dependsOnValues = watch(dependsOn); dependsOnValues = watch(dependsOn);
} }
React.useEffect(() => { React.useEffect(() => {
const hasDependencies = dependsOnValues.length; const hasDependencies = dependsOnValues.length;
const allDepsSatisfied = dependsOnValues.every(Boolean); const allDepsSatisfied = dependsOnValues.every(Boolean);
@@ -44,6 +46,7 @@ function ControlledAutocomplete(props) {
resetField(name); resetField(name);
} }
}, dependsOnValues); }, dependsOnValues);
return ( return (
<Controller <Controller
rules={{ required }} rules={{ required }}

View File

@@ -47,6 +47,7 @@ const CustomOptions = (props) => {
}, },
}, },
]} ]}
className="nowheel"
> >
<Paper elevation={5} sx={{ width: '100%' }}> <Paper elevation={5} sx={{ width: '100%' }}>
<Tabs <Tabs

View File

@@ -8,9 +8,11 @@ import { Stack } from '@mui/material';
import { UPDATE_STEP } from 'graphql/mutations/update-step'; import { UPDATE_STEP } from 'graphql/mutations/update-step';
import { useAutoLayout } from './useAutoLayout'; import { useAutoLayout } from './useAutoLayout';
import { useScrollBoundries } from './useScrollBoundries';
import FlowStepNode from './FlowStepNode/FlowStepNode'; import FlowStepNode from './FlowStepNode/FlowStepNode';
import Edge from './Edge/Edge'; import Edge from './Edge/Edge';
import InvisibleNode from './InvisibleNode/InvisibleNode'; import InvisibleNode from './InvisibleNode/InvisibleNode';
import { EditorWrapper } from './style';
const nodeTypes = { flowStep: FlowStepNode, invisible: InvisibleNode }; const nodeTypes = { flowStep: FlowStepNode, invisible: InvisibleNode };
@@ -32,6 +34,7 @@ const EditorNew = ({ flow }) => {
const [nodes, setNodes, onNodesChange] = useNodesState([]); const [nodes, setNodes, onNodesChange] = useNodesState([]);
const [edges, setEdges, onEdgesChange] = useEdgesState([]); const [edges, setEdges, onEdgesChange] = useEdgesState([]);
useAutoLayout(); useAutoLayout();
useScrollBoundries();
const onConnect = useCallback( const onConnect = useCallback(
(params) => setEdges((eds) => addEdge(params, eds)), (params) => setEdges((eds) => addEdge(params, eds)),
@@ -125,6 +128,7 @@ const EditorNew = ({ flow }) => {
(flow, prevNodes) => { (flow, prevNodes) => {
const newNodes = flow.steps.map((step, index) => { const newNodes = flow.steps.map((step, index) => {
const node = prevNodes?.find(({ id }) => id === step.id); const node = prevNodes?.find(({ id }) => id === step.id);
const collapsed = currentStepId !== step.id;
return { return {
id: step.id, id: step.id,
type: 'flowStep', type: 'flowStep',
@@ -132,11 +136,12 @@ const EditorNew = ({ flow }) => {
x: node ? node.position.x : 0, x: node ? node.position.x : 0,
y: node ? node.position.y : 0, y: node ? node.position.y : 0,
}, },
zIndex: collapsed ? 0 : 1,
data: { data: {
step, step,
index: index, index: index,
flowId: flow.id, flowId: flow.id,
collapsed: currentStepId !== step.id, collapsed,
openNextStep: openNextStep(flow.steps[index + 1]), openNextStep: openNextStep(flow.steps[index + 1]),
onOpen: () => setCurrentStepId(step.id), onOpen: () => setCurrentStepId(step.id),
onClose: () => setCurrentStepId(null), onClose: () => setCurrentStepId(null),
@@ -178,15 +183,31 @@ const EditorNew = ({ flow }) => {
[setNodes], [setNodes],
); );
const updateEdgesData = useCallback(
(flow) => {
setEdges((edges) =>
edges.map((edge) => {
return {
...edge,
data: { ...edge.data, flowId: flow.id, flowActive: flow.active },
};
}),
);
},
[setEdges],
);
useEffect(() => { useEffect(() => {
setNodes( setNodes(
nodes.map((node) => { nodes.map((node) => {
if (node.type === 'flowStep') { if (node.type === 'flowStep') {
const collapsed = currentStepId !== node.data.step.id;
return { return {
...node, ...node,
zIndex: collapsed ? 0 : 1,
data: { data: {
...node.data, ...node.data,
collapsed: currentStepId !== node.data.step.id, collapsed,
}, },
}; };
} }
@@ -204,19 +225,12 @@ const EditorNew = ({ flow }) => {
setEdges(newEdges); setEdges(newEdges);
} else { } else {
updateNodesData(flow.steps); updateNodesData(flow.steps);
updateEdgesData(flow);
} }
}, [flow]); }, [flow]);
return ( return (
<Stack <EditorWrapper direction="column">
direction="column"
sx={{
flexGrow: 1,
'& > div': {
flexGrow: 1,
},
}}
>
<ReactFlow <ReactFlow
nodes={nodes} nodes={nodes}
edges={edges} edges={edges}
@@ -233,7 +247,7 @@ const EditorNew = ({ flow }) => {
zoomOnDoubleClick={false} zoomOnDoubleClick={false}
panActivationKeyCode={null} panActivationKeyCode={null}
/> />
</Stack> </EditorWrapper>
); );
}; };

View File

@@ -5,6 +5,8 @@ import PropTypes from 'prop-types';
import FlowStep from 'components/FlowStep'; import FlowStep from 'components/FlowStep';
import { StepPropType } from 'propTypes/propTypes'; import { StepPropType } from 'propTypes/propTypes';
import { NodeWrapper, NodeInnerWrapper } from './style.js';
function FlowStepNode({ function FlowStepNode({
data: { data: {
step, step,
@@ -19,12 +21,13 @@ function FlowStepNode({
}, },
}) { }) {
return ( return (
<Box <NodeWrapper
maxWidth={900}
width="100vw"
className="nodrag" className="nodrag"
sx={{ visibility: layouted ? 'visible' : 'hidden' }} sx={{
visibility: layouted ? 'visible' : 'hidden',
}}
> >
<NodeInnerWrapper>
<Handle <Handle
type="target" type="target"
position={Position.Top} position={Position.Top}
@@ -47,7 +50,8 @@ function FlowStepNode({
isConnectable={false} isConnectable={false}
style={{ visibility: 'hidden' }} style={{ visibility: 'hidden' }}
/> />
</Box> </NodeInnerWrapper>
</NodeWrapper>
); );
} }

View File

@@ -0,0 +1,14 @@
import { styled } from '@mui/material/styles';
import { Box } from '@mui/material';
export const NodeWrapper = styled(Box)(({ theme }) => ({
width: '100vw',
display: 'flex',
justifyContent: 'center',
padding: theme.spacing(0, 2.5),
}));
export const NodeInnerWrapper = styled(Box)(({ theme }) => ({
maxWidth: 900,
flex: 1,
}));

View File

@@ -10,19 +10,8 @@ function InvisibleNode() {
className="nodrag" className="nodrag"
sx={{ visibility: 'hidden' }} sx={{ visibility: 'hidden' }}
> >
<Handle <Handle type="target" position={Position.Top} isConnectable={false} />
type="target"
position={Position.Top}
isConnectable={false}
style={{ visibility: 'hidden' }}
/>
Invisible node Invisible node
<Handle
type="source"
position={Position.Bottom}
isConnectable={false}
style={{ visibility: 'hidden' }}
/>
</Box> </Box>
); );
} }

View File

@@ -0,0 +1,13 @@
import { Stack } from '@mui/material';
import { styled } from '@mui/material/styles';
export const EditorWrapper = styled(Stack)(({ theme }) => ({
flexGrow: 1,
'& > div': {
flexGrow: 1,
},
'& .react-flow__pane, & .react-flow__node': {
cursor: 'auto !important',
},
}));

View File

@@ -9,8 +9,6 @@ const getLayoutedElements = (nodes, edges) => {
graph.setGraph({ graph.setGraph({
rankdir: 'TB', rankdir: 'TB',
marginy: 60, marginy: 60,
marginx: 60,
universalSep: true,
ranksep: 64, ranksep: 64,
}); });
edges.forEach((edge) => graph.setEdge(edge.source, edge.target)); edges.forEach((edge) => graph.setEdge(edge.source, edge.target));

View File

@@ -0,0 +1,13 @@
import { useEffect } from 'react';
import { useViewport, useReactFlow } from 'reactflow';
export const useScrollBoundries = () => {
const { setViewport } = useReactFlow();
const { x, y, zoom } = useViewport();
useEffect(() => {
if (y > 0) {
setViewport({ x, y: 0, zoom });
}
}, [y]);
};

View File

@@ -80,6 +80,7 @@ export default function InputCreator(props) {
disabled={disabled} disabled={disabled}
showOptionValue={showOptionValue} showOptionValue={showOptionValue}
shouldUnregister={shouldUnregister} shouldUnregister={shouldUnregister}
componentsProps={{ popper: { className: 'nowheel' } }}
/> />
)} )}

View File

@@ -17,6 +17,7 @@ import { StepExecutionsContext } from 'contexts/StepExecutions';
import Popper from './Popper'; import Popper from './Popper';
import { processStepWithExecutions } from './data'; import { processStepWithExecutions } from './data';
import { ChildrenWrapper, FakeInput, InputLabelWrapper } from './style'; import { ChildrenWrapper, FakeInput, InputLabelWrapper } from './style';
const PowerInput = (props) => { const PowerInput = (props) => {
const { control } = useFormContext(); const { control } = useFormContext();
const { const {
@@ -31,33 +32,41 @@ const PowerInput = (props) => {
} = props; } = props;
const priorStepsWithExecutions = React.useContext(StepExecutionsContext); const priorStepsWithExecutions = React.useContext(StepExecutionsContext);
const editorRef = React.useRef(null); const editorRef = React.useRef(null);
const renderElement = React.useCallback( const renderElement = React.useCallback(
(props) => <Element {...props} />, (props) => <Element {...props} />,
[], [],
); );
const [editor] = React.useState(() => customizeEditor(createEditor())); const [editor] = React.useState(() => customizeEditor(createEditor()));
const [showVariableSuggestions, setShowVariableSuggestions] = const [showVariableSuggestions, setShowVariableSuggestions] =
React.useState(false); React.useState(false);
const disappearSuggestionsOnShift = (event) => { const disappearSuggestionsOnShift = (event) => {
if (event.code === 'Tab') { if (event.code === 'Tab') {
setShowVariableSuggestions(false); setShowVariableSuggestions(false);
} }
}; };
const stepsWithVariables = React.useMemo(() => { const stepsWithVariables = React.useMemo(() => {
return processStepWithExecutions(priorStepsWithExecutions); return processStepWithExecutions(priorStepsWithExecutions);
}, [priorStepsWithExecutions]); }, [priorStepsWithExecutions]);
const handleBlur = React.useCallback( const handleBlur = React.useCallback(
(value) => { (value) => {
onBlur?.(value); onBlur?.(value);
}, },
[onBlur], [onBlur],
); );
const handleVariableSuggestionClick = React.useCallback( const handleVariableSuggestionClick = React.useCallback(
(variable) => { (variable) => {
insertVariable(editor, variable, stepsWithVariables); insertVariable(editor, variable, stepsWithVariables);
}, },
[stepsWithVariables], [stepsWithVariables],
); );
return ( return (
<Controller <Controller
rules={{ required }} rules={{ required }}
@@ -127,6 +136,7 @@ const PowerInput = (props) => {
anchorEl={editorRef.current} anchorEl={editorRef.current}
data={stepsWithVariables} data={stepsWithVariables}
onSuggestionClick={handleVariableSuggestionClick} onSuggestionClick={handleVariableSuggestionClick}
className="nowheel"
/> />
<FormHelperText variant="outlined">{description}</FormHelperText> <FormHelperText variant="outlined">{description}</FormHelperText>