Repository navigation
fix(frontend): draw cables for links without a pad name - #1035
Conversation
A link end may name only an element or block ("id" or "id::"), and the
backend links it with GStreamer picking the pad. The flow editor parsed
link ends with parse_pad_ref, which returns None for "id", so the end
resolved to an empty node id and no cable was drawn. "id::" parsed as a
pad literally named ":", and pads-from-links rendered that bogus pad on
elements without pad info.
Resolve a padless end to the node's first pad in the link's direction
(output pad for from, input pad for to), taken from the pads the editor
already renders (element pad templates or block external pads). With no
known pad the end falls back to the node edge, so a cable is always
drawn. Padless ends no longer add pads when pads come from links.
Explicit-pad ends parse as before. Stored links are not rewritten.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
srperens
left a comment
There was a problem hiding this comment.
Verdict: Approve — the editor now reads link ends the way the backend does for "id" and "id::", both drawing paths and the pad-list builders go through one parser, and the three new tests ran in CI and pass.
Posted as a comment because GitHub refuses an approval from the account that opened the PR. The verdict is Approve. A human needs to merge it.
Claims
| Claim | Verdict | Evidence |
|---|---|---|
| Padless ends used to resolve to an empty node and draw nothing | CONFIRMED |
on main, parse_pad_ref returns None without a colon and the call was .unwrap_or_default(). Both call sites are replaced: frontend/src/graph/interaction.rs:16 — let (from_id, from_pad) = self.resolve_link_endpoint(&link.from, false); and the hit-test at frontend/src/graph/interaction.rs:202 — let (from_id, from_pad) = self.resolve_link_endpoint(&link.from, false); |
"id::" no longer becomes a pad named ":" |
CONFIRMED |
frontend/src/graph/mod.rs:286 — if let Some(id) = pad_ref.strip_suffix("::") {, the same element-only form the backend parses at types/src/element.rs:103 — if let Some(stripped) = spec.strip_suffix("::") { |
| Explicit pads unchanged | CONFIRMED |
everything else still goes through parse_pad_ref's first-colon split; only an empty pad name changes: frontend/src/graph/mod.rs:291 — Some((id, _)) => (id, None), |
| New tests guard the change | CONFIRMED |
Check (Linux) job 112838200945, cargo test --package strom-frontend: all three graph::interaction::tests::* cases print ok. Two of the three fail on revert: resolve_link_endpoint disappears, and get_actual_input_pads("dec") gets back the ":" pad |
Diagnosis — This is the right layer. The backend already accepts these links, so the editor is the only thing that was wrong. Coverage is BOUNDED to drawing and hit-testing. Two other frontend paths still assume id:pad, and this PR does not make either of them worse:
- Re-routing a cable from its input pad.
frontend/src/graph/data.rs:440—let existing = self.links.iter().position(|link| link.to == pad_ref);A padlesstoend now draws on the first sink pad, but dragging from that pad does not detach it. It starts a second link instead. - Copying a flow.
frontend/src/app/import_export.rs:314—if let Some((old_id, pad_name)) = link.from.split_once(':') {A bare"vsrc"end is never remapped to the new id, so the copied flow links to an id that does not exist."vsrc::"is remapped correctly. This bug was there before the PR, and is worth a follow-up issue.
Radius — LOCAL: three files under frontend/src/graph/. No backend, API or stored-link change. Check & Build (WASM) is green, so both targets compile.
Overlaps — none. #897 is the only other open PR touching frontend/src/graph/data.rs. It removes PadToRender::template_name, and this diff reads only .name, so the two do not conflict.
Design note — ElementPadRef::from_string in strom-types already parses this grammar, but it splits at the last colon. The author kept the editor's first-colon split on purpose so that explicit-pad behaviour stays identical. That is a fair reason not to reuse it here.
Tests & CI — Check (Linux), Build (Linux x86_64/ARM64), Check & Build (WASM), API Contract Check and Static JS Tests are green at 22e7b73. macOS and Windows were skipped, but nothing here is platform-specific.
Confidence: HIGH
Written by Claude (Claude Code).
Problem
A flow link may name an element or block without a pad (
"vsrc"or"vsrc::"). The API accepts it, and the backend links it with GStreamer picking the pad, so the flow runs. But the flow editor drew no cable for such a link, and the graph looked unconnected. Found while building flows through the API for #1034.Change
draw_linkandis_point_near_link(frontend/src/graph/interaction.rs) read each link end withparse_pad_ref(..).unwrap_or_default(). That returnsNonefor"vsrc", so the end resolved to an empty node and no cable was drawn."vsrc::"parsed as a pad literally named":". On an element without pad info (e.g. decodebin), that bogus pad also showed up among the pads taken from links.parse_link_endpoint(graph/mod.rs). It returns no pad for"id","id::"and"id:". Explicit pads still parse throughparse_pad_ref, unchanged.GraphEditor::resolve_link_endpoint. A padlessfromend goes to the node's first output pad, and a padlesstoend to its first input pad. The pads come from what the editor already renders: element pads, or a block's external pads. With no known pad, the cable is drawn to the node edge rather than not at all.get_actual_input_pads/get_actual_output_pads(graph/data.rs).This is a rendering change only: no backend, API or stored-link change.
Evidence
frontend/src/graph/interaction.rs)id::included, for elements and blocks, with a node-edge fallbackpadless_link_ends_resolve_to_the_first_pad_in_the_link_directionexplicit_pad_link_ends_are_unchanged":"pad to an element without pad infopadless_link_ends_add_no_pad_to_an_element_without_pad_infoChecked by hand in the web GUI (macOS) by the maintainer: a flow created through the API with padless links now shows all its cables.
Tests
Ran on macOS, on the head rebased onto main:
cargo test --workspace --lib graph::: the 14 frontend graph tests passed, including the 3 new ones.cargo clippy --workspace --all-targets -- -D warningsis clean. The pre-commit hook also ran wasm32 clippy.Not run: the native GUI.
For the reviewer
sink_0). It is drawn correctly, but it is not necessarily the pad GStreamer picks at runtime."id:"(an empty pad name) is now treated as padless. Before, it was drawn to the node centre.ElementPadRef::from_stringsplits at the last one. This is left alone so that explicit-pad behaviour stays identical.🤖 Generated with Claude Code