Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
66 commits
Select commit Hold shift + click to select a range
e5f4483
initial node preview draft
ravi-kumar-pilla Jan 16, 2026
f8f5656
basic testing done for previews
ravi-kumar-pilla Jan 17, 2026
56c7de0
basic testing done for previews
ravi-kumar-pilla Jan 17, 2026
c16edf5
fix mermaid renderer
ravi-kumar-pilla Jan 19, 2026
06b7be5
plotly preview renderer fixed
ravi-kumar-pilla Jan 19, 2026
aae28b8
fix table renderer
ravi-kumar-pilla Jan 19, 2026
eba62be
fix json preview
ravi-kumar-pilla Jan 19, 2026
0b2787d
simplify example
ravi-kumar-pilla Jan 19, 2026
e38909f
add metadata code preview
ravi-kumar-pilla Jan 19, 2026
0f851e4
simplify previews
ravi-kumar-pilla Jan 19, 2026
b96a4bb
adding html folder for easy testing
ravi-kumar-pilla Jan 19, 2026
07e3946
Merge branch 'main' into feat/node_preview
ravi-kumar-pilla Jan 19, 2026
9b58d0d
cleaning previews as suggested
ravi-kumar-pilla Jan 20, 2026
fc78cbc
Merge branch 'feat/node_preview' of https://github.com/kedro-org/kedr…
ravi-kumar-pilla Jan 20, 2026
7b8c4f1
remove html
ravi-kumar-pilla Jan 20, 2026
4368323
remove html
ravi-kumar-pilla Jan 20, 2026
02e07df
filtering in the backend
ravi-kumar-pilla Jan 20, 2026
e8c174f
remove preview changes
ravi-kumar-pilla Jan 20, 2026
2211ca6
remove preview changes fe
ravi-kumar-pilla Jan 20, 2026
c0c3431
remove preview changes
ravi-kumar-pilla Jan 20, 2026
bd33b06
remove tasknode previews from metadata-modal
ravi-kumar-pilla Jan 20, 2026
d37d7e5
revert metadatacode styles
ravi-kumar-pilla Jan 20, 2026
38cdae5
revert metadatacode styles
ravi-kumar-pilla Jan 20, 2026
1a6d2b2
revert metadata changes
ravi-kumar-pilla Jan 20, 2026
145d117
revert make file change
ravi-kumar-pilla Jan 20, 2026
5285eaa
revert plotly changes
ravi-kumar-pilla Jan 20, 2026
23b7e71
revert plotly changes
ravi-kumar-pilla Jan 20, 2026
af7738e
revert table scss changes
ravi-kumar-pilla Jan 20, 2026
f817546
plotly rename
ravi-kumar-pilla Jan 20, 2026
4a85d53
refactor preview to be reused in modal and metadata preview block
ravi-kumar-pilla Jan 20, 2026
0b32b0c
refactor preview to be reused in modal and metadata preview block
ravi-kumar-pilla Jan 20, 2026
2109875
refactor preview to be reused in modal and metadata preview block
ravi-kumar-pilla Jan 20, 2026
b50813e
add test files for new preview helper components
ravi-kumar-pilla Jan 20, 2026
aae3cf0
remove unnecessary hook and convert it to utility
ravi-kumar-pilla Jan 20, 2026
77ab142
adjust preview text
ravi-kumar-pilla Jan 20, 2026
9b355cf
adjust test
ravi-kumar-pilla Jan 20, 2026
88e2ef3
task node preview backend changes
ravi-kumar-pilla Jan 20, 2026
aca005c
task node preview backend changes
ravi-kumar-pilla Jan 20, 2026
06ea173
add mermaid renderer component
ravi-kumar-pilla Jan 21, 2026
2abeff2
unmount containerRef mermaid renderer
ravi-kumar-pilla Jan 21, 2026
d453a44
add text renderer
ravi-kumar-pilla Jan 21, 2026
e1888cb
include task node previews
ravi-kumar-pilla Jan 21, 2026
0f1cb55
include task node previews
ravi-kumar-pilla Jan 21, 2026
edc8bcc
missing styles
ravi-kumar-pilla Jan 21, 2026
b4ea3bc
renderer parent divs added
ravi-kumar-pilla Jan 21, 2026
f5428e1
text preview with code support
ravi-kumar-pilla Jan 21, 2026
dd52db3
warning added
ravi-kumar-pilla Jan 21, 2026
cb3f832
add backwar compat
ravi-kumar-pilla Jan 21, 2026
f7ee814
merge main
ravi-kumar-pilla Jan 21, 2026
1b54768
switch added back
ravi-kumar-pilla Jan 21, 2026
a12da47
fix lint
ravi-kumar-pilla Jan 21, 2026
83d5c4d
scss comment fix
ravi-kumar-pilla Jan 21, 2026
bf56a61
update backend tests for preview
ravi-kumar-pilla Jan 21, 2026
31d0065
update backend tests for preview
ravi-kumar-pilla Jan 21, 2026
85f65b7
fix pytests
ravi-kumar-pilla Jan 21, 2026
fb58fcb
lint fix
ravi-kumar-pilla Jan 21, 2026
40d37c6
fix fe tests
ravi-kumar-pilla Jan 21, 2026
822c75f
fix mermaid flickering
ravi-kumar-pilla Jan 21, 2026
785f332
add mermaid preview to split data node
ravi-kumar-pilla Jan 21, 2026
84e6ad7
add mermaid preview to split data node
ravi-kumar-pilla Jan 21, 2026
8c785e6
inline term changed for better understanding
ravi-kumar-pilla Jan 21, 2026
7234668
update release note
ravi-kumar-pilla Jan 21, 2026
376c6ac
add syntax highlighter
ravi-kumar-pilla Jan 22, 2026
89be7b9
update tests
ravi-kumar-pilla Jan 22, 2026
f610806
remove theme from text renderer
ravi-kumar-pilla Jan 22, 2026
5d7abbf
update release note
ravi-kumar-pilla Jan 22, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,7 @@ runs:
shell: bash
- name: Install Python dependencies
run: |-
# Previously used bleeding-edge Kedro from main branch:
# uv pip install --system git+https://github.com/kedro-org/kedro@main
# Now using latest Kedro 0.19.x from PyPI until Kedro-Viz is upgraded for 1.0
uv pip install --system kedro
uv pip install --system git+https://github.com/kedro-org/kedro@main
uv pip install --system -r package/test_requirements.txt -r demo-project/src/docker_requirements.txt -U
shell: bash
- name: Echo package versions
Expand Down
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ package:

