Repository navigation
This release adds port and edge value inspection, connection checks
and canvas drops for interactive graph editing. Node and Edge properties now sync to
the browser in place, batches of changes render as a single update, and
an error boundary keeps a malformed graph from blanking the canvas.
Highlights
-
Port and edge inspection: handle and edge click events can open a
Panel popup withflow.show_popup(content, position). Set
popup_trigger="hover"to use hover events instead; use
flow.close_popup()to dismiss it. Applications supply the value to
display, andexamples/port_value_inspection.pyshows both interactions
(#74). -
Connection validation: opt-in browser policies reject connections
with the wrong direction or handle type, full inputs, duplicate edges,
and cycles. Register Python rules withadd_connection_validator()to
show rejection reasons on candidate handles during a drag. Python
validators check interactive drags only; they do not restrict
flow.add_edge()or direct changes toflow.edges. See
Validate Connections and
examples/connection_validation.py
(#75). -
Error recovery: the canvas is now wrapped in an error boundary,
controlled by the newerror_recoveryparameter ("auto"by default,
or"manual"/"off"). In"auto"mode a React render error
remounts the canvas, then remounts again in a view-only safe mode that
repairs or hides elements it cannot render (invalid positions, unknown
node/edge types, dangling edges, duplicate or missing ids) without
mutating the server-side graph. If retries are exhausted a recovery
panel offers Try again, Reload page and Copy details. Every
error is logged to thepanel.reactflowlogger and emitted as a
client_errorevent, so browser-side failures are no longer invisible
to the server
(#70). -
Base property sync: the top-level React Flow fields on
Nodeand
Edge(label,type,style,className,draggable,
connectable,deletable, ...) are now synced to the frontend, so
assigningnode.label = "Start (running)"patches the browser in place
instead of requiringflow.nodesto be replaced. Parameters declared
on a subclass continue to sync intodata. Newpatch_node_props()
andpatch_edge_props()methods do the same for dict-based nodes and
edges, where passingNoneclears a field back to the CSS/theme
default, and newon_props_changehooks fire onNode/Edge
subclasses when the frontend changes a property.positionand
selectedremain browser-owned during drag and selection and are only
pushed viapatch_node_props()
(#71).
Enhancements
-
Batch removal:
remove_node()andremove_edge()now accept
several ids, either as separate arguments
(flow.remove_node("n1", "n2")) or as a sequence
(flow.remove_node(["n1", "n2"])), and remove them in a single update.
For any other batch of changes made from Python, wrap them in
pn.io.hold()to render them at once
(#72). -
Drop data onto the canvas:
drop_typeslists MIME types the canvas
accepts, and each drop of one of them emits adropevent with the
dropped data, its flow position, and the node or handle under the
pointer, so a handler can add and wire what was dropped. Draggable
panel_material_ui.MenuListitems work as a source; see
React to Events
(#77).
Bug fixes
-
Nodes remounted when node types change: any change to
node_typesrebuilt the component for every node type, so React
remounted every node and detached its embedded view, which could leave
Bokeh plots blank. Each type's component is now reused until its own
spec or the popup settings change
(#77). -
Progressive re-render when deleting multiple elements: deleting a
multi-node selection removed the nodes one at a time, syncing an
intermediate graph to the browser per node so the nodes visibly
disappeared one by one. Updates triggered by a frontend message are now
held and combined into a single patch, and node/edge deletion assigns
nodesandedgesonce
(#72). -
Serialization error when updating
node_types: assigning
NodeTypeorEdgeTypedescriptors with aschemaclass after
construction synced them to the browser before they were converted to
JSON descriptors, so the server failed withcan't serialize ParameterizedMetaclass. They are now converted before syncing, and
updatingnode_typesandedge_typestogether no longer raises a
TypeError
(#76).