11import { Tile } from "@carbon/react"
22
3- import { Handle , NodeProps , Position } from "@xyflow/react"
4- import { EipFlowNode , Layout } from "../../api/flow"
3+ import { Handle , NodeProps , Position , useNodesData } from "@xyflow/react"
4+ import {
5+ EipFlowNode ,
6+ FollowerNode as FollowerNodeType ,
7+ Layout ,
8+ } from "../../api/flow"
59import { ConnectionType , EipRole } from "../../api/generated/eipComponentDef"
6- import { lookupEipComponent } from "../../singletons/eipDefinitions"
10+ import { EipId } from "../../api/generated/eipFlow"
11+ import {
12+ eipIdToString ,
13+ lookupEipComponent ,
14+ } from "../../singletons/eipDefinitions"
715import getIconUrl from "../../singletons/eipIconCatalog"
16+ import { describeFollower } from "../../singletons/followerNodeDefs"
817import { clearSelectedChildNode } from "../../singletons/store/appActions"
918import {
1019 useGetEnabledChildren ,
@@ -15,11 +24,17 @@ import { getNamespacedTitle } from "../../utils/titleTransform"
1524import { ChildrenNavigationPopover } from "./ChildrenNavigationPopover"
1625import "./nodes.scss"
1726
27+ interface NodeContentProps {
28+ eipId : EipId
29+ label : string
30+ }
31+
1832const DEFAULT_NODE_LABEL = "New Node"
1933
2034const renderHorizontalHandles = ( connectionType : ConnectionType ) => {
2135 switch ( connectionType ) {
2236 case "source" :
37+ case "inbound_request_reply" :
2338 return < Handle id = "output" type = "source" position = { Position . Right } />
2439 case "sink" :
2540 return < Handle id = "input" type = "target" position = { Position . Left } />
@@ -46,6 +61,7 @@ const renderHorizontalHandles = (connectionType: ConnectionType) => {
4661const renderVerticalHandles = ( connectionType : ConnectionType ) => {
4762 switch ( connectionType ) {
4863 case "source" :
64+ case "inbound_request_reply" :
4965 return < Handle id = "output" type = "source" position = { Position . Bottom } />
5066 case "sink" :
5167 return < Handle id = "input" type = "target" position = { Position . Top } />
@@ -78,13 +94,23 @@ const renderHandles = (
7894 ? renderHorizontalHandles ( connectionType )
7995 : renderVerticalHandles ( connectionType )
8096
81- const getClassNames = ( props : NodeProps < EipFlowNode > , role : EipRole ) => {
97+ const getNodeClassNames = ( isSelected : boolean , role : EipRole ) => {
8298 const roleClsName =
8399 role === "channel" ? "eip-channel-node" : "eip-endpoint-node"
84- const selectedClsName = props . selected ? "eip-node-selected" : ""
100+ const selectedClsName = isSelected ? "eip-node-selected" : ""
85101 return [ "eip-node" , roleClsName , selectedClsName ] . join ( " " )
86102}
87103
104+ const NodeDisplayContent = ( { eipId, label } : NodeContentProps ) => (
105+ < >
106+ < div className = "eip-node-title" > { getNamespacedTitle ( eipId ) } </ div >
107+ < img className = "eip-node-image" src = { getIconUrl ( eipId ) } />
108+ < div className = "eip-node-label" >
109+ < strong > { label } </ strong >
110+ </ div >
111+ </ >
112+ )
113+
88114export const EipNode = ( props : NodeProps < EipFlowNode > ) => {
89115 const layout = useGetLayout ( )
90116 const children = useGetEnabledChildren ( props . id )
@@ -105,16 +131,65 @@ export const EipNode = (props: NodeProps<EipFlowNode>) => {
105131
106132 return (
107133 < Tile
108- className = { getClassNames ( props , componentDefinition . role ) }
134+ className = { getNodeClassNames ( props . selected , componentDefinition . role ) }
109135 onClick = { hasChildren ? ( ) => clearSelectedChildNode ( ) : undefined }
110136 >
111- < div > { getNamespacedTitle ( eipId ) } </ div >
112- < img className = "eip-node-image" src = { getIconUrl ( eipId ) } />
113- < div className = "eip-node-label" >
114- < strong > { data . label || DEFAULT_NODE_LABEL } </ strong >
115- </ div >
137+ < NodeDisplayContent
138+ eipId = { eipId }
139+ label = { data . label || DEFAULT_NODE_LABEL }
140+ />
116141 { hasChildren && < ChildrenNavigationPopover /> }
117142 { handles }
118143 </ Tile >
119144 )
120145}
146+
147+ export const FollowerNode = ( props : NodeProps < FollowerNodeType > ) => {
148+ const layout = useGetLayout ( )
149+ const leaderId = props . data . leaderId
150+ const leaderData = useNodesData < EipFlowNode > ( leaderId )
151+
152+ const eipId = getEipId ( props . id )
153+ const componentDefinition = eipId && lookupEipComponent ( eipId )
154+
155+ const leaderEipId = getEipId ( leaderId )
156+
157+ if ( ! componentDefinition || ! leaderEipId ) {
158+ console . error (
159+ `Failed to render follower node with eipId: (${ eipId && eipIdToString ( eipId ) } ) for leaderId: (${ leaderId } )`
160+ )
161+ return null
162+ }
163+
164+ const followerDescriptor = describeFollower ( leaderEipId )
165+
166+ if ( ! followerDescriptor ) {
167+ console . error (
168+ `Failed to find follower descriptor for node with eipId: (${ eipIdToString ( eipId ) } ) for leaderId: (${ leaderId } )`
169+ )
170+ return null
171+ }
172+
173+ const handles = renderHandles (
174+ followerDescriptor . overrides ?. connectionType ??
175+ componentDefinition . connectionType ,
176+ layout . orientation
177+ )
178+
179+ return (
180+ < Tile
181+ className = {
182+ getNodeClassNames ( props . selected , componentDefinition . role ) +
183+ " eip-follower-node"
184+ }
185+ >
186+ < NodeDisplayContent
187+ eipId = { eipId }
188+ label = { followerDescriptor . generateLabel (
189+ leaderData ?. data . label ?? leaderId
190+ ) }
191+ />
192+ { handles }
193+ </ Tile >
194+ )
195+ }
0 commit comments