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

hansva 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 d1e8938f5a add drag & drop support to metadata items, fixes #6779 
(#6780)
d1e8938f5a is described below

commit d1e8938f5a8270982bdf66d6a3c9503b0c8118ec
Author: Hans Van Akelyen <[email protected]>
AuthorDate: Fri Mar 13 16:16:43 2026 +0100

    add drag & drop support to metadata items, fixes #6779 (#6780)
---
 .../hop/ui/core/metadata/MetadataManager.java      |  28 ++-
 .../hopgui/perspective/IMetadataDropReceiver.java  |  35 ++++
 .../ui/hopgui/perspective/MetadataTransfer.java    |  72 ++++++++
 .../hop/ui/hopgui/perspective/TabItemReorder.java  |  60 ++++++-
 .../perspective/metadata/MetadataPerspective.java  | 196 ++++++++++++++++++++-
 .../metadata/messages/messages_en_US.properties    |   5 +-
 6 files changed, 380 insertions(+), 16 deletions(-)

diff --git 
a/ui/src/main/java/org/apache/hop/ui/core/metadata/MetadataManager.java 
b/ui/src/main/java/org/apache/hop/ui/core/metadata/MetadataManager.java
index d1dce1a530..c50d48a262 100644
--- a/ui/src/main/java/org/apache/hop/ui/core/metadata/MetadataManager.java
+++ b/ui/src/main/java/org/apache/hop/ui/core/metadata/MetadataManager.java
@@ -278,18 +278,32 @@ public class MetadataManager<T extends IHopMetadata> {
    * @return True if anything was deleted
    */
   public boolean deleteMetadata(String elementName) {
+    return deleteMetadata(elementName, false);
+  }
+
+  /**
+   * delete an element, optionally skipping the confirmation dialog (when the 
caller already
+   * confirmed, e.g. metadata perspective with reference check).
+   *
+   * @param elementName The name of the element to delete
+   * @param skipConfirmation When true, do not show the "Are you sure?" dialog
+   * @return True if anything was deleted
+   */
+  public boolean deleteMetadata(String elementName, boolean skipConfirmation) {
 
     if (StringUtils.isEmpty(elementName)) {
       return false;
     }
 
-    MessageBox confirmBox =
-        new MessageBox(HopGui.getInstance().getShell(), SWT.ICON_QUESTION | 
SWT.YES | SWT.NO);
-    confirmBox.setText("Delete?");
-    confirmBox.setMessage("Are you sure you want to delete element " + 
elementName + "?");
-    int anwser = confirmBox.open();
-    if ((anwser & SWT.YES) == 0) {
-      return false;
+    if (!skipConfirmation) {
+      MessageBox confirmBox =
+          new MessageBox(HopGui.getInstance().getShell(), SWT.ICON_QUESTION | 
SWT.YES | SWT.NO);
+      confirmBox.setText("Delete?");
+      confirmBox.setMessage("Are you sure you want to delete element " + 
elementName + "?");
+      int anwser = confirmBox.open();
+      if ((anwser & SWT.YES) == 0) {
+        return false;
+      }
     }
 
     try {
diff --git 
a/ui/src/main/java/org/apache/hop/ui/hopgui/perspective/IMetadataDropReceiver.java
 
b/ui/src/main/java/org/apache/hop/ui/hopgui/perspective/IMetadataDropReceiver.java
new file mode 100644
index 0000000000..65e1ce2b5a
--- /dev/null
+++ 
b/ui/src/main/java/org/apache/hop/ui/hopgui/perspective/IMetadataDropReceiver.java
@@ -0,0 +1,35 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.hop.ui.hopgui.perspective;
+
+/**
+ * Optional interface for perspectives that can open metadata when it is 
dropped onto the tab folder
+ * (e.g. from the metadata tree). When the DropTarget on the tab folder 
receives metadata transfer
+ * data, it delegates to this interface if the perspective implements it.
+ */
+public interface IMetadataDropReceiver {
+
+  /**
+   * Open the given metadata object as a new tab. Called when the user drops a 
metadata element onto
+   * the canvas.
+   *
+   * @param objectKey the metadata type key (e.g. "pipeline", "workflow")
+   * @param name the name of the metadata object
+   */
+  void openDroppedMetadata(String objectKey, String name);
+}
diff --git 
a/ui/src/main/java/org/apache/hop/ui/hopgui/perspective/MetadataTransfer.java 
b/ui/src/main/java/org/apache/hop/ui/hopgui/perspective/MetadataTransfer.java
new file mode 100644
index 0000000000..898d424215
--- /dev/null
+++ 
b/ui/src/main/java/org/apache/hop/ui/hopgui/perspective/MetadataTransfer.java
@@ -0,0 +1,72 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.hop.ui.hopgui.perspective;
+
+import java.nio.charset.StandardCharsets;
+import org.eclipse.swt.dnd.ByteArrayTransfer;
+import org.eclipse.swt.dnd.TransferData;
+
+/**
+ * Transfer type for dragging metadata elements (objectKey + name) within the 
metadata perspective
+ * tree or onto the canvas to open them. Payload is a String array: [0] = 
objectKey, [1] = name.
+ */
+public class MetadataTransfer extends ByteArrayTransfer {
+
+  public static final MetadataTransfer INSTANCE = new MetadataTransfer();
+  private static final String TYPE_NAME =
+      "MetadataTransfer.String[] " + System.currentTimeMillis() + ":" + 
INSTANCE.hashCode();
+  private static final int TYPEID = registerType(TYPE_NAME);
+
+  /** Cached payload for same-JVM transfer (drag from tree to tree or tree to 
tab folder). */
+  private String[] metadataPayload;
+
+  private MetadataTransfer() {}
+
+  @Override
+  protected int[] getTypeIds() {
+    return new int[] {TYPEID};
+  }
+
+  @Override
+  protected String[] getTypeNames() {
+    return new String[] {TYPE_NAME};
+  }
+
+  @Override
+  public void javaToNative(Object object, TransferData transferData) {
+    metadataPayload = (String[]) object;
+    if (metadataPayload != null && metadataPayload.length >= 2 && transferData 
!= null) {
+      String encoded = metadataPayload[0] + "\n" + metadataPayload[1];
+      super.javaToNative(encoded.getBytes(StandardCharsets.UTF_8), 
transferData);
+    }
+  }
+
+  @Override
+  public Object nativeToJava(TransferData transferData) {
+    byte[] bytes = (byte[]) super.nativeToJava(transferData);
+    if (bytes == null) {
+      return metadataPayload;
+    }
+    String encoded = new String(bytes, StandardCharsets.UTF_8);
+    int idx = encoded.indexOf('\n');
+    if (idx >= 0) {
+      return new String[] {encoded.substring(0, idx), encoded.substring(idx + 
1)};
+    }
+    return metadataPayload;
+  }
+}
diff --git 
a/ui/src/main/java/org/apache/hop/ui/hopgui/perspective/TabItemReorder.java 
b/ui/src/main/java/org/apache/hop/ui/hopgui/perspective/TabItemReorder.java
index c58d4cee86..dd7e2935e6 100644
--- a/ui/src/main/java/org/apache/hop/ui/hopgui/perspective/TabItemReorder.java
+++ b/ui/src/main/java/org/apache/hop/ui/hopgui/perspective/TabItemReorder.java
@@ -116,7 +116,10 @@ public class TabItemReorder {
 
     DropTarget dropTarget = new DropTarget(folder, DND.DROP_MOVE | 
DND.DROP_COPY | DND.DROP_LINK);
     dropTarget.setTransfer(
-        TabTransfer.INSTANCE, TextTransfer.getInstance(), 
FileTransfer.getInstance());
+        TabTransfer.INSTANCE,
+        TextTransfer.getInstance(),
+        FileTransfer.getInstance(),
+        MetadataTransfer.INSTANCE);
 
     // Paint a drop indicator (highlight) on the tab we're about to swap with
     Listener paintListener =
@@ -138,15 +141,20 @@ public class TabItemReorder {
     dropTarget.addDropListener(
         new DropTargetListener() {
           private boolean isFileDrop;
+          private boolean isMetadataDrop;
 
           @Override
           public void dragEnter(DropTargetEvent event) {
             isFileDrop = isFileTransferType(event);
+            isMetadataDrop = isMetadataTransferType(event);
             if (isFileDrop) {
               event.currentDataType = getFileTransferDataType(event);
               if (event.detail == DND.DROP_DEFAULT) {
                 event.detail = preferredFileDropOperation(event);
               }
+            } else if (isMetadataDrop) {
+              event.currentDataType = getMetadataTransferDataType(event);
+              event.detail = DND.DROP_MOVE;
             }
             handleDragEvent(event);
           }
@@ -172,16 +180,21 @@ public class TabItemReorder {
 
           @Override
           public void dragOver(DropTargetEvent event) {
-            if (!isFileDrop) {
+            if (!isFileDrop && !isMetadataDrop) {
               isFileDrop = isFileTransferType(event);
+              isMetadataDrop = isMetadataTransferType(event);
               if (isFileDrop) {
                 event.currentDataType = getFileTransferDataType(event);
+              } else if (isMetadataDrop) {
+                event.currentDataType = getMetadataTransferDataType(event);
               }
             }
             if (isFileDrop) {
               if (event.detail == DND.DROP_DEFAULT) {
                 event.detail = preferredFileDropOperation(event);
               }
+            } else if (isMetadataDrop) {
+              event.detail = DND.DROP_MOVE;
             }
             handleDragEvent(event);
             // Update drop indicator for tab reorder
@@ -206,6 +219,13 @@ public class TabItemReorder {
               dropTargetTab = null;
               folder.redraw();
             }
+            if (isMetadataTransferType(event)
+                && event.data instanceof String[] metadataData
+                && metadataData.length >= 2
+                && perspective instanceof IMetadataDropReceiver receiver) {
+              receiver.openDroppedMetadata(metadataData[0], metadataData[1]);
+              return;
+            }
             if (event.data instanceof String[] paths
                 && perspective instanceof IFileDropReceiver receiver) {
               perspective.setDropTargetFolder(folder);
@@ -262,6 +282,18 @@ public class TabItemReorder {
           }
 
           private void handleDragEvent(DropTargetEvent event) {
+            if (isMetadataDrop && perspective instanceof 
IMetadataDropReceiver) {
+              if (event.dataTypes != null
+                  && 
!MetadataTransfer.INSTANCE.isSupportedType(event.currentDataType)) {
+                event.currentDataType = getMetadataTransferDataType(event);
+              }
+              if (event.currentDataType != null
+                  && 
MetadataTransfer.INSTANCE.isSupportedType(event.currentDataType)) {
+                event.detail = DND.DROP_MOVE;
+                event.feedback = DND.FEEDBACK_NONE;
+                return;
+              }
+            }
             if (isFileDrop && perspective instanceof IFileDropReceiver) {
               if (event.dataTypes != null
                   && 
!FileTransfer.getInstance().isSupportedType(event.currentDataType)) {
@@ -301,6 +333,30 @@ public class TabItemReorder {
             }
             return false;
           }
+
+          private boolean isMetadataTransferType(DropTargetEvent event) {
+            if (event.dataTypes == null) {
+              return false;
+            }
+            for (TransferData td : event.dataTypes) {
+              if (MetadataTransfer.INSTANCE.isSupportedType(td)) {
+                return true;
+              }
+            }
+            return false;
+          }
+
+          private TransferData getMetadataTransferDataType(DropTargetEvent 
event) {
+            if (event.dataTypes == null) {
+              return null;
+            }
+            for (TransferData td : event.dataTypes) {
+              if (MetadataTransfer.INSTANCE.isSupportedType(td)) {
+                return td;
+              }
+            }
+            return null;
+          }
         });
   }
 
diff --git 
a/ui/src/main/java/org/apache/hop/ui/hopgui/perspective/metadata/MetadataPerspective.java
 
b/ui/src/main/java/org/apache/hop/ui/hopgui/perspective/metadata/MetadataPerspective.java
index 68c164c4b2..9a466a3369 100644
--- 
a/ui/src/main/java/org/apache/hop/ui/hopgui/perspective/metadata/MetadataPerspective.java
+++ 
b/ui/src/main/java/org/apache/hop/ui/hopgui/perspective/metadata/MetadataPerspective.java
@@ -75,6 +75,8 @@ import org.apache.hop.ui.hopgui.file.empty.EmptyFileType;
 import org.apache.hop.ui.hopgui.file.empty.EmptyHopFileTypeHandler;
 import org.apache.hop.ui.hopgui.perspective.HopPerspectivePlugin;
 import org.apache.hop.ui.hopgui.perspective.IHopPerspective;
+import org.apache.hop.ui.hopgui.perspective.IMetadataDropReceiver;
+import org.apache.hop.ui.hopgui.perspective.MetadataTransfer;
 import org.apache.hop.ui.hopgui.perspective.TabClosable;
 import org.apache.hop.ui.hopgui.perspective.TabCloseHandler;
 import org.apache.hop.ui.hopgui.perspective.TabItemHandler;
@@ -89,13 +91,23 @@ import org.eclipse.swt.custom.CTabFolderEvent;
 import org.eclipse.swt.custom.CTabItem;
 import org.eclipse.swt.custom.SashForm;
 import org.eclipse.swt.custom.TreeEditor;
+import org.eclipse.swt.dnd.DND;
+import org.eclipse.swt.dnd.DragSource;
+import org.eclipse.swt.dnd.DragSourceAdapter;
+import org.eclipse.swt.dnd.DragSourceEvent;
+import org.eclipse.swt.dnd.DropTarget;
+import org.eclipse.swt.dnd.DropTargetAdapter;
+import org.eclipse.swt.dnd.DropTargetEvent;
+import org.eclipse.swt.graphics.GC;
 import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.graphics.Rectangle;
 import org.eclipse.swt.layout.FormAttachment;
 import org.eclipse.swt.layout.FormData;
 import org.eclipse.swt.layout.FormLayout;
 import org.eclipse.swt.widgets.Button;
 import org.eclipse.swt.widgets.Composite;
 import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Display;
 import org.eclipse.swt.widgets.Label;
 import org.eclipse.swt.widgets.Menu;
 import org.eclipse.swt.widgets.MenuItem;
@@ -105,6 +117,7 @@ import org.eclipse.swt.widgets.ToolBar;
 import org.eclipse.swt.widgets.ToolItem;
 import org.eclipse.swt.widgets.Tree;
 import org.eclipse.swt.widgets.TreeItem;
+import org.eclipse.swt.widgets.Widget;
 
 @HopPerspectivePlugin(
     id = "200-HopMetadataPerspective",
@@ -115,7 +128,7 @@ import org.eclipse.swt.widgets.TreeItem;
 @GuiPlugin(
     name = "i18n::MetadataPerspective.Name",
     description = "i18n::MetadataPerspective.GuiPlugin.Description")
-public class MetadataPerspective implements IHopPerspective, TabClosable {
+public class MetadataPerspective implements IHopPerspective, TabClosable, 
IMetadataDropReceiver {
 
   public static final Class<?> PKG = MetadataPerspective.class; // i18n
   private static final String METADATA_PERSPECTIVE_TREE = "Metadata 
perspective tree";
@@ -372,6 +385,169 @@ public class MetadataPerspective implements 
IHopPerspective, TabClosable {
 
     // Remember tree node expanded/Collapsed
     TreeMemory.addTreeListener(tree, METADATA_PERSPECTIVE_TREE);
+
+    // Drag and drop: reorganize within tree (same type only) and drag to 
canvas to open
+    createTreeDragSource(tree);
+    createTreeDropTarget(tree);
+  }
+
+  /**
+   * Returns the metadata type key (objectKey) for the given tree item by 
walking up to the root
+   * class item.
+   */
+  private String getObjectKey(TreeItem item) {
+    TreeItem root = item;
+    while (root.getParentItem() != null) {
+      root = root.getParentItem();
+    }
+    return (String) root.getData();
+  }
+
+  private void createTreeDragSource(Tree tree) {
+    DragSource dragSource = new DragSource(tree, DND.DROP_MOVE);
+    dragSource.setTransfer(MetadataTransfer.INSTANCE);
+    dragSource.addDragListener(
+        new DragSourceAdapter() {
+          private Image dragImage;
+
+          @Override
+          public void dragStart(DragSourceEvent event) {
+            if (tree.getSelectionCount() != 1) {
+              event.doit = false;
+              return;
+            }
+            TreeItem item = tree.getSelection()[0];
+            if (item == null || !FILE.equals(item.getData(KEY_TYPE))) {
+              event.doit = false;
+              return;
+            }
+            if (dragImage != null) {
+              dragImage.dispose();
+              dragImage = null;
+            }
+            Rectangle bounds = item.getBounds();
+            if (bounds.width > 0 && bounds.height > 0) {
+              try {
+                dragImage = new Image(Display.getCurrent(), bounds.width, 
bounds.height);
+                GC gc = new GC(tree);
+                try {
+                  gc.copyArea(dragImage, bounds.x, bounds.y);
+                } finally {
+                  gc.dispose();
+                }
+                event.image = dragImage;
+              } catch (Exception e) {
+                LogChannel.GENERAL.logDebug("Could not create metadata drag 
image", e);
+              }
+            }
+          }
+
+          @Override
+          public void dragSetData(DragSourceEvent event) {
+            if (MetadataTransfer.INSTANCE.isSupportedType(event.dataType)) {
+              TreeItem item = tree.getSelection()[0];
+              String objectKey = getObjectKey(item);
+              String name = item.getText(0);
+              event.data = new String[] {objectKey, name};
+            }
+          }
+
+          @Override
+          public void dragFinished(DragSourceEvent event) {
+            if (dragImage != null) {
+              dragImage.dispose();
+              dragImage = null;
+            }
+          }
+        });
+  }
+
+  private void createTreeDropTarget(Tree tree) {
+    DropTarget dropTarget = new DropTarget(tree, DND.DROP_MOVE);
+    dropTarget.setTransfer(MetadataTransfer.INSTANCE);
+    dropTarget.addDropListener(
+        new DropTargetAdapter() {
+          @Override
+          public void dragOver(DropTargetEvent event) {
+            if (event.item == null) {
+              event.detail = DND.DROP_NONE;
+              return;
+            }
+            if 
(!MetadataTransfer.INSTANCE.isSupportedType(event.currentDataType)) {
+              return;
+            }
+            TreeItem targetItem = (TreeItem) event.item;
+            String targetType = (String) targetItem.getData(KEY_TYPE);
+            // Only allow drop on folder or on class root (MetadataItem); not 
on another file
+            if (FILE.equals(targetType)) {
+              event.detail = DND.DROP_NONE;
+              event.feedback = DND.FEEDBACK_NONE;
+              return;
+            }
+            // Same-type check is enforced in drop()
+            event.feedback = DND.FEEDBACK_SELECT | DND.FEEDBACK_SCROLL | 
DND.FEEDBACK_EXPAND;
+            event.detail = DND.DROP_MOVE;
+          }
+
+          @Override
+          public void drop(DropTargetEvent event) {
+            if 
(!MetadataTransfer.INSTANCE.isSupportedType(event.currentDataType)
+                || event.data == null
+                || !(event.data instanceof String[])) {
+              return;
+            }
+            String[] payload = (String[]) event.data;
+            if (payload.length < 2) {
+              return;
+            }
+            String sourceObjectKey = payload[0];
+            String name = payload[1];
+            Widget item = event.item;
+            if (!(item instanceof TreeItem targetItem)) {
+              return;
+            }
+            String targetType = (String) targetItem.getData(KEY_TYPE);
+            if (FILE.equals(targetType)) {
+              return;
+            }
+            if (!sourceObjectKey.equals(getObjectKey(targetItem))) {
+              return;
+            }
+            String newVirtualPath =
+                FOLDER.equals(targetType) ? (String) 
targetItem.getData(VIRTUAL_PATH) : "";
+            try {
+              IHopMetadataProvider provider = hopGui.getMetadataProvider();
+              IHopMetadataSerializer<IHopMetadata> serializer =
+                  
provider.getSerializer(provider.getMetadataClassForKey(sourceObjectKey));
+              IHopMetadata metadata = serializer.load(name);
+              metadata.setVirtualPath(Utils.isEmpty(newVirtualPath) ? "" : 
newVirtualPath);
+              serializer.save(metadata);
+              
hopGui.getEventsHandler().fire(HopGuiEvents.MetadataChanged.name());
+              refresh();
+            } catch (Exception e) {
+              new ErrorDialog(
+                  getShell(),
+                  ERROR,
+                  BaseMessages.getString(PKG, 
"MetadataPerspective.DragDropMove.Error"),
+                  e);
+            }
+          }
+        });
+  }
+
+  @Override
+  public void openDroppedMetadata(String objectKey, String name) {
+    try {
+      MetadataManager<IHopMetadata> manager = getMetadataManager(objectKey);
+      manager.editWithEditor(name);
+      hopGui.getEventsHandler().fire(HopGuiEvents.MetadataChanged.name());
+    } catch (Exception e) {
+      new ErrorDialog(
+          getShell(),
+          ERROR,
+          BaseMessages.getString(PKG, 
"MetadataPerspective.DragDropOpen.Error"),
+          e);
+    }
   }
 
   protected void createTabFolder(Composite parent) {
@@ -1208,6 +1384,7 @@ public class MetadataPerspective implements 
IHopPerspective, TabClosable {
           
fileRefs.stream().mapToInt(MetadataReferenceResult::getReferenceCount).sum();
       int totalRefCount = fileRefCount + metadataRefs.size();
 
+      boolean confirmed;
       if (totalRefCount > 0) {
         List<String> detailLines = new ArrayList<>();
         for (MetadataReferenceResult r : fileRefs) {
@@ -1221,16 +1398,23 @@ public class MetadataPerspective implements 
IHopPerspective, TabClosable {
                   r.getContainerMetadataKey(),
                   r.getContainerObjectName()));
         }
-        boolean confirmed =
+        confirmed =
             showDeleteWithReferencesDialog(
                 objectName, totalRefCount, fileRefs.size(), 
metadataRefs.size(), detailLines);
-        if (!confirmed) {
-          return;
-        }
+      } else {
+        MessageBox confirmBox = new MessageBox(getShell(), SWT.ICON_QUESTION | 
SWT.YES | SWT.NO);
+        confirmBox.setText(BaseMessages.getString(PKG, 
"MetadataPerspective.DeleteMetadata.Title"));
+        confirmBox.setMessage(
+            BaseMessages.getString(
+                PKG, "MetadataPerspective.DeleteMetadata.ConfirmNoRefs", 
objectName));
+        confirmed = (confirmBox.open() & SWT.YES) != 0;
+      }
+      if (!confirmed) {
+        return;
       }
 
       MetadataManager<IHopMetadata> manager = getMetadataManager(objectKey);
-      manager.deleteMetadata(objectName);
+      manager.deleteMetadata(objectName, true);
 
       refresh();
       updateSelection();
diff --git 
a/ui/src/main/resources/org/apache/hop/ui/hopgui/perspective/metadata/messages/messages_en_US.properties
 
b/ui/src/main/resources/org/apache/hop/ui/hopgui/perspective/metadata/messages/messages_en_US.properties
index fc3e925a59..f016a85788 100644
--- 
a/ui/src/main/resources/org/apache/hop/ui/hopgui/perspective/metadata/messages/messages_en_US.properties
+++ 
b/ui/src/main/resources/org/apache/hop/ui/hopgui/perspective/metadata/messages/messages_en_US.properties
@@ -63,7 +63,10 @@ 
MetadataPerspective.RenameMetadata.NotYetUpdated.WorkflowRunConfig=The following
 MetadataPerspective.RenameMetadata.NotYetUpdated.ExecutionInfoLocation=The 
following transforms are not yet supported: Kafka Consumer.
 MetadataPerspective.RenameMetadata.NotYetUpdated.ExecutionDataProfile=The 
following transforms are not yet supported: Kafka Consumer.
 MetadataPerspective.DeleteMetadata.Title=Delete metadata
+MetadataPerspective.DeleteMetadata.ConfirmNoRefs=Are you sure you want to 
delete ''{0}''?
 MetadataPerspective.DeleteMetadata.Message=Found {0} reference(s) to ''{1}'' 
in {2} pipeline/workflow file(s) and {3} metadata object(s).\n\nDeleting this 
item may break those references. Are you sure you want to delete ''{1}''?
 MetadataPerspective.DeleteMetadata.Button.Details=Details
 MetadataPerspective.DeleteMetadata.Details.Title=References to {0}
-MetadataPerspective.DeleteMetadata.Details.Message=The following files and 
metadata objects still reference ''{0}'':
\ No newline at end of file
+MetadataPerspective.DeleteMetadata.Details.Message=The following files and 
metadata objects still reference ''{0}'':
+MetadataPerspective.DragDropMove.Error=Error moving metadata to folder
+MetadataPerspective.DragDropOpen.Error=Error opening metadata
\ No newline at end of file

Reply via email to