Update react flow package implementation

This commit is contained in:
Hazem Krimi
2023-04-09 22:31:25 +01:00
parent ca2b2de8bd
commit 9967dc9d6a
4 changed files with 270 additions and 231 deletions
+44 -37
View File
@@ -1,53 +1,60 @@
import { Handle, Position } from 'reactflow';
import { Box, Text } from '..';
import { FeatureOutput } from '../../graphql/types';
type FrontendFeatureCardProps = {
feature: FeatureOutput;
data: FeatureOutput;
isConnectable?: boolean;
className?: string;
};
const FrontendFeatureCard = ({
feature,
data,
isConnectable = false,
className,
}: FrontendFeatureCardProps) => {
return (
<Box
className={className}
padding='10px'
background='white'
boxShadow='1px 1px 10px rgba(50, 59, 105, 0.25)'
display='grid'
gridTemplateRows='auto'
alignItems='center'
rowGap='10px'
borderRadius='10px'
cursor='pointer'
textAlign='left'
>
<Box display='flex' flexDirection='row' alignItems='center'>
<Box flexGrow='1'>
<Text variant='title' weight='bold'>
{feature.name}
</Text>
<>
<Handle type="target" position={Position.Top} isConnectable={isConnectable} />
<Box
className={className}
padding='10px'
background='white'
boxShadow='1px 1px 10px rgba(50, 59, 105, 0.25)'
display='grid'
gridTemplateRows='auto'
alignItems='center'
rowGap='10px'
borderRadius='10px'
cursor='pointer'
textAlign='left'
>
<Box display='flex' flexDirection='row' alignItems='center'>
<Box flexGrow='1'>
<Text variant='title' weight='bold'>
{data.name}
</Text>
</Box>
</Box>
<Box
display='flex'
flexDirection='row'
alignItems='center'
justifyContent='space-between'
padding='5px 20px'
>
{data.wireframes?.map((wireframe) => (
<img
src={wireframe.src}
alt={wireframe.name}
key={wireframe.id}
style={{ width: '100px', height: 'auto', marginRight: '10px' }}
/>
))}
</Box>
</Box>
<Box
display='flex'
flexDirection='row'
alignItems='center'
justifyContent='space-between'
padding='5px 20px'
>
{feature.wireframes?.map((wireframe) => (
<img
src={wireframe.src}
alt={wireframe.name}
key={wireframe.id}
style={{ width: '100px', height: 'auto', marginRight: '10px' }}
/>
))}
</Box>
</Box>
<Handle type="source" position={Position.Bottom} isConnectable={isConnectable} />
</>
);
};
+54 -71
View File
@@ -1,16 +1,21 @@
import { useEffect, useState, useRef, useCallback, useMemo } from 'react';
import ReactFlow, {
removeElements,
addEdge,
MiniMap,
Controls,
ControlButton,
FlowElement,
Elements,
Connection,
Edge,
ArrowHeadType,
} from 'react-flow-renderer';
import { useEffect, useState, useRef } from 'react';
Node,
MarkerType,
applyNodeChanges,
applyEdgeChanges,
NodeChange,
EdgeChange,
useEdgesState,
useNodesState
} from 'reactflow';
import 'reactflow/dist/style.css';
import { useNavigate, useParams } from 'react-router-dom';
import { useLazyQuery, useMutation, useReactiveVar } from '@apollo/client';
import { Navigate } from 'react-router';
@@ -29,6 +34,7 @@ import { Wrapper } from './styles';
import {
AddPrototypeMutation,
AddPrototypeMutationVariables,
FeatureOutput,
GetPrototypeByIdQuery,
GetPrototypeByIdQueryVariables,
GetTemplateByIdQuery,
@@ -49,9 +55,11 @@ const Prototype = () => {
const role = useReactiveVar(roleVar);
const navigate = useNavigate();
const { id } = useParams<{ id: string }>();
const nodeTypes = useMemo(() => ({ featureCard: FrontendFeatureCard }), []);
const [template, setTemplate] = useState<TemplateOutput>();
const [prototype, setPrototype] = useState<Array<ProtoTypeOutput>>();
const [elements, setElements] = useState<Elements>([]);
const [nodes, setNodes, onNodesChange] = useNodesState<FeatureOutput>([]);
const [edges, setEdges, onEdgesChange] = useEdgesState([]);
const [editing, setEditing] = useState<boolean>(false);
const [error, setError] = useState<string>('');
const [success, setSuccess] = useState<boolean>(false);
@@ -107,91 +115,66 @@ const Prototype = () => {
getTemplate({ variables: { id } });
getPrototype({ variables: { id } });
}
// eslint-disable-next-line
}, [id]);
useEffect(() => {
if (template && template.features) {
const initialElements = template.features.map((feature, index) => {
if (['frontend', 'fullstack'].includes(feature.featureType)) {
return {
id: feature.id,
type: 'default',
data: {
label: <FrontendFeatureCard feature={feature} />,
},
position: { x: index * 100, y: index * 200 },
style: {
width: 'auto',
},
connectable: role === 'developer' && editing,
} as FlowElement;
}
return {} as FlowElement;
});
// if (template && template.features) {
const initialNodes = template?.features?.map((feature, index) => ({
id: feature.id,
type: 'featureCard',
data: feature,
position: { x: index * 100, y: index * 200 },
style: {
width: 'auto',
},
connectable: role === 'developer' && editing
}));
if (initialElements) setElements(initialElements);
}
if (initialNodes) setNodes(initialNodes);
// }
if (prototype) {
const initialElements: Array<Edge> = [];
const initialEdges: Array<Edge> = [];
prototype.forEach((link) => {
link.connections.forEach((connection) => {
initialElements.push({
initialEdges.push({
id: `edge-${link.feature.id}`,
source: link.feature.id,
target: connection.to,
arrowHeadType: ArrowHeadType.ArrowClosed,
className: 'normal-edge',
markerEnd: MarkerType.Arrow,
className: 'normal-edge'
});
});
});
if (initialElements) setElements((els) => [...els, ...initialElements]);
if (initialEdges) setEdges(initialEdges);
}
// eslint-disable-next-line
}, [template, prototype, editing]);
const onElementsRemove = (elementsToRemove: Elements<any>) =>
setElements((els) => removeElements(elementsToRemove, els));
const onConnect = (params: Edge<any> | Connection) =>
setElements((els) =>
addEdge({ ...params, arrowHeadType: ArrowHeadType.ArrowClosed }, els)
);
const onConnect = useCallback(
(params: Edge | Connection) => setEdges((els) => addEdge(params, els)),
[setEdges]
);
const handleEditPrototype = () => {
if (editing) {
const prototypeInput = elements
// @ts-ignore
.filter((element) => element.source || element.target)
.map((element) => {
if (
element.hasOwnProperty('source') ||
element.hasOwnProperty('target')
) {
return {
// @ts-ignore
featureId: element.source,
connections: [
{
// @ts-ignore
to: element.target,
releations: { back: false, forword: true },
},
],
};
}
return {};
});
const prototypeInput = nodes
.map((node) => ({
featureId: node.id,
connections: [
{
to: node.id,
releations: { back: false, forword: true },
},
],
}));
if (prototypeInput && prototypeInput.length > 0) {
if (prototype) {
updatePrototype({
variables: {
prototype: {
templateId: id as string,
// @ts-ignore
prototype: prototypeInput,
},
},
@@ -201,7 +184,6 @@ const Prototype = () => {
variables: {
prototype: {
templateId: id as string,
// @ts-ignore
prototype: prototypeInput,
},
},
@@ -283,18 +265,19 @@ const Prototype = () => {
height='auto'
>
<ReactFlow
elements={elements}
onElementsRemove={onElementsRemove}
nodes={nodes}
edges={edges}
nodeTypes={nodeTypes}
onNodesChange={onNodesChange}
onEdgesChange={onEdgesChange}
onConnect={onConnect}
deleteKeyCode={46}
edgeTypes={{ arrowHeadType: 'arrow' }}
>
{role === 'developer' && (
<>
<MiniMap />
<Controls
showInteractive={false}
showFitView={false}
showFitView
>
<ControlButton onClick={handleEditPrototype}>
{!editing ? <Edit /> : <CheckCircle />}