Skip to content

Commit 8a86e79

Browse files
committed
Refactor TaskNode Callback Generation
1 parent 46027f5 commit 8a86e79

File tree

8 files changed

+75
-86
lines changed

8 files changed

+75
-86
lines changed

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

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

374374
setComponentSpec(updatedComponentSpec);
375375
},
376-
[
377-
reactFlowInstance,
378-
componentSpec,
379-
nodeData,
380-
setComponentSpec,
381-
updateOrAddNodes,
382-
],
376+
[reactFlowInstance, componentSpec, setComponentSpec, updateOrAddNodes],
383377
);
384378

385379
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
setCacheStaleness: (cacheStaleness: string | undefined) => void;
@@ -35,13 +40,14 @@ interface TaskNodeCallbacks {
3540
}
3641

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

4349
export type NodeCallbacks = {
44-
[K in keyof TaskNodeCallbacks]: CallbackWithIds<K>;
50+
[K in keyof TaskCallbacks]: CallbackWithIds<K>;
4551
};
4652

4753
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: 17 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,39 @@
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 taskCallbacks = convertNodeCallbacksToTaskCallbacks(
22+
{ taskId, nodeId },
23+
nodeCallbacks,
24+
);
25+
26+
const taskNodeData: TaskNodeData = {
27+
...data,
28+
taskSpec,
29+
taskId,
30+
highlighted: false,
31+
callbacks: taskCallbacks,
32+
};
2233

2334
return {
2435
id: nodeId,
25-
data: {
26-
...nodeData,
27-
taskSpec,
28-
taskId,
29-
highlighted: false,
30-
callbacks: dynamicCallbacks, // Use these callbacks internally within the node
31-
},
36+
data: taskNodeData,
3237
position: position,
3338
type: "task",
3439
} as Node;

src/utils/nodes/generateDynamicNodeCallbacks.ts

Lines changed: 0 additions & 42 deletions
This file was deleted.
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
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+
export const createEmptyTaskCallbacks = (): TaskCallbacks => ({
27+
setArguments: () => {},
28+
setAnnotations: () => {},
29+
onDelete: () => {},
30+
onDuplicate: () => {},
31+
onUpgrade: () => {},
32+
});

0 commit comments

Comments
 (0)