panel-reactflow 0.2.1__tar.gz → 0.3.0rc1__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.2.1 → panel_reactflow-0.3.0rc1}/.github/workflows/docs.yml +17 -1
- {panel_reactflow-0.2.1 → panel_reactflow-0.3.0rc1}/.github/workflows/test.yml +1 -1
- {panel_reactflow-0.2.1 → panel_reactflow-0.3.0rc1}/PKG-INFO +3 -3
- {panel_reactflow-0.2.1 → panel_reactflow-0.3.0rc1}/README.md +2 -2
- panel_reactflow-0.3.0rc1/docs/assets/screenshots/declare-types.png +0 -0
- panel_reactflow-0.3.0rc1/docs/assets/screenshots/define-editors-edge.png +0 -0
- panel_reactflow-0.3.0rc1/docs/assets/screenshots/define-editors-node.png +0 -0
- panel_reactflow-0.3.0rc1/docs/assets/screenshots/define-nodes-edges.png +0 -0
- panel_reactflow-0.3.0rc1/docs/assets/screenshots/embed-views-in-nodes.png +0 -0
- panel_reactflow-0.3.0rc1/docs/assets/screenshots/examples/advanced.png +0 -0
- panel_reactflow-0.3.0rc1/docs/assets/screenshots/examples/custom_editor.png +0 -0
- panel_reactflow-0.3.0rc1/docs/assets/screenshots/examples/edge_editors.png +0 -0
- panel_reactflow-0.3.0rc1/docs/assets/screenshots/examples/node_edge_instances.png +0 -0
- panel_reactflow-0.3.0rc1/docs/assets/screenshots/examples/schema_types.png +0 -0
- panel_reactflow-0.3.0rc1/docs/assets/screenshots/examples/simple.png +0 -0
- panel_reactflow-0.3.0rc1/docs/assets/screenshots/examples/threejs_viewer.png +0 -0
- panel_reactflow-0.3.0rc1/docs/assets/screenshots/examples/threejs_viewer_instances.png +0 -0
- panel_reactflow-0.3.0rc1/docs/assets/screenshots/quickstart.png +0 -0
- panel_reactflow-0.3.0rc1/docs/assets/screenshots/react-to-events.png +0 -0
- panel_reactflow-0.3.0rc1/docs/assets/screenshots/style-nodes-edges.png +0 -0
- panel_reactflow-0.3.0rc1/docs/examples/advanced.md +12 -0
- panel_reactflow-0.3.0rc1/docs/examples/custom-editor.md +12 -0
- panel_reactflow-0.3.0rc1/docs/examples/edge-editors.md +12 -0
- panel_reactflow-0.3.0rc1/docs/examples/index.md +64 -0
- panel_reactflow-0.3.0rc1/docs/examples/node-edge-instances.md +12 -0
- panel_reactflow-0.3.0rc1/docs/examples/schema-types.md +12 -0
- panel_reactflow-0.3.0rc1/docs/examples/simple.md +11 -0
- panel_reactflow-0.3.0rc1/docs/examples/threejs-viewer-instances.md +12 -0
- panel_reactflow-0.3.0rc1/docs/examples/threejs-viewer.md +12 -0
- panel_reactflow-0.3.0rc1/docs/how-to/declare-types.md +239 -0
- {panel_reactflow-0.2.1 → panel_reactflow-0.3.0rc1}/docs/how-to/define-editors.md +110 -0
- {panel_reactflow-0.2.1 → panel_reactflow-0.3.0rc1}/docs/how-to/define-nodes-edges.md +162 -3
- {panel_reactflow-0.2.1 → panel_reactflow-0.3.0rc1}/docs/how-to/embed-views-in-nodes.md +68 -0
- {panel_reactflow-0.2.1 → panel_reactflow-0.3.0rc1}/docs/how-to/react-to-events.md +67 -9
- {panel_reactflow-0.2.1 → panel_reactflow-0.3.0rc1}/docs/how-to/style-nodes-edges.md +112 -0
- {panel_reactflow-0.2.1 → panel_reactflow-0.3.0rc1}/docs/index.md +4 -0
- {panel_reactflow-0.2.1 → panel_reactflow-0.3.0rc1}/docs/quickstart.md +0 -6
- panel_reactflow-0.3.0rc1/examples/node_edge_instances.py +138 -0
- {panel_reactflow-0.2.1 → panel_reactflow-0.3.0rc1}/examples/threejs_viewer.py +2 -2
- panel_reactflow-0.3.0rc1/examples/threejs_viewer_instances.py +335 -0
- {panel_reactflow-0.2.1 → panel_reactflow-0.3.0rc1}/pixi.lock +1916 -1912
- {panel_reactflow-0.2.1 → panel_reactflow-0.3.0rc1}/src/panel_reactflow/__init__.py +4 -0
- {panel_reactflow-0.2.1 → panel_reactflow-0.3.0rc1}/src/panel_reactflow/base.py +775 -103
- {panel_reactflow-0.2.1 → panel_reactflow-0.3.0rc1}/src/panel_reactflow/dist/css/reactflow.css +15 -8
- panel_reactflow-0.3.0rc1/src/panel_reactflow/dist/panel-reactflow.bundle.js +88 -0
- {panel_reactflow-0.2.1 → panel_reactflow-0.3.0rc1}/src/panel_reactflow/models/reactflow.jsx +190 -13
- {panel_reactflow-0.2.1 → panel_reactflow-0.3.0rc1}/tests/test_api.py +312 -1
- {panel_reactflow-0.2.1 → panel_reactflow-0.3.0rc1}/tests/test_core.py +40 -1
- {panel_reactflow-0.2.1 → panel_reactflow-0.3.0rc1}/zensical.toml +11 -1
- panel_reactflow-0.2.1/docs/assets/screenshots/declare-types.png +0 -0
- panel_reactflow-0.2.1/docs/assets/screenshots/define-editors-edge.png +0 -0
- panel_reactflow-0.2.1/docs/assets/screenshots/define-editors-node.png +0 -0
- panel_reactflow-0.2.1/docs/assets/screenshots/define-nodes-edges.png +0 -0
- panel_reactflow-0.2.1/docs/assets/screenshots/embed-views-in-nodes.png +0 -0
- panel_reactflow-0.2.1/docs/assets/screenshots/quickstart.png +0 -0
- panel_reactflow-0.2.1/docs/assets/screenshots/react-to-events.png +0 -0
- panel_reactflow-0.2.1/docs/assets/screenshots/style-nodes-edges.png +0 -0
- panel_reactflow-0.2.1/docs/examples.md +0 -13
- panel_reactflow-0.2.1/docs/how-to/declare-types.md +0 -125
- panel_reactflow-0.2.1/src/panel_reactflow/dist/panel-reactflow.bundle.js +0 -82
- {panel_reactflow-0.2.1 → panel_reactflow-0.3.0rc1}/.copier-answers.yml +0 -0
- {panel_reactflow-0.2.1 → panel_reactflow-0.3.0rc1}/.gitattributes +0 -0
- {panel_reactflow-0.2.1 → panel_reactflow-0.3.0rc1}/.github/CODEOWNERS +0 -0
- {panel_reactflow-0.2.1 → panel_reactflow-0.3.0rc1}/.github/dependabot.yml +0 -0
- {panel_reactflow-0.2.1 → panel_reactflow-0.3.0rc1}/.github/workflows/build.yml +0 -0
- {panel_reactflow-0.2.1 → panel_reactflow-0.3.0rc1}/.gitignore +0 -0
- {panel_reactflow-0.2.1 → panel_reactflow-0.3.0rc1}/.pre-commit-config.yaml +0 -0
- {panel_reactflow-0.2.1 → panel_reactflow-0.3.0rc1}/.prettierrc +0 -0
- {panel_reactflow-0.2.1 → panel_reactflow-0.3.0rc1}/LICENSE.txt +0 -0
- {panel_reactflow-0.2.1 → panel_reactflow-0.3.0rc1}/MANIFEST.in +0 -0
- {panel_reactflow-0.2.1 → panel_reactflow-0.3.0rc1}/docs/assets/logo.svg +0 -0
- {panel_reactflow-0.2.1 → panel_reactflow-0.3.0rc1}/docs/reference/panel_reactflow.md +0 -0
- {panel_reactflow-0.2.1 → panel_reactflow-0.3.0rc1}/docs/releases.md +0 -0
- {panel_reactflow-0.2.1 → panel_reactflow-0.3.0rc1}/examples/advanced.py +0 -0
- {panel_reactflow-0.2.1 → panel_reactflow-0.3.0rc1}/examples/custom_editor.py +0 -0
- {panel_reactflow-0.2.1 → panel_reactflow-0.3.0rc1}/examples/edge_editors.py +0 -0
- {panel_reactflow-0.2.1 → panel_reactflow-0.3.0rc1}/examples/schema_types.py +0 -0
- {panel_reactflow-0.2.1 → panel_reactflow-0.3.0rc1}/examples/simple.py +0 -0
- {panel_reactflow-0.2.1 → panel_reactflow-0.3.0rc1}/hatch_build.py +0 -0
- {panel_reactflow-0.2.1 → panel_reactflow-0.3.0rc1}/pixi.toml +0 -0
- {panel_reactflow-0.2.1 → panel_reactflow-0.3.0rc1}/pyproject.toml +0 -0
- {panel_reactflow-0.2.1 → panel_reactflow-0.3.0rc1}/src/panel_reactflow/__version.py +0 -0
- {panel_reactflow-0.2.1 → panel_reactflow-0.3.0rc1}/src/panel_reactflow/dist/icons/gear.svg +0 -0
- {panel_reactflow-0.2.1 → panel_reactflow-0.3.0rc1}/src/panel_reactflow/dist/panel-reactflow.bundle.css +0 -0
- {panel_reactflow-0.2.1 → panel_reactflow-0.3.0rc1}/src/panel_reactflow/py.typed +0 -0
- {panel_reactflow-0.2.1 → panel_reactflow-0.3.0rc1}/src/panel_reactflow/schema.py +0 -0
- {panel_reactflow-0.2.1 → panel_reactflow-0.3.0rc1}/tests/__init__.py +0 -0
- {panel_reactflow-0.2.1 → panel_reactflow-0.3.0rc1}/tests/conftest.py +0 -0
- {panel_reactflow-0.2.1 → panel_reactflow-0.3.0rc1}/tests/ui/__init__.py +0 -0
- {panel_reactflow-0.2.1 → panel_reactflow-0.3.0rc1}/tests/ui/test_ui.py +0 -0
|
@@ -70,6 +70,22 @@ jobs:
|
|
|
70
70
|
runs-on: ubuntu-latest
|
|
71
71
|
needs: build
|
|
72
72
|
steps:
|
|
73
|
-
- name: Deploy
|
|
73
|
+
- name: Deploy dev
|
|
74
|
+
uses: peaceiris/actions-gh-pages@v4
|
|
75
|
+
# Dev site built on PRs
|
|
76
|
+
if: |
|
|
77
|
+
(github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name == github.repository) ||
|
|
78
|
+
(github.event_name == 'workflow_dispatch' && github.event.inputs.target == 'dev') ||
|
|
79
|
+
(github.event_name == 'push' && (contains(steps.vars.outputs.tag, 'a') || contains(steps.vars.outputs.tag, 'b') || contains(steps.vars.outputs.tag, 'rc')))
|
|
80
|
+
with:
|
|
81
|
+
personal_token: ${{ secrets.HOLOVIZ_ACCESS_TOKEN }}
|
|
82
|
+
external_repository: holoviz-dev/panel-reactflow
|
|
83
|
+
publish_dir: ./builtdocs
|
|
84
|
+
force_orphan: true
|
|
85
|
+
- name: Deploy main
|
|
86
|
+
if: |
|
|
87
|
+
(github.event_name != 'pull_request') &&
|
|
88
|
+
((github.event_name == 'workflow_dispatch' && github.event.inputs.target == 'main') ||
|
|
89
|
+
(github.event_name == 'push' && !(contains(steps.vars.outputs.tag, 'a') || contains(steps.vars.outputs.tag, 'b') || contains(steps.vars.outputs.tag, 'rc'))))
|
|
74
90
|
id: deployment
|
|
75
91
|
uses: actions/deploy-pages@v4
|
|
@@ -135,7 +135,7 @@ jobs:
|
|
|
135
135
|
environment: ["test-ui"]
|
|
136
136
|
timeout-minutes: 60
|
|
137
137
|
env:
|
|
138
|
-
|
|
138
|
+
PYTHONUTF8: 1
|
|
139
139
|
PANEL_LOG_LEVEL: info
|
|
140
140
|
FAIL: "--screenshot only-on-failure --full-page-screenshot --output ui_screenshots --tracing retain-on-failure"
|
|
141
141
|
steps:
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: panel-reactflow
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.3.0rc1
|
|
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
|
|
@@ -59,7 +59,7 @@ A Panel wrapper for the React Flow JS library.
|
|
|
59
59
|
- Panel viewables inside nodes via node ``view`` entries
|
|
60
60
|
- Interactive editing (drag/select/connect/delete) with sync back to Python
|
|
61
61
|
- Optional schema definitions for node/edge properties
|
|
62
|
-
- Event callbacks via `ReactFlow.on(...)` for app-level handling
|
|
62
|
+
- Event callbacks via `ReactFlow.on(...)` for app-level handling (callback signature: `callback(payload, flow)`)
|
|
63
63
|
|
|
64
64
|
## Pin your version!
|
|
65
65
|
|
|
@@ -112,7 +112,7 @@ flow = ReactFlow(
|
|
|
112
112
|
flow
|
|
113
113
|
```
|
|
114
114
|
|
|
115
|
-
For property schemas and richer editors, provide `node_types`/`edge_types` with `PropertySpec` and handle changes via `ReactFlow.on(...)`.
|
|
115
|
+
For property schemas and richer editors, provide `node_types`/`edge_types` with `PropertySpec` and handle changes via `ReactFlow.on(...)`. `.on` callbacks receive the event payload as the first argument and can optionally accept the `ReactFlow` instance as a second argument.
|
|
116
116
|
|
|
117
117
|
## Development
|
|
118
118
|
|
|
@@ -16,7 +16,7 @@ A Panel wrapper for the React Flow JS library.
|
|
|
16
16
|
- Panel viewables inside nodes via node ``view`` entries
|
|
17
17
|
- Interactive editing (drag/select/connect/delete) with sync back to Python
|
|
18
18
|
- Optional schema definitions for node/edge properties
|
|
19
|
-
- Event callbacks via `ReactFlow.on(...)` for app-level handling
|
|
19
|
+
- Event callbacks via `ReactFlow.on(...)` for app-level handling (callback signature: `callback(payload, flow)`)
|
|
20
20
|
|
|
21
21
|
## Pin your version!
|
|
22
22
|
|
|
@@ -69,7 +69,7 @@ flow = ReactFlow(
|
|
|
69
69
|
flow
|
|
70
70
|
```
|
|
71
71
|
|
|
72
|
-
For property schemas and richer editors, provide `node_types`/`edge_types` with `PropertySpec` and handle changes via `ReactFlow.on(...)`.
|
|
72
|
+
For property schemas and richer editors, provide `node_types`/`edge_types` with `PropertySpec` and handle changes via `ReactFlow.on(...)`. `.on` callbacks receive the event payload as the first argument and can optionally accept the `ReactFlow` instance as a second argument.
|
|
73
73
|
|
|
74
74
|
## Development
|
|
75
75
|
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
# Advanced
|
|
2
|
+
|
|
3
|
+
Schema-driven editor workflow with a custom node type, type stylesheets,
|
|
4
|
+
and top-panel event feedback.
|
|
5
|
+
|
|
6
|
+

|
|
7
|
+
|
|
8
|
+
## Source
|
|
9
|
+
|
|
10
|
+
```python
|
|
11
|
+
--8<-- "examples/advanced.py"
|
|
12
|
+
```
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
# Custom Editor
|
|
2
|
+
|
|
3
|
+
Registers a callable editor for `metric` nodes and pushes incremental updates
|
|
4
|
+
using `on_patch`.
|
|
5
|
+
|
|
6
|
+

|
|
7
|
+
|
|
8
|
+
## Source
|
|
9
|
+
|
|
10
|
+
```python
|
|
11
|
+
--8<-- "examples/custom_editor.py"
|
|
12
|
+
```
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
# Edge Editors
|
|
2
|
+
|
|
3
|
+
Shows schema-backed edge editing plus a custom callable edge editor for
|
|
4
|
+
specialized edge types.
|
|
5
|
+
|
|
6
|
+

|
|
7
|
+
|
|
8
|
+
## Source
|
|
9
|
+
|
|
10
|
+
```python
|
|
11
|
+
--8<-- "examples/edge_editors.py"
|
|
12
|
+
```
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
# Examples Gallery
|
|
2
|
+
|
|
3
|
+
Browse runnable examples from `examples/`. Each card links to a dedicated page
|
|
4
|
+
with a screenshot and full source code.
|
|
5
|
+
|
|
6
|
+
<div class="grid cards" markdown>
|
|
7
|
+
|
|
8
|
+
- 
|
|
9
|
+
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
**[Advanced](advanced.md)**
|
|
13
|
+
Schema-driven task nodes with event tracking.
|
|
14
|
+
|
|
15
|
+
- 
|
|
16
|
+
|
|
17
|
+
---
|
|
18
|
+
|
|
19
|
+
**[Custom Editor](custom-editor.md)**
|
|
20
|
+
Callable node editor with custom widgets.
|
|
21
|
+
|
|
22
|
+
- 
|
|
23
|
+
|
|
24
|
+
---
|
|
25
|
+
|
|
26
|
+
**[Edge Editors](edge-editors.md)**
|
|
27
|
+
Schema-backed and callable edge editors.
|
|
28
|
+
|
|
29
|
+
- 
|
|
30
|
+
|
|
31
|
+
---
|
|
32
|
+
|
|
33
|
+
**[Node/Edge Instances](node-edge-instances.md)**
|
|
34
|
+
Class-based nodes and edges with hooks.
|
|
35
|
+
|
|
36
|
+
- 
|
|
37
|
+
|
|
38
|
+
---
|
|
39
|
+
|
|
40
|
+
**[Schema Types](schema-types.md)**
|
|
41
|
+
Multiple node types, each with its own schema.
|
|
42
|
+
|
|
43
|
+
- 
|
|
44
|
+
|
|
45
|
+
---
|
|
46
|
+
|
|
47
|
+
**[Simple](simple.md)**
|
|
48
|
+
Minimal graph setup with top panel.
|
|
49
|
+
|
|
50
|
+
- 
|
|
51
|
+
|
|
52
|
+
---
|
|
53
|
+
|
|
54
|
+
**[ThreeJS Viewer](threejs-viewer.md)**
|
|
55
|
+
Graph-driven 3D cube viewer controls.
|
|
56
|
+
|
|
57
|
+
- 
|
|
58
|
+
|
|
59
|
+
---
|
|
60
|
+
|
|
61
|
+
**[ThreeJS Viewer (Instances)](threejs-viewer-instances.md)**
|
|
62
|
+
ThreeJS viewer with Node and Edge instances.
|
|
63
|
+
|
|
64
|
+
</div>
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
# Node/Edge Instances
|
|
2
|
+
|
|
3
|
+
Uses `Node` and `Edge` subclasses for rich behavior, custom editors, and event
|
|
4
|
+
hooks while still rendering in a standard ReactFlow canvas.
|
|
5
|
+
|
|
6
|
+

|
|
7
|
+
|
|
8
|
+
## Source
|
|
9
|
+
|
|
10
|
+
```python
|
|
11
|
+
--8<-- "examples/node_edge_instances.py"
|
|
12
|
+
```
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
# Schema Types
|
|
2
|
+
|
|
3
|
+
Demonstrates multiple node types where each type contributes its own schema,
|
|
4
|
+
including both Param-derived and raw JSON Schema definitions.
|
|
5
|
+
|
|
6
|
+

|
|
7
|
+
|
|
8
|
+
## Source
|
|
9
|
+
|
|
10
|
+
```python
|
|
11
|
+
--8<-- "examples/schema_types.py"
|
|
12
|
+
```
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
# ThreeJS Viewer (Instances)
|
|
2
|
+
|
|
3
|
+
The ThreeJS viewer example implemented with `Node` and `Edge` subclass
|
|
4
|
+
instances for object-oriented graph behavior.
|
|
5
|
+
|
|
6
|
+

|
|
7
|
+
|
|
8
|
+
## Source
|
|
9
|
+
|
|
10
|
+
```python
|
|
11
|
+
--8<-- "examples/threejs_viewer_instances.py"
|
|
12
|
+
```
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
# ThreeJS Viewer
|
|
2
|
+
|
|
3
|
+
Interactive 3D cube rendering controlled through graph-connected parameter
|
|
4
|
+
nodes.
|
|
5
|
+
|
|
6
|
+

|
|
7
|
+
|
|
8
|
+
## Source
|
|
9
|
+
|
|
10
|
+
```python
|
|
11
|
+
--8<-- "examples/threejs_viewer.py"
|
|
12
|
+
```
|
|
@@ -0,0 +1,239 @@
|
|
|
1
|
+
# Declare Node & Edge Types
|
|
2
|
+
|
|
3
|
+
Node and edge types are lightweight descriptors that define **what data each
|
|
4
|
+
kind of node/edge carries**. A type can provide:
|
|
5
|
+
|
|
6
|
+
- a type name (`type`)
|
|
7
|
+
- a display label (`label`)
|
|
8
|
+
- node handles (`inputs` / `outputs`)
|
|
9
|
+
- a schema for the `data` payload (`schema`)
|
|
10
|
+
|
|
11
|
+
Types are separate from editors. A type defines structure; an editor defines
|
|
12
|
+
the UI used to edit it.
|
|
13
|
+
|
|
14
|
+

|
|
15
|
+
|
|
16
|
+
---
|
|
17
|
+
|
|
18
|
+
## Complete runnable example
|
|
19
|
+
|
|
20
|
+
This script is a minimal, working example that produces the visualization
|
|
21
|
+
shown above.
|
|
22
|
+
|
|
23
|
+
```python
|
|
24
|
+
import param
|
|
25
|
+
import panel as pn
|
|
26
|
+
|
|
27
|
+
from panel_reactflow import EdgeType, NodeType, ReactFlow
|
|
28
|
+
|
|
29
|
+
pn.extension("jsoneditor")
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
class Job(param.Parameterized):
|
|
33
|
+
status = param.Selector(objects=["idle", "running", "done"])
|
|
34
|
+
retries = param.Integer(default=0)
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
decision_schema = {
|
|
38
|
+
"type": "object",
|
|
39
|
+
"properties": {
|
|
40
|
+
"question": {"type": "string", "title": "Question"},
|
|
41
|
+
"outcome": {
|
|
42
|
+
"type": "string",
|
|
43
|
+
"enum": ["yes", "no", "maybe"],
|
|
44
|
+
"title": "Outcome",
|
|
45
|
+
},
|
|
46
|
+
},
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
node_types = {
|
|
50
|
+
"job": NodeType(type="job", label="Job", schema=Job, inputs=["in"], outputs=["out"]),
|
|
51
|
+
"decision": NodeType(
|
|
52
|
+
type="decision",
|
|
53
|
+
label="Decision",
|
|
54
|
+
schema=decision_schema,
|
|
55
|
+
inputs=["in"],
|
|
56
|
+
outputs=["yes", "no"],
|
|
57
|
+
),
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
edge_types = {
|
|
61
|
+
"flow": EdgeType(
|
|
62
|
+
type="flow",
|
|
63
|
+
label="Flow",
|
|
64
|
+
schema={
|
|
65
|
+
"type": "object",
|
|
66
|
+
"properties": {"weight": {"type": "number", "title": "Weight"}},
|
|
67
|
+
},
|
|
68
|
+
),
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
nodes = [
|
|
72
|
+
{
|
|
73
|
+
"id": "j1",
|
|
74
|
+
"type": "job",
|
|
75
|
+
"label": "Fetch Data",
|
|
76
|
+
"position": {"x": 0, "y": 0},
|
|
77
|
+
"data": {"status": "idle", "retries": 0},
|
|
78
|
+
},
|
|
79
|
+
{
|
|
80
|
+
"id": "d1",
|
|
81
|
+
"type": "decision",
|
|
82
|
+
"label": "Valid?",
|
|
83
|
+
"position": {"x": 300, "y": 250},
|
|
84
|
+
"data": {"question": "Is data valid?", "outcome": "yes"},
|
|
85
|
+
},
|
|
86
|
+
{
|
|
87
|
+
"id": "j2",
|
|
88
|
+
"type": "job",
|
|
89
|
+
"label": "Process",
|
|
90
|
+
"position": {"x": 600, "y": 400},
|
|
91
|
+
"data": {"status": "running", "retries": 1},
|
|
92
|
+
},
|
|
93
|
+
]
|
|
94
|
+
|
|
95
|
+
edges = [
|
|
96
|
+
{"id": "e1", "source": "j1", "target": "d1", "type": "flow", "data": {"weight": 1.0}},
|
|
97
|
+
{"id": "e2", "source": "d1", "target": "j2", "type": "flow", "data": {"weight": 0.8}},
|
|
98
|
+
]
|
|
99
|
+
|
|
100
|
+
TASK_NODE_CSS = """
|
|
101
|
+
.react-flow__node-job {
|
|
102
|
+
background-color: white;
|
|
103
|
+
border-radius: 8px;
|
|
104
|
+
border: 1.5px solid #7c3aed;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
.react-flow__node-decision {
|
|
108
|
+
background-color: white;
|
|
109
|
+
border-radius: 8px;
|
|
110
|
+
border: 1.5px solid green;
|
|
111
|
+
}
|
|
112
|
+
"""
|
|
113
|
+
|
|
114
|
+
flow = ReactFlow(
|
|
115
|
+
nodes=nodes,
|
|
116
|
+
edges=edges,
|
|
117
|
+
node_types=node_types,
|
|
118
|
+
edge_types=edge_types,
|
|
119
|
+
editor_mode="node",
|
|
120
|
+
sizing_mode="stretch_both",
|
|
121
|
+
stylesheets=[TASK_NODE_CSS]
|
|
122
|
+
)
|
|
123
|
+
|
|
124
|
+
pn.Column(flow, sizing_mode="stretch_both").servable()
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
## How this code maps to the visualization
|
|
128
|
+
|
|
129
|
+
- `node_types["job"]` and `node_types["decision"]` define the two node kinds you see.
|
|
130
|
+
- `inputs` and `outputs` define the left/right handles rendered on each node.
|
|
131
|
+
- `edge_types["flow"]` defines the edge payload schema used by both connections.
|
|
132
|
+
- `nodes` controls labels (`Fetch Data`, `Valid?`, `Process`) and positions.
|
|
133
|
+
- `editor_mode="side"` makes selection open the schema-driven editor in the right panel.
|
|
134
|
+
|
|
135
|
+
---
|
|
136
|
+
|
|
137
|
+
## Node type snippet
|
|
138
|
+
|
|
139
|
+
Use `NodeType` to define node handles and payload schema.
|
|
140
|
+
|
|
141
|
+
```python
|
|
142
|
+
from panel_reactflow import NodeType
|
|
143
|
+
|
|
144
|
+
task_schema = {
|
|
145
|
+
"type": "object",
|
|
146
|
+
"properties": {
|
|
147
|
+
"status": {"type": "string", "enum": ["idle", "running", "done"]},
|
|
148
|
+
"priority": {"type": "integer"},
|
|
149
|
+
},
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
node_types = {
|
|
153
|
+
"task": NodeType(
|
|
154
|
+
type="task",
|
|
155
|
+
label="Task",
|
|
156
|
+
schema=task_schema,
|
|
157
|
+
inputs=["in"],
|
|
158
|
+
outputs=["out"],
|
|
159
|
+
),
|
|
160
|
+
}
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
## Edge type snippet
|
|
164
|
+
|
|
165
|
+
Use `EdgeType` for edge payload schema and label.
|
|
166
|
+
|
|
167
|
+
```python
|
|
168
|
+
from panel_reactflow import EdgeType
|
|
169
|
+
|
|
170
|
+
edge_types = {
|
|
171
|
+
"pipe": EdgeType(
|
|
172
|
+
type="pipe",
|
|
173
|
+
label="Pipe",
|
|
174
|
+
schema={
|
|
175
|
+
"type": "object",
|
|
176
|
+
"properties": {
|
|
177
|
+
"throughput": {"type": "number"},
|
|
178
|
+
"protocol": {"type": "string", "enum": ["tcp", "udp", "http"]},
|
|
179
|
+
},
|
|
180
|
+
},
|
|
181
|
+
),
|
|
182
|
+
}
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
---
|
|
186
|
+
|
|
187
|
+
## Schema sources
|
|
188
|
+
|
|
189
|
+
The `schema` field accepts multiple inputs and normalizes them to JSON Schema.
|
|
190
|
+
|
|
191
|
+
| Source | Example |
|
|
192
|
+
|--------|---------|
|
|
193
|
+
| **JSON Schema dict** | `{"type": "object", "properties": {...}}` |
|
|
194
|
+
| **Param class** | A `param.Parameterized` subclass |
|
|
195
|
+
| **Pydantic model** | A `pydantic.BaseModel` subclass |
|
|
196
|
+
|
|
197
|
+
### Param class shorthand
|
|
198
|
+
|
|
199
|
+
```python
|
|
200
|
+
import param
|
|
201
|
+
from panel_reactflow import NodeType
|
|
202
|
+
|
|
203
|
+
class Job(param.Parameterized):
|
|
204
|
+
status = param.Selector(objects=["idle", "running", "done"])
|
|
205
|
+
retries = param.Integer(default=0)
|
|
206
|
+
|
|
207
|
+
node_types = {"job": NodeType(type="job", label="Job", schema=Job)}
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
### Pydantic model shorthand
|
|
211
|
+
|
|
212
|
+
```python
|
|
213
|
+
from pydantic import BaseModel
|
|
214
|
+
from panel_reactflow import NodeType
|
|
215
|
+
|
|
216
|
+
class Config(BaseModel):
|
|
217
|
+
host: str = "localhost"
|
|
218
|
+
port: int = 8080
|
|
219
|
+
|
|
220
|
+
node_types = {"config": NodeType(type="config", label="Config", schema=Config)}
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
---
|
|
224
|
+
|
|
225
|
+
## Register on `ReactFlow`
|
|
226
|
+
|
|
227
|
+
Pass `node_types` and `edge_types` as dictionaries keyed by type name:
|
|
228
|
+
|
|
229
|
+
```python
|
|
230
|
+
flow = ReactFlow(
|
|
231
|
+
nodes=nodes,
|
|
232
|
+
edges=edges,
|
|
233
|
+
node_types=node_types,
|
|
234
|
+
edge_types=edge_types,
|
|
235
|
+
)
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
Types without a schema still work; they just do not get schema-driven
|
|
239
|
+
validation or auto-generated forms.
|
|
@@ -18,6 +18,65 @@ or falls back to a raw JSON editor.
|
|
|
18
18
|
|
|
19
19
|
---
|
|
20
20
|
|
|
21
|
+
## Complete runnable example (node editor screenshot)
|
|
22
|
+
|
|
23
|
+
This script is a minimal, working example for the screenshot above. Run it,
|
|
24
|
+
then click the `Start` node to open the schema-driven editor in the side panel.
|
|
25
|
+
|
|
26
|
+
```python
|
|
27
|
+
import panel as pn
|
|
28
|
+
|
|
29
|
+
from panel_reactflow import NodeType, ReactFlow
|
|
30
|
+
|
|
31
|
+
pn.extension("jsoneditor")
|
|
32
|
+
|
|
33
|
+
task_schema = {
|
|
34
|
+
"type": "object",
|
|
35
|
+
"properties": {
|
|
36
|
+
"status": {"type": "string", "enum": ["idle", "running", "done"], "title": "Status"},
|
|
37
|
+
"priority": {"type": "integer", "title": "Priority"},
|
|
38
|
+
"notes": {"type": "string", "title": "Notes"},
|
|
39
|
+
},
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
nodes = [
|
|
43
|
+
{
|
|
44
|
+
"id": "start",
|
|
45
|
+
"type": "task",
|
|
46
|
+
"label": "Start",
|
|
47
|
+
"position": {"x": 0, "y": 0},
|
|
48
|
+
"data": {"status": "idle", "priority": 1, "notes": ""},
|
|
49
|
+
},
|
|
50
|
+
{
|
|
51
|
+
"id": "finish",
|
|
52
|
+
"type": "task",
|
|
53
|
+
"label": "Finish",
|
|
54
|
+
"position": {"x": 300, "y": 80},
|
|
55
|
+
"data": {"status": "done", "priority": 2, "notes": "All clear"},
|
|
56
|
+
},
|
|
57
|
+
]
|
|
58
|
+
|
|
59
|
+
edges = [{"id": "e1", "source": "start", "target": "finish"}]
|
|
60
|
+
|
|
61
|
+
flow = ReactFlow(
|
|
62
|
+
nodes=nodes,
|
|
63
|
+
edges=edges,
|
|
64
|
+
node_types={"task": NodeType(type="task", label="Task", schema=task_schema)},
|
|
65
|
+
editor_mode="side",
|
|
66
|
+
sizing_mode="stretch_both",
|
|
67
|
+
)
|
|
68
|
+
|
|
69
|
+
pn.Column(flow, sizing_mode="stretch_both").servable()
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
## How this code maps to the node-editor screenshot
|
|
73
|
+
|
|
74
|
+
- `task_schema` defines fields rendered in the side-panel form.
|
|
75
|
+
- `node_types={"task": ...}` binds that schema to both `task` nodes.
|
|
76
|
+
- Clicking a node selects it and opens its editor because `editor_mode="side"`.
|
|
77
|
+
|
|
78
|
+
---
|
|
79
|
+
|
|
21
80
|
## Editor signature
|
|
22
81
|
|
|
23
82
|
Every editor — whether a simple function, a lambda, or a class — receives
|
|
@@ -106,6 +165,57 @@ edge type) or `default_edge_editor` for a blanket default.
|
|
|
106
165
|
|
|
107
166
|

|
|
108
167
|
|
|
168
|
+
### Complete runnable example (edge editor screenshot)
|
|
169
|
+
|
|
170
|
+
This script reproduces the edge-editor screenshot. Run it, then click the
|
|
171
|
+
`pipe` edge to open its schema-driven editor.
|
|
172
|
+
|
|
173
|
+
```python
|
|
174
|
+
import panel as pn
|
|
175
|
+
|
|
176
|
+
from panel_reactflow import EdgeType, NodeType, ReactFlow
|
|
177
|
+
|
|
178
|
+
pn.extension("jsoneditor")
|
|
179
|
+
|
|
180
|
+
pipe_schema = {
|
|
181
|
+
"type": "object",
|
|
182
|
+
"properties": {
|
|
183
|
+
"throughput": {"type": "number", "title": "Throughput"},
|
|
184
|
+
"protocol": {
|
|
185
|
+
"type": "string",
|
|
186
|
+
"enum": ["tcp", "udp", "http"],
|
|
187
|
+
"title": "Protocol",
|
|
188
|
+
},
|
|
189
|
+
},
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
nodes = [
|
|
193
|
+
{"id": "src", "type": "device", "label": "Source", "position": {"x": 0, "y": 0}, "data": {}},
|
|
194
|
+
{"id": "sink", "type": "device", "label": "Sink", "position": {"x": 400, "y": 0}, "data": {}},
|
|
195
|
+
]
|
|
196
|
+
|
|
197
|
+
edges = [
|
|
198
|
+
{
|
|
199
|
+
"id": "e1",
|
|
200
|
+
"source": "src",
|
|
201
|
+
"target": "sink",
|
|
202
|
+
"type": "pipe",
|
|
203
|
+
"label": "pipe",
|
|
204
|
+
"data": {"throughput": 100.0, "protocol": "tcp"},
|
|
205
|
+
},
|
|
206
|
+
]
|
|
207
|
+
|
|
208
|
+
flow = ReactFlow(
|
|
209
|
+
nodes=nodes,
|
|
210
|
+
edges=edges,
|
|
211
|
+
node_types={"device": NodeType(type="device", label="Device")},
|
|
212
|
+
edge_types={"pipe": EdgeType(type="pipe", label="Pipe", schema=pipe_schema)},
|
|
213
|
+
sizing_mode="stretch_both",
|
|
214
|
+
)
|
|
215
|
+
|
|
216
|
+
pn.Column(flow, sizing_mode="stretch_both").servable()
|
|
217
|
+
```
|
|
218
|
+
|
|
109
219
|
### Schema-driven edge editor
|
|
110
220
|
|
|
111
221
|
If you declare an `EdgeType` with a schema and do not provide an explicit
|