Skip to content

Commit

Permalink
refactor(core): allow setting handleId in useNodeConnections (#1732)
Browse files Browse the repository at this point in the history
* refactor(core): allow setting handleId in useNodeConnections

Signed-off-by: braks <[email protected]>

* chore(core): deprecate useHandleConnections

Signed-off-by: braks <[email protected]>

* chore(examples): cleanup

Signed-off-by: braks <[email protected]>

* chore(docs): cleanup

Signed-off-by: braks <[email protected]>

* chore(core): cleanup

Signed-off-by: braks <[email protected]>

* chore(core): cleanup

Signed-off-by: braks <[email protected]>

* chore(docs): cleanup

Signed-off-by: braks <[email protected]>

---------

Signed-off-by: braks <[email protected]>
  • Loading branch information
bcakmakoglu authored Jan 7, 2025
1 parent e1ded78 commit b293e16
Show file tree
Hide file tree
Showing 12 changed files with 122 additions and 114 deletions.
4 changes: 2 additions & 2 deletions docs/examples/custom-node/OutputNode.vue
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<script setup>
import { Handle, Position, useHandleConnections, useNodesData } from '@vue-flow/core'
import { Handle, Position, useNodeConnections, useNodesData } from '@vue-flow/core'
const connections = useHandleConnections({
const connections = useNodeConnections({
type: 'target',
})
Expand Down
6 changes: 3 additions & 3 deletions docs/examples/layout/ProcessNode.vue
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<script setup>
import { computed, toRef } from 'vue'
import { Handle, useHandleConnections } from '@vue-flow/core'
import { Handle, useNodeConnections } from '@vue-flow/core'
const props = defineProps({
data: {
Expand All @@ -15,11 +15,11 @@ const props = defineProps({
},
})
const sourceConnections = useHandleConnections({
const sourceConnections = useNodeConnections({
type: 'target',
})
const targetConnections = useHandleConnections({
const targetConnections = useNodeConnections({
type: 'source',
})
Expand Down
5 changes: 2 additions & 3 deletions docs/examples/math/ResultNode.vue
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<script setup>
import { computed } from 'vue'
import { Handle, Position, useHandleConnections, useNodeConnections, useNodesData } from '@vue-flow/core'
import { Handle, Position, useNodeConnections, useNodesData } from '@vue-flow/core'
defineProps(['id'])
Expand All @@ -12,7 +12,7 @@ const mathFunctions = {
}
// Get the source connections of the result node. In this example it's only one operator node.
const sourceConnections = useHandleConnections({
const sourceConnections = useNodeConnections({
// type target means all connections where *this* node is the target
// that means we go backwards in the graph to find the source of the connection(s)
type: 'target',
Expand Down Expand Up @@ -49,7 +49,6 @@ const result = computed(() => {
</script>
<template>
{{ operatorSourceConnections }}
<div class="calculation">
<template v-for="(value, i) in valueData" :key="`${value.id}-${value.data}`">
<span>
Expand Down
4 changes: 2 additions & 2 deletions docs/src/examples/math.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
# Math Operation

This example demonstrates how to use the different composables like `useHandleConnections` or `useNodesData` to create a data flow between nodes.
This example demonstrates how to use the different composables like `useNodeConnections` or `useNodesData` to create a data flow between nodes.

In this example we use nodes to create a simple math operation, where the user can input two numbers and select an operation to perform.
We use nodes to create a simple math operation, where the user can input two numbers and select an operation to perform.

<div class="mt-6">
<Repl example="math"></Repl>
Expand Down
7 changes: 5 additions & 2 deletions docs/src/guide/composables.md
Original file line number Diff line number Diff line change
Expand Up @@ -102,8 +102,7 @@ const connections = useHandleConnections({
## [useNodeConnections](/typedocs/functions/useNodeConnections)

`useNodeConnections` provides you with an array of connections that are connected to a specific node.
This composable is especially useful when you want to get all connections (of either type `source` or `target`) of a node
instead of just the connections of a specific `<Handle>`.
This composable is especially useful when you want to get all connections (of either type `source` or `target`) of a node.

```ts
import { type HandleConnection, useNodeConnections } from '@vue-flow/core'
Expand All @@ -119,6 +118,10 @@ const sourceConnections = useNodeConnections({
type: 'source',
})

const handleConnections = useNodeConnections({
handleId: 'handle-1', // you can explicitly pass a handle id if you want to get connections of a specific handle
})

const connections = useNodeConnections({
nodeId: '1', // you can explicitly pass a node id, otherwise it's used from the `NodeId injection
type: 'target',
Expand Down
6 changes: 3 additions & 3 deletions examples/vite/src/Layouting/ProcessNode.vue
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
<script setup lang="ts">
import type { NodeProps } from '@vue-flow/core'
import { Handle, useHandleConnections } from '@vue-flow/core'
import { Handle, useNodeConnections } from '@vue-flow/core'
import type { ProcessNodeData } from './types'
const props = defineProps<NodeProps<ProcessNodeData>>()
const sourceConnections = useHandleConnections({
const sourceConnections = useNodeConnections({
type: 'target',
})
const targetConnections = useHandleConnections({
const targetConnections = useNodeConnections({
type: 'source',
})
Expand Down
4 changes: 2 additions & 2 deletions examples/vite/src/Math/ResultNode.vue
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
<script setup lang="ts">
import type { GraphNode } from '@vue-flow/core'
import { Handle, Position, useHandleConnections, useNodeConnections, useNodesData } from '@vue-flow/core'
import { Handle, Position, useNodeConnections, useNodesData } from '@vue-flow/core'
import type { OperatorNodeData, ValueNodeData } from './types'
import { mathFunctions } from './utils'
defineProps<{ id: string }>()
// Get the source connections of the result node. In this example it's only one operator node.
const sourceConnections = useHandleConnections({
const sourceConnections = useNodeConnections({
// type target means all connections where *this* node is the target
// that means we go backwards in the graph to find the source of the connection(s)
type: 'target',
Expand Down
1 change: 1 addition & 0 deletions packages/core/src/composables/useHandleConnections.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ export interface UseHandleConnectionsParams {
/**
* Composable that returns existing connections of a `<Handle />`.
*
* @deprecated use `useNodeConnections` instead
* @public
* @param params
* @param params.type - handle type `source` or `target`
Expand Down
114 changes: 37 additions & 77 deletions packages/core/src/composables/useNodeConnections.ts
Original file line number Diff line number Diff line change
@@ -1,120 +1,80 @@
import type { ComputedRef, MaybeRefOrGetter } from 'vue'
import { computed, ref, toRef, toValue, watch } from 'vue'
import type { HandleConnection, HandleElement, HandleType } from '../types'
import type { MaybeRefOrGetter } from 'vue'
import { computed, ref, toValue, watch } from 'vue'
import type { HandleType, NodeConnection } from '../types'
import { areConnectionMapsEqual, handleConnectionChange } from '../utils'
import { useNodeId } from './useNodeId'
import { useVueFlow } from './useVueFlow'

export interface UseNodeConnectionsParams {
type: MaybeRefOrGetter<HandleType>
type?: MaybeRefOrGetter<HandleType>
handleId?: MaybeRefOrGetter<string | null>
nodeId?: MaybeRefOrGetter<string | null>
onConnect?: (connections: HandleConnection[]) => void
onDisconnect?: (connections: HandleConnection[]) => void
onConnect?: (connections: NodeConnection[]) => void
onDisconnect?: (connections: NodeConnection[]) => void
}

/**
* Composable that returns existing connections of a node by handle type.
* This is useful when you want to get all connections of a node by a specific handle type.
* Hook to retrieve all edges connected to a node. Can be filtered by handle type and id.
*
* @public
* @param params
* @param params.type - handle type `source` or `target`
* @param params.nodeId - node id - if not provided, the node id from the `useNodeId` (meaning, the context-based injection) is used
* @param params.handleId - the handle id (this is required if the node has multiple handles of the same type)
* @param params.onConnect - gets called when a connection is created
* @param params.onDisconnect - gets called when a connection is removed
*
* @returns An array of connections
*/
export function useNodeConnections(params: UseNodeConnectionsParams): ComputedRef<HandleConnection[]> {
const { type, nodeId, onConnect, onDisconnect } = params
export function useNodeConnections(params: UseNodeConnectionsParams = {}) {
const { type, handleId, nodeId, onConnect, onDisconnect } = params

const { connectionLookup, findNode } = useVueFlow()
const { connectionLookup } = useVueFlow()

const _nodeId = useNodeId()

const currentNodeId = toRef(() => toValue(nodeId) ?? _nodeId)
const prevConnections = ref<Map<string, NodeConnection> | null>(null)

const handleType = toRef(() => toValue(type))
const connections = ref<Map<string, NodeConnection>>()

const node = computed(() => findNode(currentNodeId.value))
const lookupKey = computed(() => {
const currNodeId = toValue(nodeId) ?? _nodeId
const handleType = toValue(type)
const currHandleId = toValue(handleId)

const handleIds = computed(() => {
if (!node.value) {
return []
}

const handles: HandleElement['id'][] = []
for (const handle of node.value?.handleBounds?.[handleType.value] ?? []) {
handles.push(handle.id)
}

return handles
})

const prevConnections = ref<Map<string, HandleConnection> | null>(null)

const connectionsFromLookup = computed(() => {
const nodeConnections = [] as Map<string, HandleConnection>[]

for (const handleId of handleIds.value) {
const connectionMap = connectionLookup.value.get(`${currentNodeId.value}-${handleType.value}-${handleId}`)
if (connectionMap) {
nodeConnections.push(connectionMap)
}
}

return nodeConnections
return `${currNodeId}${handleType ? (currHandleId ? `-${handleType}-${currHandleId}` : `-${handleType}`) : ''}`
})

watch(
[connectionsFromLookup, () => typeof onConnect !== 'undefined', () => typeof onDisconnect !== 'undefined'],
([currentConnections]) => {
if (!currentConnections) {
() => connectionLookup.value.get(lookupKey.value),
(nextConnections) => {
if (areConnectionMapsEqual(connections.value, nextConnections)) {
return
}

const newConnections = new Map<string, HandleConnection>()

for (const connectionMap of currentConnections) {
for (const [key, connection] of connectionMap) {
newConnections.set(key, connection)
}
}

if (!prevConnections.value) {
prevConnections.value = new Map(newConnections)
return
}

const prevConnectionsValue = prevConnections.value

const addedConnections = Array.from(newConnections.keys()).filter((key) => !prevConnectionsValue.has(key))

const removedConnections = Array.from(prevConnectionsValue.keys()).filter((key) => !newConnections.has(key))

if (addedConnections.length && onConnect) {
const added = addedConnections.map((key) => newConnections.get(key)!)
onConnect(added)
}
connections.value = nextConnections
},
{ immediate: true },
)

if (removedConnections.length && onDisconnect) {
const removed = removedConnections.map((key) => prevConnectionsValue.get(key)!)
onDisconnect(removed)
watch(
[connections, () => typeof onConnect !== 'undefined', () => typeof onDisconnect !== 'undefined'],
([currentConnections = new Map<string, NodeConnection>()]) => {
if (prevConnections.value && prevConnections.value !== currentConnections) {
handleConnectionChange(prevConnections.value, currentConnections, onDisconnect)
handleConnectionChange(currentConnections, prevConnections.value, onConnect)
}

prevConnections.value = new Map(newConnections)
prevConnections.value = currentConnections
},
{ immediate: true },
)

return computed(() => {
const connections = [] as HandleConnection[]

for (const connectionMap of connectionsFromLookup.value) {
for (const connection of connectionMap.values()) {
connections.push(connection)
}
if (!connections.value) {
return []
}

return connections
return Array.from(connections.value.values())
})
}
6 changes: 3 additions & 3 deletions packages/core/src/store/actions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -349,7 +349,7 @@ export function useActions(state: State, nodeLookup: ComputedRef<NodeLookup>, ed
state.edges,
)

updateConnectionLookup(state.connectionLookup, validEdges)
updateConnectionLookup(state.connectionLookup, edgeLookup.value, validEdges)

state.edges = validEdges
}
Expand Down Expand Up @@ -527,7 +527,7 @@ export function useActions(state: State, nodeLookup: ComputedRef<NodeLookup>, ed

state.edges.splice(state.edges.indexOf(prevEdge), 1, validEdge)

updateConnectionLookup(state.connectionLookup, [validEdge])
updateConnectionLookup(state.connectionLookup, edgeLookup.value, [validEdge])

return validEdge
}
Expand All @@ -554,7 +554,7 @@ export function useActions(state: State, nodeLookup: ComputedRef<NodeLookup>, ed
const applyEdgeChanges: Actions['applyEdgeChanges'] = (changes) => {
const changedEdges = applyChanges(changes, state.edges)

updateConnectionLookup(state.connectionLookup, changedEdges)
updateConnectionLookup(state.connectionLookup, edgeLookup.value, changedEdges)

return changedEdges
}
Expand Down
12 changes: 10 additions & 2 deletions packages/core/src/types/connection.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,11 +33,19 @@ export interface Connection {
targetHandle?: string | null
}

/** Connection with edge id */
/**
* Connection with edge id
* @deprecated
* todo: remove in next major release
*/
export interface HandleConnection extends Connection {
edgeId: string
}

export type NodeConnection = Connection & {
edgeId: string
}

export type Connector = (
params: Connection,
) => Promise<(Connection & Partial<Edge>) | false> | ((Connection & Partial<Edge>) | false)
Expand Down Expand Up @@ -89,4 +97,4 @@ export interface ConnectionLineProps {
connectionStatus: ConnectionStatus | null
}

export type ConnectionLookup = Map<string, Map<string, HandleConnection>>
export type ConnectionLookup = Map<string, Map<string, NodeConnection>>
Loading

0 comments on commit b293e16

Please sign in to comment.