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

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


The following commit(s) were added to refs/heads/main by this push:
     new 0a88f9900148 CAMEL-23807: render the route-diagram dev console with 
the HTML web component
0a88f9900148 is described below

commit 0a88f9900148183a0d8c66c34de96e56dcbfa52e
Author: Ravi <[email protected]>
AuthorDate: Sun Jun 21 11:29:53 2026 +0530

    CAMEL-23807: render the route-diagram dev console with the HTML web 
component
    
    The route-diagram developer console now renders its HTML output with the
    interactive <camel-route-diagram> web component instead of a static base64
    PNG image. The web component is fed by the sibling route-structure dev
    console. Request ?format=png for the legacy inline image; ascii/unicode
    themes are unchanged.
    
    The web component JS now sets Accept: application/json explicitly so the
    dev console content-negotiation returns structured data instead of plain
    text.
    
    Closes #24156
---
 .../camel-diagram/src/main/docs/diagram.adoc       |  7 +++++
 .../apache/camel/diagram/DiagramDevConsole.java    | 30 +++++++++++++++++++++-
 .../resources/camel/diagram/camel-route-diagram.js |  6 ++++-
 .../camel/diagram/DiagramDevConsoleTest.java       | 16 +++++++++++-
 4 files changed, 56 insertions(+), 3 deletions(-)

diff --git a/components/camel-diagram/src/main/docs/diagram.adoc 
b/components/camel-diagram/src/main/docs/diagram.adoc
index a7cde4eb2f5e..414231173fd2 100644
--- a/components/camel-diagram/src/main/docs/diagram.adoc
+++ b/components/camel-diagram/src/main/docs/diagram.adoc
@@ -110,6 +110,13 @@ The diagram rendering is used by the `camel cmd 
route-diagram` command in Camel
 camel cmd route-diagram MyRoute.java
 ----
 
+=== Developer console
+
+When the developer console is enabled (for example with `camel run 
--console`), the `route-diagram`
+console renders the running routes using the interactive 
`<camel-route-diagram>` web component,
+fed by the `route-structure` console. Request `?format=png` to get the legacy 
inline PNG image
+instead, or use the `ascii` / `unicode` themes for plain-text output.
+
 == Color Themes
 
 The following built-in themes are available:
diff --git 
a/components/camel-diagram/src/main/java/org/apache/camel/diagram/DiagramDevConsole.java
 
