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

davsclaus pushed a commit to branch worktree-happy-tickling-stream
in repository https://gitbox.apache.org/repos/asf/camel.git

commit ac933e347609a606341151c024ff63e0ff5f3a63
Author: Claus Ibsen <[email protected]>
AuthorDate: Fri Jun 5 21:36:53 2026 +0200

    CAMEL-23672: camel-jbang - TUI highlight individual changed keys in yellow
    
    When headers/properties/variables change between steps, highlight the
    specific keys that were added or modified in yellow while unchanged
    keys stay cyan. Applied in both table detail view and diagram info panel.
    
    Co-Authored-By: Claude Opus 4.6 <[email protected]>
    Signed-off-by: Claus Ibsen <[email protected]>
---
 .../dsl/jbang/core/commands/tui/ErrorsTab.java     |  6 +-
 .../dsl/jbang/core/commands/tui/HistoryTab.java    | 95 ++++++++++++++--------
 2 files changed, 65 insertions(+), 36 deletions(-)

diff --git 
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/ErrorsTab.java
 
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/ErrorsTab.java
index 9a6964158776..c0adaf580826 100644
--- 
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/ErrorsTab.java
+++ 
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/ErrorsTab.java
@@ -468,13 +468,13 @@ class ErrorsTab implements MonitorTab {
 
         // exchange properties, variables, headers, body
         if (showProperties && !ei.properties.isEmpty()) {
-            HistoryTab.addKvLines(lines, " Exchange Properties:", 
ei.properties, ei.propertyTypes, false);
+            HistoryTab.addKvLines(lines, " Exchange Properties:", 
ei.properties, ei.propertyTypes, false, null);
         }
         if (showVariables && !ei.variables.isEmpty()) {
-            HistoryTab.addKvLines(lines, " Exchange Variables:", ei.variables, 
ei.variableTypes, false);
+            HistoryTab.addKvLines(lines, " Exchange Variables:", ei.variables, 
ei.variableTypes, false, null);
         }
         if (showHeaders && !ei.headers.isEmpty()) {
-            HistoryTab.addKvLines(lines, " Headers:", ei.headers, 
ei.headerTypes, false);
+            HistoryTab.addKvLines(lines, " Headers:", ei.headers, 
ei.headerTypes, false, null);
         }
         if (showBody) {
             HistoryTab.addBodyLines(lines, ei.body, ei.bodyType, false);
diff --git 
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/HistoryTab.java
 
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/HistoryTab.java
index 332be145f19c..ab15cb065f48 100644
--- 
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/HistoryTab.java
+++ 
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/HistoryTab.java
@@ -683,6 +683,9 @@ class HistoryTab implements MonitorTab {
         Map<String, Object> headers = null;
         Map<String, Object> properties = null;
         Map<String, Object> variables = null;
+        Map<String, Object> prevHeaders = null;
+        Map<String, Object> prevProperties = null;
+        Map<String, Object> prevVariables = null;
 
         if (!diagramTraceSteps.isEmpty() && stepIdx >= 0 && stepIdx < 
diagramTraceSteps.size()) {
             TraceEntry e = diagramTraceSteps.get(stepIdx);
@@ -701,6 +704,12 @@ class HistoryTab implements MonitorTab {
             headers = e.headers;
             properties = e.exchangeProperties;
             variables = e.exchangeVariables;
+            if (stepIdx > 0) {
+                TraceEntry p = diagramTraceSteps.get(stepIdx - 1);
+                prevHeaders = p.headers;
+                prevProperties = p.exchangeProperties;
+                prevVariables = p.exchangeVariables;
+            }
         } else if (!diagramHistorySteps.isEmpty() && stepIdx >= 0 && stepIdx < 
diagramHistorySteps.size()) {
             HistoryEntry e = diagramHistorySteps.get(stepIdx);
             exchangeId = e.exchangeId;
@@ -718,6 +727,12 @@ class HistoryTab implements MonitorTab {
             headers = e.headers;
             properties = e.exchangeProperties;
             variables = e.exchangeVariables;
+            if (stepIdx > 0) {
+                HistoryEntry p = diagramHistorySteps.get(stepIdx - 1);
+                prevHeaders = p.headers;
+                prevProperties = p.exchangeProperties;
+                prevVariables = p.exchangeVariables;
+            }
         }
 
         if (exchangeId == null) {
@@ -817,39 +832,24 @@ class HistoryTab implements MonitorTab {
         }
 
         if (showHeaders && headers != null && !headers.isEmpty()) {
-            Style headerStyle = headersChanged ? 
Style.EMPTY.fg(Color.YELLOW).bold() : Style.EMPTY.fg(Color.GREEN).bold();
+            Style sectionStyle = headersChanged ? 
Style.EMPTY.fg(Color.YELLOW).bold() : Style.EMPTY.fg(Color.GREEN).bold();
             lines.add(Line.from(Span.raw("")));
-            lines.add(Line.from(Span.styled(" Headers", headerStyle)));
-            for (var entry : headers.entrySet()) {
-                String val = entry.getValue() != null ? 
entry.getValue().toString() : "null";
-                lines.add(Line.from(
-                        Span.styled(" " + entry.getKey(), 
Style.EMPTY.fg(Color.CYAN)),
-                        Span.raw(" = " + val)));
-            }
+            lines.add(Line.from(Span.styled(" Headers", sectionStyle)));
+            addInfoKvLines(lines, headers, headersChanged, prevHeaders);
         }
 
         if (showProps && properties != null && !properties.isEmpty()) {
-            Style headerStyle = propsChanged ? 
Style.EMPTY.fg(Color.YELLOW).bold() : Style.EMPTY.fg(Color.GREEN).bold();
+            Style sectionStyle = propsChanged ? 
Style.EMPTY.fg(Color.YELLOW).bold() : Style.EMPTY.fg(Color.GREEN).bold();
             lines.add(Line.from(Span.raw("")));
-            lines.add(Line.from(Span.styled(" Properties", headerStyle)));
-            for (var entry : properties.entrySet()) {
-                String val = entry.getValue() != null ? 
entry.getValue().toString() : "null";
-                lines.add(Line.from(
-                        Span.styled(" " + entry.getKey(), 
Style.EMPTY.fg(Color.CYAN)),
-                        Span.raw(" = " + val)));
-            }
+            lines.add(Line.from(Span.styled(" Properties", sectionStyle)));
+            addInfoKvLines(lines, properties, propsChanged, prevProperties);
         }
 
         if (showVars && variables != null && !variables.isEmpty()) {
-            Style headerStyle = varsChanged ? 
Style.EMPTY.fg(Color.YELLOW).bold() : Style.EMPTY.fg(Color.GREEN).bold();
+            Style sectionStyle = varsChanged ? 
Style.EMPTY.fg(Color.YELLOW).bold() : Style.EMPTY.fg(Color.GREEN).bold();
             lines.add(Line.from(Span.raw("")));
-            lines.add(Line.from(Span.styled(" Variables", headerStyle)));
-            for (var entry : variables.entrySet()) {
-                String val = entry.getValue() != null ? 
entry.getValue().toString() : "null";
-                lines.add(Line.from(
-                        Span.styled(" " + entry.getKey(), 
Style.EMPTY.fg(Color.CYAN)),
-                        Span.raw(" = " + val)));
-            }
+            lines.add(Line.from(Span.styled(" Variables", sectionStyle)));
+            addInfoKvLines(lines, variables, varsChanged, prevVariables);
         }
 
         boolean wordWrap = !diagramTraceSteps.isEmpty() ? traceWordWrap : 
historyWordWrap;
@@ -862,6 +862,23 @@ class HistoryTab implements MonitorTab {
         frame.renderWidget(pb.build(), area);
     }
 
+    private static void addInfoKvLines(
+            List<Line> lines, Map<String, Object> map,
+            boolean sectionChanged, Map<String, Object> prevMap) {
+        for (var entry : map.entrySet()) {
+            String val = entry.getValue() != null ? 
entry.getValue().toString() : "null";
+            boolean keyChanged = sectionChanged && prevMap != null
+                    && (!prevMap.containsKey(entry.getKey())
+                            || !Objects.equals(prevMap.get(entry.getKey()), 
entry.getValue()));
+            Style keyStyle = keyChanged ? Style.EMPTY.fg(Color.YELLOW) : 
Style.EMPTY.fg(Color.CYAN);
+            Style valStyle = keyChanged ? Style.EMPTY.fg(Color.YELLOW) : 
Style.EMPTY;
+            lines.add(Line.from(
+                    Span.styled(" " + entry.getKey(), keyStyle),
+                    Span.raw(" = "),
+                    Span.styled(val, valStyle)));
+        }
+    }
+
     // ---- Diagram loading ----
 
     private void loadDiagramForCurrentView() {
@@ -1115,13 +1132,16 @@ class HistoryTab implements MonitorTab {
         addExchangeInfoLines(lines, entry.exchangeId, entry.routeId, 
entry.nodeId, entry.nodeLabel,
                 entry.location, entry.elapsed, entry.threadName, entry.failed);
         if (showTraceProperties) {
-            addKvLines(lines, " Exchange Properties:", 
entry.exchangeProperties, entry.exchangePropertyTypes, propsChanged);
+            addKvLines(lines, " Exchange Properties:", 
entry.exchangeProperties, entry.exchangePropertyTypes,
+                    propsChanged, prev != null ? prev.exchangeProperties : 
null);
         }
         if (showTraceVariables) {
-            addKvLines(lines, " Exchange Variables:", entry.exchangeVariables, 
entry.exchangeVariableTypes, varsChanged);
+            addKvLines(lines, " Exchange Variables:", entry.exchangeVariables, 
entry.exchangeVariableTypes,
+                    varsChanged, prev != null ? prev.exchangeVariables : null);
         }
         if (showTraceHeaders) {
-            addKvLines(lines, " Headers:", entry.headers, entry.headerTypes, 
headersChanged);
+            addKvLines(lines, " Headers:", entry.headers, entry.headerTypes,
+                    headersChanged, prev != null ? prev.headers : null);
         }
         if (showTraceBody) {
             addBodyLines(lines, entry.body, entry.bodyType, bodyChanged);
@@ -1383,13 +1403,16 @@ class HistoryTab implements MonitorTab {
         addExchangeInfoLines(lines, entry.exchangeId, entry.routeId, 
entry.nodeId, entry.nodeLabel,
                 entry.location, entry.elapsed, entry.threadName, entry.failed);
         if (showHistoryProperties) {
-            addKvLines(lines, " Exchange Properties:", 
entry.exchangeProperties, entry.exchangePropertyTypes, propsChanged);
+            addKvLines(lines, " Exchange Properties:", 
entry.exchangeProperties, entry.exchangePropertyTypes,
+                    propsChanged, prev != null ? prev.exchangeProperties : 
null);
         }
         if (showHistoryVariables) {
-            addKvLines(lines, " Exchange Variables:", entry.exchangeVariables, 
entry.exchangeVariableTypes, varsChanged);
+            addKvLines(lines, " Exchange Variables:", entry.exchangeVariables, 
entry.exchangeVariableTypes,
+                    varsChanged, prev != null ? prev.exchangeVariables : null);
         }
         if (showHistoryHeaders) {
-            addKvLines(lines, " Headers:", entry.headers, entry.headerTypes, 
headersChanged);
+            addKvLines(lines, " Headers:", entry.headers, entry.headerTypes,
+                    headersChanged, prev != null ? prev.headers : null);
         }
         if (showHistoryBody) {
             addBodyLines(lines, entry.body, entry.bodyType, bodyChanged);
@@ -1848,7 +1871,8 @@ class HistoryTab implements MonitorTab {
 
     static void addKvLines(
             List<Line> lines, String section,
-            Map<String, Object> map, Map<String, String> types, boolean 
changed) {
+            Map<String, Object> map, Map<String, String> types,
+            boolean changed, Map<String, Object> prevMap) {
         if (map == null || map.isEmpty()) {
             return;
         }
@@ -1871,11 +1895,16 @@ class HistoryTab implements MonitorTab {
                 // ignore
             }
             val = stripControlChars(val);
+            boolean keyChanged = changed && prevMap != null
+                    && (!prevMap.containsKey(entry.getKey())
+                            || !Objects.equals(prevMap.get(entry.getKey()), 
entry.getValue()));
+            Style keyStyle = keyChanged ? Style.EMPTY.fg(Color.YELLOW) : 
Style.EMPTY.fg(Color.CYAN);
+            Style valStyle = keyChanged ? Style.EMPTY.fg(Color.YELLOW) : 
Style.EMPTY;
             lines.add(Line.from(
                     Span.styled("   " + typeLabel, Style.EMPTY.dim()),
-                    Span.styled(entry.getKey(), Style.EMPTY.fg(Color.CYAN)),
+                    Span.styled(entry.getKey(), keyStyle),
                     Span.raw(" = "),
-                    Span.raw(val)));
+                    Span.styled(val, valStyle)));
         }
         lines.add(Line.from(Span.raw("")));
     }

Reply via email to