-
Notifications
You must be signed in to change notification settings - Fork 62
sync(ladder): reimplement handle branches on ladder #750
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
bd86224
7619bb3
986b4a0
e1244ec
f290310
fa04fa9
f306987
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -10,6 +10,10 @@ import { checkVariableName } from '../../../../store/slices/project/validation/v | |
| import { cn } from '../../../../utils/cn' | ||
| import { toast } from '../../../_features/[app]/toast/use-toast' | ||
| import { updateDiagramElementsPosition } from '../../../_molecules/graphical-editor/ladder/rung/ladder-utils/elements/diagram' | ||
| import { | ||
| findInvalidatedBranches, | ||
| reconcileBranches, | ||
| } from '../../../_molecules/graphical-editor/ladder/rung/ladder-utils/elements/handle-branch' | ||
| import { HighlightedTextArea } from '../../highlighted-textarea' | ||
| import { InputWithRef } from '../../input' | ||
| import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from '../../tooltip' | ||
|
|
@@ -60,7 +64,7 @@ export const BlockNodeElement = <T extends object>({ | |
| editorActions: { updateModelVariables }, | ||
| libraries, | ||
| ladderFlows, | ||
| ladderFlowActions: { setNodes, setEdges }, | ||
| ladderFlowActions, | ||
| project: { | ||
| data: { pous }, | ||
| }, | ||
|
|
@@ -176,6 +180,26 @@ export const BlockNodeElement = <T extends object>({ | |
| }) | ||
| if (!pou || !rung || !node) return | ||
|
|
||
| /** | ||
| * Handle-branch reconciliation: a block-variant change can rename or | ||
| * retype handles in ways that orphan existing branches. If any branch | ||
| * on this block would be invalidated by the new variant, ask the user | ||
| * for confirmation before silently dropping them. | ||
| */ | ||
| const invalidatedBranches = findInvalidatedBranches(rung, node.id, libraryBlock as BlockVariant) | ||
| if (invalidatedBranches.length > 0) { | ||
| const handleNames = invalidatedBranches.map((b) => `${b.handleId} (${b.direction})`).join(', ') | ||
| const confirmed = window.confirm( | ||
| `Changing this block to "${blockNameValue}" will drop ${invalidatedBranches.length} handle ` + | ||
| `branch${invalidatedBranches.length === 1 ? '' : 'es'} on the following pin${invalidatedBranches.length === 1 ? '' : 's'}: ${handleNames}.\n\n` + | ||
| `Continue?`, | ||
| ) | ||
| if (!confirmed) { | ||
| setBlockNameValue(validBlockNameValue) | ||
| return | ||
| } | ||
| } | ||
|
Comment on lines
+189
to
+201
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Consider replacing with an in-app modal (the project already has As per coding guidelines: "Use 🤖 Prompt for AI Agents |
||
|
|
||
| if (libraryBlock && pou.pouType === 'function' && (libraryBlock as BlockVariant).type !== 'function') { | ||
| setWrongName(true) | ||
| toast({ | ||
|
|
@@ -242,7 +266,7 @@ export const BlockNodeElement = <T extends object>({ | |
| } | ||
| } | ||
|
|
||
| let newNodes = [...rung.nodes] | ||
| let newNodes: typeof rung.nodes = [...rung.nodes] | ||
| let newEdges = [...rung.edges] | ||
|
|
||
| /** | ||
|
|
@@ -263,7 +287,7 @@ export const BlockNodeElement = <T extends object>({ | |
| variable: variable ?? { name: '' }, | ||
| } | ||
|
|
||
| newNodes = newNodes.map((n) => (n.id === node.id ? newBlockNode : n)) | ||
| newNodes = newNodes.map((n) => (n.id === node.id ? newBlockNode : n)) as typeof newNodes | ||
|
|
||
| edges.source?.forEach((edge) => { | ||
| const newEdge = { | ||
|
|
@@ -284,12 +308,23 @@ export const BlockNodeElement = <T extends object>({ | |
| newEdges = newEdges.map((e) => (e.id === edge.id ? newEdge : e)) | ||
| }) | ||
|
|
||
| // Reconcile any handle branches on this block before layout runs: | ||
| // - drop branches whose handle disappeared or stopped being BOOL | ||
| // - remap surviving branches' references to the new block id | ||
| const reconciled = reconcileBranches( | ||
| { ...rung, nodes: newNodes, edges: newEdges } as typeof rung, | ||
| node.id, | ||
| newBlockNode.id, | ||
| libraryBlock as BlockVariant, | ||
| ) | ||
|
|
||
| const { nodes: variableNodes, edges: variableEdges } = updateDiagramElementsPosition( | ||
| { | ||
| ...rung, | ||
| nodes: newNodes, | ||
| edges: newEdges, | ||
| }, | ||
| nodes: reconciled.nodes, | ||
| edges: reconciled.edges, | ||
| handleBranches: reconciled.handleBranches, | ||
| } as typeof rung, | ||
| [rung.defaultBounds[0], rung.defaultBounds[1]], | ||
| ) | ||
|
|
||
|
|
@@ -300,15 +335,12 @@ export const BlockNodeElement = <T extends object>({ | |
| body: currentPou2?.body.value, | ||
| }) | ||
|
|
||
| setNodes({ | ||
| ladderFlowActions.updateRungData({ | ||
| editorName: editor.meta.name, | ||
| rungId: rung.id, | ||
| nodes: variableNodes, | ||
| }) | ||
| setEdges({ | ||
| editorName: editor.meta.name, | ||
| rungId: rung.id, | ||
| edges: variableEdges, | ||
| handleBranches: reconciled.handleBranches, | ||
| }) | ||
|
|
||
| setWrongName(false) | ||
|
|
@@ -353,7 +385,7 @@ export const BlockNodeElement = <T extends object>({ | |
| <div | ||
| key={index} | ||
| className='absolute text-xs' | ||
| style={{ top: DEFAULT_BLOCK_CONNECTOR_Y + index * DEFAULT_BLOCK_CONNECTOR_Y_OFFSET - 10, left: 6 }} | ||
| style={{ top: (data.inputHandles[index]?.relPosition.y ?? 0) - 10, left: 6 }} | ||
| > | ||
| {connector} | ||
| </div> | ||
|
|
@@ -362,7 +394,7 @@ export const BlockNodeElement = <T extends object>({ | |
| <div | ||
| key={index} | ||
| className='absolute text-xs' | ||
| style={{ top: DEFAULT_BLOCK_CONNECTOR_Y + index * DEFAULT_BLOCK_CONNECTOR_Y_OFFSET - 10, right: 6 }} | ||
| style={{ top: (data.outputHandles[index]?.relPosition.y ?? 0) - 10, right: 6 }} | ||
| > | ||
| {connector} | ||
| </div> | ||
|
|
@@ -619,7 +651,7 @@ export const Block = <T extends object>(block: BlockProps<T>) => { | |
| const libPou = pous.find((pou) => pou.name === libMatch.name) | ||
| if (!libPou) return | ||
|
|
||
| const blockVariant = node.data.variant as BlockVariant | ||
| const blockVariant = (node.data as BlockNodeData<BlockVariant>).variant | ||
| const newNodeVariables = (libPou.interface?.variables ?? []).map((variable) => { | ||
| let newType | ||
| switch (variable.type.definition) { | ||
|
|
@@ -717,10 +749,10 @@ export const Block = <T extends object>(block: BlockProps<T>) => { | |
|
|
||
| const newBlockNode = { ...updatedNewNode } | ||
|
|
||
| let newNodes = [...rung.nodes] | ||
| let newNodes: typeof rung.nodes = [...rung.nodes] | ||
| let newEdges = [...rung.edges] | ||
|
|
||
| newNodes = newNodes.map((n) => (n.id === node.id ? newBlockNode : n)) | ||
| newNodes = newNodes.map((n) => (n.id === node.id ? newBlockNode : n)) as typeof newNodes | ||
|
|
||
| edges.source?.forEach((edge) => { | ||
| const newEdge = { | ||
|
|
@@ -746,7 +778,7 @@ export const Block = <T extends object>(block: BlockProps<T>) => { | |
| ...rung, | ||
| nodes: newNodes, | ||
| edges: newEdges, | ||
| }, | ||
| } as typeof rung, | ||
| [rung.defaultBounds[0], rung.defaultBounds[1]], | ||
| ) | ||
|
|
||
|
|
@@ -841,7 +873,7 @@ export const Block = <T extends object>(block: BlockProps<T>) => { | |
| rungId: rung.id, | ||
| node: { | ||
| ...node, | ||
| draggable: node.data.draggable as boolean, | ||
| draggable: node.data.draggable, | ||
| }, | ||
| }) | ||
| return | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 Analysis chain
🏁 Script executed:
Repository: Autonomy-Logic/openplc-editor
Length of output: 941
🏁 Script executed:
Repository: Autonomy-Logic/openplc-editor
Length of output: 4807
🏁 Script executed:
Repository: Autonomy-Logic/openplc-editor
Length of output: 55
🏁 Script executed:
Repository: Autonomy-Logic/openplc-editor
Length of output: 408
🏁 Script executed:
Repository: Autonomy-Logic/openplc-editor
Length of output: 543
🏁 Script executed:
Repository: Autonomy-Logic/openplc-editor
Length of output: 55
🏁 Script executed:
Repository: Autonomy-Logic/openplc-editor
Length of output: 456
🏁 Script executed:
Repository: Autonomy-Logic/openplc-editor
Length of output: 3957
🏁 Script executed:
Repository: Autonomy-Logic/openplc-editor
Length of output: 248
🏁 Script executed:
Repository: Autonomy-Logic/openplc-editor
Length of output: 759
🏁 Script executed:
Repository: Autonomy-Logic/openplc-editor
Length of output: 936
🏁 Script executed:
Repository: Autonomy-Logic/openplc-editor
Length of output: 55
🏁 Script executed:
Repository: Autonomy-Logic/openplc-editor
Length of output: 55
Correct the edge type references to use
FBDFlowTypeinstead ofLadderFlowType.Lines 25–26 should reference
FBDFlowType['rung']['edges']instead ofLadderFlowType['rungs'][0]['edges']. The function is FBD-specific, therungparameter is already typed asFBDFlowType['rung'], and the implementation retrieves edges fromrung?.edges. This inconsistency mirrors the fix already applied to line 28 for thenodetype. While both type references resolve toEdge[]structurally, usingFBDFlowTypemaintains consistency with the function's actual context.🤖 Prompt for AI Agents