b/components/camel-diagram/src/main/java/org/apache/camel/diagram/DiagramDevConsole.java
index 78a3881ab81e..165eaa63f300 100644
--- 
a/components/camel-diagram/src/main/java/org/apache/camel/diagram/DiagramDevConsole.java
+++ 
b/components/camel-diagram/src/main/java/org/apache/camel/diagram/DiagramDevConsole.java
@@ -69,6 +69,12 @@ public class DiagramDevConsole extends AbstractDevConsole {
      */
     public static final String MODE = "mode";
 
+    /**
+     * Output format for the HTML rendering: html (default, interactive web 
component) or png (legacy inline image).
+     * Only applies to image themes; ascii/unicode themes always render as 
text.
+     */
+    public static final String FORMAT = "format";
+
     public DiagramDevConsole() {
         super("camel", "route-diagram", "Route Diagram", "Visual route 
diagrams");
     }
@@ -87,6 +93,7 @@ public class DiagramDevConsole extends AbstractDevConsole {
         String nodeLabel = (String) options.getOrDefault(NODE_LABEL, 
RouteDiagramDumper.NodeLabelMode.CODE.name());
         boolean metric = "true".equalsIgnoreCase((String) 
options.getOrDefault(METRIC, "true"));
         boolean refresh = "true".equalsIgnoreCase((String) 
options.getOrDefault(AUTO_REFRESH, "true"));
+        String format = (String) options.getOrDefault(FORMAT, "html");
 
         try {
             RouteDiagramDumper dumper = 
PluginHelper.getRouteDiagramDumper(getCamelContext());
@@ -97,7 +104,7 @@ public class DiagramDevConsole extends AbstractDevConsole {
                         
RouteDiagramDumper.NodeLabelMode.valueOf(nodeLabel.toUpperCase()),
                         nodeWidth, isUnicodeTheme(theme));
                 sj.add(text);
-            } else {
+            } else if ("png".equalsIgnoreCase(format)) {
                 BufferedImage image = dumper.dumpRoutesAsImage(filter,
                         RouteDiagramDumper.Theme.valueOf(theme.toUpperCase()),
                         metric, 
RouteDiagramDumper.NodeLabelMode.valueOf(nodeLabel.toUpperCase()), nodeWidth, 
fontSize);
@@ -110,6 +117,8 @@ public class DiagramDevConsole extends AbstractDevConsole {
                 }
                 html = "<html>\n" + html + "</html>\n";
                 sj.add(html);
+            } else {
+                sj.add(buildRouteWebComponentHtml(filter, refresh));
             }
         } catch (Exception e) {
             // ignore
@@ -196,6 +205,25 @@ public class DiagramDevConsole extends AbstractDevConsole {
         return root;
     }
 
+    private static String buildRouteWebComponentHtml(String filter, boolean 
refresh) {
+        String f = filter == null ? "*" : filter;
+        String refreshAttr = refresh ? " refresh=\"5000\"" : "";
+        // script path + route-structure src assume the dev console and static 
resources share an origin
+        return "<html>\n"
+               + "  <head>\n"
+               + "    <script type=\"module\" 
src=\"/camel/diagram/camel-route-diagram.js\"></script>\n"
+               + "  </head>\n"
+               + "  <body>\n"
+               + String.format("    <camel-route-diagram 
src=\"route-structure\" filter=\"%s\"%s></camel-route-diagram>%n",
+                       escapeAttr(f), refreshAttr)
+               + "  </body>\n"
+               + "</html>\n";
+    }
+
+    private static String escapeAttr(String s) {
+        return s.replace("&", "&amp;").replace("<", "&lt;").replace(">", 
"&gt;").replace("\"", "&quot;");
+    }
+
     private static boolean isTextTheme(String theme) {
         return "ascii".equalsIgnoreCase(theme) || 
"unicode".equalsIgnoreCase(theme);
     }
diff --git 
a/components/camel-diagram/src/main/resources/META-INF/resources/camel/diagram/camel-route-diagram.js
 
b/components/camel-diagram/src/main/resources/META-INF/resources/camel/diagram/camel-route-diagram.js
index 869f075288d1..665887f27ca9 100644
--- 
a/components/camel-diagram/src/main/resources/META-INF/resources/camel/diagram/camel-route-diagram.js
+++ 
b/components/camel-diagram/src/main/resources/META-INF/resources/camel/diagram/camel-route-diagram.js
@@ -372,7 +372,11 @@ class CamelRouteDiagram extends HTMLElement {
             const url = new URL(src, location.href);
             if (this.#filter) url.searchParams.set('filter', this.#filter);
             url.searchParams.set('metric', 'true');
-            const res = await fetch(url, { signal: this.#controller.signal });
+            // Ask for JSON explicitly; the dev console serves plain text for 
a default */* Accept.
+            const res = await fetch(url, {
+                signal: this.#controller.signal,
+                headers: { 'Accept': 'application/json' },
+            });
             if (!res.ok) {
                 this.#error = `HTTP ${res.status} ${res.statusText}`;
                 this.#render();
diff --git 
a/components/camel-diagram/src/test/java/org/apache/camel/diagram/DiagramDevConsoleTest.java
 
b/components/camel-diagram/src/test/java/org/apache/camel/diagram/DiagramDevConsoleTest.java
index 681a48877ad1..524bc0e10ffc 100644
--- 
a/components/camel-diagram/src/test/java/org/apache/camel/diagram/DiagramDevConsoleTest.java
+++ 
b/components/camel-diagram/src/test/java/org/apache/camel/diagram/DiagramDevConsoleTest.java
@@ -17,6 +17,7 @@
 package org.apache.camel.diagram;
 
 import java.util.Base64;
+import java.util.Map;
 
 import org.apache.camel.builder.RouteBuilder;
 import org.apache.camel.console.DevConsole;
@@ -68,9 +69,22 @@ class DiagramDevConsoleTest extends CamelTestSupport {
         DevConsole console = resolveConsole();
         String text = (String) console.call(DevConsole.MediaType.TEXT);
         assertThat(text).isNotNull();
-        // default theme renders HTML with inline image
+        assertThat(text).contains("<html>");
+        assertThat(text).contains("<camel-route-diagram");
+        assertThat(text).contains("src=\"route-structure\"");
+        assertThat(text).contains("camel-route-diagram.js");
+        assertThat(text).doesNotContain("data:image/png;base64,");
+    }
+
+    @Test
+    void testTextOutputPngFormat() {
+        System.setProperty("java.awt.headless", "true");
+        DevConsole console = resolveConsole();
+        String text = (String) console.call(DevConsole.MediaType.TEXT, 
Map.of(DiagramDevConsole.FORMAT, "png"));
+        assertThat(text).isNotNull();
         assertThat(text).contains("<html>");
         assertThat(text).contains("data:image/png;base64,");
+        assertThat(text).doesNotContain("<camel-route-diagram");
     }
 
     @Test

Reply via email to