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 12a26db20f Button to view object references, fixes  #7101 (#7471)
12a26db20f is described below

commit 12a26db20fb0b0d6bded9f83c841a93b20c1074a
Author: Hans Van Akelyen <[email protected]>
AuthorDate: Thu Jul 9 15:46:05 2026 +0200

    Button to view object references, fixes  #7101 (#7471)
---
 .../perspective/explorer/ExplorerPerspective.java  |  93 +++++++++++
 .../perspective/metadata/MetadataPerspective.java  |  68 ++++++++
 .../ui/hopgui/search/HopGuiSearchResultsPanel.java |  43 +++++-
 .../ui/hopgui/search/ReferenceSearchResults.java   | 172 +++++++++++++++++++++
 .../explorer/messages/messages_en_US.properties    |   6 +
 .../metadata/messages/messages_en_US.properties    |   6 +
 6 files changed, 384 insertions(+), 4 deletions(-)

diff --git 
a/ui/src/main/java/org/apache/hop/ui/hopgui/perspective/explorer/ExplorerPerspective.java
 
b/ui/src/main/java/org/apache/hop/ui/hopgui/perspective/explorer/ExplorerPerspective.java
index de696b85da..00f8071d14 100644
--- 
a/ui/src/main/java/org/apache/hop/ui/hopgui/perspective/explorer/ExplorerPerspective.java
+++ 
b/ui/src/main/java/org/apache/hop/ui/hopgui/perspective/explorer/ExplorerPerspective.java
@@ -53,6 +53,7 @@ import 
org.apache.hop.core.gui.plugin.toolbar.GuiToolbarElement;
 import org.apache.hop.core.listeners.IContentChangedListener;
 import org.apache.hop.core.plugins.IPlugin;
 import org.apache.hop.core.plugins.PluginRegistry;
+import org.apache.hop.core.search.ISearchResult;
 import org.apache.hop.core.search.ISearchable;
 import org.apache.hop.core.search.SearchMatcher;
 import org.apache.hop.core.svg.SvgCache;
@@ -118,6 +119,7 @@ import 
org.apache.hop.ui.hopgui.perspective.explorer.file.types.GenericFileType;
 import org.apache.hop.ui.hopgui.perspective.metadata.MetadataPerspective;
 import org.apache.hop.ui.hopgui.search.HopGuiPipelineSearchable;
 import org.apache.hop.ui.hopgui.search.HopGuiWorkflowSearchable;
+import org.apache.hop.ui.hopgui.search.ReferenceSearchResults;
 import org.apache.hop.ui.hopgui.shared.CanvasZoomHelper;
 import org.apache.hop.ui.hopgui.shared.SashFormMemory;
 import org.apache.hop.ui.pipeline.transform.BaseTransformDialog;
@@ -213,6 +215,8 @@ public class ExplorerPerspective implements 
IHopPerspective, TabClosable, IFileD
       "ExplorerPerspective-ContextMenu-10400-CopyName";
   public static final String CONTEXT_MENU_COPY_PATH =
       "ExplorerPerspective-ContextMenu-10401-CopyPath";
+  public static final String CONTEXT_MENU_FIND_REFERENCES =
+      "ExplorerPerspective-ContextMenu-10402-FindReferences";
   public static final String CONTEXT_MENU_DELETE = 
"ExplorerPerspective-ContextMenu-90000-Delete";
   private static final String FILE_EXPLORER_TREE = "File explorer tree";
   private static final String TREE_WIDTH_AUDIT_TYPE = 
"explorer-perspective-tree-width";
@@ -633,6 +637,17 @@ public class ExplorerPerspective implements 
IHopPerspective, TabClosable, IFileD
 
           
menuWidgets.findMenuItem(CONTEXT_MENU_RENAME).setEnabled(selection.length == 1);
 
+          // Finding references is only meaningful for a single pipeline or 
workflow file.
+          //
+          MenuItem findReferencesItem = 
menuWidgets.findMenuItem(CONTEXT_MENU_FIND_REFERENCES);
+          if (findReferencesItem != null) {
+            findReferencesItem.setEnabled(
+                selection.length == 1
+                    && tif != null
+                    && !tif.folder
+                    && isPipelineOrWorkflowFile(tif.path));
+          }
+
           // Show the menu
           //
           menu.setVisible(true);