# Dev server
run:
PYTHONWARNINGS=$(PYTHONWARNINGS) PYTHONPATH="$(shell pwd)/package" python3 package/kedro_viz/server.py $(PROJECT_PATH)
PYTHONWARNINGS=$(PYTHONWARNINGS) PYTHONPATH="$(shell pwd)/package" python package/kedro_viz/server.py $(PROJECT_PATH)

# Tests
pytest:
Expand Down
5 changes: 5 additions & 0 deletions RELEASE.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,11 @@ Please follow the established format:
- Include the ID number for the related PR (or PRs) in parentheses
-->

# Release 12.3.0

## Major features and improvements
- Support for node previews (mermaid, text and image). (#2554)

# Release 12.2.0

## Major features and improvements
Expand Down
26 changes: 26 additions & 0 deletions demo-project/src/demo_project/pipelines/modelling/nodes.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,37 @@
from typing import Any, Dict, Tuple

import pandas as pd
from kedro.pipeline.preview_contract import MermaidPreview
from sklearn.base import BaseEstimator
from sklearn.metrics import r2_score
from sklearn.model_selection import train_test_split


def get_split_data_graph() -> MermaidPreview:
return MermaidPreview(
content="""graph TD
A[Input Dataset] --> B{Split Data}
B -->|Features| C[X: Independent Variables]
B -->|Target| D[y: Target Variable]
C --> E[train_test_split]
D --> E
E -->|Training Set| F[X_train]
E -->|Training Set| G[y_train]
E -->|Test Set| H[X_test]
E -->|Test Set| I[y_test]

classDef inputNode fill:#4A90E2,stroke:#2E5C8A,color:#FFFFFF
classDef trainNode fill:#50C878,stroke:#2D7A4A,color:#FFFFFF
classDef testNode fill:#F5A623,stroke:#C17D11,color:#FFFFFF
classDef processNode fill:#9B59B6,stroke:#6C3A84,color:#FFFFFF

class A inputNode
class F,G trainNode
class H,I testNode
class E processNode"""
)


def split_data(data: pd.DataFrame, split_options: Dict) -> Tuple:
"""Splits data into features and targets training and test sets.

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

from kedro.pipeline import Pipeline, node, pipeline

from .nodes import evaluate_model, split_data, train_model
from .nodes import evaluate_model, get_split_data_graph, split_data, train_model


def new_train_eval_template() -> Pipeline:
Expand Down Expand Up @@ -73,6 +73,7 @@ def create_pipeline(model_types: List[str]) -> Pipeline:
func=split_data,
inputs=["model_input_table", "params:split_options"],
outputs=test_train_refs,
preview_fn=get_split_data_graph,
)
]
)
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@
"isomorphic-dompurify": "^2.28.0",
"kiwi.js": "^1.1.3",
"lodash": "^4.17.21",
"mermaid": "^11.12.2",
"plotly.js-dist-min": "^2.26.0",
"react-custom-scrollbars-2": "^4.5.0",
"react-json-view": "^1.21.3",
Expand Down
7 changes: 7 additions & 0 deletions package/kedro_viz/api/rest/responses/nodes.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ class TaskNodeMetadataAPIResponse(BaseAPIResponse):
inputs (List[str]): The list of input data for the task node.
outputs (List[str]): The list of output data from the task node.
run_command (Optional[str]): The command to run the task node.
preview (Optional[Dict]): The serialized preview payload for the task node.
"""

code: Optional[str] = None
Expand All @@ -39,6 +40,7 @@ class TaskNodeMetadataAPIResponse(BaseAPIResponse):
inputs: List[str]
outputs: List[str]
run_command: Optional[str] = None
preview: Optional[Dict] = None
model_config = ConfigDict(
json_schema_extra={
"example": {
Expand All @@ -48,6 +50,11 @@ class TaskNodeMetadataAPIResponse(BaseAPIResponse):
"inputs": ["params:input1", "input2"],
"outputs": ["output1"],
"run_command": "kedro run --to-nodes=split_data",
"preview": {
"kind": "mermaid",
"content": "graph string",
"meta": {"title": "Pipeline Graph"},
},
}
}
)
Expand Down
53 changes: 53 additions & 0 deletions package/kedro_viz/models/flowchart/node_metadata.py
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,12 @@ class TaskNodeMetadata(GraphNodeMetadata):
default=None, validate_default=True, description="The outputs from the TaskNode"
)

