panel-reactflow 0.1.0__tar.gz → 0.2.0rc0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {panel_reactflow-0.1.0 → panel_reactflow-0.2.0rc0}/PKG-INFO +2 -2
- {panel_reactflow-0.1.0 → panel_reactflow-0.2.0rc0}/README.md +1 -1
- panel_reactflow-0.2.0rc0/docs/how-to/define-nodes-edges.md +219 -0
- {panel_reactflow-0.1.0 → panel_reactflow-0.2.0rc0}/docs/how-to/embed-views-in-nodes.md +8 -4
- {panel_reactflow-0.1.0 → panel_reactflow-0.2.0rc0}/docs/index.md +5 -1
- {panel_reactflow-0.1.0 → panel_reactflow-0.2.0rc0}/docs/quickstart.md +6 -0
- {panel_reactflow-0.1.0 → panel_reactflow-0.2.0rc0}/pixi.lock +776 -792
- {panel_reactflow-0.1.0 → panel_reactflow-0.2.0rc0}/pyproject.toml +3 -0
- panel_reactflow-0.2.0rc0/src/panel_reactflow/base.py +2233 -0
- panel_reactflow-0.2.0rc0/src/panel_reactflow/dist/css/reactflow.css +74 -0
- panel_reactflow-0.2.0rc0/src/panel_reactflow/dist/icons/gear.svg +1 -0
- panel_reactflow-0.2.0rc0/src/panel_reactflow/dist/panel-reactflow.bundle.css +1 -0
- panel_reactflow-0.2.0rc0/src/panel_reactflow/dist/panel-reactflow.bundle.js +82 -0
- {panel_reactflow-0.1.0 → panel_reactflow-0.2.0rc0}/src/panel_reactflow/models/reactflow.jsx +33 -76
- {panel_reactflow-0.1.0 → panel_reactflow-0.2.0rc0}/src/panel_reactflow/schema.py +5 -2
- {panel_reactflow-0.1.0 → panel_reactflow-0.2.0rc0}/tests/test_api.py +246 -4
- {panel_reactflow-0.1.0 → panel_reactflow-0.2.0rc0}/tests/ui/test_ui.py +1 -2
- panel_reactflow-0.1.0/docs/how-to/define-nodes-edges.md +0 -133
- panel_reactflow-0.1.0/src/panel_reactflow/base.py +0 -1016
- {panel_reactflow-0.1.0 → panel_reactflow-0.2.0rc0}/.copier-answers.yml +0 -0
- {panel_reactflow-0.1.0 → panel_reactflow-0.2.0rc0}/.gitattributes +0 -0
- {panel_reactflow-0.1.0 → panel_reactflow-0.2.0rc0}/.github/CODEOWNERS +0 -0
- {panel_reactflow-0.1.0 → panel_reactflow-0.2.0rc0}/.github/dependabot.yml +0 -0
- {panel_reactflow-0.1.0 → panel_reactflow-0.2.0rc0}/.github/workflows/build.yml +0 -0
- {panel_reactflow-0.1.0 → panel_reactflow-0.2.0rc0}/.github/workflows/docs.yml +0 -0
- {panel_reactflow-0.1.0 → panel_reactflow-0.2.0rc0}/.github/workflows/test.yml +0 -0
- {panel_reactflow-0.1.0 → panel_reactflow-0.2.0rc0}/.gitignore +0 -0
- {panel_reactflow-0.1.0 → panel_reactflow-0.2.0rc0}/.pre-commit-config.yaml +0 -0
- {panel_reactflow-0.1.0 → panel_reactflow-0.2.0rc0}/.prettierrc +0 -0
- {panel_reactflow-0.1.0 → panel_reactflow-0.2.0rc0}/LICENSE.txt +0 -0
- {panel_reactflow-0.1.0 → panel_reactflow-0.2.0rc0}/MANIFEST.in +0 -0
- {panel_reactflow-0.1.0 → panel_reactflow-0.2.0rc0}/docs/assets/logo.svg +0 -0
- {panel_reactflow-0.1.0 → panel_reactflow-0.2.0rc0}/docs/assets/screenshots/declare-types.png +0 -0
- {panel_reactflow-0.1.0 → panel_reactflow-0.2.0rc0}/docs/assets/screenshots/define-editors-edge.png +0 -0
- {panel_reactflow-0.1.0 → panel_reactflow-0.2.0rc0}/docs/assets/screenshots/define-editors-node.png +0 -0
- {panel_reactflow-0.1.0 → panel_reactflow-0.2.0rc0}/docs/assets/screenshots/define-nodes-edges.png +0 -0
- {panel_reactflow-0.1.0 → panel_reactflow-0.2.0rc0}/docs/assets/screenshots/embed-views-in-nodes.png +0 -0
- {panel_reactflow-0.1.0 → panel_reactflow-0.2.0rc0}/docs/assets/screenshots/quickstart.png +0 -0
- {panel_reactflow-0.1.0 → panel_reactflow-0.2.0rc0}/docs/assets/screenshots/react-to-events.png +0 -0
- {panel_reactflow-0.1.0 → panel_reactflow-0.2.0rc0}/docs/assets/screenshots/style-nodes-edges.png +0 -0
- {panel_reactflow-0.1.0 → panel_reactflow-0.2.0rc0}/docs/examples.md +0 -0
- {panel_reactflow-0.1.0 → panel_reactflow-0.2.0rc0}/docs/how-to/declare-types.md +0 -0
- {panel_reactflow-0.1.0 → panel_reactflow-0.2.0rc0}/docs/how-to/define-editors.md +0 -0
- {panel_reactflow-0.1.0 → panel_reactflow-0.2.0rc0}/docs/how-to/react-to-events.md +0 -0
- {panel_reactflow-0.1.0 → panel_reactflow-0.2.0rc0}/docs/how-to/style-nodes-edges.md +0 -0
- {panel_reactflow-0.1.0 → panel_reactflow-0.2.0rc0}/docs/reference/panel_reactflow.md +0 -0
- {panel_reactflow-0.1.0 → panel_reactflow-0.2.0rc0}/docs/releases.md +0 -0
- {panel_reactflow-0.1.0 → panel_reactflow-0.2.0rc0}/examples/advanced.py +0 -0
- {panel_reactflow-0.1.0 → panel_reactflow-0.2.0rc0}/examples/custom_editor.py +0 -0
- {panel_reactflow-0.1.0 → panel_reactflow-0.2.0rc0}/examples/edge_editors.py +0 -0
- {panel_reactflow-0.1.0 → panel_reactflow-0.2.0rc0}/examples/schema_types.py +0 -0
- {panel_reactflow-0.1.0 → panel_reactflow-0.2.0rc0}/examples/simple.py +0 -0
- {panel_reactflow-0.1.0 → panel_reactflow-0.2.0rc0}/examples/threejs_viewer.py +0 -0
- {panel_reactflow-0.1.0 → panel_reactflow-0.2.0rc0}/hatch_build.py +0 -0
- {panel_reactflow-0.1.0 → panel_reactflow-0.2.0rc0}/pixi.toml +0 -0
- {panel_reactflow-0.1.0 → panel_reactflow-0.2.0rc0}/src/panel_reactflow/__init__.py +0 -0
- {panel_reactflow-0.1.0 → panel_reactflow-0.2.0rc0}/src/panel_reactflow/__version.py +0 -0
- {panel_reactflow-0.1.0 → panel_reactflow-0.2.0rc0}/src/panel_reactflow/py.typed +0 -0
- {panel_reactflow-0.1.0 → panel_reactflow-0.2.0rc0}/tests/__init__.py +0 -0
- {panel_reactflow-0.1.0 → panel_reactflow-0.2.0rc0}/tests/conftest.py +0 -0
- {panel_reactflow-0.1.0 → panel_reactflow-0.2.0rc0}/tests/test_core.py +0 -0
- {panel_reactflow-0.1.0 → panel_reactflow-0.2.0rc0}/tests/ui/__init__.py +0 -0
- {panel_reactflow-0.1.0 → panel_reactflow-0.2.0rc0}/zensical.toml +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: panel-reactflow
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.2.0rc0
|
|
4
4
|
Summary: A Panel wrapper for the Reactflow JS library.
|
|
5
5
|
Project-URL: Homepage, https://github.com/panel-extensions/panel-reactflow
|
|
6
6
|
Project-URL: Source, https://github.com/panel-extensions/panel-reactflow
|
|
@@ -80,7 +80,7 @@ import panel as pn
|
|
|
80
80
|
|
|
81
81
|
from panel_reactflow import ReactFlow
|
|
82
82
|
|
|
83
|
-
pn.extension()
|
|
83
|
+
pn.extension("jsoneditor")
|
|
84
84
|
|
|
85
85
|
nodes = [
|
|
86
86
|
{
|
|
@@ -0,0 +1,219 @@
|
|
|
1
|
+
# Define Nodes & Edges
|
|
2
|
+
|
|
3
|
+
Every graph in Panel-ReactFlow is built from two lists: **nodes** and
|
|
4
|
+
**edges**. Nodes represent entities on the canvas; edges represent
|
|
5
|
+
connections between them. Both are plain Python dictionaries, so you can
|
|
6
|
+
construct them from any data source — a database, a config file, or user
|
|
7
|
+
input at runtime.
|
|
8
|
+
|
|
9
|
+
This guide covers how to create nodes and edges, use the helper dataclasses,
|
|
10
|
+
and update data after the graph is live.
|
|
11
|
+
|
|
12
|
+

|
|
13
|
+
|
|
14
|
+
---
|
|
15
|
+
|
|
16
|
+
## Define nodes
|
|
17
|
+
|
|
18
|
+
A node dict requires `id`, `position`, and `data`. The display label is a
|
|
19
|
+
**top-level** field — keep it out of `data` so the frontend can render it
|
|
20
|
+
without parsing the payload.
|
|
21
|
+
|
|
22
|
+
```python
|
|
23
|
+
import panel as pn
|
|
24
|
+
|
|
25
|
+
nodes = [
|
|
26
|
+
{
|
|
27
|
+
"id": "n1",
|
|
28
|
+
"type": "panel",
|
|
29
|
+
"label": "Start",
|
|
30
|
+
"position": {"x": 0, "y": 0},
|
|
31
|
+
"data": {"status": "idle"},
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
"id": "n2",
|
|
35
|
+
"type": "panel",
|
|
36
|
+
"label": "End",
|
|
37
|
+
"position": {"x": 260, "y": 60},
|
|
38
|
+
"data": {"status": "done"},
|
|
39
|
+
"view": pn.pane.Markdown("Optional node body"),
|
|
40
|
+
},
|
|
41
|
+
]
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
| Key | Required | Description |
|
|
45
|
+
|------------|----------|-------------|
|
|
46
|
+
| `id` | yes | Unique string identifier. |
|
|
47
|
+
| `position` | yes | `{"x": float, "y": float}` canvas coordinates. |
|
|
48
|
+
| `data` | yes | Arbitrary dict of payload data. |
|
|
49
|
+
| `label` | no | Display text shown in the node header. |
|
|
50
|
+
| `type` | no | Node type name (default `"panel"`). |
|
|
51
|
+
| `view` | no | A Panel viewable rendered inside the node. |
|
|
52
|
+
|
|
53
|
+
---
|
|
54
|
+
|
|
55
|
+
## Define edges
|
|
56
|
+
|
|
57
|
+
Edges link two nodes by their `id`. Use the top-level `label` for the
|
|
58
|
+
text shown on the edge.
|
|
59
|
+
|
|
60
|
+
```python
|
|
61
|
+
edges = [
|
|
62
|
+
{"id": "e1", "source": "n1", "target": "n2", "label": "next"},
|
|
63
|
+
]
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
| Key | Required | Description |
|
|
67
|
+
|----------------|----------|-------------|
|
|
68
|
+
| `id` | yes | Unique string identifier. |
|
|
69
|
+
| `source` | yes | ID of the source node. |
|
|
70
|
+
| `target` | yes | ID of the target node. |
|
|
71
|
+
| `label` | no | Text rendered on the edge. |
|
|
72
|
+
| `type` | no | Edge type name (for styling / editors). |
|
|
73
|
+
| `data` | no | Arbitrary dict of payload data. |
|
|
74
|
+
| `sourceHandle` | no | Specific output handle on the source node. |
|
|
75
|
+
| `targetHandle` | no | Specific input handle on the target node. |
|
|
76
|
+
|
|
77
|
+
---
|
|
78
|
+
|
|
79
|
+
## Use the NodeSpec / EdgeSpec helpers
|
|
80
|
+
|
|
81
|
+
If you prefer a typed API, use the dataclass helpers. They validate fields
|
|
82
|
+
at construction time and are **automatically converted to dictionaries** when
|
|
83
|
+
passed to `ReactFlow`.
|
|
84
|
+
|
|
85
|
+
```python
|
|
86
|
+
from panel_reactflow import NodeSpec, EdgeSpec, ReactFlow
|
|
87
|
+
|
|
88
|
+
# Create nodes and edges using NodeSpec/EdgeSpec
|
|
89
|
+
nodes = [
|
|
90
|
+
NodeSpec(
|
|
91
|
+
id="n1",
|
|
92
|
+
type="panel",
|
|
93
|
+
label="Start",
|
|
94
|
+
position={"x": 0, "y": 0},
|
|
95
|
+
data={"status": "idle"},
|
|
96
|
+
),
|
|
97
|
+
NodeSpec(
|
|
98
|
+
id="n2",
|
|
99
|
+
type="panel",
|
|
100
|
+
label="End",
|
|
101
|
+
position={"x": 260, "y": 60},
|
|
102
|
+
data={"status": "done"},
|
|
103
|
+
),
|
|
104
|
+
]
|
|
105
|
+
|
|
106
|
+
edges = [
|
|
107
|
+
EdgeSpec(
|
|
108
|
+
id="e1",
|
|
109
|
+
source="n1",
|
|
110
|
+
target="n2",
|
|
111
|
+
label="next",
|
|
112
|
+
),
|
|
113
|
+
]
|
|
114
|
+
|
|
115
|
+
# No need to call .to_dict() - automatic serialization!
|
|
116
|
+
flow = ReactFlow(nodes=nodes, edges=edges)
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
!!! note "Automatic Serialization"
|
|
120
|
+
`NodeSpec` and `EdgeSpec` objects are automatically converted to dictionaries
|
|
121
|
+
when passed to `ReactFlow`. You don't need to call `.to_dict()` manually.
|
|
122
|
+
|
|
123
|
+
However, `.to_dict()` is still available if you need to convert them explicitly
|
|
124
|
+
for other use cases:
|
|
125
|
+
|
|
126
|
+
```python
|
|
127
|
+
node_dict = NodeSpec(id="n1", position={"x": 0, "y": 0}).to_dict()
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
---
|
|
131
|
+
|
|
132
|
+
## Connect to specific handles
|
|
133
|
+
|
|
134
|
+
When a node type defines multiple input or output handles (via `inputs=["a", "b"]` or `outputs=["x", "y"]`), you can route edges to specific handles using `sourceHandle` and `targetHandle`.
|
|
135
|
+
|
|
136
|
+
```python
|
|
137
|
+
from panel_reactflow import ReactFlow, NodeSpec, EdgeSpec, NodeType
|
|
138
|
+
|
|
139
|
+
# Define node types with multiple handles
|
|
140
|
+
node_types = {
|
|
141
|
+
"producer": NodeType(
|
|
142
|
+
type="producer",
|
|
143
|
+
label="Producer",
|
|
144
|
+
inputs=[],
|
|
145
|
+
outputs=["result", "error"]
|
|
146
|
+
),
|
|
147
|
+
"consumer": NodeType(
|
|
148
|
+
type="consumer",
|
|
149
|
+
label="Consumer",
|
|
150
|
+
inputs=["data", "config"],
|
|
151
|
+
outputs=[]
|
|
152
|
+
),
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
# Create nodes
|
|
156
|
+
nodes = [
|
|
157
|
+
NodeSpec(id="p", type="producer", position={"x": 0, "y": 0}, label="Producer").to_dict(),
|
|
158
|
+
NodeSpec(id="c", type="consumer", position={"x": 400, "y": 0}, label="Consumer").to_dict(),
|
|
159
|
+
]
|
|
160
|
+
|
|
161
|
+
# Connect producer's "result" output to consumer's "data" input
|
|
162
|
+
edges = [
|
|
163
|
+
EdgeSpec(
|
|
164
|
+
id="e1",
|
|
165
|
+
source="p",
|
|
166
|
+
target="c",
|
|
167
|
+
sourceHandle="result",
|
|
168
|
+
targetHandle="data"
|
|
169
|
+
).to_dict(),
|
|
170
|
+
]
|
|
171
|
+
|
|
172
|
+
flow = ReactFlow(nodes=nodes, edges=edges, node_types=node_types)
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
Without `sourceHandle` and `targetHandle`, edges connect to the default (first) handle on each node.
|
|
176
|
+
|
|
177
|
+
---
|
|
178
|
+
|
|
179
|
+
## Update data vs. label
|
|
180
|
+
|
|
181
|
+
`data` and `label` live in different places and are updated differently:
|
|
182
|
+
|
|
183
|
+
- **Data** — use `patch_node_data()` or `patch_edge_data()`. This sends
|
|
184
|
+
an incremental patch to the frontend without replacing the full list.
|
|
185
|
+
- **Label** — replace the node/edge in `flow.nodes` or `flow.edges`.
|
|
186
|
+
|
|
187
|
+
```python
|
|
188
|
+
# Patch a data field
|
|
189
|
+
flow.patch_node_data("n1", {"status": "running"})
|
|
190
|
+
flow.patch_edge_data("e1", {"weight": 0.75})
|
|
191
|
+
|
|
192
|
+
# Update a label
|
|
193
|
+
flow.nodes = [
|
|
194
|
+
{**node, "label": "Start (running)"} if node["id"] == "n1" else node
|
|
195
|
+
for node in flow.nodes
|
|
196
|
+
]
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
---
|
|
200
|
+
|
|
201
|
+
## Add and remove at runtime
|
|
202
|
+
|
|
203
|
+
You can use either plain dictionaries or `NodeSpec`/`EdgeSpec` objects with the
|
|
204
|
+
`add_node()` and `add_edge()` methods:
|
|
205
|
+
|
|
206
|
+
```python
|
|
207
|
+
# Using plain dictionaries
|
|
208
|
+
flow.add_node({"id": "n3", "position": {"x": 520, "y": 0}, "label": "New", "data": {}})
|
|
209
|
+
flow.add_edge({"source": "n2", "target": "n3", "data": {}})
|
|
210
|
+
|
|
211
|
+
# Or using NodeSpec/EdgeSpec (no .to_dict() needed)
|
|
212
|
+
from panel_reactflow import NodeSpec, EdgeSpec
|
|
213
|
+
|
|
214
|
+
flow.add_node(NodeSpec(id="n4", position={"x": 780, "y": 0}, label="Another"))
|
|
215
|
+
flow.add_edge(EdgeSpec(id="e2", source="n3", target="n4"))
|
|
216
|
+
|
|
217
|
+
flow.remove_node("n3") # also removes connected edges
|
|
218
|
+
flow.remove_edge("e1")
|
|
219
|
+
```
|
|
@@ -50,13 +50,17 @@ flow = ReactFlow(nodes=nodes, edges=[], sizing_mode="stretch_both")
|
|
|
50
50
|
|
|
51
51
|
## Add a view when adding a node at runtime
|
|
52
52
|
|
|
53
|
-
`
|
|
53
|
+
Pass a `NodeSpec` with a `view` to `add_node()`:
|
|
54
54
|
|
|
55
55
|
```python
|
|
56
|
-
|
|
57
|
-
|
|
56
|
+
from panel_reactflow import NodeSpec
|
|
57
|
+
|
|
58
|
+
flow.add_node(NodeSpec(
|
|
59
|
+
id="live",
|
|
60
|
+
label="Live Feed",
|
|
61
|
+
position={"x": 600, "y": 0},
|
|
58
62
|
view=pn.indicators.Number(value=42, name="Metric"),
|
|
59
|
-
)
|
|
63
|
+
))
|
|
60
64
|
```
|
|
61
65
|
|
|
62
66
|
---
|
|
@@ -22,11 +22,15 @@ generate forms, and plug in editors where you need full control.
|
|
|
22
22
|
|
|
23
23
|
## Quickstart
|
|
24
24
|
|
|
25
|
+
!!! tip "JSONEditor Extension Required"
|
|
26
|
+
ReactFlow requires the `jsoneditor` Panel extension for editing node and edge data.
|
|
27
|
+
Always call `pn.extension("jsoneditor")` at the start of your application.
|
|
28
|
+
|
|
25
29
|
```python
|
|
26
30
|
import panel as pn
|
|
27
31
|
from panel_reactflow import NodeType, ReactFlow
|
|
28
32
|
|
|
29
|
-
pn.extension()
|
|
33
|
+
pn.extension("jsoneditor")
|
|
30
34
|
|
|
31
35
|
task_schema = {
|
|
32
36
|
"type": "object",
|
|
@@ -14,6 +14,12 @@ pip install panel-reactflow
|
|
|
14
14
|
|
|
15
15
|
## Minimal app
|
|
16
16
|
|
|
17
|
+
!!! note "Required Extension"
|
|
18
|
+
ReactFlow uses Panel's JSONEditor widget for editing node and edge data.
|
|
19
|
+
You must call `pn.extension("jsoneditor")` before creating ReactFlow instances
|
|
20
|
+
to ensure the extension loads correctly. This should be done early in your
|
|
21
|
+
application, typically right after your imports.
|
|
22
|
+
|
|
17
23
|
```python
|
|
18
24
|
import panel as pn
|
|
19
25
|
|