This is an automated email from the ASF dual-hosted git repository.

bamaer pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/hop.git


The following commit(s) were added to refs/heads/main by this push:
     new cce3854ffc Issue #5371 : Add bulk remove and bypass for a transform 
selection (#8699)
cce3854ffc is described below

commit cce3854ffc4e762d57acf60ce8970e574d9114f8
Author: Matt Casters <[email protected]>
AuthorDate: Thu Oct 1 15:19:58 2026 +0200

    Issue #5371 : Add bulk remove and bypass for a transform selection (#8699)
---
 .../ROOT/pages/hop-gui/hop-gui-popup-dialog.adoc   |   5 +
 .../ROOT/pages/pipeline/create-pipeline.adoc       |   4 +
 .../ROOT/pages/pipeline/pipeline-unit-testing.adoc |  15 +++
 .../apache/hop/testing/gui/TestingGuiPlugin.java   | 123 +++++++++++++++++++--
 .../testing/gui/messages/messages_en_US.properties |   9 ++
 .../hop/testing/gui/TestingGuiPluginTweakTest.java |  63 ++++++++++-
 6 files changed, 208 insertions(+), 11 deletions(-)

diff --git 
a/docs/hop-user-manual/modules/ROOT/pages/hop-gui/hop-gui-popup-dialog.adoc 
b/docs/hop-user-manual/modules/ROOT/pages/hop-gui/hop-gui-popup-dialog.adoc
index 1a0ce2e868..328f1232cd 100644
--- a/docs/hop-user-manual/modules/ROOT/pages/hop-gui/hop-gui-popup-dialog.adoc
+++ b/docs/hop-user-manual/modules/ROOT/pages/hop-gui/hop-gui-popup-dialog.adoc
@@ -186,6 +186,11 @@ When clicking on a transform icon, the popup contains a 
number of actions to wor
 * Unit Testing
 ** **Unit testing**: create an empty xref:metadata-types/data-set.adoc[data 
set] with the output fields and layout for this transform
 ** **Write rows to data set**: run the current pipeline and write the output 
of the current transform to a data set.
+* Bulk (only when two or more transforms are selected and a unit test is 
active)
+** **Remove selection from test**: do not include the selected transforms when 
this unit test runs.
+** **Include selection in test**: include the selected transforms in this unit 
test again.
+** **Bypass selection in test**: replace each selected transform with a dummy 
while this unit test runs.
+** **Remove bypass from selection**: do not bypass the selected transforms 
during testing.
 
 image:hop-gui/popup-transform.png[Hop Gui Popup Dialog - Workflow Transform 
Options, width="65%"]
 
diff --git 
a/docs/hop-user-manual/modules/ROOT/pages/pipeline/create-pipeline.adoc 
b/docs/hop-user-manual/modules/ROOT/pages/pipeline/create-pipeline.adoc
index b52c5bdf3e..afda546891 100644
--- a/docs/hop-user-manual/modules/ROOT/pages/pipeline/create-pipeline.adoc
+++ b/docs/hop-user-manual/modules/ROOT/pages/pipeline/create-pipeline.adoc
@@ -127,6 +127,10 @@ This will show a real-time table with a continuous output 
of the selected transf
 |Include in test|Run the current pipeline and write the data to a data set
 |Bypass in tess|When this unit test is run, bypass this transform (replace 
with a dummy)
 |Remove bypass in test|Do not bypass this transform in the current pipeline 
during testing
+|Remove selection from test|When two or more transforms are selected, do not 
include those transforms in this unit test
+|Include selection in test|When two or more transforms are selected, include 
those transforms in this unit test
+|Bypass selection in test|When two or more transforms are selected, bypass 
those transforms (replace each with a dummy)
+|Remove bypass from selection|When two or more transforms are selected, do not 
bypass those transforms during testing
 |===
 
 == Add a Hop between transforms
diff --git 
a/docs/hop-user-manual/modules/ROOT/pages/pipeline/pipeline-unit-testing.adoc 
b/docs/hop-user-manual/modules/ROOT/pages/pipeline/pipeline-unit-testing.adoc
index 90ab0d9ebe..f87bdc6f3c 100644
--- 
a/docs/hop-user-manual/modules/ROOT/pages/pipeline/pipeline-unit-testing.adoc
+++ 
b/docs/hop-user-manual/modules/ROOT/pages/pipeline/pipeline-unit-testing.adoc
@@ -112,6 +112,17 @@ image::pipeline-unit-testing-data-sets.png[Pipeline Unit 
Testing - Data Sets,wid
 * **Bypass in test**: When this unit test is run, bypass this transform 
(replace with a dummy)
 * **Remove bypass in test**: Do not bypass this transform in the current 
pipeline during testing
 
+Select two or more transforms and open the context dialog on one of them.
+Those four actions move to a *Bulk* category and apply to every selected 
transform:
+
+* **Remove selection from test**: When this unit test is run, do not include 
the selected transforms
+* **Include selection in test**: Include the selected transforms in this unit 
test
+* **Bypass selection in test**: When this unit test is run, bypass the 
selected transforms (replace each with a dummy)
+* **Remove bypass from selection**: Do not bypass the selected transforms 
during testing
+
+This is the same idea as *Enable hops between selection* and *Disable hops 
between selection* on a hop: one action updates the whole selection.
+With a single transform selected, the Unit Testing actions still apply to that 
transform only.
+
 If a unit test is active and you rename a transform that has an input data 
set, a golden data set, or a tweak, Hop updates that location on the unit test 
so the attachment stays on the renamed transform.
 
 TIP: creating data sets is also possible from the 'New' context menu or 
metadata perspective.
@@ -226,6 +237,10 @@ Click on the transform icon and select either 'Bypass in 
Test' or 'Remove from t
 Bypassing a transform in a test will replace the transform with a Dummy 
transform while executing the test.
 As the name implies, 'Remove from test' will remove the transform from the 
test pipeline, exactly like you would remove a transform from a pipeline.
 
+To remove or bypass several transforms at once, select them and open the 
context dialog on one of the selected transforms.
+Use *Remove selection from test* or *Bypass selection in test* in the Bulk 
category.
+*Include selection in test* and *Remove bypass from selection* clear those 
tweaks on the same selection.
+
 In the case of bypassing a transform, your pipeline will look like the one 
below ('Remove' will add a similar icon to the transform icon, crossing it out).
 
 image::pipeline-unit-testing-bypass-transform.png[Unit Test - Bypass 
transform,width="65%"]
diff --git 
a/plugins/misc/testing/src/main/java/org/apache/hop/testing/gui/TestingGuiPlugin.java
 
b/plugins/misc/testing/src/main/java/org/apache/hop/testing/gui/TestingGuiPlugin.java
index e2d8df47e0..7fcc53f8d4 100644
--- 
a/plugins/misc/testing/src/main/java/org/apache/hop/testing/gui/TestingGuiPlugin.java
+++ 
b/plugins/misc/testing/src/main/java/org/apache/hop/testing/gui/TestingGuiPlugin.java
@@ -118,6 +118,14 @@ public class TestingGuiPlugin {
       "pipeline-graph-transform-20820-enable-tweak-bypass-transform";
   public static final String 
ACTION_ID_PIPELINE_GRAPH_TRANSFORM_DISABLE_TWEAK_BYPASS_TRANSFORM =
       "pipeline-graph-transform-20830-disable-tweak-bypass-transform";
+  public static final String 
ACTION_ID_PIPELINE_GRAPH_TRANSFORM_BULK_REMOVE_TRANSFORM =
+      "pipeline-graph-transform-20840-bulk-remove-transform";
+  public static final String 
ACTION_ID_PIPELINE_GRAPH_TRANSFORM_BULK_INCLUDE_TRANSFORM =
+      "pipeline-graph-transform-20850-bulk-include-transform";
+  public static final String 
ACTION_ID_PIPELINE_GRAPH_TRANSFORM_BULK_BYPASS_TRANSFORM =
+      "pipeline-graph-transform-20860-bulk-bypass-transform";
+  public static final String 
ACTION_ID_PIPELINE_GRAPH_TRANSFORM_BULK_REMOVE_BYPASS_TRANSFORM =
+      "pipeline-graph-transform-20870-bulk-remove-bypass-transform";
   protected static final Class<?> PKG = TestingGuiPlugin.class;
 
   public static final String ID_TOOLBAR_ITEM_UNIT_TEST_EDIT =
@@ -686,32 +694,77 @@ public class TestingGuiPlugin {
           && 
currentTest.findGoldenLocation(context.getTransformMeta().getName()) != null;
     }
 
-    // Tweaks
+    // Tweaks. A multi-selection uses the Bulk actions (issue #5371), like 
enable and disable hops
+    // between selection. The single-transform actions stay for one selected 
transform.
     //
     PipelineUnitTestTweak tweak = null;
     if (currentTest != null) {
       tweak = currentTest.findTweak(context.getTransformMeta().getName());
     }
+    int selectedCount = selectedTransformCount(context.getPipelineMeta());
+    boolean unitTestActive = currentTest != null;
     if 
(ACTION_ID_PIPELINE_GRAPH_TRANSFORM_ENABLE_TWEAK_REMOVE_TRANSFORM.equals(contextActionId))
 {
-      return currentTest != null && tweak == null;
+      return showSingleUnitTestTweak(
+          unitTestActive, tweak, PipelineTweak.REMOVE_TRANSFORM, true, 
selectedCount);
     }
     if 
(ACTION_ID_PIPELINE_GRAPH_TRANSFORM_DISABLE_TWEAK_REMOVE_TRANSFORM.equals(contextActionId))
 {
-      return currentTest != null
-          && tweak != null
-          && tweak.getTweak() == PipelineTweak.REMOVE_TRANSFORM;
+      return showSingleUnitTestTweak(
+          unitTestActive, tweak, PipelineTweak.REMOVE_TRANSFORM, false, 
selectedCount);
     }
     if 
(ACTION_ID_PIPELINE_GRAPH_TRANSFORM_ENABLE_TWEAK_BYPASS_TRANSFORM.equals(contextActionId))
 {
-      return currentTest != null && tweak == null;
+      return showSingleUnitTestTweak(
+          unitTestActive, tweak, PipelineTweak.BYPASS_TRANSFORM, true, 
selectedCount);
     }
     if 
(ACTION_ID_PIPELINE_GRAPH_TRANSFORM_DISABLE_TWEAK_BYPASS_TRANSFORM.equals(contextActionId))
 {
-      return currentTest != null
-          && tweak != null
-          && tweak.getTweak() == PipelineTweak.BYPASS_TRANSFORM;
+      return showSingleUnitTestTweak(
+          unitTestActive, tweak, PipelineTweak.BYPASS_TRANSFORM, false, 
selectedCount);
+    }
+    if (isBulkUnitTestTweakAction(contextActionId)) {
+      return showBulkUnitTestTweak(unitTestActive, selectedCount);
     }
 
     return true;
   }
 
+  static boolean isBulkUnitTestTweakAction(String contextActionId) {
+    return 
ACTION_ID_PIPELINE_GRAPH_TRANSFORM_BULK_REMOVE_TRANSFORM.equals(contextActionId)
+        || 
ACTION_ID_PIPELINE_GRAPH_TRANSFORM_BULK_INCLUDE_TRANSFORM.equals(contextActionId)
+        || 
ACTION_ID_PIPELINE_GRAPH_TRANSFORM_BULK_BYPASS_TRANSFORM.equals(contextActionId)
+        || 
ACTION_ID_PIPELINE_GRAPH_TRANSFORM_BULK_REMOVE_BYPASS_TRANSFORM.equals(contextActionId);
+  }
+
+  /**
+   * Whether a single-transform tweak action is shown. Hidden while more than 
one transform is
+   * selected, so the bulk actions are the ones that change the selection.
+   */
+  static boolean showSingleUnitTestTweak(
+      boolean unitTestActive,
+      PipelineUnitTestTweak clickedTweak,
+      PipelineTweak tweak,
+      boolean enable,
+      int selectedCount) {
+    if (!unitTestActive || selectedCount > 1) {
+      return false;
+    }
+    if (enable) {
+      return clickedTweak == null;
+    }
+    return clickedTweak != null && clickedTweak.getTweak() == tweak;
+  }
+
+  /** Whether the bulk remove and bypass actions are shown for the current 
selection. */
+  static boolean showBulkUnitTestTweak(boolean unitTestActive, int 
selectedCount) {
+    return unitTestActive && selectedCount > 1;
+  }
+
+  static int selectedTransformCount(PipelineMeta pipelineMeta) {
+    if (pipelineMeta == null) {
+      return 0;
+    }
+    List<TransformMeta> selected = pipelineMeta.getSelectedTransforms();
+    return selected == null ? 0 : selected.size();
+  }
+
   /**
    * Get the active unit test directly from the pipeline graph context. This 
method is used by
    * filterTestingActions as an alternative to 
getCurrentUnitTest(pipelineMeta) which doesn't work
@@ -1586,6 +1639,58 @@ public class TestingGuiPlugin {
     tweakBypassTransformInUnitTest(context, false);
   }
 
+  @GuiContextAction(
+      id = ACTION_ID_PIPELINE_GRAPH_TRANSFORM_BULK_REMOVE_TRANSFORM,
+      parentId = HopGuiPipelineTransformContext.CONTEXT_ID,
+      type = GuiActionType.Modify,
+      name = "i18n::TestingGuiPlugin.ContextAction.BulkRemoveFromTest.Name",
+      tooltip = 
"i18n::TestingGuiPlugin.ContextAction.BulkRemoveFromTest.Tooltip",
+      image = "Test_tube_icon.svg",
+      category = "i18n::TestingGuiPlugin.Category.Bulk",
+      categoryOrder = "81")
+  public void bulkRemoveSelectionFromUnitTest(HopGuiPipelineTransformContext 
context) {
+    tweakRemoveTransformInUnitTest(context, true);
+  }
+
+  @GuiContextAction(
+      id = ACTION_ID_PIPELINE_GRAPH_TRANSFORM_BULK_INCLUDE_TRANSFORM,
+      parentId = HopGuiPipelineTransformContext.CONTEXT_ID,
+      type = GuiActionType.Modify,
+      name = "i18n::TestingGuiPlugin.ContextAction.BulkIncludeInTest.Name",
+      tooltip = 
"i18n::TestingGuiPlugin.ContextAction.BulkIncludeInTest.Tooltip",
+      image = "Test_tube_icon.svg",
+      category = "i18n::TestingGuiPlugin.Category.Bulk",
+      categoryOrder = "81")
+  public void bulkIncludeSelectionInUnitTest(HopGuiPipelineTransformContext 
context) {
+    tweakRemoveTransformInUnitTest(context, false);
+  }
+
+  @GuiContextAction(
+      id = ACTION_ID_PIPELINE_GRAPH_TRANSFORM_BULK_BYPASS_TRANSFORM,
+      parentId = HopGuiPipelineTransformContext.CONTEXT_ID,
+      type = GuiActionType.Modify,
+      name = "i18n::TestingGuiPlugin.ContextAction.BulkBypassInTest.Name",
+      tooltip = 
"i18n::TestingGuiPlugin.ContextAction.BulkBypassInTest.Tooltip",
+      image = "Test_tube_icon.svg",
+      category = "i18n::TestingGuiPlugin.Category.Bulk",
+      categoryOrder = "81")
+  public void bulkBypassSelectionInUnitTest(HopGuiPipelineTransformContext 
context) {
+    tweakBypassTransformInUnitTest(context, true);
+  }
+
+  @GuiContextAction(
+      id = ACTION_ID_PIPELINE_GRAPH_TRANSFORM_BULK_REMOVE_BYPASS_TRANSFORM,
+      parentId = HopGuiPipelineTransformContext.CONTEXT_ID,
+      type = GuiActionType.Modify,
+      name = 
"i18n::TestingGuiPlugin.ContextAction.BulkRemoveBypassInTest.Name",
+      tooltip = 
"i18n::TestingGuiPlugin.ContextAction.BulkRemoveBypassInTest.Tooltip",
+      image = "Test_tube_icon.svg",
+      category = "i18n::TestingGuiPlugin.Category.Bulk",
+      categoryOrder = "81")
+  public void 
bulkRemoveBypassFromSelectionInUnitTest(HopGuiPipelineTransformContext context) 
{
+    tweakBypassTransformInUnitTest(context, false);
+  }
+
   private void tweakBypassTransformInUnitTest(
       HopGuiPipelineTransformContext context, boolean enable) {
     tweakUnitTestTransform(context, PipelineTweak.BYPASS_TRANSFORM, enable);
diff --git 
a/plugins/misc/testing/src/main/resources/org/apache/hop/testing/gui/messages/messages_en_US.properties
 
b/plugins/misc/testing/src/main/resources/org/apache/hop/testing/gui/messages/messages_en_US.properties
index cbfe91395b..42c9c798f4 100644
--- 
a/plugins/misc/testing/src/main/resources/org/apache/hop/testing/gui/messages/messages_en_US.properties
+++ 
b/plugins/misc/testing/src/main/resources/org/apache/hop/testing/gui/messages/messages_en_US.properties
@@ -21,6 +21,15 @@ 
ShowUnitTestMenuExtensionPoint.ErrorFindingUnitTestsForPipeline.Title=Error
 ShowUnitTestMenuExtensionPoint.ErrorSwitchingUnitTest.Message=Error switching 
to test {0}
 ShowUnitTestMenuExtensionPoint.ErrorSwitchingUnitTest.Title=Error
 TestingGuiPlugin.Category=Unit Testing
+TestingGuiPlugin.Category.Bulk=Bulk
+TestingGuiPlugin.ContextAction.BulkBypassInTest.Name=Bypass selection in test
+TestingGuiPlugin.ContextAction.BulkBypassInTest.Tooltip=When this unit test is 
run, bypass the selected transforms (replace each with a dummy)
+TestingGuiPlugin.ContextAction.BulkIncludeInTest.Name=Include selection in test
+TestingGuiPlugin.ContextAction.BulkIncludeInTest.Tooltip=Include the selected 
transforms in this unit test
+TestingGuiPlugin.ContextAction.BulkRemoveBypassInTest.Name=Remove bypass from 
selection
+TestingGuiPlugin.ContextAction.BulkRemoveBypassInTest.Tooltip=Do not bypass 
the selected transforms during testing
+TestingGuiPlugin.ContextAction.BulkRemoveFromTest.Name=Remove selection from 
test
+TestingGuiPlugin.ContextAction.BulkRemoveFromTest.Tooltip=When this unit test 
is run, do not include the selected transforms
 TestingGuiPlugin.ContextAction.BypassInTest.Name=Bypass in test
 TestingGuiPlugin.ContextAction.BypassInTest.Tooltip=When this unit test is 
run, bypass this transform (replace with a dummy)
 TestingGuiPlugin.ContextAction.CheckTestPresent.Header=First create a test-case
diff --git 
a/plugins/misc/testing/src/test/java/org/apache/hop/testing/gui/TestingGuiPluginTweakTest.java
 
b/plugins/misc/testing/src/test/java/org/apache/hop/testing/gui/TestingGuiPluginTweakTest.java
index 697e06a56f..a801b1407d 100644
--- 
a/plugins/misc/testing/src/test/java/org/apache/hop/testing/gui/TestingGuiPluginTweakTest.java
+++ 
b/plugins/misc/testing/src/test/java/org/apache/hop/testing/gui/TestingGuiPluginTweakTest.java
@@ -18,6 +18,7 @@
 package org.apache.hop.testing.gui;
 
 import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
 import static org.junit.jupiter.api.Assertions.assertNull;
 import static org.junit.jupiter.api.Assertions.assertSame;
 import static org.junit.jupiter.api.Assertions.assertTrue;
@@ -35,8 +36,8 @@ import org.junit.jupiter.api.Test;
 import org.mockito.MockedStatic;
 
 /**
- * Unit tests for multi-transform unit-test tweak application (issue #2742). 
Covers pure helpers in
- * {@link TestingGuiPlugin} that do not require a HopGui instance.
+ * Unit tests for multi-transform unit-test tweak application (issues #2742 
and #5371). Covers pure
+ * helpers in {@link TestingGuiPlugin} that do not require a HopGui instance.
  */
 class TestingGuiPluginTweakTest {
 
@@ -161,6 +162,64 @@ class TestingGuiPluginTweakTest {
     assertTrue(unitTest.getTweaks().isEmpty());
   }
 
+  @Test
+  void singleTweakActionHiddenWhenSeveralTransformsAreSelected() {
+    PipelineUnitTestTweak bypass = new 
PipelineUnitTestTweak(PipelineTweak.BYPASS_TRANSFORM, "A");
+
+    assertFalse(
+        TestingGuiPlugin.showSingleUnitTestTweak(
+            true, null, PipelineTweak.REMOVE_TRANSFORM, true, 2));
+    assertFalse(
+        TestingGuiPlugin.showSingleUnitTestTweak(
+            true, bypass, PipelineTweak.BYPASS_TRANSFORM, false, 3));
+    assertTrue(
+        TestingGuiPlugin.showSingleUnitTestTweak(
+            true, null, PipelineTweak.REMOVE_TRANSFORM, true, 1));
+    assertTrue(
+        TestingGuiPlugin.showSingleUnitTestTweak(
+            true, bypass, PipelineTweak.BYPASS_TRANSFORM, false, 1));
+    assertFalse(
+        TestingGuiPlugin.showSingleUnitTestTweak(
+            true, bypass, PipelineTweak.REMOVE_TRANSFORM, false, 1));
+    assertFalse(
+        TestingGuiPlugin.showSingleUnitTestTweak(
+            false, null, PipelineTweak.BYPASS_TRANSFORM, true, 1));
+  }
+
+  @Test
+  void bulkTweakActionsShownOnlyForAnActiveTestAndAMultiSelection() {
+    assertTrue(TestingGuiPlugin.showBulkUnitTestTweak(true, 2));
+    assertFalse(TestingGuiPlugin.showBulkUnitTestTweak(true, 1));
+    assertFalse(TestingGuiPlugin.showBulkUnitTestTweak(true, 0));
+    assertFalse(TestingGuiPlugin.showBulkUnitTestTweak(false, 4));
+    assertTrue(
+        TestingGuiPlugin.isBulkUnitTestTweakAction(
+            
TestingGuiPlugin.ACTION_ID_PIPELINE_GRAPH_TRANSFORM_BULK_REMOVE_TRANSFORM));
+    assertTrue(
+        TestingGuiPlugin.isBulkUnitTestTweakAction(
+            
TestingGuiPlugin.ACTION_ID_PIPELINE_GRAPH_TRANSFORM_BULK_BYPASS_TRANSFORM));
+    assertTrue(
+        TestingGuiPlugin.isBulkUnitTestTweakAction(
+            
TestingGuiPlugin.ACTION_ID_PIPELINE_GRAPH_TRANSFORM_BULK_INCLUDE_TRANSFORM));
+    assertTrue(
+        TestingGuiPlugin.isBulkUnitTestTweakAction(
+            
TestingGuiPlugin.ACTION_ID_PIPELINE_GRAPH_TRANSFORM_BULK_REMOVE_BYPASS_TRANSFORM));
+    assertFalse(
+        TestingGuiPlugin.isBulkUnitTestTweakAction(
+            
TestingGuiPlugin.ACTION_ID_PIPELINE_GRAPH_TRANSFORM_ENABLE_TWEAK_REMOVE_TRANSFORM));
+  }
+
+  @Test
+  void selectedTransformCountIgnoresUnselectedTransforms() {
+    PipelineMeta pipelineMeta = new PipelineMeta();
+    pipelineMeta.addTransform(transform("A", true));
+    pipelineMeta.addTransform(transform("B", true));
+    pipelineMeta.addTransform(transform("C", false));
+
+    assertEquals(2, TestingGuiPlugin.selectedTransformCount(pipelineMeta));
+    assertEquals(0, TestingGuiPlugin.selectedTransformCount(null));
+  }
+
   @Test
   void applyTweakEnableOnMultipleTransforms() {
     PipelineUnitTest unitTest = new PipelineUnitTest();

Reply via email to