preview: Optional[Dict] = Field(
default=None,
validate_default=True,
description="Serialized preview payload of the TaskNode",
)

@model_validator(mode="before")
@classmethod
def check_task_node_exists(cls, values):
Expand Down Expand Up @@ -138,6 +144,53 @@ def set_inputs(cls, _):
def set_outputs(cls, _):
return cls.kedro_node.outputs

@field_validator("preview")
@classmethod
def set_preview(cls, _):
try:
task_node_preview_fn = getattr(cls.kedro_node, "preview", None)

# for Kedro versions that do not support preview_fn
if task_node_preview_fn is None: # pragma: no cover
return None

preview_payload = task_node_preview_fn()

if preview_payload is None:
return None

from kedro.pipeline.preview_contract import (
ImagePreview,
MermaidPreview,
TextPreview,
)

if not isinstance(
preview_payload, (TextPreview, MermaidPreview, ImagePreview)
):
return None

# serialized payload
return preview_payload.to_dict()

except ImportError: # pragma: no cover
if not getattr(cls.set_preview, "_import_warning_shown", False):
logger.warning(
"Task node previews are disabled because this Kedro version "
"does not provide 'kedro.pipeline.preview_contract'."
)
cls.set_preview._import_warning_shown = True
return None

except Exception as exc: # noqa: BLE001
logger.warning(
"'%s' could not be previewed. Full exception: %s: %s",
cls.task_node.name,
type(exc).__name__,
exc,
)
return None


