From 581524c270709a8ca461ee72dca21587d3072d8f Mon Sep 17 00:00:00 2001 From: Jonas Lagoni Date: Wed, 28 Sep 2022 23:16:13 +0200 Subject: [PATCH] feat: add optional edge types (#20) --- examples/simple-react/src/SimpleAsyncapi.tsx | 2 +- examples/simple-react/src/SimpleSystem.tsx | 1 + library/src/types.ts | 7 + .../src/visualiser/helpers/collect-nodes.ts | 142 +++++++++++------- .../ApplicationFocusView.tsx | 21 ++- .../react-flow-renderer/ApplicationView.tsx | 26 +++- .../react-flow-renderer/SystemView.tsx | 6 +- 7 files changed, 130 insertions(+), 75 deletions(-) diff --git a/examples/simple-react/src/SimpleAsyncapi.tsx b/examples/simple-react/src/SimpleAsyncapi.tsx index 8e10e20..4428932 100644 --- a/examples/simple-react/src/SimpleAsyncapi.tsx +++ b/examples/simple-react/src/SimpleAsyncapi.tsx @@ -230,7 +230,7 @@ function Asyncapi() { let node; if (document !== undefined) { node = ( - + ); } else { node =

Wait...

; diff --git a/examples/simple-react/src/SimpleSystem.tsx b/examples/simple-react/src/SimpleSystem.tsx index 40f964e..c991f7a 100644 --- a/examples/simple-react/src/SimpleSystem.tsx +++ b/examples/simple-react/src/SimpleSystem.tsx @@ -5,6 +5,7 @@ function App() {
{ +export function collectApplicationNodes( + { + asyncapi, + application, + incomingOperations, + outgoingOperations, + }: ApplicationViewData, + edgeType: EdgeType = 'smoothstep', +): Array { const nodes: Array = []; if (asyncapi) { - nodes.push(...collectAsyncAPINodes(asyncapi)); + nodes.push(...collectAsyncAPINodes(asyncapi, { edgeType })); } else if (application) { nodes.push(...createApplicationNode(application)); } if (incomingOperations) { incomingOperations.forEach(op => { - nodes.push(...createIncomingNode(op)); + nodes.push(...createIncomingNode(op, edgeType)); }); } if (outgoingOperations) { outgoingOperations.forEach(op => { - nodes.push(...createOutgoingNode(op)); + nodes.push(...createOutgoingNode(op, edgeType)); }); } return nodes; } -export function collectApplicationFocusNodes({ - asyncapi, - application, - external, - incomingOperations, - outgoingOperations, -}: ApplicationFocusViewData): Array { +export function collectApplicationFocusNodes( + { + asyncapi, + application, + external, + incomingOperations, + outgoingOperations, + }: ApplicationFocusViewData, + edgeType: EdgeType = 'smoothstep', +): Array { const nodes: Array = []; const leadApplicationIncomingChannels: string[] = []; const leadApplicationOutgoingChannels: string[] = []; @@ -54,20 +61,20 @@ export function collectApplicationFocusNodes({ if (asyncapi) { const createIncomingNodeFn = (data: IncomingNodeData) => { leadApplicationIncomingChannels.push(data.id); - return createIncomingNode(data); + return createIncomingNode(data, edgeType); }; const createOutgoingNodeFn = (data: OutgoingNodeData) => { leadApplicationOutgoingChannels.push(data.id); - return createOutgoingNode(data); + return createOutgoingNode(data, edgeType); }; nodes.push( - ...collectAsyncAPINodes( - asyncapi, - createApplicationNode, + ...collectAsyncAPINodes(asyncapi, { + createApplicationNodeFn: createApplicationNode, createIncomingNodeFn, createOutgoingNodeFn, - ), + edgeType, + }), ); } else if (application) { nodes.push(...createApplicationNode(application)); @@ -75,13 +82,13 @@ export function collectApplicationFocusNodes({ if (incomingOperations) { incomingOperations.forEach(op => { - nodes.push(...createIncomingNode(op)); + nodes.push(...createIncomingNode(op, edgeType)); leadApplicationIncomingChannels.push(op.id); }); } if (outgoingOperations) { outgoingOperations.forEach(op => { - nodes.push(...createOutgoingNode(op)); + nodes.push(...createOutgoingNode(op, edgeType)); leadApplicationOutgoingChannels.push(op.id); }); } @@ -106,12 +113,12 @@ export function collectApplicationFocusNodes({ external.forEach(externalApp => { if (externalApp.asyncapi) { nodes.push( - ...collectAsyncAPINodes( - externalApp.asyncapi, - createExternalApplicationNode, + ...collectAsyncAPINodes(externalApp.asyncapi, { + createApplicationNodeFn: createExternalApplicationNode, createIncomingNodeFn, createOutgoingNodeFn, - ), + edgeType, + }), ); } else if (externalApp.application) { nodes.push(...createExternalApplicationNode(externalApp.application)); @@ -129,9 +136,10 @@ export function collectApplicationFocusNodes({ return nodes; } -export function collectSystemNodes({ - applications = [], -}: SystemViewData): Array { +export function collectSystemNodes( + { applications = [] }: SystemViewData, + edgeType: EdgeType = 'floating', +): Array { const nodes: Array = []; const outgoingConnections: { [key: string]: string[] } = {}; const incomingConnections: { [key: string]: string[] } = {}; @@ -158,12 +166,12 @@ export function collectSystemNodes({ applications.forEach(app => { if (app.asyncapi) { - collectAsyncAPINodes( - app.asyncapi, + collectAsyncAPINodes(app.asyncapi, { createApplicationNodeFn, createOutgoingNodeFn, createIncomingNodeFn, - ); + edgeType, + }); } else if (app.application) { nodes.push(...createApplicationNode(app.application)); } @@ -182,7 +190,7 @@ export function collectSystemNodes({ for (const incomingApp of incomingConnections[uniqueChannel]) { const edge = { id: `${appId}-to-${incomingApp}`, - type: 'floating', + type: edgeType, style: { stroke: 'orange', strokeWidth: 4 }, source: appId, target: incomingApp, @@ -196,11 +204,19 @@ export function collectSystemNodes({ return nodes; } -export function collectAsyncAPINodes( +function collectAsyncAPINodes( { document, topExtended }: AsyncapiApplicationData, - createApplicationNodeFn: typeof createApplicationNode = createApplicationNode, - createIncomingNodeFn: typeof createIncomingNode = createIncomingNode, - createOutgoingNodeFn: typeof createOutgoingNode = createOutgoingNode, + { + createApplicationNodeFn = createApplicationNode, + createIncomingNodeFn = createIncomingNode, + createOutgoingNodeFn = createOutgoingNode, + edgeType = 'floating', + }: { + createApplicationNodeFn?: typeof createApplicationNode; + createIncomingNodeFn?: typeof createIncomingNode; + createOutgoingNodeFn?: typeof createOutgoingNode; + edgeType?: EdgeType; + }, ): Array { const nodes: Array = []; const documentTitle = document.info().title(); @@ -216,13 +232,16 @@ export function collectAsyncAPINodes( }); nodes.push( - ...createIncomingNodeFn({ - id: `incoming_${channelId}`, - channel: channelPath, - description: channel.description() || 'No description', - messages, - forApplication: documentTitle, - }), + ...createIncomingNodeFn( + { + id: `incoming_${channelId}`, + channel: channelPath, + description: channel.description() || 'No description', + messages, + forApplication: documentTitle, + }, + edgeType, + ), ); } else if (channel.hasSubscribe()) { const messages: MessageData[] = channel @@ -233,13 +252,16 @@ export function collectAsyncAPINodes( }); nodes.push( - ...createOutgoingNodeFn({ - id: `outgoing_${channelId}`, - channel: channelPath, - description: channel.description() || 'No description', - messages, - forApplication: documentTitle, - }), + ...createOutgoingNodeFn( + { + id: `outgoing_${channelId}`, + channel: channelPath, + description: channel.description() || 'No description', + messages, + forApplication: documentTitle, + }, + edgeType, + ), ); } } @@ -323,7 +345,10 @@ export function createExternalApplicationNode( return [externalOutgoing, externalIncoming]; } -export function createIncomingNode(data: IncomingNodeData): Array { +export function createIncomingNode( + data: IncomingNodeData, + edgeType: EdgeType, +): Array { const appId = data.forApplication || ''; const incomingNode: Node = { id: data.id, @@ -333,7 +358,7 @@ export function createIncomingNode(data: IncomingNodeData): Array { }; const connectionEdge: Edge = { id: `incoming-${appId}-${data.id}`, - type: 'smoothstep', + type: edgeType, style: { stroke: '#7ee3be', strokeWidth: 4 }, target: appId, source: data.id, @@ -357,7 +382,10 @@ export function createExternalIncomingNode( ] as Edge[]; } -export function createOutgoingNode(data: OutgoingNodeData): Array { +export function createOutgoingNode( + data: OutgoingNodeData, + edgeType: EdgeType, +): Array { const appId = data.forApplication || ''; const outgoingNode: Node = { id: data.id, @@ -367,7 +395,7 @@ export function createOutgoingNode(data: OutgoingNodeData): Array { }; const connectionEdge: Edge = { id: `outgoing-${appId}-${data.id}`, - type: 'smoothstep', + type: edgeType, style: { stroke: 'orange', strokeWidth: 4 }, source: appId, target: data.id, diff --git a/library/src/visualiser/react-flow-renderer/ApplicationFocusView.tsx b/library/src/visualiser/react-flow-renderer/ApplicationFocusView.tsx index b0bb136..a82eba1 100644 --- a/library/src/visualiser/react-flow-renderer/ApplicationFocusView.tsx +++ b/library/src/visualiser/react-flow-renderer/ApplicationFocusView.tsx @@ -11,7 +11,7 @@ import nodeTypes from '../../components/react-flow-renderer-nodes'; import FloatingEdge from '../../components/react-flow-renderer-nodes/FloatingEdge'; import { collectApplicationFocusNodes } from '../helpers/collect-nodes'; -import { ApplicationFocusViewData, LayoutProps } from '../../types'; +import { ApplicationFocusViewData, EdgeType, LayoutProps } from '../../types'; const edgeTypes: EdgeTypesType = { floating: FloatingEdge, @@ -23,6 +23,7 @@ export interface ApplicationFocusViewProps extends ApplicationFocusViewData { ) => React.JSXElementConstructor; sideMenu?: () => React.JSXElementConstructor; includeControls?: boolean; + edgeType?: EdgeType; } export const ApplicationFocusView: React.FunctionComponent = ({ @@ -44,15 +45,19 @@ export const ApplicationFocusView: React.FunctionComponent { const [loaded, setLoaded] = useState(false); - const elements = collectApplicationFocusNodes({ - asyncapi, - application, - external, - incomingOperations, - outgoingOperations, - }); + const elements = collectApplicationFocusNodes( + { + asyncapi, + application, + external, + incomingOperations, + outgoingOperations, + }, + edgeType, + ); const handleLoaded = (reactFlowInstance: any) => { setLoaded(true); diff --git a/library/src/visualiser/react-flow-renderer/ApplicationView.tsx b/library/src/visualiser/react-flow-renderer/ApplicationView.tsx index a2e164f..461c6d5 100644 --- a/library/src/visualiser/react-flow-renderer/ApplicationView.tsx +++ b/library/src/visualiser/react-flow-renderer/ApplicationView.tsx @@ -4,11 +4,17 @@ import ReactFlow, { BackgroundVariant, FlowElement, Controls, + EdgeTypesType, } from 'react-flow-renderer'; import { ColumnLayout } from '../../components/layouts'; import { collectApplicationNodes } from '../helpers/collect-nodes'; import nodeTypes from '../../components/react-flow-renderer-nodes'; -import { ApplicationViewData, LayoutProps } from '../../types'; +import { ApplicationViewData, EdgeType, LayoutProps } from '../../types'; +import FloatingEdge from '../../components/react-flow-renderer-nodes/FloatingEdge'; + +const edgeTypes: EdgeTypesType = { + floating: FloatingEdge, +}; export interface ApplicationViewProps extends ApplicationViewData { layout?: ( @@ -16,6 +22,7 @@ export interface ApplicationViewProps extends ApplicationViewData { ) => React.JSXElementConstructor; sideMenu?: () => React.JSXElementConstructor; includeControls?: boolean; + edgeType?: EdgeType; } export const ApplicationView: React.FunctionComponent = ({ @@ -36,14 +43,18 @@ export const ApplicationView: React.FunctionComponent = ({ ); }, includeControls = false, + edgeType = 'smoothstep', }) => { const [loaded, setLoaded] = useState(false); - const elements = collectApplicationNodes({ - asyncapi, - application, - incomingOperations, - outgoingOperations, - }); + const elements = collectApplicationNodes( + { + asyncapi, + application, + incomingOperations, + outgoingOperations, + }, + edgeType, + ); const handleLoaded = (reactFlowInstance: any) => { setLoaded(true); @@ -61,6 +72,7 @@ export const ApplicationView: React.FunctionComponent = ({ elements={elements} minZoom={0.1} onLoad={handleLoaded} + edgeTypes={edgeTypes} > React.JSXElementConstructor; sideMenu?: () => React.JSXElementConstructor; includeControls?: boolean; + edgeType?: EdgeType; } export const SystemView: React.FunctionComponent = ({ @@ -40,9 +41,10 @@ export const SystemView: React.FunctionComponent = ({ ); }, includeControls = false, + edgeType = 'floating', }) => { const [loaded, setLoaded] = useState(false); - const elements = collectSystemNodes({ applications }); + const elements = collectSystemNodes({ applications }, edgeType); const handleLoaded = (reactFlowInstance: any) => { setLoaded(true);