@@ -2817,6 +2832,84 @@ public class ExplorerPerspective implements 
IHopPerspective, TabClosable, IFileD
     GuiResource.getInstance().toClipboard(folder.path);
   }
 
+  @GuiMenuElement(
+      root = GUI_PLUGIN_CONTEXT_MENU_PARENT_ID,
+      parentId = GUI_PLUGIN_CONTEXT_MENU_PARENT_ID,
+      id = CONTEXT_MENU_FIND_REFERENCES,
+      label = "i18n::ExplorerPerspective.Menu.FindReferences",
+      image = "ui/images/search.svg",
+      separator = true)
+  public void findReferences() {
+    TreeItem[] selection = tree.getSelection();
+    if (selection == null || selection.length != 1) {
+      return;
+    }
+    TreeItemFolder tif = (TreeItemFolder) selection[0].getData();
+    if (tif == null || tif.folder || !isPipelineOrWorkflowFile(tif.path)) {
+      return;
+    }
+    findReferences(tif.path, tif.name);
+  }
+
+  /**
+   * Best-effort static scan (same engine as rename) for pipelines/workflows 
and metadata objects
+   * that reference the given file. Results are shown in the shared 
search-results UI, in a
+   * bottom-dock tab, so each one can be opened by double-clicking it.
+   */
+  private void findReferences(String path, String name) {
+    String projectHome = hopGui.getVariables().resolve(Const.VAR_PROJECT_HOME);
+    if (Utils.isEmpty(projectHome) || 
Const.VAR_PROJECT_HOME.equals(projectHome)) {
+      // Without an active project there is nothing to scan.
+      showNoReferencesFound(name);
+      return;
+    }
+    List<String> searchRoots = 
java.util.Collections.singletonList(projectHome);
+    try {
+      MetadataReferenceFinder finder = new 
MetadataReferenceFinder(hopGui.getMetadataProvider());
+      List<MetadataReferenceResult> fileReferences =
+          finder.findFileReferences(searchRoots, path, hopGui.getVariables());
+      List<MetadataObjectReference> metadataReferences =
+          finder.findFilePathReferencesInMetadata(path, hopGui.getVariables());
+
+      List<ISearchResult> results =
+          ReferenceSearchResults.build(hopGui, fileReferences, 
metadataReferences);
+      if (results.isEmpty()) {
+        showNoReferencesFound(name);
+        return;
+      }
+      ReferenceSearchResults.showInBottomDock(
+          hopGui,
+          BaseMessages.getString(PKG, 
"ExplorerPerspective.FindReferences.Tab.Title", name),
+          name,
+          results);
+    } catch (HopException e) {
+      new ErrorDialog(
+          hopGui.getShell(),
+          BaseMessages.getString(PKG, 
"ExplorerPerspective.FindReferences.Error.Title"),
+          BaseMessages.getString(PKG, 
"ExplorerPerspective.FindReferences.Error.Message", name),
+          e);
+    }
+  }
+
+  private void showNoReferencesFound(String name) {
+    MessageBox box = new MessageBox(hopGui.getShell(), SWT.ICON_INFORMATION | 
SWT.OK);
+    box.setText(
+        BaseMessages.getString(PKG, 
"ExplorerPerspective.FindReferences.NoReferences.Title"));
+    box.setMessage(
+        BaseMessages.getString(
+            PKG, "ExplorerPerspective.FindReferences.NoReferences.Message", 
name));
+    box.open();
+  }
+
+  /** True when the path is a pipeline (.hpl) or workflow (.hwf) file. */
+  private static boolean isPipelineOrWorkflowFile(String path) {
+    if (path == null) {
+      return false;
+    }
+    String lower = path.toLowerCase(java.util.Locale.ROOT);
+    return lower.endsWith(".hpl") || lower.endsWith(".hwf");
+  }
+
   @GuiToolbarElement(
       root = GUI_PLUGIN_TOOLBAR_PARENT_ID,
       id = TOOLBAR_ITEM_REFRESH,
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 f482d7396a..f9e2fc874d 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
@@ -39,6 +39,7 @@ import 
org.apache.hop.core.gui.plugin.toolbar.GuiToolbarElement;
 import org.apache.hop.core.logging.LogChannel;
 import org.apache.hop.core.plugins.IPlugin;
 import org.apache.hop.core.plugins.PluginRegistry;
+import org.apache.hop.core.search.ISearchResult;
 import org.apache.hop.core.search.ISearchable;
 import org.apache.hop.core.util.TranslateUtil;
 import org.apache.hop.core.util.Utils;
@@ -92,6 +93,7 @@ import org.apache.hop.ui.hopgui.perspective.TabCloseHandler;
 import org.apache.hop.ui.hopgui.perspective.TabItemHandler;
 import org.apache.hop.ui.hopgui.perspective.TabItemReorder;
 import org.apache.hop.ui.hopgui.perspective.explorer.ExplorerPerspective;
+import org.apache.hop.ui.hopgui.search.ReferenceSearchResults;
 import org.apache.hop.ui.hopgui.shared.SashFormMemory;
 import org.apache.hop.ui.pipeline.transform.BaseTransformDialog;
 import org.apache.hop.ui.util.HelpUtils;
@@ -448,6 +450,13 @@ public class MetadataPerspective implements 
IHopPerspective, TabClosable, IMetad
                 
menuItem.setImage(GuiResource.getInstance().getImageDuplicate());
                 menuItem.addListener(SWT.Selection, e -> duplicateMetadata());
 
+                menuItem = new MenuItem(menu, SWT.POP_UP);
+                menuItem.setText(
+                    BaseMessages.getString(PKG, 
"MetadataPerspective.Menu.FindReferences"));
+                menuItem.setImage(
+                    GuiResource.getInstance().getImage("ui/images/search.svg", 
16, 16));
+                menuItem.addListener(SWT.Selection, e -> onFindReferences());
+
                 new MenuItem(menu, SWT.SEPARATOR);
 
                 menuItem = new MenuItem(menu, SWT.POP_UP);
@@ -926,6 +935,65 @@ public class MetadataPerspective implements 
IHopPerspective, TabClosable, IMetad
     return new String[] {key.toString(), name};
   }
 
