From 846f45aa1b360c5ad7674811a10c49084f508ef2 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 9 Feb 2026 05:54:08 +0000 Subject: [PATCH 1/3] Initial plan From 0c54ea08525560c5218b643268fe41042bedbf43 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 9 Feb 2026 05:57:06 +0000 Subject: [PATCH 2/3] Add rf-node-label class to label div Co-authored-by: MarcSkovMadsen <42288570+MarcSkovMadsen@users.noreply.github.com> --- src/panel_reactflow/models/reactflow.jsx | 104 ++++++----------------- 1 file changed, 28 insertions(+), 76 deletions(-) diff --git a/src/panel_reactflow/models/reactflow.jsx b/src/panel_reactflow/models/reactflow.jsx index 7df0cc9..779175a 100644 --- a/src/panel_reactflow/models/reactflow.jsx +++ b/src/panel_reactflow/models/reactflow.jsx @@ -1,19 +1,5 @@ import React from "react"; -import { - Background, - Controls, - Handle, - MiniMap, - NodeToolbar, - Panel, - Position, - ReactFlow, - ReactFlowProvider, - addEdge, - useEdgesState, - useNodesState, - useReactFlow, -} from "@xyflow/react"; +import { Background, Controls, Handle, MiniMap, NodeToolbar, Panel, Position, ReactFlow, ReactFlowProvider, addEdge, useEdgesState, useNodesState, useReactFlow } from "@xyflow/react"; import "@xyflow/react/dist/style.css"; const { useCallback, useEffect, useMemo, useRef } = React; @@ -26,12 +12,7 @@ const BUILTIN_NODE_TYPES = { function renderHandles(direction, handles) { if (!handles?.length) { - return ( - - ); + return ; } const spacing = 100 / (handles.length + 1); return handles.map((handle, index) => ( @@ -51,7 +32,7 @@ function makeNodeComponent(typeName, typeSpec, editorMode) { const spec = typeSpec || {}; const hasEditor = data?._hasEditor; const showGear = editorMode === "toolbar" && hasEditor; - const showToolbar = (editorMode === "toolbar" && toolbarOpen && hasEditor); + const showToolbar = editorMode === "toolbar" && toolbarOpen && hasEditor; const showInlineEditor = editorMode === "node" && hasEditor; const showView = data?.view && !spec.minimal; @@ -65,43 +46,31 @@ function makeNodeComponent(typeName, typeSpec, editorMode) { return (
{showToolbar ? ( - + {data.editor} - ): null} + ) : null} {showGear && ( )} {renderHandles("input", spec.inputs)} -
+
{displayLabel}
{(showView || showInlineEditor) && ( @@ -130,7 +99,7 @@ function useDebouncedSync(syncMode, debounceMs, syncFn) { syncFn(payload); } }, - [syncMode, debounceMs, syncFn] + [syncMode, debounceMs, syncFn], ); } @@ -193,7 +162,7 @@ function FlowInner({ } const data = { ...(node.data || {}), ...(msg.patch || {}) }; return { ...node, data }; - }) + }), ); return; } @@ -206,7 +175,7 @@ function FlowInner({ const data = { ...(edge.data || {}), ...(msg.patch || {}) }; const nextLabel = msg.patch?.label ?? edge.label; return { ...edge, data, label: nextLabel }; - }) + }), ); } }; @@ -226,13 +195,8 @@ function FlowInner({ useEffect(() => { const nodesSig = signature(pyNodes); - const viewsSig = signature( - (views || []).map((view) => view?.props?.id ?? null) - ); - if ( - nodesSig === lastHydrated.current.nodesSig && - viewsSig === lastHydrated.current.viewsRef - ) { + const viewsSig = signature((views || []).map((view) => view?.props?.id ?? null)); + if (nodesSig === lastHydrated.current.nodesSig && viewsSig === lastHydrated.current.viewsRef) { return; } lastHydrated.current.nodesSig = nodesSig; @@ -279,7 +243,7 @@ function FlowInner({ } model.send_msg(payload); }, - [model] + [model], ); const schedulePatch = useDebouncedSync(syncMode, debounceMs, sendPatch); @@ -295,15 +259,13 @@ function FlowInner({ setEdges(updated); sendPatch({ type: "edge_added", edge: newEdge }); }, - [enableConnect, sendPatch, setEdges] + [enableConnect, sendPatch, setEdges], ); const handleNodesChange = useCallback( (changes) => { onNodesChange(changes); - const moved = changes.filter( - (change) => change.type === "position" && change.dragging !== true - ); + const moved = changes.filter((change) => change.type === "position" && change.dragging !== true); if (!moved.length) { return; } @@ -315,7 +277,7 @@ function FlowInner({ }); }); }, - [onNodesChange, schedulePatch] + [onNodesChange, schedulePatch], ); const onSelectionChange = useCallback( @@ -334,7 +296,7 @@ function FlowInner({ edges: selection.edges, }); }, - [currentSelection, schedulePatch, selectionSetter] + [currentSelection, schedulePatch, selectionSetter], ); const onNodesDelete = useCallback( @@ -363,13 +325,10 @@ function FlowInner({ ...node, data: { ...node.data, view_idx: viewIdx - shift }, }; - }) + }), ); } - const deletedEdges = edgesRef.current.filter( - (edge) => - deletedIds.includes(edge.source) || deletedIds.includes(edge.target) - ); + const deletedEdges = edgesRef.current.filter((edge) => deletedIds.includes(edge.source) || deletedIds.includes(edge.target)); schedulePatch({ type: "node_deleted", node_id: deletedIds.length === 1 ? deletedIds[0] : null, @@ -377,7 +336,7 @@ function FlowInner({ deleted_edges: deletedEdges.map((edge) => edge.id), }); }, - [schedulePatch, setNodes] + [schedulePatch, setNodes], ); const onEdgesDelete = useCallback( @@ -388,7 +347,7 @@ function FlowInner({ edge_ids: deletedEdges.map((edge) => edge.id), }); }, - [schedulePatch] + [schedulePatch], ); const onMoveEnd = useCallback( @@ -397,7 +356,7 @@ function FlowInner({ viewportSetter(nextViewport); } }, - [viewport, viewportSetter] + [viewport, viewportSetter], ); return ( @@ -452,10 +411,7 @@ export function render({ model, view }) { const leftPanels = model.get_child("left_panel"); const rightPanels = model.get_child("right_panel"); - const allNodeTypes = useMemo( - () => ({ ...BUILTIN_NODE_TYPES, ...(pyNodeTypes || {}) }), - [pyNodeTypes] - ); + const allNodeTypes = useMemo(() => ({ ...BUILTIN_NODE_TYPES, ...(pyNodeTypes || {}) }), [pyNodeTypes]); const nodeEditorMap = {}; const nodeHasEditorMap = {}; @@ -515,11 +471,7 @@ export function render({ model, view }) { const hydratedNodeTypes = useMemo(() => { const mapping = {}; Object.entries({ ...BUILTIN_NODE_TYPES, ...(pyNodeTypes || {}) }).forEach(([typeName, spec]) => { - mapping[typeName] = makeNodeComponent( - typeName, - spec, - editorMode, - ); + mapping[typeName] = makeNodeComponent(typeName, spec, editorMode); }); return mapping; }, [editorMode, pyNodeTypes]); @@ -558,8 +510,8 @@ export function render({ model, view }) { {rightPanels} - {(selection.nodes.length && editorMode === "side" && nodeHasEditorMap[selection.nodes[0]]) ? nodeEditorMap[selection.nodes[0]] : null} - {(selection.edges.length && !selection.nodes.length && edgeHasEditorMap[selection.edges[0]]) ? edgeEditorMap[selection.edges[0]] : null} + {selection.nodes.length && editorMode === "side" && nodeHasEditorMap[selection.nodes[0]] ? nodeEditorMap[selection.nodes[0]] : null} + {selection.edges.length && !selection.nodes.length && edgeHasEditorMap[selection.edges[0]] ? edgeEditorMap[selection.edges[0]] : null}
From 4a2a50ca55c2365daace639f3deb5c75087661ad Mon Sep 17 00:00:00 2001 From: MarcSkovMadsen Date: Mon, 9 Feb 2026 08:15:25 +0000 Subject: [PATCH 3/3] review feedback --- src/panel_reactflow/dist/css/reactflow.css | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/panel_reactflow/dist/css/reactflow.css b/src/panel_reactflow/dist/css/reactflow.css index ffa065f..eb51f62 100644 --- a/src/panel_reactflow/dist/css/reactflow.css +++ b/src/panel_reactflow/dist/css/reactflow.css @@ -28,9 +28,7 @@ } .rf-node-toolbar-button { - position: absolute; - top: 7px; - right: 7px; + float: right; border: none; background: transparent; font-size: 17px; @@ -38,6 +36,7 @@ cursor: pointer; z-index: 2; padding: 0; + margin: 0 0 0 6px; transition: color 0.1s; }