feat: migrate UI to @cameleer/design-system, add backend endpoints
Backend: - Add agent_events table (V5) and lifecycle event recording - Add route catalog endpoint (GET /routes/catalog) - Add route metrics endpoint (GET /routes/metrics) - Add agent events endpoint (GET /agents/events-log) - Enrich AgentInstanceResponse with tps, errorRate, activeRoutes, uptimeSeconds - Add TimescaleDB retention/compression policies (V6) Frontend: - Replace custom Mission Control UI with @cameleer/design-system components - Rebuild all pages: Dashboard, ExchangeDetail, RoutesMetrics, AgentHealth, AgentInstance, RBAC, AuditLog, OIDC, DatabaseAdmin, OpenSearchAdmin, Swagger - New LayoutShell with design system AppShell, Sidebar, TopBar, CommandPalette - Consume design system from Gitea npm registry (@cameleer/design-system@0.0.1) - Add .npmrc for scoped registry, update Dockerfile with REGISTRY_TOKEN arg CI: - Pass REGISTRY_TOKEN build-arg to UI Docker build step Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,24 @@
|
||||
package com.cameleer3.server.app.dto;
|
||||
|
||||
import com.cameleer3.server.core.agent.AgentEventRecord;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
|
||||
import java.time.Instant;
|
||||
|
||||
@Schema(description = "Agent lifecycle event")
|
||||
public record AgentEventResponse(
|
||||
@NotNull long id,
|
||||
@NotNull String agentId,
|
||||
@NotNull String appId,
|
||||
@NotNull String eventType,
|
||||
String detail,
|
||||
@NotNull Instant timestamp
|
||||
) {
|
||||
public static AgentEventResponse from(AgentEventRecord record) {
|
||||
return new AgentEventResponse(
|
||||
record.id(), record.agentId(), record.appId(),
|
||||
record.eventType(), record.detail(), record.timestamp()
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -4,10 +4,11 @@ import com.cameleer3.server.core.agent.AgentInfo;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.time.Instant;
|
||||
import java.util.List;
|
||||
|
||||
@Schema(description = "Agent instance summary")
|
||||
@Schema(description = "Agent instance summary with runtime metrics")
|
||||
public record AgentInstanceResponse(
|
||||
@NotNull String id,
|
||||
@NotNull String name,
|
||||
@@ -15,13 +16,29 @@ public record AgentInstanceResponse(
|
||||
@NotNull String status,
|
||||
@NotNull List<String> routeIds,
|
||||
@NotNull Instant registeredAt,
|
||||
@NotNull Instant lastHeartbeat
|
||||
@NotNull Instant lastHeartbeat,
|
||||
double tps,
|
||||
double errorRate,
|
||||
int activeRoutes,
|
||||
int totalRoutes,
|
||||
long uptimeSeconds
|
||||
) {
|
||||
public static AgentInstanceResponse from(AgentInfo info) {
|
||||
long uptime = Duration.between(info.registeredAt(), Instant.now()).toSeconds();
|
||||
return new AgentInstanceResponse(
|
||||
info.id(), info.name(), info.group(),
|
||||
info.state().name(), info.routeIds(),
|
||||
info.registeredAt(), info.lastHeartbeat()
|
||||
info.registeredAt(), info.lastHeartbeat(),
|
||||
0.0, 0.0,
|
||||
0, info.routeIds() != null ? info.routeIds().size() : 0,
|
||||
uptime
|
||||
);
|
||||
}
|
||||
|
||||
public AgentInstanceResponse withMetrics(double tps, double errorRate, int activeRoutes) {
|
||||
return new AgentInstanceResponse(
|
||||
id, name, group, status, routeIds, registeredAt, lastHeartbeat,
|
||||
tps, errorRate, activeRoutes, totalRoutes, uptimeSeconds
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
package com.cameleer3.server.app.dto;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
|
||||
@Schema(description = "Summary of an agent instance for sidebar display")
|
||||
public record AgentSummary(
|
||||
@NotNull String id,
|
||||
@NotNull String name,
|
||||
@NotNull String status,
|
||||
@NotNull double tps
|
||||
) {}
|
||||
@@ -0,0 +1,16 @@
|
||||
package com.cameleer3.server.app.dto;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Schema(description = "Application catalog entry with routes and agents")
|
||||
public record AppCatalogEntry(
|
||||
@NotNull String appId,
|
||||
@NotNull List<RouteSummary> routes,
|
||||
@NotNull List<AgentSummary> agents,
|
||||
@NotNull int agentCount,
|
||||
@NotNull String health,
|
||||
@NotNull long exchangeCount
|
||||
) {}
|
||||
@@ -0,0 +1,19 @@
|
||||
package com.cameleer3.server.app.dto;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Schema(description = "Aggregated route performance metrics")
|
||||
public record RouteMetrics(
|
||||
@NotNull String routeId,
|
||||
@NotNull String appId,
|
||||
@NotNull long exchangeCount,
|
||||
@NotNull double successRate,
|
||||
@NotNull double avgDurationMs,
|
||||
@NotNull double p99DurationMs,
|
||||
@NotNull double errorRate,
|
||||
@NotNull double throughputPerSec,
|
||||
@NotNull List<Double> sparkline
|
||||
) {}
|
||||
@@ -0,0 +1,13 @@
|
||||
package com.cameleer3.server.app.dto;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
|
||||
import java.time.Instant;
|
||||
|
||||
@Schema(description = "Summary of a route within an application")
|
||||
public record RouteSummary(
|
||||
@NotNull String routeId,
|
||||
@NotNull long exchangeCount,
|
||||
Instant lastSeen
|
||||
) {}
|
||||
Reference in New Issue
Block a user