Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
4 changes: 4 additions & 0 deletions src/ewoksdraw/css_styles/css_link_cubic_bezier.css
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,7 @@
stroke-linejoin: round;
stroke-dasharray: none;
}

.link_cubic_bezier[data-import-error=''] {
stroke: var(--error);
}
6 changes: 5 additions & 1 deletion src/ewoksdraw/graph_to_svg.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,11 @@ def graph_to_svg(graph: TaskGraph, output_path: str | Path) -> None:
canvas = SvgCanvas(width=elk_graph["width"], height=elk_graph["height"])
canvas.add_background()
canvas.add_element(
build_svg_link_group(elk_graph, group_id=f"{graph.graph_id}-links")
build_svg_link_group(
elk_graph,
task_group.extract_import_errors(),
group_id=f"{graph.graph_id}-links",
)
)
canvas.add_element(task_group)
canvas.draw(output_path)
21 changes: 19 additions & 2 deletions src/ewoksdraw/layout/elk_link_group_builder.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,31 +3,48 @@
from ..geometry.cubic_bezier_path import Point
from ..svg.svg_group import SvgGroup
from ..svg.svg_link_cubic_bezier import SvgLinkCubicBezier
from .elk_converter import ElkEdge
from .elk_converter import ElkGraph
from .elk_converter import ElkSection


def build_svg_link_group(
elk_graph: ElkGraph, group_id: str | None = None
elk_graph: ElkGraph,
task_import_errors: dict[str, bool] | None = None,
group_id: str | None = None,
) -> SvgGroup[SvgLinkCubicBezier]:
"""Build an SVG link group from the routed edges of an ELK graph."""
link_group: SvgGroup[SvgLinkCubicBezier] = SvgGroup(group_id=group_id)
svg_links: list[SvgLinkCubicBezier] = []

for edge in elk_graph["edges"]:
import_error = _edge_has_import_error(edge, task_import_errors)
for section in edge.get("sections", list()):
points = _section_points(section)
cubic_bezier_path = CubicBezierPath.from_points(
points=points,
radius=LINK_TURN_RADIUS,
)
svg_link = SvgLinkCubicBezier(cubic_bezier_path)
svg_link = SvgLinkCubicBezier(cubic_bezier_path, import_error=import_error)
svg_links.append(svg_link)

link_group.add_elements(svg_links)
return link_group


def _edge_has_import_error(
edge: ElkEdge, task_import_errors: dict[str, bool] | None = None
) -> bool:
if task_import_errors is None:
return False
# FIXME:
source_task_id = edge["sources"][0].split(".output.")[0]
Comment on lines +40 to +41

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As a mentionned in the PR description, there is implicit coupling added here that we will have to fix.

target_task_id = edge["targets"][0].split(".input.")[0]
return task_import_errors.get(source_task_id, False) or task_import_errors.get(
target_task_id, False
)


def _section_points(section: ElkSection) -> list[Point]:
"""Convert an ELK edge section into an ordered list of points.

Expand Down
4 changes: 4 additions & 0 deletions src/ewoksdraw/svg/svg_link_cubic_bezier.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ class SvgLinkCubicBezier(SvgElement):
:param color: The stroke color of the link.
:param stroke_width: The stroke width of the link.
:param stroke_dasharray: The SVG stroke-dasharray value of the link.
:param import_error: Whether the link connects to a task that cannot be imported.
"""

def __init__(
Expand All @@ -18,10 +19,13 @@ def __init__(
color: str | None = None,
stroke_width: float | None = None,
stroke_dasharray: str | None = None,
import_error: bool = False,
):
string_svg = self._convert_path_data_to_svg_attribute(path)

attr = {"d": string_svg}
if import_error:
attr["data-import-error"] = ""
styles = []

if color is not None:
Expand Down
4 changes: 4 additions & 0 deletions src/ewoksdraw/svg/svg_task.py
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,10 @@ def _scale_vertical(self) -> None:
y2=self._title.height - self._title.vertical_margin // 2,
)

@property
def import_error(self) -> bool:
return self._box.get_attr("data-import-error") is not None
Comment on lines +138 to +140

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is how we expose the import error from SvgTask so that SvgTaskGroup can generate the dict of import errors.


@property
def width(self) -> float:
return self._box.width
Expand Down
6 changes: 6 additions & 0 deletions src/ewoksdraw/svg/svg_task_group.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,12 @@ def extract_task_sizes(self) -> TaskSizes:
for task_id, svg_task in self._svg_tasks.items()
}

def extract_import_errors(self) -> dict[str, bool]:
return {
task_id: svg_task.import_error
for task_id, svg_task in self._svg_tasks.items()
}

def extract_input_positions(self) -> TaskInputPositions:
return {
task_id: svg_task.get_input_positions()
Expand Down
6 changes: 6 additions & 0 deletions src/ewoksdraw/tests/test_graph_to_svg.py
Original file line number Diff line number Diff line change
Expand Up @@ -124,3 +124,9 @@ def test_workflow_with_non_importable_task(
task_box = element
assert task_box is not None
assert "data-import-error" in task_box.keys()

tree_root = ElementTree.parse(output_path).getroot()
link_group = _find_svg_group(tree_root, f"{ewoks_graph.graph_id}-links")
links = [element for element in link_group if element.tag.endswith("path")]
flagged_links = [link for link in links if "data-import-error" in link.keys()]
assert len(flagged_links) == 2
Loading