+  /** Context-menu handler: find where the selected metadata item is 
referenced. */
+  private void onFindReferences() {
+    String[] keyAndName = getSelectedMetadataKeyAndName();
+    if (keyAndName == null) {
+      return;
+    }
+    findReferences(keyAndName[0], keyAndName[1]);
+  }
+
+  /**
+   * Best-effort static scan (same engine as rename) for pipelines/workflows 
and metadata objects
+   * that reference the given metadata element by name. Results are shown in 
the shared
+   * search-results UI, in a bottom-dock tab, so each one can be opened by 
double-clicking it.
+   */
+  private void findReferences(String metadataKey, String name) {
+    String projectHome = hopGui.getVariables().resolve(Const.VAR_PROJECT_HOME);
+    if (Utils.isEmpty(projectHome) || 
Const.VAR_PROJECT_HOME.equals(projectHome)) {
+      // Without an active project there is nothing to scan.
+      showNoReferencesFound(name);
+      return;
+    }
+    List<String> searchRoots = 
java.util.Collections.singletonList(projectHome);
+    try {
+      MetadataReferenceFinder finder = new 
MetadataReferenceFinder(hopGui.getMetadataProvider());
+      List<MetadataReferenceResult> fileReferences =
+          finder.findReferences(metadataKey, name, searchRoots);
+      List<MetadataObjectReference> metadataReferences =
+          finder.findReferencesInMetadata(metadataKey, name);
+
+      List<ISearchResult> results =
+          ReferenceSearchResults.build(hopGui, fileReferences, 
metadataReferences);
+      if (results.isEmpty()) {
+        showNoReferencesFound(name);
+        return;
+      }
+      ReferenceSearchResults.showInBottomDock(
+          hopGui,
+          BaseMessages.getString(PKG, 
"MetadataPerspective.FindReferences.Tab.Title", name),
+          name,
+          results);
+    } catch (HopException e) {
+      new ErrorDialog(
+          getShell(),
+          BaseMessages.getString(PKG, 
"MetadataPerspective.FindReferences.Error.Title"),
+          BaseMessages.getString(PKG, 
"MetadataPerspective.FindReferences.Error.Message", name),
+          e);
+    }
+  }
+
+  private void showNoReferencesFound(String name) {
+    MessageBox box = new MessageBox(getShell(), SWT.ICON_INFORMATION | SWT.OK);
+    box.setText(
+        BaseMessages.getString(PKG, 
"MetadataPerspective.FindReferences.NoReferences.Title"));
+    box.setMessage(
+        BaseMessages.getString(
+            PKG, "MetadataPerspective.FindReferences.NoReferences.Message", 
name));
+    box.open();
+  }
+
   /**
    * Append context-menu items contributed by plugins (annotated with {@link
    * org.apache.hop.core.gui.plugin.menu.GuiMenuElement} under {@link
diff --git 
a/ui/src/main/java/org/apache/hop/ui/hopgui/search/HopGuiSearchResultsPanel.java
 
b/ui/src/main/java/org/apache/hop/ui/hopgui/search/HopGuiSearchResultsPanel.java
index f97d8552e8..eb2bf4ddb4 100644
--- 
a/ui/src/main/java/org/apache/hop/ui/hopgui/search/HopGuiSearchResultsPanel.java
+++ 
b/ui/src/main/java/org/apache/hop/ui/hopgui/search/HopGuiSearchResultsPanel.java
@@ -18,6 +18,7 @@
 package org.apache.hop.ui.hopgui.search;
 
 import java.util.ArrayList;
+import java.util.Collections;
 import java.util.List;
 import java.util.Map;
 import org.apache.hop.core.Const;
@@ -107,6 +108,12 @@ public class HopGuiSearchResultsPanel extends Composite {
 
   private final Runnable searchRunnable = () -> search(new Event());
 
+  /**
+   * When true, programmatic changes to the search field (e.g. showing a 
reference label) must not
+   * trigger the debounced text search that would otherwise clobber injected 
results.
+   */
+  private boolean suppressAutoSearch;
+
   public HopGuiSearchResultsPanel(Composite parent, HopGui hopGui) {
     super(parent, SWT.NONE);
     this.hopGui = hopGui;
@@ -310,7 +317,7 @@ public class HopGuiSearchResultsPanel extends Composite {
   }
 
   private void scheduleSearch() {
-    if (isDisposed()) {
+    if (isDisposed() || suppressAutoSearch) {
       return;
     }
     getDisplay().timerExec(-1, searchRunnable);
@@ -451,18 +458,46 @@ public class HopGuiSearchResultsPanel extends Composite {
       hopGui.getLog().logError("Error while searching", e);
       results = new ArrayList<>();
     }
-    populateTree(results);
+    populateTree(results, cachedEnumeration.getSourceByKey());
+  }
+
+  /**
+   * Show a pre-computed set of results (e.g. "find references") without 
running a text search. The
+   * search field is set to {@code targetLabel} for context only; typing a new 
query afterwards
+   * turns this back into a normal search tab.
+   *
+   * @param targetLabel a label describing what the results relate to (shown 
in the search field)
+   * @param results the results to display; all are grouped under the Project 
section
+   */
+  public void showReferenceResults(String targetLabel, List<ISearchResult> 
results) {
+    if (wTree == null || wTree.isDisposed()) {
+      return;
+    }
+    suppressAutoSearch = true;
+    try {
+      if (wSearchString != null && !wSearchString.isDisposed()) {
+        wSearchString.setText(Const.NVL(targetLabel, ""));
+      }
+    } finally {
+      suppressAutoSearch = false;
+    }
+    wTree.removeAll();
+    clearDetails();
+    wbOpen.setEnabled(false);
+    // Reference results have no enumeration behind them: an empty source map 
puts them all under
+    // the Project section.
+    populateTree(results, Collections.emptyMap());
   }
 
   /**
    * Render the two-tier tree: section (Open/Project) -> type -> object -> the 
matches inside it.
    */
-  private void populateTree(List<ISearchResult> results) {
+  private void populateTree(List<ISearchResult> results, Map<String, Integer> 
sourceByKey) {
     String searchTerm = wRegEx.getSelection() ? null : wSearchString.getText();
 
     TreeItem firstLeaf = null;
     for (HopGuiSearchHelper.SearchSection section :
-        HopGuiSearchHelper.groupResults(results, 
cachedEnumeration.getSourceByKey())) {
+        HopGuiSearchHelper.groupResults(results, sourceByKey)) {
       TreeItem sectionItem = new TreeItem(wTree, SWT.NONE);
       sectionItem.setText(
           0, sectionLabel(section.getKey()) + "  (" + section.getObjectCount() 
+ ")");
diff --git 
a/ui/src/main/java/org/apache/hop/ui/hopgui/search/ReferenceSearchResults.java 
b/ui/src/main/java/org/apache/hop/ui/hopgui/search/ReferenceSearchResults.java
new file mode 100644
index 0000000000..ad422b22d0
--- /dev/null
+++ 
b/ui/src/main/java/org/apache/hop/ui/hopgui/search/ReferenceSearchResults.java
@@ -0,0 +1,172 @@
+/*
+ * 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.search;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Locale;
+import org.apache.hop.core.search.ISearchResult;
+import org.apache.hop.core.search.ISearchable;
+import org.apache.hop.core.search.SearchResult;
+import org.apache.hop.metadata.api.IHopMetadata;
+import org.apache.hop.metadata.api.IHopMetadataProvider;
+import org.apache.hop.metadata.api.IHopMetadataSerializer;
+import org.apache.hop.metadata.refactor.MetadataObjectReference;
+import org.apache.hop.metadata.refactor.MetadataReferenceResult;
+import org.apache.hop.pipeline.PipelineMeta;
+import org.apache.hop.ui.core.gui.GuiResource;
+import org.apache.hop.ui.hopgui.HopGui;
+import org.apache.hop.ui.hopgui.terminal.HopGuiBottomDock;
+import org.apache.hop.workflow.WorkflowMeta;
+import org.eclipse.swt.widgets.Control;
+
+/**
+ * Turns the output of {@link 
org.apache.hop.metadata.refactor.MetadataReferenceFinder} into {@link
+ * ISearchResult}s that the shared search-results UI ({@link 
HopGuiSearchResultsPanel}) can render
+ * and open. Each referencing pipeline/workflow file or metadata object is 
wrapped in the existing
+ * searchable for that object type, so double-clicking a result opens it with 
no new open logic.
+ */
+public final class ReferenceSearchResults {
+
+  private static final String EXT_HPL = ".hpl";
+  private static final String EXT_HWF = ".hwf";
+  private static final String LOCATION_PIPELINE = "Project pipeline file";
+  private static final String LOCATION_WORKFLOW = "Project workflow file";
+
+  private ReferenceSearchResults() {}
+
+  /**
+   * Builds openable search results for the given references. Objects that 
fail to load (corrupt,
+   * missing plugin, ...) are skipped so the feature stays best-effort.
+   *
+   * @param hopGui the active HopGui (for metadata provider, variables and 
logging)
+   * @param fileReferences referencing pipeline/workflow files (from {@code 
findFileReferences})
+   * @param metadataReferences referencing metadata objects (from {@code
+   *     findFilePathReferencesInMetadata})
+   * @return the search results, in file-first then metadata order
+   */
+  public static List<ISearchResult> build(
+      HopGui hopGui,
+      List<MetadataReferenceResult> fileReferences,
+      List<MetadataObjectReference> metadataReferences) {
+    List<ISearchResult> results = new ArrayList<>();
+    if (fileReferences != null) {
+      for (MetadataReferenceResult fileReference : fileReferences) {
+        ISearchable<?> searchable = toFileSearchable(hopGui, 
fileReference.getFilePath());
+        if (searchable != null) {
+          results.add(asObjectResult(searchable));
+        }
+      }
+    }
+    if (metadataReferences != null) {
+      for (MetadataObjectReference reference : metadataReferences) {
+        ISearchable<?> searchable = toMetadataSearchable(hopGui, reference);
+        if (searchable != null) {
+          results.add(asObjectResult(searchable));
+        }
+      }
+    }
+    return results;
+  }
+
+  /**
+   * Opens the given reference results in a bottom-dock tab hosting the shared 
search-results panel,
+   * so each result can be opened by double-clicking it. Does nothing when the 
dock is unavailable.
+   *
+   * @param hopGui the active HopGui
+   * @param tabTitle the dock tab title
+   * @param label a short label describing what the results relate to (shown 
in the search field)
+   * @param results the (non-empty) results to display
+   */
+  public static void showInBottomDock(
+      HopGui hopGui, String tabTitle, String label, List<ISearchResult> 
results) {
+    HopGuiBottomDock dock = hopGui.getTerminalPanel();
+    if (dock == null || dock.isDisposed()) {
+      return;
+    }
+    Control content =
+        dock.openToolTab(
+            tabTitle,
+            GuiResource.getInstance().getImage("ui/images/search.svg", 16, 16),
+            true,
+            container -> new HopGuiSearchResultsPanel(container, hopGui));
+    if (content instanceof HopGuiSearchResultsPanel panel) {
+      panel.showReferenceResults(label, results);
+    }
+  }
+
+  /**
+   * A result whose matching string equals the object's name, so the shared 
results tree renders it
+   * as a plain object node (no inner field/transform match rows) and no 
component is selected on
+   * open.
+   */
+  private static ISearchResult asObjectResult(ISearchable<?> searchable) {
+    return new SearchResult(searchable, searchable.getName(), null, null, 
null);
+  }
+
+  private static ISearchable<?> toFileSearchable(HopGui hopGui, String path) {
+    if (path == null) {
+      return null;
+    }
+    String lower = path.toLowerCase(Locale.ROOT);
+    try {
+      if (lower.endsWith(EXT_HPL)) {
+        PipelineMeta pipelineMeta =
+            new PipelineMeta(path, hopGui.getMetadataProvider(), 
hopGui.getVariables());
+        return new HopGuiPipelineSearchable(LOCATION_PIPELINE, pipelineMeta);
+      } else if (lower.endsWith(EXT_HWF)) {
+        WorkflowMeta workflowMeta =
+            new WorkflowMeta(hopGui.getVariables(), path, 
hopGui.getMetadataProvider());
+        return new HopGuiWorkflowSearchable(LOCATION_WORKFLOW, workflowMeta);
+      }
+    } catch (Exception e) {
+      hopGui.getLog().logBasic("Find references: could not load " + path + ": 
" + e.getMessage());
+    }
+    return null;
+  }
+
+  @SuppressWarnings("unchecked")
+  private static ISearchable<?> toMetadataSearchable(
+      HopGui hopGui, MetadataObjectReference reference) {
+    try {
+      IHopMetadataProvider provider = hopGui.getMetadataProvider();
+      Class<? extends IHopMetadata> containerClass =
+          provider.getMetadataClassForKey(reference.getContainerMetadataKey());
+      if (containerClass == null) {
+        return null;
+      }
+      IHopMetadataSerializer<IHopMetadata> serializer =
+          (IHopMetadataSerializer<IHopMetadata>) 
provider.getSerializer(containerClass);
+      IHopMetadata object = 
serializer.load(reference.getContainerObjectName());
+      if (object == null) {
+        return null;
+      }
+      return new HopGuiMetadataSearchable(
+          provider, serializer, object, (Class<IHopMetadata>) containerClass);
+    } catch (Exception e) {
+      hopGui
+          .getLog()
+          .logBasic(
+              "Find references: could not load metadata object "
+                  + reference.getContainerObjectName()
+                  + ": "
+                  + e.getMessage());
+      return null;
+    }
+  }
+}
diff --git 
a/ui/src/main/resources/org/apache/hop/ui/hopgui/perspective/explorer/messages/messages_en_US.properties
 
b/ui/src/main/resources/org/apache/hop/ui/hopgui/perspective/explorer/messages/messages_en_US.properties
index a449d125ad..8290f42516 100644
--- 
a/ui/src/main/resources/org/apache/hop/ui/hopgui/perspective/explorer/messages/messages_en_US.properties
+++ 
b/ui/src/main/resources/org/apache/hop/ui/hopgui/perspective/explorer/messages/messages_en_US.properties
@@ -41,6 +41,7 @@ ExplorerPerspective.Menu.CopyName=Copy name
 ExplorerPerspective.Menu.CopyPath=Copy path
 ExplorerPerspective.Menu.CreateFolder=Create folder
 ExplorerPerspective.Menu.Delete=Delete
+ExplorerPerspective.Menu.FindReferences=Find references
 ExplorerPerspective.Menu.Open=Open
 ExplorerPerspective.Menu.OpenInExplorer=Open in explorer
 ExplorerPerspective.Menu.Rename=Rename
@@ -65,6 +66,11 @@ ExplorerPerspective.UpdateFileReferences.Message=Found {0} 
reference(s) in {1} p
 ExplorerPerspective.UpdateFileReferences.MessageWithMetadata=Found {0} 
reference(s) in {1} pipeline/workflow file(s) and {2} metadata object(s). 
Update references to the new path(s)?
 ExplorerPerspective.UpdateFileReferences.ExperimentalFeatureNote=Note: 
Reference detection and replacement is an experimental feature. Not all 
transforms and actions may be updated automatically.
 ExplorerPerspective.UpdateFileReferences.Button.Details=Details
+ExplorerPerspective.FindReferences.Tab.Title=References: {0}
+ExplorerPerspective.FindReferences.NoReferences.Title=Find references
+ExplorerPerspective.FindReferences.NoReferences.Message=No references to 
''{0}'' were found in this project.
+ExplorerPerspective.FindReferences.Error.Title=Error finding references
+ExplorerPerspective.FindReferences.Error.Message=There was an error while 
searching for references to ''{0}''.
 ExplorerPerspective.UpdateFileReferences.Details.Title=Details
 ExplorerPerspective.UpdateFileReferences.Details.Message=Files and metadata 
objects that will be modified:
 ExplorerPerspective.UpdateFileReferences.Details.MetadataEntry=Metadata ({0}): 
{1}
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 41f7829dd9..7c30a6ff17 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
@@ -31,6 +31,7 @@ MetadataPerspective.GuiPlugin.Description=This perspective 
allows you to see and
 MetadataPerspective.Menu.Delete=Delete\tDelete
 MetadataPerspective.Menu.Duplicate=Duplicate
 MetadataPerspective.Menu.Edit=Edit\tF3
+MetadataPerspective.Menu.FindReferences=Find references
 MetadataPerspective.Menu.Help=Help\tF1
 MetadataPerspective.Menu.New=New
 MetadataPerspective.Menu.NewFolder=New Folder
@@ -47,6 +48,11 @@ MetadataPerspective.ToolbarElement.New.Tooltip=Create a new 
metadata element
 MetadataPerspective.ToolbarElement.Refresh.Tooltip=Refresh
 MetadataPerspective.ToolbarElement.Rename.Tooltip=Rename
 MetadataPerspective.Search.Placeholder=Search metadata...
+MetadataPerspective.FindReferences.Tab.Title=References: {0}
+MetadataPerspective.FindReferences.NoReferences.Title=Find references
+MetadataPerspective.FindReferences.NoReferences.Message=No references to 
''{0}'' were found in this project.
+MetadataPerspective.FindReferences.Error.Title=Error finding references
+MetadataPerspective.FindReferences.Error.Message=There was an error while 
searching for references to ''{0}''.
 MetadataPerspective.RenameMetadata.UpdateReferences.Title=Rename metadata
 MetadataPerspective.RenameMetadata.UpdateReferences.Message=Found {0} 
reference(s) in {1} file(s). Update references to the new name?
 MetadataPerspective.RenameMetadata.UpdateReferences.MessageWithMetadata=Found 
{0} reference(s) in {1} pipeline/workflow file(s) and {2} metadata object(s). 
Update references to the new name?

Reply via email to