class DataNodeMetadata(GraphNodeMetadata):
"""Represent the metadata of a DataNode.
Expand Down
147 changes: 146 additions & 1 deletion package/tests/test_models/test_flowchart/test_node_metadata.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import sys
from functools import partial, wraps
from pathlib import Path
from textwrap import dedent
Expand Down Expand Up @@ -433,3 +432,149 @@ def test_parameters_metadata_single_parameter(self):
parameters_node=parameters_node
)
assert parameters_node_metadata.parameters == {"test_split_ratio": 0.3}

def test_text_preview(self):
"""Test that TextPreview is correctly serialized."""
from kedro.pipeline.preview_contract import TextPreview

def get_text_preview():
return TextPreview(
content="Sample text content", meta={"language": "python"}
)

kedro_node = node(
identity,
inputs="x",
outputs="y",
name="preview_node",
preview_fn=get_text_preview,
)

task_node = GraphNode.create_task_node(kedro_node, "preview_node", set())
task_node_metadata = TaskNodeMetadata(task_node=task_node)

assert task_node_metadata.preview == {
"kind": "text",
"content": "Sample text content",
"meta": {"language": "python"},
}

def test_mermaid_preview(self):
"""Test that MermaidPreview is correctly serialized."""
from kedro.pipeline.preview_contract import MermaidPreview

def get_mermaid_preview():
return MermaidPreview(content="graph TD; A-->B;", meta={"theme": "default"})

kedro_node = node(
identity,
inputs="x",
outputs="y",
name="preview_node",
preview_fn=get_mermaid_preview,
)

task_node = GraphNode.create_task_node(kedro_node, "preview_node", set())
task_node_metadata = TaskNodeMetadata(task_node=task_node)

assert task_node_metadata.preview == {
"kind": "mermaid",
"content": "graph TD; A-->B;",
"meta": {"theme": "default"},
}

def test_image_preview(self):
"""Test that ImagePreview is correctly serialized."""
from kedro.pipeline.preview_contract import ImagePreview

def get_image_preview():
return ImagePreview(content="base64encodedcontent", meta={"format": "png"})

kedro_node = node(
identity,
inputs="x",
outputs="y",
name="preview_node",
preview_fn=get_image_preview,
)

task_node = GraphNode.create_task_node(kedro_node, "preview_node", set())
task_node_metadata = TaskNodeMetadata(task_node=task_node)

assert task_node_metadata.preview == {
"kind": "image",
"content": "base64encodedcontent",
"meta": {"format": "png"},
}

def test_not_supported_preview(self):
"""Test that JsonPreview is not supported."""
from kedro.pipeline.preview_contract import JsonPreview

def get_json_preview():
return JsonPreview(content={"random": "value"})

kedro_node = node(
identity,
inputs="x",
outputs="y",
name="preview_node",
preview_fn=get_json_preview,
)

task_node = GraphNode.create_task_node(kedro_node, "preview_node", set())
task_node_metadata = TaskNodeMetadata(task_node=task_node)

assert task_node_metadata.preview is None

def test_no_preview_attr(self):
"""Test that preview is None when kedro_node has no preview attribute."""
kedro_node = node(
identity,
inputs="x",
outputs="y",
name="preview_node",
)

task_node = GraphNode.create_task_node(kedro_node, "preview_node", set())
task_node_metadata = TaskNodeMetadata(task_node=task_node)

assert task_node_metadata.preview is None

def test_preview_returns_none(self):
"""Test that preview is None when preview() returns None."""

def dummy_preview():
return None

kedro_node = node(
identity,
inputs="x",
outputs="y",
name="preview_node",
preview_fn=dummy_preview,
)

task_node = GraphNode.create_task_node(kedro_node, "preview_node", set())
task_node_metadata = TaskNodeMetadata(task_node=task_node)

assert task_node_metadata.preview is None

def test_preview_exception_handler(self, mocker, caplog):
"""Test that exceptions during preview() are handled gracefully."""
kedro_node = node(
identity,
inputs="x",
outputs="y",
name="exception_node",
)
kedro_node.preview = mocker.MagicMock(
side_effect=RuntimeError("Preview failed")
)

task_node = GraphNode.create_task_node(kedro_node, "exception_node", set())
task_node_metadata = TaskNodeMetadata(task_node=task_node)

assert task_node_metadata.preview is None
assert "'exception_node' could not be previewed" in caplog.text
assert "RuntimeError" in caplog.text
1 change: 1 addition & 0 deletions src/components/mermaid-renderer/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { default } from './mermaid-renderer';
Loading