Skip to content

Commit 0a624fb

Browse files
committed
more fixes for templates
Signed-off-by: Teo Koon Peng <[email protected]>
1 parent 9b35b49 commit 0a624fb

File tree

4 files changed

+150
-107
lines changed

4 files changed

+150
-107
lines changed

diagram-editor/frontend/add-operation.tsx

Lines changed: 55 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { Button, ButtonGroup, styled } from '@mui/material';
22
import {
3-
useReactFlow,
43
type NodeAddChange,
4+
useReactFlow,
55
type XYPosition,
66
} from '@xyflow/react';
77
import React from 'react';
@@ -46,15 +46,16 @@ export interface AddOperationProps {
4646

4747
function createSectionInterfaceChange(
4848
type: SectionInterfaceNodeTypes,
49-
connectKey: string,
49+
remappedId: string,
50+
targetId: string,
5051
position: XYPosition,
5152
): NodeAddChange<SectionInterfaceNode> {
5253
return {
5354
type: 'add',
5455
item: {
5556
id: uuidv4(),
5657
type,
57-
data: { namespace: ROOT_NAMESPACE, connectKey },
58+
data: { namespace: ROOT_NAMESPACE, remappedId, targetId },
5859
position,
5960
},
6061
};
@@ -172,50 +173,57 @@ function AddOperation({ parentId, newNodePosition, onAdd }: AddOperationProps) {
172173
>
173174
{editorMode.mode === EditorMode.Template &&
174175
namespace === ROOT_NAMESPACE && (
175-
<>
176-
<StyledOperationButton
177-
startIcon={<SectionInputIcon />}
178-
onClick={() => {
179-
onAdd?.([
180-
createSectionInterfaceChange(
181-
'sectionInput',
182-
'input',
183-
newNodePosition,
184-
),
185-
]);
186-
}}
187-
>
188-
Section Input
189-
</StyledOperationButton>
190-
<StyledOperationButton
191-
startIcon={<SectionOutputIcon />}
192-
onClick={() => {
193-
onAdd?.([
194-
createSectionInterfaceChange(
195-
'sectionOutput',
196-
'output',
197-
newNodePosition,
198-
),
199-
]);
200-
}}
201-
>
202-
Section Output
203-
</StyledOperationButton>
204-
<StyledOperationButton
205-
startIcon={<SectionBufferIcon />}
206-
onClick={() => {
207-
onAdd?.([
208-
createSectionInterfaceChange(
209-
'sectionBuffer',
210-
'buffer',
211-
newNodePosition,
212-
),
213-
]);
214-
}}
215-
>
216-
Section Buffer
217-
</StyledOperationButton>
218-
</>
176+
<StyledOperationButton
177+
startIcon={<SectionInputIcon />}
178+
onClick={() => {
179+
onAdd?.([
180+
createSectionInterfaceChange(
181+
'sectionInput',
182+
'input',
183+
'input',
184+
newNodePosition,
185+
),
186+
]);
187+
}}
188+
>
189+
Section Input
190+
</StyledOperationButton>
191+
)}
192+
{editorMode.mode === EditorMode.Template &&
193+
namespace === ROOT_NAMESPACE && (
194+
<StyledOperationButton
195+
startIcon={<SectionOutputIcon />}
196+
onClick={() => {
197+
onAdd?.([
198+
createSectionInterfaceChange(
199+
'sectionOutput',
200+
'output',
201+
'output',
202+
newNodePosition,
203+
),
204+
]);
205+
}}
206+
>
207+
Section Output
208+
</StyledOperationButton>
209+
)}
210+
{editorMode.mode === EditorMode.Template &&
211+
namespace === ROOT_NAMESPACE && (
212+
<StyledOperationButton
213+
startIcon={<SectionBufferIcon />}
214+
onClick={() => {
215+
onAdd?.([
216+
createSectionInterfaceChange(
217+
'sectionBuffer',
218+
'buffer',
219+
'buffer',
220+
newNodePosition,
221+
),
222+
]);
223+
}}
224+
>
225+
Section Buffer
226+
</StyledOperationButton>
219227
)}
220228
<StyledOperationButton
221229
startIcon={<NodeIcon />}

diagram-editor/frontend/diagram-editor.tsx

Lines changed: 38 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { v4 as uuidv4 } from 'uuid';
12
import {
23
Alert,
34
alpha,
@@ -43,7 +44,11 @@ import {
4344
type OperationNode,
4445
} from './nodes';
4546
import { useTemplates } from './templates-provider';
46-
import { exhaustiveCheck, allowEdges as getAllowEdges } from './utils';
47+
import {
48+
exhaustiveCheck,
49+
allowEdges as getAllowEdges,
50+
ROOT_NAMESPACE,
51+
} from './utils';
4752
import { autoLayout } from './utils/auto-layout';
4853
import { calculateScopeBounds, LAYOUT_OPTIONS } from './utils/layout';
4954
import { loadDiagramJson, loadEmpty } from './utils/load-diagram';
@@ -92,6 +97,35 @@ function getChangeParentIdAndPosition(
9297
}
9398
}
9499

100+
function defaultTemplateNodes(): DiagramEditorNode[] {
101+
return [
102+
{
103+
id: uuidv4(),
104+
type: 'sectionInput',
105+
position: { x: 0, y: 0 },
106+
data: {
107+
namespace: ROOT_NAMESPACE,
108+
remappedId: 'input',
109+
targetId: 'input',
110+
},
111+
width: LAYOUT_OPTIONS.nodeWidth,
112+
height: LAYOUT_OPTIONS.nodeHeight,
113+
},
114+
{
115+
id: uuidv4(),
116+
type: 'sectionOutput',
117+
position: { x: 0, y: 400 },
118+
data: {
119+
namespace: ROOT_NAMESPACE,
120+
remappedId: 'output',
121+
targetId: 'output',
122+
},
123+
width: LAYOUT_OPTIONS.nodeWidth,
124+
height: LAYOUT_OPTIONS.nodeHeight,
125+
},
126+
];
127+
}
128+
95129
const DiagramEditor = () => {
96130
const reactFlowInstance = React.useRef<ReactFlowInstance<
97131
DiagramEditorNode,
@@ -103,8 +137,9 @@ const DiagramEditor = () => {
103137
const [nodes, setNodes] = React.useState<DiagramEditorNode[]>(
104138
() => loadEmpty().nodes,
105139
);
106-
const [templateNodes, _setTemplateNodes] =
107-
React.useState<DiagramEditorNode[]>();
140+
const [templateNodes, _setTemplateNodes] = React.useState<
141+
DiagramEditorNode[]
142+
>(() => defaultTemplateNodes());
108143
const renderedNodes = React.useMemo(() => {
109144
switch (editorMode.mode) {
110145
case EditorMode.Normal:

diagram-editor/frontend/nodes/section-node.tsx

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,8 @@ import {
1313
export type SectionInterfaceData = {
1414
// section interfaces is always in the root namespace
1515
namespace: typeof ROOT_NAMESPACE;
16-
connectKey: string;
16+
remappedId: string;
17+
targetId: string;
1718
};
1819

1920
export function SectionNode(props: NodeProps<OperationNode<'section'>>) {
@@ -49,7 +50,7 @@ export function SectionInputNode(
4950
{...props}
5051
color="secondary"
5152
icon={<SectionInputIcon />}
52-
label={props.data.connectKey}
53+
label={props.data.remappedId}
5354
variant="output"
5455
/>
5556
);
@@ -63,7 +64,7 @@ export function SectionOutputNode(
6364
{...props}
6465
color="secondary"
6566
icon={<SectionOutputIcon />}
66-
label={props.data.connectKey}
67+
label={props.data.remappedId}
6768
variant="input"
6869
/>
6970
);
@@ -77,7 +78,7 @@ export function SectionBufferNode(
7778
{...props}
7879
color="secondary"
7980
icon={<SectionBufferIcon />}
80-
label={props.data.connectKey}
81+
label={props.data.remappedId}
8182
variant="output"
8283
/>
8384
);

diagram-editor/frontend/utils/export-diagram.ts

Lines changed: 52 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import equal from 'fast-deep-equal';
22
import type { DiagramEditorEdge, StreamOutEdge } from '../edges';
33
import type { NodeManager } from '../node-manager';
4-
import { isBuiltinNode, isOperationNode } from '../nodes';
4+
import { isOperationNode } from '../nodes';
55
import type {
66
BufferSelection,
77
Diagram,
@@ -143,7 +143,7 @@ function syncBufferSelection(
143143
*/
144144
function syncEdge(
145145
nodeManager: NodeManager,
146-
diagram: Diagram,
146+
root: SubOperations,
147147
edge: DiagramEditorEdge,
148148
): void {
149149
if (edge.type === 'bufferKey' || edge.type === 'bufferSeq') {
@@ -156,7 +156,7 @@ function syncEdge(
156156
if (sourceNode.type === 'start') {
157157
const subOps: SubOperations = (() => {
158158
if (!sourceNode.parentId) {
159-
return diagram;
159+
return root;
160160
}
161161
const scopeNode = nodeManager.getNode(sourceNode.parentId);
162162
if (!isScopeNode(scopeNode)) {
@@ -285,15 +285,15 @@ function syncEdge(
285285
/**
286286
* Update the operation connections from the edges.
287287
*
288-
* @param diagram only used to update the `start` field, does not actually populate the operations.
288+
* @param root only used to update the `start` field, does not actually populate the operations.
289289
*/
290290
function syncEdges(
291291
nodeManager: NodeManager,
292-
diagram: Diagram,
292+
root: SubOperations,
293293
edges: DiagramEditorEdge[],
294294
): void {
295295
// first clear all the connections
296-
diagram.start = { builtin: 'dispose' };
296+
root.start = { builtin: 'dispose' };
297297
for (const node of nodeManager.iterNodes()) {
298298
if (!isOperationNode(node)) {
299299
continue;
@@ -356,7 +356,7 @@ function syncEdges(
356356
}
357357

358358
for (const edge of edges) {
359-
syncEdge(nodeManager, diagram, edge);
359+
syncEdge(nodeManager, root, edge);
360360
}
361361
}
362362

@@ -395,56 +395,55 @@ export function exportDiagram(
395395
}
396396
}
397397

398-
for (const edge of edges) {
399-
const source = nodeManager.getNode(edge.source);
400-
if (source.type === 'start') {
401-
const subOps = getSubOperations(diagram, source.data.namespace);
402-
const target = nodeManager.getNode(edge.target);
403-
if (isOperationNode(target)) {
404-
subOps.start = target.data.opId;
405-
} else if (isBuiltinNode(target)) {
406-
subOps.start = { builtin: target.type };
407-
} else {
408-
throw new Error('unknown node');
409-
}
410-
}
411-
}
412-
413398
return diagram;
414399
}
415400

416-
// export function exportTemplate(
417-
// nodeManager: NodeManager,
418-
// edges: DiagramEditorEdge[],
419-
// ): Record<string, DiagramOperation> {
420-
// const root: SubOperations = {
421-
// start: { builtin: 'dispose' },
422-
// ops: {},
423-
// };
401+
export function exportTemplate(
402+
nodeManager: NodeManager,
403+
edges: DiagramEditorEdge[],
404+
): SectionTemplate {
405+
const template: Required<SectionTemplate> = {
406+
inputs: {},
407+
outputs: [],
408+
buffers: {},
409+
ops: {},
410+
};
411+
const fakeRoot: SubOperations = {
412+
start: { builtin: 'dispose' },
413+
ops: {},
414+
};
424415

425-
// for (const node of nodeManager.iterNodes()) {
426-
// const subOps = getSubOperations(root, node.data.namespace);
416+
syncEdges(nodeManager, fakeRoot, edges);
427417

428-
// if (isOperationNode(node)) {
429-
// subOps.ops[node.data.opId] = node.data.op;
430-
// }
431-
// }
418+
// visit the nodes breath first to ensure that the parents exist in the diagram before
419+
// populating the children.
420+
const sortedNodes = Array.from(nodeManager.iterNodes()).sort(
421+
(a, b) =>
422+
splitNamespaces(a.data.namespace).length -
423+
splitNamespaces(b.data.namespace).length,
424+
);
425+
for (const node of sortedNodes) {
426+
const subOps = getSubOperations(fakeRoot, node.data.namespace);
432427

433-
// for (const edge of edges) {
434-
// const source = nodeManager.getNode(edge.source);
435-
// if (source.type === 'start') {
436-
// const subOps = getSubOperations(root, source.data.namespace);
437-
// const target = nodeManager.getNode(edge.target);
438-
// if (isOperationNode(target)) {
439-
// subOps.start = target.data.opId;
440-
// } else if (isBuiltinNode(target)) {
441-
// subOps.start = { builtin: target.type };
442-
// } else {
443-
// throw new Error('unknown node');
444-
// }
445-
// }
446-
// nodeManager.syncEdge(edge);
447-
// }
428+
if (isOperationNode(node)) {
429+
subOps.ops[node.data.opId] = { ...node.data.op };
430+
if (node.data.op.type === 'scope') {
431+
// do not carry over stale ops from the node data
432+
subOps.ops[node.data.opId].ops = {};
433+
}
434+
} else if (node.type === 'sectionInput') {
435+
template.inputs[node.data.remappedId] = node.data.targetId;
436+
} else if (node.type === 'sectionOutput') {
437+
template.outputs.push(node.data.remappedId);
438+
} else if (node.type === 'sectionBuffer') {
439+
template.buffers[node.data.remappedId] = node.data.targetId;
440+
}
441+
}
448442

449-
// return root.ops;
450-
// }
443+
return {
444+
inputs: {},
445+
outputs: [],
446+
buffers: {},
447+
ops: fakeRoot.ops,
448+
};
449+
}

0 commit comments

Comments
 (0)