fix: persist environment selection in Zustand store instead of URL params
All checks were successful
CI / cleanup-branch (push) Has been skipped
CI / build (push) Successful in 1m5s
CI / docker (push) Successful in 57s
CI / deploy-feature (push) Has been skipped
CI / deploy (push) Successful in 36s

Environment selector was losing its value on navigation because URL search
params were silently dropped by navigate() calls. Moved to a Zustand store
with localStorage persistence so the selection survives navigation, page
refresh, and new tabs. Switching environment now resets all filters, clears
URL params, invalidates queries, and remounts pages via Outlet key. Also
syncs openapi.json schema with running backend.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
hsiegeln
2026-04-04 17:12:16 +02:00
parent 37eb56332a
commit 69055f7d74
4 changed files with 157 additions and 42 deletions

144
ui/src/api/schema.d.ts vendored
View File

@@ -190,7 +190,7 @@ export interface paths {
put?: never;
/**
* Ingest application log entries
* @description Accepts a batch of log entries from an agent. Entries are stored in the configured log store.
* @description Accepts a batch of log entries from an agent. Entries are buffered and flushed periodically.
*/
post: operations["ingestLogs"];
delete?: never;
@@ -372,7 +372,7 @@ export interface paths {
put?: never;
/**
* Agent heartbeat ping
* @description Updates the agent's last heartbeat timestamp
* @description Updates the agent's last heartbeat timestamp. Auto-registers the agent if not in registry (e.g. after server restart).
*/
post: operations["heartbeat"];
delete?: never;
@@ -472,7 +472,7 @@ export interface paths {
put?: never;
/**
* Send command to all agents in a group
* @description Sends a command to all LIVE agents in the specified group
* @description Sends a command to all LIVE agents in the specified group and waits for responses
*/
post: operations["sendGroupCommand"];
delete?: never;
@@ -762,6 +762,23 @@ export interface paths {
patch?: never;
trace?: never;
};
"/search/attributes/keys": {
parameters: {
query?: never;
header?: never;
path?: never;
cookie?: never;
};
/** Distinct attribute key names across all executions */
get: operations["attributeKeys"];
put?: never;
post?: never;
delete?: never;
options?: never;
head?: never;
patch?: never;
trace?: never;
};
"/routes/metrics": {
parameters: {
query?: never;
@@ -831,7 +848,7 @@ export interface paths {
};
/**
* Search application log entries
* @description Returns log entries for a given application, optionally filtered by agent, level, time range, and text query
* @description Returns log entries with cursor-based pagination and level count aggregation. Supports free-text search, multi-level filtering, and optional application scoping.
*/
get: operations["searchLogs"];
put?: never;
@@ -1350,6 +1367,24 @@ export interface components {
/** Format: int32 */
version?: number;
};
AgentResponse: {
agentId?: string;
status?: string;
message?: string;
};
CommandGroupResponse: {
success?: boolean;
/** Format: int32 */
total?: number;
/** Format: int32 */
responded?: number;
responses?: components["schemas"]["AgentResponse"][];
timedOut?: string[];
};
ConfigUpdateResponse: {
config?: components["schemas"]["ApplicationConfig"];
pushResult?: components["schemas"]["CommandGroupResponse"];
};
UpdateUserRequest: {
displayName?: string;
email?: string;
@@ -1610,6 +1645,15 @@ export interface components {
accessToken: string;
refreshToken: string;
};
HeartbeatRequest: {
routeStates?: {
[key: string]: string;
};
capabilities?: {
[key: string]: Record<string, never>;
};
environmentId?: string;
};
/** @description Command to send to agent(s) */
CommandRequest: {
/** @description Command type: config-update, deep-trace, or replay */
@@ -1633,6 +1677,8 @@ export interface components {
displayName: string;
/** @default default */
applicationId: string;
/** @default default */
environmentId: string;
version?: string;
routeIds?: string[];
capabilities?: {
@@ -1830,12 +1876,14 @@ export interface components {
lastSeen: string;
/** @description The from() endpoint URI, e.g. 'direct:processOrder' */
fromEndpointUri: string;
/** @description Operational state of the route: stopped, suspended, or null (started/default) */
routeState: string;
};
/** @description Application log entry */
LogEntryResponse: {
/** @description Log timestamp (ISO-8601) */
timestamp?: string;
/** @description Log level (INFO, WARN, ERROR, DEBUG) */
/** @description Log level (INFO, WARN, ERROR, DEBUG, TRACE) */
level?: string;
/** @description Logger name */
loggerName?: string;
@@ -1845,6 +1893,29 @@ export interface components {
threadName?: string;
/** @description Stack trace (if present) */
stackTrace?: string;
/** @description Camel exchange ID (if present) */
exchangeId?: string;
/** @description Agent instance ID */
instanceId?: string;
/** @description Application ID */
application?: string;
/** @description MDC context map */
mdc?: {
[key: string]: string;
};
};
/** @description Log search response with cursor pagination and level counts */
LogSearchPageResponse: {
/** @description Log entries for the current page */
data?: components["schemas"]["LogEntryResponse"][];
/** @description Cursor for next page (null if no more results) */
nextCursor?: string;
/** @description Whether more results exist beyond this page */
hasMore?: boolean;
/** @description Count of logs per level (unaffected by level filter) */
levelCounts?: {
[key: string]: number;
};
};
ExecutionDetail: {
executionId: string;
@@ -1961,7 +2032,7 @@ export interface components {
instanceId: string;
displayName: string;
applicationId: string;
environmentId?: string;
environmentId: string;
status: string;
routeIds: string[];
/** Format: date-time */
@@ -2294,7 +2365,7 @@ export interface operations {
[name: string]: unknown;
};
content: {
"*/*": components["schemas"]["ApplicationConfig"];
"*/*": components["schemas"]["ConfigUpdateResponse"];
};
};
};
@@ -3204,7 +3275,11 @@ export interface operations {
};
cookie?: never;
};
requestBody?: never;
requestBody?: {
content: {
"application/json": components["schemas"]["HeartbeatRequest"];
};
};
responses: {
/** @description Heartbeat accepted */
200: {
@@ -3213,13 +3288,6 @@ export interface operations {
};
content?: never;
};
/** @description Agent not registered */
404: {
headers: {
[name: string]: unknown;
};
content?: never;
};
};
};
deregister: {
@@ -3382,13 +3450,13 @@ export interface operations {
};
};
responses: {
/** @description Commands accepted */
202: {
/** @description Commands dispatched and responses collected */
200: {
headers: {
[name: string]: unknown;
};
content: {
"*/*": components["schemas"]["CommandBroadcastResponse"];
"*/*": components["schemas"]["CommandGroupResponse"];
};
};
/** @description Invalid command payload */
@@ -3397,7 +3465,7 @@ export interface operations {
[name: string]: unknown;
};
content: {
"*/*": components["schemas"]["CommandBroadcastResponse"];
"*/*": components["schemas"]["CommandGroupResponse"];
};
};
};
@@ -3949,6 +4017,26 @@ export interface operations {
};
};
};
attributeKeys: {
parameters: {
query?: never;
header?: never;
path?: never;
cookie?: never;
};
requestBody?: never;
responses: {
/** @description OK */
200: {
headers: {
[name: string]: unknown;
};
content: {
"*/*": string[];
};
};
};
};
getMetrics: {
parameters: {
query?: {
@@ -4003,6 +4091,7 @@ export interface operations {
query?: {
from?: string;
to?: string;
environment?: string;
};
header?: never;
path?: never;
@@ -4023,15 +4112,20 @@ export interface operations {
};
searchLogs: {
parameters: {
query: {
application: string;
agentId?: string;
level?: string;
query?: {
q?: string;
query?: string;
level?: string;
application?: string;
agentId?: string;
exchangeId?: string;
logger?: string;
environment?: string;
from?: string;
to?: string;
cursor?: string;
limit?: number;
sort?: string;
};
header?: never;
path?: never;
@@ -4045,7 +4139,7 @@ export interface operations {
[name: string]: unknown;
};
content: {
"*/*": components["schemas"]["LogEntryResponse"][];
"*/*": components["schemas"]["LogSearchPageResponse"];
};
};
};
@@ -4394,7 +4488,7 @@ export interface operations {
"text/event-stream": components["schemas"]["SseEmitter"];
};
};
/** @description Agent not registered */
/** @description Agent not registered and cannot be auto-registered */
404: {
headers: {
[name: string]: unknown;