feat: use endpointUri for cross-route drill-down instead of label parsing
All checks were successful
CI / cleanup-branch (push) Has been skipped
CI / build (push) Successful in 1m2s
CI / docker (push) Successful in 1m0s
CI / deploy-feature (push) Has been skipped
CI / deploy (push) Successful in 38s

Server:
- Add endpointUri to PositionedNode (from RouteNode)
- Add fromEndpointUri to RouteSummary (catalog API)
- Catalog controller resolves endpoint URI from diagram store

UI:
- Build endpointRouteMap from catalog's fromEndpointUri field
- Drill-down uses exact match on node.endpointUri against the map
- Remove label parsing heuristics (extractTargetEndpoint, camelToKebab)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
hsiegeln
2026-03-28 18:31:08 +01:00
parent 0516207e83
commit e5e6175aca
9 changed files with 67 additions and 44 deletions

View File

@@ -3,9 +3,11 @@ package com.cameleer3.server.app.controller;
import com.cameleer3.server.app.dto.AgentSummary;
import com.cameleer3.server.app.dto.AppCatalogEntry;
import com.cameleer3.server.app.dto.RouteSummary;
import com.cameleer3.common.graph.RouteGraph;
import com.cameleer3.server.core.agent.AgentInfo;
import com.cameleer3.server.core.agent.AgentRegistryService;
import com.cameleer3.server.core.agent.AgentState;
import com.cameleer3.server.core.storage.DiagramStore;
import com.cameleer3.server.core.storage.StatsStore;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
@@ -34,10 +36,14 @@ import java.util.stream.Collectors;
public class RouteCatalogController {
private final AgentRegistryService registryService;
private final DiagramStore diagramStore;
private final JdbcTemplate jdbc;
public RouteCatalogController(AgentRegistryService registryService, JdbcTemplate jdbc) {
public RouteCatalogController(AgentRegistryService registryService,
DiagramStore diagramStore,
JdbcTemplate jdbc) {
this.registryService = registryService;
this.diagramStore = diagramStore;
this.jdbc = jdbc;
}
@@ -114,12 +120,14 @@ public class RouteCatalogController {
// Routes
Set<String> routeIds = routesByApp.getOrDefault(appId, Set.of());
List<String> agentIds = agents.stream().map(AgentInfo::id).toList();
List<RouteSummary> routeSummaries = routeIds.stream()
.map(routeId -> {
String key = appId + "/" + routeId;
long count = routeExchangeCounts.getOrDefault(key, 0L);
Instant lastSeen = routeLastSeen.get(key);
return new RouteSummary(routeId, count, lastSeen);
String fromUri = resolveFromEndpointUri(routeId, agentIds);
return new RouteSummary(routeId, count, lastSeen, fromUri);
})
.toList();
@@ -141,6 +149,15 @@ public class RouteCatalogController {
return ResponseEntity.ok(catalog);
}
/** Resolve the from() endpoint URI for a route by looking up its diagram. */
private String resolveFromEndpointUri(String routeId, List<String> agentIds) {
return diagramStore.findContentHashForRouteByAgents(routeId, agentIds)
.flatMap(diagramStore::findByContentHash)
.map(RouteGraph::getRoot)
.map(root -> root.getEndpointUri())
.orElse(null);
}
private String computeWorstHealth(List<AgentInfo> agents) {
boolean hasDead = false;
boolean hasStale = false;

View File

@@ -666,7 +666,7 @@ public class ElkDiagramRenderer implements DiagramRenderer {
getAbsoluteX(wrapperElk, rootNode),
getAbsoluteY(wrapperElk, rootNode),
wrapperElk.getWidth(), wrapperElk.getHeight(),
wrapperChildren));
wrapperChildren, null));
ctx.compoundInfos.put(wrapperId, new CompoundInfo(wrapperId, Color.WHITE));
}
// Handler children in order: DO_FINALLY first, then DO_CATCH
@@ -693,7 +693,8 @@ public class ElkDiagramRenderer implements DiagramRenderer {
rn.getType() != null ? rn.getType().name() : "UNKNOWN",
absX, absY,
elkNode.getWidth(), elkNode.getHeight(),
children
children,
rn.getEndpointUri()
);
}

View File

@@ -9,5 +9,7 @@ import java.time.Instant;
public record RouteSummary(
@NotNull String routeId,
@NotNull long exchangeCount,
Instant lastSeen
Instant lastSeen,
@Schema(description = "The from() endpoint URI, e.g. 'direct:processOrder'")
String fromEndpointUri
) {}