davsclaus commented on code in PR #29397:
URL: https://github.com/apache/camel/pull/29397#discussion_r4505484402


##########
dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/ChaosSuggestList.java:
##########
@@ -0,0 +1,171 @@
+/*
+ * 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.camel.dsl.jbang.core.commands.tui;
+
+import java.util.ArrayList;
+import java.util.EnumSet;
+import java.util.List;
+
+import dev.tamboui.layout.Constraint;
+import dev.tamboui.layout.Layout;
+import dev.tamboui.layout.Rect;
+import dev.tamboui.style.Overflow;
+import dev.tamboui.style.Style;
+import dev.tamboui.terminal.Frame;
+import dev.tamboui.text.Line;
+import dev.tamboui.text.Span;
+import dev.tamboui.text.Text;
+import dev.tamboui.tui.event.KeyEvent;
+import dev.tamboui.widgets.Clear;
+import dev.tamboui.widgets.block.Block;
+import dev.tamboui.widgets.block.BorderType;
+import dev.tamboui.widgets.block.Borders;
+import dev.tamboui.widgets.paragraph.Paragraph;
+import org.apache.camel.util.json.JsonObject;
+
+/**
+ * What to try ({@code w} on the Chaos screen, CAMEL-26727): the rules the 
integration suggests per route from what its
+ * routes do, the most worth trying first, each with why. Enter types the 
selected rule in, to change or add.
+ */
+final class ChaosSuggestList {
+
+    /** What a key did to the list. */
+    enum Outcome {
+        NONE,
+        CLOSED,
+        PICKED
+    }
+
+    /** A suggestion, as the chaos action of the integration gives it. */
+    record Item(String route, String kind, String title, String rule, String 
why, boolean tried) {
+    }
+
+    private final String name;
+    private final List<Item> items = new ArrayList<>();
+    private int selected;
+
+    ChaosSuggestList(String name, JsonObject reply) {
+        this.name = name;
+        if (reply != null && reply.getCollection("suggestions") != null) {
+            for (Object o : reply.getCollection("suggestions")) {
+                if (o instanceof JsonObject jo && jo.getString("rule") != 
null) {
+                    items.add(new Item(
+                            jo.getString("route"), jo.getString("kind"), 
jo.getString("title"),
+                            jo.getString("rule"), jo.getString("why"), 
jo.getBooleanOrDefault("tried", false)));
+                }
+            }
+        }
+    }
+
+    List<Item> items() {
+        return items;
+    }
+
+    /** The selected suggestion, or null when there are none. */
+    Item selected() {
+        return items.isEmpty() ? null : items.get(selected);
+    }
+
+    Outcome handleKey(KeyEvent ke) {
+        if (ke.isCancel()) {
+            return Outcome.CLOSED;
+        }
+        if (ke.isUp() && selected > 0) {
+            selected--;
+        } else if (ke.isDown() && selected < items.size() - 1) {
+            selected++;
+        } else if (ke.isConfirm() && !items.isEmpty()) {
+            return Outcome.PICKED;
+        }
+        return Outcome.NONE;
+    }
+
+    void render(Frame frame, Rect area) {
+        int width = Math.min(area.width() - 4, 150);
+        int height = Math.min(area.height() - 2, 30);
+        Rect popup = DialogHelper.centered(area, width, height);
+        frame.renderWidget(Clear.INSTANCE, popup);
+        Block outer = 
Block.builder().borderType(BorderType.ROUNDED).borders(Borders.ALL).borderStyle(Theme.warning())
+                .title(" What to try in " + name + " ").build();
+        frame.renderWidget(outer, popup);
+        Rect inner = outer.inner(popup);
+        if (items.isEmpty()) {
+            
frame.renderWidget(Paragraph.builder().overflow(Overflow.WRAP_WORD).text(Text.from(List.of(Line.empty(),
+                    Line.from(Span.styled(" Nothing to suggest: the routes 
call nothing remote, and have no input from"
+                                          + " outside, dead letter channel or 
hand-off to another route",
+                            Theme.muted())))))
+                    .build(),
+                    inner);
+            return;
+        }
+        List<Rect> cols = Layout.horizontal()
+                .constraints(Constraint.length(Math.min(56, inner.width() / 
2)), Constraint.fill())
+                .split(inner);
+        renderList(frame, cols.get(0));
+        renderDetail(frame, cols.get(1));
+    }
+
+    private void renderList(Frame frame, Rect area) {
+        List<Line> lines = new ArrayList<>();
+        lines.add(Line.from(Span.styled(" The most worth trying first", 
Style.EMPTY.bold())));
+        int selectedLine = 0;
+        for (int i = 0; i < items.size(); i++) {
+            Item item = items.get(i);
+            boolean sel = i == selected;
+            if (sel) {
+                selectedLine = lines.size();
+            }
+            Style style = sel ? Theme.selectionBg().bold() : Style.EMPTY;
+            List<Span> spans = new ArrayList<>();
+            spans.add(Span.styled((sel ? " > " : "   ") + item.title(), 
style));
+            spans.add(Span.styled("  " + item.route(), Theme.muted()));
+            if (item.tried()) {
+                spans.add(Span.styled("  tried", Theme.success()));
+            }
+            lines.add(Line.from(spans));
+        }
+        // keep the selected one in sight
+        int scroll = Math.max(0, selectedLine - (area.height() - 2));
+        
frame.renderWidget(Paragraph.builder().text(Text.from(lines)).scroll(scroll)
+                
.block(Block.builder().borders(EnumSet.of(Borders.RIGHT)).borderStyle(Theme.border()).build()).build(),
 area);
+    }
+
+    private void renderDetail(Frame frame, Rect area) {
+        Item item = selected();
+        List<Line> lines = new ArrayList<>();
+        lines.add(Line.from(Span.styled(" " + item.title(), 
Style.EMPTY.bold()),
+                Span.styled("  route " + item.route() + " · " + item.kind(), 
Theme.muted())));
+        lines.add(Line.empty());
+        lines.add(Line.from(Span.raw(" " + item.why())));
+        lines.add(Line.empty());
+        lines.add(Line.from(Span.styled(" " + item.rule(), Theme.warning())));
+        if (item.tried()) {
+            lines.add(Line.empty());
+            lines.add(Line.from(Span.styled(" A rule of this kind was tried in 
route " + item.route() + " already",
+                    Theme.success())));
+        }

Review Comment:
   Fixed in c59d5975b874: this PR no longer reads or shows a `tried` flag. It 
belongs to the stacked #29398 (CAMEL-26728), where `ChaosManager.suggest()` 
sets it from what has been tried per route, and the list shows it.
   
   _Claude Code on behalf of Claus Ibsen_



##########
components/camel-chaos/src/main/java/org/apache/camel/component/chaos/ChaosManager.java:
##########
@@ -461,6 +461,33 @@ public boolean hasRule(String id) {
         }
     }
 
+    /**
+     * What to try (CAMEL-26727): rules suggested per route from what the 
routes do, the most worth trying first, each
+     * with the known rule it comes from and why, such as an HTTP call without 
a circuit breaker, a dead letter channel,
+     * or a hand-off to another route over seda.
+     *
+     * @return {@code suggestions}: a list of {@code route}, {@code kind}, 
{@code recipe}, {@code title}, {@code rule}
+     *         and {@code why}
+     */
+    public Map<String, Object> suggest() {
+        JsonArray list = new JsonArray();
+        for (ChaosAdvisor.Suggestion s : ChaosAdvisor.suggest(camelContext)) {
+            JsonObject jo = new JsonObject();
+            jo.put("route", s.route());
+            jo.put("kind", s.kind().key);
+            if (s.recipe() != null) {
+                jo.put("recipe", s.recipe());
+            }
+            jo.put("title", s.title());
+            jo.put("rule", s.rule());
+            jo.put("why", s.why());

Review Comment:
   Fixed in c59d5975b874: this PR no longer reads or shows a `tried` flag. It 
belongs to the stacked #29398 (CAMEL-26728), where `ChaosManager.suggest()` 
sets it from what has been tried per route, and the list shows it.
   
   _Claude Code on behalf of Claus Ibsen_



##########
dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/ChaosSuggestList.java:
##########
@@ -0,0 +1,171 @@
+/*
+ * 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.camel.dsl.jbang.core.commands.tui;
+
+import java.util.ArrayList;
+import java.util.EnumSet;
+import java.util.List;
+
+import dev.tamboui.layout.Constraint;
+import dev.tamboui.layout.Layout;
+import dev.tamboui.layout.Rect;
+import dev.tamboui.style.Overflow;
+import dev.tamboui.style.Style;
+import dev.tamboui.terminal.Frame;
+import dev.tamboui.text.Line;
+import dev.tamboui.text.Span;
+import dev.tamboui.text.Text;
+import dev.tamboui.tui.event.KeyEvent;
+import dev.tamboui.widgets.Clear;
+import dev.tamboui.widgets.block.Block;
+import dev.tamboui.widgets.block.BorderType;
+import dev.tamboui.widgets.block.Borders;
+import dev.tamboui.widgets.paragraph.Paragraph;
+import org.apache.camel.util.json.JsonObject;
+
+/**
+ * What to try ({@code w} on the Chaos screen, CAMEL-26727): the rules the 
integration suggests per route from what its
+ * routes do, the most worth trying first, each with why. Enter types the 
selected rule in, to change or add.
+ */
+final class ChaosSuggestList {
+
+    /** What a key did to the list. */
+    enum Outcome {
+        NONE,
+        CLOSED,
+        PICKED
+    }
+
+    /** A suggestion, as the chaos action of the integration gives it. */
+    record Item(String route, String kind, String title, String rule, String 
why, boolean tried) {
+    }
+
+    private final String name;
+    private final List<Item> items = new ArrayList<>();
+    private int selected;
+
+    ChaosSuggestList(String name, JsonObject reply) {
+        this.name = name;
+        if (reply != null && reply.getCollection("suggestions") != null) {
+            for (Object o : reply.getCollection("suggestions")) {
+                if (o instanceof JsonObject jo && jo.getString("rule") != 
null) {
+                    items.add(new Item(
+                            jo.getString("route"), jo.getString("kind"), 
jo.getString("title"),
+                            jo.getString("rule"), jo.getString("why"), 
jo.getBooleanOrDefault("tried", false)));
+                }
+            }
+        }
+    }
+
+    List<Item> items() {
+        return items;
+    }
+
+    /** The selected suggestion, or null when there are none. */
+    Item selected() {
+        return items.isEmpty() ? null : items.get(selected);
+    }
+
+    Outcome handleKey(KeyEvent ke) {
+        if (ke.isCancel()) {
+            return Outcome.CLOSED;
+        }
+        if (ke.isUp() && selected > 0) {
+            selected--;
+        } else if (ke.isDown() && selected < items.size() - 1) {
+            selected++;
+        } else if (ke.isConfirm() && !items.isEmpty()) {
+            return Outcome.PICKED;
+        }
+        return Outcome.NONE;
+    }
+
+    void render(Frame frame, Rect area) {
+        int width = Math.min(area.width() - 4, 150);
+        int height = Math.min(area.height() - 2, 30);
+        Rect popup = DialogHelper.centered(area, width, height);
+        frame.renderWidget(Clear.INSTANCE, popup);
+        Block outer = 
Block.builder().borderType(BorderType.ROUNDED).borders(Borders.ALL).borderStyle(Theme.warning())
+                .title(" What to try in " + name + " ").build();
+        frame.renderWidget(outer, popup);
+        Rect inner = outer.inner(popup);
+        if (items.isEmpty()) {
+            
frame.renderWidget(Paragraph.builder().overflow(Overflow.WRAP_WORD).text(Text.from(List.of(Line.empty(),
+                    Line.from(Span.styled(" Nothing to suggest: the routes 
call nothing remote, and have no input from"
+                                          + " outside, dead letter channel or 
hand-off to another route",
+                            Theme.muted())))))
+                    .build(),
+                    inner);
+            return;
+        }
+        List<Rect> cols = Layout.horizontal()
+                .constraints(Constraint.length(Math.min(56, inner.width() / 
2)), Constraint.fill())
+                .split(inner);
+        renderList(frame, cols.get(0));
+        renderDetail(frame, cols.get(1));
+    }
+
+    private void renderList(Frame frame, Rect area) {
+        List<Line> lines = new ArrayList<>();
+        lines.add(Line.from(Span.styled(" The most worth trying first", 
Style.EMPTY.bold())));
+        int selectedLine = 0;
+        for (int i = 0; i < items.size(); i++) {
+            Item item = items.get(i);
+            boolean sel = i == selected;
+            if (sel) {
+                selectedLine = lines.size();
+            }
+            Style style = sel ? Theme.selectionBg().bold() : Style.EMPTY;
+            List<Span> spans = new ArrayList<>();
+            spans.add(Span.styled((sel ? " > " : "   ") + item.title(), 
style));
+            spans.add(Span.styled("  " + item.route(), Theme.muted()));
+            if (item.tried()) {
+                spans.add(Span.styled("  tried", Theme.success()));
+            }

Review Comment:
   Fixed in c59d5975b874: this PR no longer reads or shows a `tried` flag. It 
belongs to the stacked #29398 (CAMEL-26728), where `ChaosManager.suggest()` 
sets it from what has been tried per route, and the list shows it.
   
   _Claude Code on behalf of Claus Ibsen_



##########
dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/ChaosSuggestList.java:
##########
@@ -0,0 +1,171 @@
+/*
+ * 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.camel.dsl.jbang.core.commands.tui;
+
+import java.util.ArrayList;
+import java.util.EnumSet;
+import java.util.List;
+
+import dev.tamboui.layout.Constraint;
+import dev.tamboui.layout.Layout;
+import dev.tamboui.layout.Rect;
+import dev.tamboui.style.Overflow;
+import dev.tamboui.style.Style;
+import dev.tamboui.terminal.Frame;
+import dev.tamboui.text.Line;
+import dev.tamboui.text.Span;
+import dev.tamboui.text.Text;
+import dev.tamboui.tui.event.KeyEvent;
+import dev.tamboui.widgets.Clear;
+import dev.tamboui.widgets.block.Block;
+import dev.tamboui.widgets.block.BorderType;
+import dev.tamboui.widgets.block.Borders;
+import dev.tamboui.widgets.paragraph.Paragraph;
+import org.apache.camel.util.json.JsonObject;
+
+/**
+ * What to try ({@code w} on the Chaos screen, CAMEL-26727): the rules the 
integration suggests per route from what its
+ * routes do, the most worth trying first, each with why. Enter types the 
selected rule in, to change or add.
+ */
+final class ChaosSuggestList {
+
+    /** What a key did to the list. */
+    enum Outcome {
+        NONE,
+        CLOSED,
+        PICKED
+    }
+
+    /** A suggestion, as the chaos action of the integration gives it. */
+    record Item(String route, String kind, String title, String rule, String 
why, boolean tried) {
+    }
+
+    private final String name;
+    private final List<Item> items = new ArrayList<>();
+    private int selected;
+
+    ChaosSuggestList(String name, JsonObject reply) {
+        this.name = name;
+        if (reply != null && reply.getCollection("suggestions") != null) {
+            for (Object o : reply.getCollection("suggestions")) {
+                if (o instanceof JsonObject jo && jo.getString("rule") != 
null) {
+                    items.add(new Item(
+                            jo.getString("route"), jo.getString("kind"), 
jo.getString("title"),
+                            jo.getString("rule"), jo.getString("why"), 
jo.getBooleanOrDefault("tried", false)));
+                }
+            }
+        }
+    }
+
+    List<Item> items() {
+        return items;
+    }
+
+    /** The selected suggestion, or null when there are none. */
+    Item selected() {
+        return items.isEmpty() ? null : items.get(selected);
+    }
+
+    Outcome handleKey(KeyEvent ke) {
+        if (ke.isCancel()) {
+            return Outcome.CLOSED;
+        }
+        if (ke.isUp() && selected > 0) {
+            selected--;
+        } else if (ke.isDown() && selected < items.size() - 1) {
+            selected++;
+        } else if (ke.isConfirm() && !items.isEmpty()) {
+            return Outcome.PICKED;
+        }
+        return Outcome.NONE;
+    }
+
+    void render(Frame frame, Rect area) {
+        int width = Math.min(area.width() - 4, 150);
+        int height = Math.min(area.height() - 2, 30);
+        Rect popup = DialogHelper.centered(area, width, height);
+        frame.renderWidget(Clear.INSTANCE, popup);
+        Block outer = 
Block.builder().borderType(BorderType.ROUNDED).borders(Borders.ALL).borderStyle(Theme.warning())
+                .title(" What to try in " + name + " ").build();
+        frame.renderWidget(outer, popup);
+        Rect inner = outer.inner(popup);
+        if (items.isEmpty()) {
+            
frame.renderWidget(Paragraph.builder().overflow(Overflow.WRAP_WORD).text(Text.from(List.of(Line.empty(),
+                    Line.from(Span.styled(" Nothing to suggest: the routes 
call nothing remote, and have no input from"
+                                          + " outside, dead letter channel or 
hand-off to another route",
+                            Theme.muted())))))
+                    .build(),
+                    inner);
+            return;
+        }
+        List<Rect> cols = Layout.horizontal()
+                .constraints(Constraint.length(Math.min(56, inner.width() / 
2)), Constraint.fill())
+                .split(inner);
+        renderList(frame, cols.get(0));
+        renderDetail(frame, cols.get(1));
+    }
+
+    private void renderList(Frame frame, Rect area) {
+        List<Line> lines = new ArrayList<>();
+        lines.add(Line.from(Span.styled(" The most worth trying first", 
Style.EMPTY.bold())));
+        int selectedLine = 0;
+        for (int i = 0; i < items.size(); i++) {
+            Item item = items.get(i);
+            boolean sel = i == selected;
+            if (sel) {
+                selectedLine = lines.size();
+            }
+            Style style = sel ? Theme.selectionBg().bold() : Style.EMPTY;
+            List<Span> spans = new ArrayList<>();
+            spans.add(Span.styled((sel ? " > " : "   ") + item.title(), 
style));
+            spans.add(Span.styled("  " + item.route(), Theme.muted()));
+            if (item.tried()) {
+                spans.add(Span.styled("  tried", Theme.success()));
+            }
+            lines.add(Line.from(spans));
+        }
+        // keep the selected one in sight
+        int scroll = Math.max(0, selectedLine - (area.height() - 2));
+        
frame.renderWidget(Paragraph.builder().text(Text.from(lines)).scroll(scroll)
+                
.block(Block.builder().borders(EnumSet.of(Borders.RIGHT)).borderStyle(Theme.border()).build()).build(),
 area);
+    }
+
+    private void renderDetail(Frame frame, Rect area) {
+        Item item = selected();
+        List<Line> lines = new ArrayList<>();
+        lines.add(Line.from(Span.styled(" " + item.title(), 
Style.EMPTY.bold()),
+                Span.styled("  route " + item.route() + " · " + item.kind(), 
Theme.muted())));
+        lines.add(Line.empty());
+        lines.add(Line.from(Span.raw(" " + item.why())));
+        lines.add(Line.empty());
+        lines.add(Line.from(Span.styled(" " + item.rule(), Theme.warning())));
+        if (item.tried()) {
+            lines.add(Line.empty());
+            lines.add(Line.from(Span.styled(" A rule of this kind was tried in 
route " + item.route() + " already",
+                    Theme.success())));
+        }

Review Comment:
   Fixed in c59d5975b874: this PR no longer reads or shows a `tried` flag. It 
belongs to the stacked #29398 (CAMEL-26728), where `ChaosManager.suggest()` 
sets it from what has been tried per route, and the list shows it.
   
   _Claude Code on behalf of Claus Ibsen_



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to