feat(operator-demo-video): add the operator drag-and-connect controller - #7641
feat(operator-demo-video): add the operator drag-and-connect controller#7641xuang7 wants to merge 5 commits into
Conversation
…ht automation foundation Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…dules use Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Automated Reviewer SuggestionsBased on the
|
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #7641 +/- ##
=========================================
Coverage 89.65% 89.66%
+ Complexity 4397 4396 -1
=========================================
Files 1177 1177
Lines 46996 46947 -49
Branches 5268 5260 -8
=========================================
- Hits 42136 42096 -40
Misses 3094 3094
+ Partials 1766 1757 -9
*This pull request uses carry forward flags. Click here to find out more. ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
|
| config | throughput | MB/s | latency | max Δ latest / 7d | |
|---|---|---|---|---|---|
| 🔴 | bs=10 sw=10 sl=64 | 356 | 0.217 | 27,605/35,107/35,107 us | 🔴 +17.0% / 🔴 +116.7% |
| 🔴 | bs=100 sw=10 sl=64 | 769 | 0.47 | 127,381/160,450/160,450 us | 🔴 +16.8% / 🔴 +49.1% |
| ⚪ | bs=1000 sw=10 sl=64 | 905 | 0.552 | 1,108,489/1,144,482/1,144,482 us | ⚪ within ±5% / 🔴 -12.2% |
Baseline details
Latest main 12169c2 from same runner
| config | metric | PR | latest main | 7d avg | Δ latest | Δ 7d |
|---|---|---|---|---|---|---|
| bs=10 sw=10 sl=64 | throughput | 356 tuples/sec | 401 tuples/sec | 774.89 tuples/sec | -11.2% | -54.1% |
| bs=10 sw=10 sl=64 | MB/s | 0.217 MB/s | 0.245 MB/s | 0.473 MB/s | -11.4% | -54.1% |
| bs=10 sw=10 sl=64 | p50 | 27,605 us | 23,596 us | 12,738 us | +17.0% | +116.7% |
| bs=10 sw=10 sl=64 | p95 | 35,107 us | 36,603 us | 16,348 us | -4.1% | +114.7% |
| bs=10 sw=10 sl=64 | p99 | 35,107 us | 36,603 us | 18,848 us | -4.1% | +86.3% |
| bs=100 sw=10 sl=64 | throughput | 769 tuples/sec | 812 tuples/sec | 1,005 tuples/sec | -5.3% | -23.5% |
| bs=100 sw=10 sl=64 | MB/s | 0.47 MB/s | 0.495 MB/s | 0.613 MB/s | -5.1% | -23.4% |
| bs=100 sw=10 sl=64 | p50 | 127,381 us | 123,434 us | 100,970 us | +3.2% | +26.2% |
| bs=100 sw=10 sl=64 | p95 | 160,450 us | 137,386 us | 107,605 us | +16.8% | +49.1% |
| bs=100 sw=10 sl=64 | p99 | 160,450 us | 137,386 us | 116,429 us | +16.8% | +37.8% |
| bs=1000 sw=10 sl=64 | throughput | 905 tuples/sec | 907 tuples/sec | 1,030 tuples/sec | -0.2% | -12.2% |
| bs=1000 sw=10 sl=64 | MB/s | 0.552 MB/s | 0.554 MB/s | 0.629 MB/s | -0.4% | -12.2% |
| bs=1000 sw=10 sl=64 | p50 | 1,108,489 us | 1,106,932 us | 991,433 us | +0.1% | +11.8% |
| bs=1000 sw=10 sl=64 | p95 | 1,144,482 us | 1,157,207 us | 1,036,668 us | -1.1% | +10.4% |
| bs=1000 sw=10 sl=64 | p99 | 1,144,482 us | 1,157,207 us | 1,070,470 us | -1.1% | +6.9% |
Raw CSV
config_idx,batch_size,schema_width,string_len,num_batches,total_ms,total_tuples,total_bytes,tuples_per_sec,mb_per_sec,lat_p50_us,lat_p95_us,lat_p99_us
0,10,10,64,20,561.80,200,128000,356,0.217,27604.88,35106.63,35106.63
1,100,10,64,20,2599.28,2000,1280000,769,0.470,127381.30,160450.49,160450.49
2,1000,10,64,20,22097.42,20000,12800000,905,0.552,1108489.17,1144482.34,1144482.34|
Could you take a look when you're available? Thanks! @carloea2 |
carloea2
left a comment
There was a problem hiding this comment.
The new node lookup can select an older node when the workflow already has the same operator type. Please use the node added after beforeCount. Also, alreadyConnected can never be true because expectedLinkCount is the current count plus one. Please check the target port instead.
There was a problem hiding this comment.
Pull request overview
Adds Playwright automation for placing and connecting operators while recording demo videos.
Changes:
- Adds drag-and-connect, navigation, login, geometry, and metadata controllers.
- Adds stable frontend automation selectors with guard tests.
- Registers the demo generator module and excludes its tooling from docs synchronization.
Reviewed changes
Copilot reviewed 23 out of 24 changed files in this pull request and generated 5 comments.
Show a summary per file
| File | Description |
|---|---|
.github/workflows/sync-docs-to-site.yml |
Excludes demo tooling from docs mirroring. |
build.sbt |
Registers the demo generator project. |
docs/operator-demo-videos/build.sbt |
Configures dependencies and Jackson overrides. |
.../config/TestDataConfig.scala |
Defines recording configuration. |
.../controllers/Constants.scala |
Defines timing and retry constants. |
.../controllers/ControllerContext.scala |
Adds controller execution infrastructure. |
.../controllers/LoginControllerBuilder.scala |
Automates authentication. |
.../controllers/NavigationControllerBuilder.scala |
Automates workflow creation and import. |
.../controllers/OperatorControllerBuilder.scala |
Implements operator placement and wiring. |
.../controllers/OperatorGroups.scala |
Maps operator groups to hierarchy paths. |
.../controllers/Utils.scala |
Adds Playwright and canvas helpers. |
.../scripts/OperatorScript.scala |
Defines the operator-demo script contract. |
user-workflow.component.html |
Adds workflow navigation selectors. |
user-workflow.component.spec.ts |
Guards workflow navigation selectors. |
texera-login.component.html |
Adds login selectors. |
texera-login.component.spec.ts |
Guards login selectors. |
left-panel.component.html |
Adds the Operators-button selector. |
left-panel.component.spec.ts |
Guards the Operators-button selector. |
operator-menu.component.html |
Adds search and operator-item selectors. |
operator-menu.component.spec.ts |
Guards operator-menu selectors. |
property-editor.component.html |
Adds the property-title selector. |
property-editor.component.spec.ts |
Guards the property-title selector. |
workflow-editor.component.html |
Adds the canvas selector. |
workflow-editor.component.spec.ts |
Guards the canvas selector. |
Suppressed comments (3)
docs/operator-demo-videos/src/main/scala/org/apache/texera/demovideos/controllers/OperatorControllerBuilder.scala:256
- If the requested anchor and target exist but their ports cannot be resolved, the controller reports success after leaving the operator disconnected. Since
autoConnectToAnchorexplicitly requests this edge, this branch should fail the step so a broken recording is not accepted.
} else {
println(s"[Operator] Warning: could not locate connectable ports for '$operatorName'")
}
docs/operator-demo-videos/src/main/scala/org/apache/texera/demovideos/controllers/OperatorControllerBuilder.scala:329
- A requested additional edge can fail both attempts, yet this branch only logs a warning and
execute()still reports the step as done. Throw here so two-input demos cannot silently continue with only one input connected.
} else {
println(
s"[Operator] Warning: could not connect additional input for '$operatorName'"
)
}
docs/operator-demo-videos/src/main/scala/org/apache/texera/demovideos/controllers/OperatorControllerBuilder.scala:270
connectAdditionalFromexplicitly requests a second upstream edge, but a missing source only produces a warning and the step succeeds with incomplete wiring. Fail the step here rather than generating a one-input recording.
if (additionalFromNode.isEmpty) {
println(
s"[Operator] Warning: connectAdditionalFrom='${connectAdditionalFrom.get}' not found on canvas"
)
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
| println(s"[Operator] Hierarchy fallback to search for '$operatorName'") | ||
| val searchInput = page | ||
| .getByTestId("operator-search-input") | ||
| .or(page.getByPlaceholder("search operator")) | ||
| .first() | ||
| Utils.waitVisible(searchInput) | ||
| Utils.clickWithCursor(page, searchInput) | ||
| searchInput.fill(sidebarSearchText) | ||
| page.waitForTimeout(Delays.Settle) | ||
| dragHandle(resolveOperatorSource(page, sidebarSearchText, operatorType)) |
| val newNode = operatorType | ||
| .flatMap(findNodeByType(page, _)) | ||
| .getOrElse(Utils.waitVisible(page.locator("g.joint-cell.joint-element").nth(beforeCount))) |
| val targetInputPort = connectAdditionalToInputIndex.getOrElse(0) | ||
|
|
||
| val inputPorts = collectInputPortCount(page, newNode) | ||
| val alreadyConnected = | ||
| inputPorts > 0 && page.locator("g.joint-cell.joint-link").count() >= expectedLinkCount |
| val entry = page | ||
| .locator(".workflow-name, .resource-name") | ||
| .filter(new Locator.FilterOptions().setHasText(workflowName)) | ||
| .first() |
| if (dragNextTo.isDefined && anchorNode.isEmpty) { | ||
| println( | ||
| s"[Operator] Warning: dragNextTo='${dragNextTo.get}' not found on canvas, using default position" | ||
| ) | ||
| } |
What changes were proposed in this PR?
This PR adds the controller that puts an operator on the canvas, the step every demo builds around.
Changes:
OperatorControllerBuilder.insertViaDrag: locates the operator in the left panel by its metadata group hierarchy (falling back to the search box), drags it onto the canvas, and wires it up. Wiring follows the operator's port topology: source operators connect nothing, single-input operators connect to the anchor, and two-input operators pull a second edge from a given upstream port into a given input port.OperatorGroups: flattens the operator group tree into name -> path, shared metadata used to walk the nested group panels.Utils(canvas-geometry helpers and a shared name normalizer) and the timing constants the controller waits on.data-testidhooks (left-panel Operators button, operator search input, per-operator list itemsoperator-item-<type>, and the property-panel title the controller waits on after a drop), each covered by a guard test in the component's existing spec.demo:
bar-chart_demo.webm
Any related issues, documentation, discussions?
Closes #7521
Depends on #7600.
How was this PR tested?
No behavior change to any existing module.
sbt DemoVideoGenerator/compile,scalafmtCheck, andscalafix --checkall pass; the three touched component specs (65 tests, including the new guard tests) pass. The drag-and-connect flow was exercised against a local deployment across all three port topologies (source, single-input, two-input join).Was this PR authored or co-authored using generative AI tooling?
Generated-by: Claude Code (Claude Fable 5)