Skip to content

Commit 62e8606

Browse files
committed
Refactor TaskNode Callback Generation
1 parent 7987e44 commit 62e8606

File tree

8 files changed

+74
-86
lines changed

8 files changed

+74
-86
lines changed

src/components/shared/ReactFlow/FlowCanvas/FlowCanvas.tsx

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -368,13 +368,7 @@ const FlowCanvas = ({
368368

369369
setComponentSpec(updatedComponentSpec);
370370
},
371-
[
372-
reactFlowInstance,
373-
componentSpec,
374-
nodeData,
375-
setComponentSpec,
376-
updateOrAddNodes,
377-
],
371+
[reactFlowInstance, componentSpec, setComponentSpec, updateOrAddNodes],
378372
);
379373

380374
useEffect(() => {

src/types/taskNode.ts

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -6,26 +6,31 @@ import type {
66

77
import type { Annotations } from "./annotations";
88

9+
export type TaskType = "task" | "input" | "output";
10+
11+
export interface NodeData extends Record<string, unknown> {
12+
readOnly?: boolean;
13+
connectable?: boolean;
14+
nodeCallbacks?: NodeCallbacks;
15+
}
16+
917
export interface TaskNodeData extends Record<string, unknown> {
1018
taskSpec?: TaskSpec;
1119
taskId?: string;
1220
readOnly?: boolean;
1321
isGhost?: boolean;
1422
connectable?: boolean;
1523
highlighted?: boolean;
16-
callbacks?: TaskNodeCallbacks;
17-
nodeCallbacks?: NodeCallbacks;
24+
callbacks?: TaskCallbacks;
1825
}
1926

2027
export type NodeAndTaskId = {
2128
taskId: string;
2229
nodeId: string;
2330
};
2431

25-
export type TaskType = "task" | "input" | "output";
26-
2732
/* Note: Optional callbacks will cause TypeScript to break when applying the callbacks to the Nodes. */
28-
interface TaskNodeCallbacks {
33+
export interface TaskCallbacks {
2934
setArguments: (args: Record<string, ArgumentType>) => void;
3035
setAnnotations: (annotations: Annotations) => void;
3136
onDelete: () => void;
@@ -34,13 +39,14 @@ interface TaskNodeCallbacks {
3439
}
3540

3641
// Dynamic Node Callback types - every callback has a version with the node & task id added to it as an input parameter
37-
export type CallbackWithIds<K extends keyof TaskNodeCallbacks> =
38-
TaskNodeCallbacks[K] extends (...args: infer A) => infer R
39-
? (ids: NodeAndTaskId, ...args: A) => R
40-
: never;
42+
type CallbackWithIds<K extends keyof TaskCallbacks> = TaskCallbacks[K] extends (
43+
...args: infer A
44+
) => infer R
45+
? (ids: NodeAndTaskId, ...args: A) => R
46+
: never;
4147

4248
export type NodeCallbacks = {
43-
[K in keyof TaskNodeCallbacks]: CallbackWithIds<K>;
49+
[K in keyof TaskCallbacks]: CallbackWithIds<K>;
4450
};
4551

4652
export type TaskNodeDimensions = { w: number; h: number | undefined };

src/utils/nodes/createInputNode.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
import { type Node } from "@xyflow/react";
22

3-
import type { TaskNodeData } from "@/types/taskNode";
3+
import type { NodeData } from "@/types/taskNode";
44

55
import type { InputSpec } from "../componentSpec";
66
import { extractPositionFromAnnotations } from "./extractPositionFromAnnotations";
77
import { inputNameToNodeId } from "./nodeIdUtils";
88

9-
export const createInputNode = (input: InputSpec, nodeData: TaskNodeData) => {
9+
export const createInputNode = (input: InputSpec, nodeData: NodeData) => {
1010
const { name, annotations, ...rest } = input;
1111

1212
const position = extractPositionFromAnnotations(annotations);

src/utils/nodes/createNodesFromComponentSpec.ts

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { type Node } from "@xyflow/react";
22

3-
import type { TaskNodeData } from "@/types/taskNode";
3+
import type { NodeData } from "@/types/taskNode";
44
import {
55
type ComponentSpec,
66
type GraphSpec,
@@ -13,7 +13,7 @@ import { createTaskNode } from "./createTaskNode";
1313

1414
const createNodesFromComponentSpec = (
1515
componentSpec: ComponentSpec,
16-
nodeData: TaskNodeData,
16+
nodeData: NodeData,
1717
): Node[] => {
1818
if (!isGraphImplementation(componentSpec.implementation)) {
1919
return [];
@@ -27,24 +27,21 @@ const createNodesFromComponentSpec = (
2727
return [...taskNodes, ...inputNodes, ...outputNodes];
2828
};
2929

30-
const createTaskNodes = (graphSpec: GraphSpec, nodeData: TaskNodeData) => {
30+
const createTaskNodes = (graphSpec: GraphSpec, nodeData: NodeData) => {
3131
return Object.entries(graphSpec.tasks).map((task) =>
3232
createTaskNode(task, nodeData),
3333
);
3434
};
3535

36-
const createInputNodes = (
37-
componentSpec: ComponentSpec,
38-
nodeData: TaskNodeData,
39-
) => {
36+
const createInputNodes = (componentSpec: ComponentSpec, nodeData: NodeData) => {
4037
return (componentSpec.inputs ?? []).map((inputSpec) =>
4138
createInputNode(inputSpec, nodeData),
4239
);
4340
};
4441

4542
const createOutputNodes = (
4643
componentSpec: ComponentSpec,
47-
nodeData: TaskNodeData,
44+
nodeData: NodeData,
4845
) => {
4946
return (componentSpec.outputs ?? []).map((outputSpec) =>
5047
createOutputNode(outputSpec, nodeData),

src/utils/nodes/createOutputNode.ts

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,12 @@
11
import { type Node } from "@xyflow/react";
22

3-
import type { TaskNodeData } from "@/types/taskNode";
3+
import type { NodeData } from "@/types/taskNode";
44

55
import type { OutputSpec } from "../componentSpec";
66
import { extractPositionFromAnnotations } from "./extractPositionFromAnnotations";
77
import { outputNameToNodeId } from "./nodeIdUtils";
88

9-
export const createOutputNode = (
10-
output: OutputSpec,
11-
nodeData: TaskNodeData,
12-
) => {
9+
export const createOutputNode = (output: OutputSpec, nodeData: NodeData) => {
1310
const { name, annotations, ...rest } = output;
1411

1512
const position = extractPositionFromAnnotations(annotations);

src/utils/nodes/createTaskNode.ts

Lines changed: 15 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,37 @@
11
import { type Node } from "@xyflow/react";
22

3-
import type { TaskNodeData } from "@/types/taskNode";
3+
import type { NodeData, TaskNodeData } from "@/types/taskNode";
44

55
import type { TaskSpec } from "../componentSpec";
66
import { extractPositionFromAnnotations } from "./extractPositionFromAnnotations";
7-
import { generateDynamicNodeCallbacks } from "./generateDynamicNodeCallbacks";
87
import { taskIdToNodeId } from "./nodeIdUtils";
8+
import { convertNodeCallbacksToTaskCallbacks } from "./taskCallbackUtils";
99

1010
export const createTaskNode = (
1111
task: [`${string}`, TaskSpec],
12-
nodeData: TaskNodeData,
12+
nodeData: NodeData,
1313
) => {
1414
const [taskId, taskSpec] = task;
15+
const { nodeCallbacks, ...data } = nodeData;
1516

1617
const position = extractPositionFromAnnotations(taskSpec.annotations);
1718
const nodeId = taskIdToNodeId(taskId);
1819

1920
// Inject the taskId and nodeId into the callbacks
20-
const nodeCallbacks = nodeData.nodeCallbacks;
21-
const dynamicCallbacks = generateDynamicNodeCallbacks(nodeId, nodeCallbacks);
21+
const ids = { taskId, nodeId };
22+
const taskCallbacks = convertNodeCallbacksToTaskCallbacks(ids, nodeCallbacks);
23+
24+
const taskNodeData: TaskNodeData = {
25+
...data,
26+
taskSpec,
27+
taskId,
28+
highlighted: false,
29+
callbacks: taskCallbacks,
30+
};
2231

2332
return {
2433
id: nodeId,
25-
data: {
26-
...nodeData,
27-
taskSpec,
28-
taskId,
29-
highlighted: false,
30-
callbacks: dynamicCallbacks, // Use these callbacks internally within the node
31-
},
34+
data: taskNodeData,
3235
position: position,
3336
type: "task",
3437
} as Node;

src/utils/nodes/generateDynamicNodeCallbacks.ts

Lines changed: 0 additions & 42 deletions
This file was deleted.
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
import type {
2+
NodeAndTaskId,
3+
NodeCallbacks,
4+
TaskCallbacks,
5+
} from "@/types/taskNode";
6+
7+
// Sync TaskCallbacks with NodeCallbacks by injecting nodeId and taskId
8+
export const convertNodeCallbacksToTaskCallbacks = (
9+
ids: NodeAndTaskId,
10+
nodeCallbacks?: NodeCallbacks,
11+
): TaskCallbacks => {
12+
if (!nodeCallbacks) {
13+
return createEmptyTaskCallbacks();
14+
}
15+
return {
16+
setArguments: (args) => nodeCallbacks.setArguments?.(ids, args),
17+
setAnnotations: (annotations) =>
18+
nodeCallbacks.setAnnotations?.(ids, annotations),
19+
onDelete: () => nodeCallbacks.onDelete?.(ids),
20+
onDuplicate: (selected) => nodeCallbacks.onDuplicate?.(ids, selected),
21+
onUpgrade: (newComponentRef) =>
22+
nodeCallbacks.onUpgrade?.(ids, newComponentRef),
23+
};
24+
};
25+
26+
// Empty callbacks
27+
export const createEmptyTaskCallbacks = (): TaskCallbacks => ({
28+
setArguments: () => {},
29+
setAnnotations: () => {},
30+
onDelete: () => {},
31+
onDuplicate: () => {},
32+
onUpgrade: () => {},
33+
});

0 commit comments

Comments
 (0)