This is an automated email from the ASF dual-hosted git repository. luigidemasi pushed a commit to branch main in repository https://gitbox.apache.org/repos/asf/camel.git
commit 633daf544521dbed8f25b596ccab9e415f6cbe6c Author: Luigi De Masi <[email protected]> AuthorDate: Sat Oct 10 14:38:43 2026 +0200 CAMEL-25499: Remove namespace from the audit screen Remove Namespace from the TUI audit table, filter bar, keyboard selectors, filter editor and record heading. Keep the backend and CLI metadata contract. Update audit help, documentation and rendering/filter-navigation checks. Co-authored-by: OpenAI Codex <[email protected]> --- .../modules/ROOT/pages/camel-jbang-tui-observe.adoc | 6 +++--- .../jbang/core/commands/tui/SemanticAuditView.java | 19 +++++++++---------- .../src/main/resources/tui/help/semantic.md | 8 ++++---- .../dsl/jbang/core/commands/tui/SemanticTabTest.java | 15 ++++++++------- 4 files changed, 24 insertions(+), 24 deletions(-) diff --git a/docs/user-manual/modules/ROOT/pages/camel-jbang-tui-observe.adoc b/docs/user-manual/modules/ROOT/pages/camel-jbang-tui-observe.adoc index 9759c6b08d1d..b7648c293c24 100644 --- a/docs/user-manual/modules/ROOT/pages/camel-jbang-tui-observe.adoc +++ b/docs/user-manual/modules/ROOT/pages/camel-jbang-tui-observe.adoc @@ -470,7 +470,7 @@ policy decisions. Configure capture in the semantic DSL. Auditing works without connection and is independent of OpenTelemetry. Use `/` for exact `field=value` filters (`category`, `action`, `expert`, `routeId`, -`namespace`, `correlationId`, `since`), `n` for older records, `g` for the latest page and `r` to refresh. +`correlationId`, `since`), `n` for older records, `g` for the latest page and `r` to refresh. The header shows the global audit default, per-expert overrides and OpenTelemetry independently, with the active filters and reader below. Decisions are coloured by action. Timestamps use the local timezone shown below the table; the inspector also retains the full timestamp. @@ -508,6 +508,6 @@ accessible only to authorized operators. AI sessions load the tool when the sele integration exposes semantic audit history. Use `tui_get_table` to inspect the visible Audit screen. `r` refreshes the current audit page; `g` returns to the newest page. Repeated refreshes are coalesced. -In Audit, `c`, `a`, `e` and `N` open searchable selectors for category, action, expert and -namespace. Use arrows and `Enter` to apply, or `Esc` to cancel. Suggestions include values +In Audit, `c`, `a` and `e` open searchable selectors for category, action and expert. +Use arrows and `Enter` to apply, or `Esc` to cancel. Suggestions include values on the current page; `/` accepts arbitrary exact filters, including an ISO-8601 `since` timestamp. diff --git a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/SemanticAuditView.java b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/SemanticAuditView.java index 2c0f586adf40..54da2f6e2f11 100644 --- a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/SemanticAuditView.java +++ b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/SemanticAuditView.java @@ -58,7 +58,7 @@ import static org.apache.camel.dsl.jbang.core.commands.tui.TuiHelper.hint; /** Audit browsing owns its state independently of live definitions and inference drafts. */ final class SemanticAuditView { private static final Set<String> FILTERS - = Set.of("category", "action", "expert", "routeId", "namespace", "correlationId", "since"); + = Set.of("category", "action", "expert", "routeId", "correlationId", "since"); private final MonitorContext context; private final LongSupplier nanoTime; private long lastRefresh; @@ -341,7 +341,7 @@ final class SemanticAuditView { for (String token : text.trim().split("\\s+")) { String[] pair = token.split("=", 2); if (pair.length != 2 || !FILTERS.contains(pair[0]) || pair[1].isBlank() || pair[1].length() > 256) { - error = "Use field=value filters: category action expert routeId namespace correlationId since"; + error = "Use field=value filters: category action expert routeId correlationId since"; return false; } if ("since".equals(pair[0])) { @@ -458,7 +458,7 @@ final class SemanticAuditView { } return true; } - for (var shortcut : Map.of('c', "category", 'a', "action", 'e', "expert", 'N', "namespace").entrySet()) { + for (var shortcut : Map.of('c', "category", 'a', "action", 'e', "expert").entrySet()) { if (key.isChar(shortcut.getKey())) { chooseFilter(shortcut.getValue()); return true; @@ -632,8 +632,8 @@ final class SemanticAuditView { lines.add(Line.empty()); List<Span> query = new ArrayList<>(); query.add(Span.styled("Filters: ", Theme.label())); - for (String field : List.of("category", "action", "expert", "namespace")) { - String shortcut = "namespace".equals(field) ? "N" : field.substring(0, 1); + for (String field : List.of("category", "action", "expert")) { + String shortcut = field.substring(0, 1); String label = Character.toUpperCase(field.charAt(0)) + field.substring(1); query.add(Span.raw(" [")); query.add(Span.styled(shortcut, Theme.label().underlined())); @@ -670,7 +670,7 @@ final class SemanticAuditView { content.add(wide ? Row.from(Cell.from(time(row, "HH:mm:ss.SSS")), action, Cell.from(text(row, "category")), Cell.from(text(row, "operation")), Cell.from(text(row, "target")), - Cell.from(text(row, "namespace")), reason, Cell.from(text(row, "correlationId"))) + reason, Cell.from(text(row, "correlationId"))) : Row.from(Cell.from(time(row, "HH:mm:ss.SSS")), action, Cell.from(text(row, "category")), Cell.from(text(row, "expert")), reason)); } @@ -685,12 +685,12 @@ final class SemanticAuditView { } else { Table table = Table.builder().rows(content) .header((wide - ? Row.from("TIMESTAMP", "DECISION", "CATEGORY", "OPERATION", "TARGET", "NAMESPACE", "REASON CODE", + ? Row.from("TIMESTAMP", "DECISION", "CATEGORY", "OPERATION", "TARGET", "REASON CODE", "CORRELATION ID") : Row.from("TIMESTAMP", "DECISION", "CATEGORY", "EXPERT", "REASON CODE")).style(Theme.label())) .widths(wide ? List.of(Constraint.length(14), Constraint.length(9), Constraint.length(11), Constraint.length(13), - Constraint.percentage(15), Constraint.percentage(10), Constraint.fill(), + Constraint.percentage(15), Constraint.fill(), Constraint.length(16)) : List.of(Constraint.length(14), Constraint.length(9), Constraint.length(11), Constraint.percentage(20), Constraint.fill())) @@ -716,8 +716,7 @@ final class SemanticAuditView { boolean decision = "decision".equals(record.get("category")); Line heading = Line.from(Span.styled(text(record, decision ? "action" : "status").toUpperCase(Locale.ROOT) + " ", actionStyle(record).bold()), Span.styled(text(record, "target"), Theme.title()), - Span.styled(" " + text(record, "operation") + " · " + text(record, "namespace") + " · " - + text(record, "correlationId"), + Span.styled(" " + text(record, "operation") + " · " + text(record, "correlationId"), Theme.muted())); List<Line> left = new ArrayList<>(); String section = switch (text(record, "category")) { diff --git a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/resources/tui/help/semantic.md b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/resources/tui/help/semantic.md index 5a8bd444c72b..840688c5bf88 100644 --- a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/resources/tui/help/semantic.md +++ b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/resources/tui/help/semantic.md @@ -102,13 +102,13 @@ come from the semantic DSL; expert overrides take precedence over the master def Auditing and OpenTelemetry are independent. - `/` edits exact `field=value` filters, separated by spaces. Available fields are - `category`, `action`, `expert`, `routeId`, `namespace`, `correlationId` and `since`. + `category`, `action`, `expert`, `routeId`, `correlationId` and `since`. Example: `expert=security since=2026-10-09T12:00:00Z`. - Up/Down select a record. `Tab` focuses the inspector; arrows scroll its details. - `n` loads older records; `g` returns to the latest page; `r` refreshes the current page. - Esc leaves details or clears the current filter. -Wide terminals show timestamp, action, category, operation, target, namespace, reason and +Wide terminals show timestamp, action, category, operation, target, reason and correlation columns. Smaller terminals move fields into the inspector. A route action is only present for an explicit decision. Linked evaluations retain their captured result meaning; missing/evicted evidence is shown as unavailable. Backend status shows the master @@ -132,8 +132,8 @@ Route decisions and linked evaluations appear side by side on wide terminals and The newest page refreshes every second. `Space` pauses/resumes; older pages do not auto-refresh. The footer reports retention, evictions, dropped records and delivery errors. -In Audit, `c`, `a`, `e` and `N` open searchable selectors for category, action, expert and -namespace. Use arrows and `Enter` to apply, or `Esc` to cancel. Suggestions include values +In Audit, `c`, `a` and `e` open searchable selectors for category, action and expert. +Use arrows and `Enter` to apply, or `Esc` to cancel. Suggestions include values on the current page; `/` accepts arbitrary exact filters, including an ISO-8601 `since` timestamp. Audit input capture is disabled by default. Per-expert `audit.experts.<name>.input.enabled` retains the selected state; the inspector shows Input, Input (redacted), or an omission reason. Tab and arrows scroll longer input. diff --git a/dsl/camel-jbang/camel-jbang-plugin-tui/src/test/java/org/apache/camel/dsl/jbang/core/commands/tui/SemanticTabTest.java b/dsl/camel-jbang/camel-jbang-plugin-tui/src/test/java/org/apache/camel/dsl/jbang/core/commands/tui/SemanticTabTest.java index 60f36084ceb5..2f46eaf1b844 100644 --- a/dsl/camel-jbang/camel-jbang-plugin-tui/src/test/java/org/apache/camel/dsl/jbang/core/commands/tui/SemanticTabTest.java +++ b/dsl/camel-jbang/camel-jbang-plugin-tui/src/test/java/org/apache/camel/dsl/jbang/core/commands/tui/SemanticTabTest.java @@ -96,7 +96,8 @@ class SemanticTabTest { "security: ON (override)", "decisions: OFF (override)", "OpenTelemetry: OFF", "Filters:", "Route decision", "Linked evaluation", "Definition: screenPrompt", "Result: true", "BLOCK", "Policy: support-access", "Model: detector-v2", "Input captured only by expert opt-in", "Memory: 2 / 1000", - "No delivery errors reported", "refresh 1 s"); + "No delivery errors reported", "refresh 1 s") + .doesNotContain("NAMESPACE", "Namespace:", "audit-test-namespace"); assertThat(TuiTestHelper.renderToString(tab, 80, 24)).contains("CATEGORY", "EXPERT"); } } @@ -169,7 +170,7 @@ class SemanticTabTest { try (var runtime = new Runtime()) { var tab = loaded(runtime); tab.setInputValue("audit.view", ""); - tab.setInputValue("audit.filter", "namespace=default"); + tab.setInputValue("audit.filter", "routeId=prompt-screen"); await().atMost(5, TimeUnit.SECONDS).until(() -> !tab.ensureDataLoaded()); tab.handleKeyEvent(KeyEvent.ofChar('c')); assertThat(tab.getTableDataAsJson()).containsEntry("filterField", "category"); @@ -180,7 +181,7 @@ class SemanticTabTest { tab.handleKeyEvent(KeyEvent.ofKey(KeyCode.ENTER)); await().atMost(5, TimeUnit.SECONDS).until(() -> !tab.ensureDataLoaded()); assertThat(new JsonObject(tab.getTableDataAsJson().getMap("filters"))) - .containsEntry("category", "decision").containsEntry("namespace", "default"); + .containsEntry("category", "decision").containsEntry("routeId", "prompt-screen"); tab.handleKeyEvent(KeyEvent.ofChar('a')); tab.handleEscape(); assertThat(new JsonObject(tab.getTableDataAsJson().getMap("filters"))).doesNotContainKey("action"); @@ -191,7 +192,7 @@ class SemanticTabTest { tab.handleKeyEvent(KeyEvent.ofKey(KeyCode.ENTER)); await().atMost(5, TimeUnit.SECONDS).until(() -> !tab.ensureDataLoaded()); assertThat(new JsonObject(tab.getTableDataAsJson().getMap("filters"))) - .containsOnlyKeys("namespace"); + .containsOnlyKeys("routeId"); } } @@ -299,12 +300,12 @@ class SemanticTabTest { try (var runtime = new Runtime()) { var tab = loaded(runtime); tab.setInputValue("audit.view", ""); - tab.setInputValue("audit.filter", "category=decision namespace=default"); + tab.setInputValue("audit.filter", "category=decision routeId=prompt-screen"); await().atMost(5, TimeUnit.SECONDS).until(() -> !tab.ensureDataLoaded()); tab.handleKeyEvent(KeyEvent.ofKey(KeyCode.ENTER)); await().atMost(5, TimeUnit.SECONDS).until(() -> !tab.ensureDataLoaded()); assertThat(tab.getTableDataAsJson()).containsEntry("selectedEventId", "evaluation-1") - .containsEntry("filter", "category=decision namespace=default"); + .containsEntry("filter", "category=decision routeId=prompt-screen"); assertThat(TuiTestHelper.renderToString(tab, 180, 45)).contains("Expert evaluation", "Result: true", "Esc / Enter returns to the decision"); tab.handleEscape(); @@ -1272,7 +1273,7 @@ class SemanticTabTest { "operation", "tools/call", "target", "support-request", "reasonCode", "prompt_injection", "timestamp", "2026-10-09T14:20:29.418Z", "evidence", List.of("evaluation-1"))); decision.put("policyId", "support-access"); - decision.put("namespace", "default"); + decision.put("namespace", "audit-test-namespace"); JsonObject status = new JsonObject( Map.of("enabled", true, "experts", new JsonObject(Map.of("security", true, "decisions", false)), "reader", "memory", "dropped", 0, "sinkErrors", new JsonObject(), "openTelemetry",
