This is an automated email from the ASF dual-hosted git repository.
github-merge-queue[bot] pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/texera.git
The following commit(s) were added to refs/heads/main by this push:
new 4f73e95255 fix: clear red change-line brackets when restoring a
workflow version (#5285)
4f73e95255 is described below
commit 4f73e952555aa7ae4d146c7a08ef0381e873d18b
Author: Kunwoo (Chris) <[email protected]>
AuthorDate: Fri Jun 5 16:09:34 2026 -0700
fix: clear red change-line brackets when restoring a workflow version
(#5285)
### What changes were proposed in this PR?
When restoring a previous workflow version that displays a **red change
line** (the bracket highlight drawn around the neighbors of deleted
operators), the red line stayed visible after the version was restored.
Versions whose diff only contained green/orange operator highlights
cleared correctly.
Why it's a bug: `highlightOpVersionDiff()` applies three kinds of
highlight when previewing a version:
- orange boundary **fill** on modified operators
- green boundary **fill** on added operators
- **red bracket strokes** (`path.left-boundary/stroke` /
`path.right-boundary/stroke`) on the neighbors of *deleted* operators
`unhighlightOpVersionDiff()` only reset the boundary fills — it never
reset the bracket strokes. `closeParticularVersionDisplay()` masked the
issue because it calls `reloadWorkflow()`, which rebuilds the JointJS
paper elements and incidentally wipes the leftover brackets.
`revertToVersion()` does **not** reload the paper, so the orphaned red
brackets persisted after restore.
This PR makes `unhighlightOpVersionDiff()` symmetric with
`highlightOpVersionDiff()`: it now also resets the deleted-operators'
neighbor brackets back to the default transparent `rgba(0,0,0,0)`, so
the red change line is cleared on restore.
### Any related issues, documentation, discussions?
Fixes #3043
Fixes #3828
### How was this PR tested?
- Manually verified in the UI that the red change line clears after
restoring a version.
https://github.com/user-attachments/assets/6417c52c-4f6e-47eb-82d4-0ac95f55ac5f
### Was this PR authored or co-authored using generative AI tooling?
Generated-by: Claude Code (Claude Opus 4.7)
---
.../workflow-version.service.spec.ts | 35 ++++++++++++++++++++++
.../workflow-version/workflow-version.service.ts | 14 +++++++++
2 files changed, 49 insertions(+)
diff --git
a/frontend/src/app/dashboard/service/user/workflow-version/workflow-version.service.spec.ts
b/frontend/src/app/dashboard/service/user/workflow-version/workflow-version.service.spec.ts
index 85c9016500..659af0feb2 100644
---
a/frontend/src/app/dashboard/service/user/workflow-version/workflow-version.service.spec.ts
+++
b/frontend/src/app/dashboard/service/user/workflow-version/workflow-version.service.spec.ts
@@ -310,6 +310,41 @@ describe("WorkflowVersionService", () => {
});
});
+ // ─── unhighlightOpVersionDiff ─────────────────────────────────────────────
+
+ describe("unhighlightOpVersionDiff", () => {
+ it("resets the boundary fill of added and modified ops to transparent", ()
=> {
+ service.unhighlightOpVersionDiff({ modified: ["m"], added: ["a"],
deleted: [] });
+
+ expect(paperGetModelById).toHaveBeenCalledWith("m");
+ expect(paperGetModelById).toHaveBeenCalledWith("a");
+ expect(modelAttr).toHaveBeenCalledWith("rect.boundary/fill",
"rgba(0,0,0,0)");
+ });
+
+ it("resets the red brackets drawn around the neighbors of deleted ops", ()
=> {
+ const tempWorkflow = buildWorkflow({
+ content: buildContent({
+ operators: [buildOperator({ operatorID: "alive-left" }),
buildOperator({ operatorID: "alive-right" })],
+ links: [buildLink("dead", "alive-right"), buildLink("alive-left",
"dead")],
+ }),
+ });
+ actionSpy.getTempWorkflow.mockReturnValue(tempWorkflow);
+
+ service.unhighlightOpVersionDiff({ modified: [], added: [], deleted:
["dead"] });
+
+ expect(modelAttr).toHaveBeenCalledWith("path.left-boundary/stroke",
"rgba(0,0,0,0)");
+ expect(modelAttr).toHaveBeenCalledWith("path.right-boundary/stroke",
"rgba(0,0,0,0)");
+ });
+
+ it("skips bracket clearing when the temp workflow is missing", () => {
+ actionSpy.getTempWorkflow.mockReturnValue(undefined);
+
+ service.unhighlightOpVersionDiff({ modified: [], added: [], deleted:
["dead"] });
+
+ expect(getMainJointPaper).not.toHaveBeenCalled();
+ });
+ });
+
// ─── getWorkflowsDifference / getOperatorsDifference ──────────────────────
describe("getWorkflowsDifference", () => {
diff --git
a/frontend/src/app/dashboard/service/user/workflow-version/workflow-version.service.ts
b/frontend/src/app/dashboard/service/user/workflow-version/workflow-version.service.ts
index 0c31b4edf1..1b527e35cb 100644
---
a/frontend/src/app/dashboard/service/user/workflow-version/workflow-version.service.ts
+++
b/frontend/src/app/dashboard/service/user/workflow-version/workflow-version.service.ts
@@ -271,6 +271,20 @@ export class WorkflowVersionService {
for (const id of
differentOpIDsList.added.concat(differentOpIDsList.modified)) {
this.highlightOpBoundary(id, "0,0,0,0");
}
+
+ if (differentOpIDsList.deleted.length > 0) {
+ const tempWorkflow = this.workflowActionService.getTempWorkflow();
+ if (tempWorkflow != undefined) {
+ for (const link of tempWorkflow.content.links) {
+ if (differentOpIDsList.deleted.includes(link.source.operatorID) &&
link.target.operatorID != undefined) {
+ this.highlightOpBracket(link.target.operatorID, "0,0,0,0",
"left-");
+ }
+ if (differentOpIDsList.deleted.includes(link.target.operatorID) &&
link.source.operatorID != undefined) {
+ this.highlightOpBracket(link.source.operatorID, "0,0,0,0",
"right-");
+ }
+ }
+ }
+ }
this.operatorPropertyDiff = {};
}