feat: add runtime configuration system and enhance trace filtering#2
feat: add runtime configuration system and enhance trace filtering#2andersonleal merged 2 commits intomainfrom
Conversation
Major changes: - Implement runtime config system with /api/config endpoint and ConfigProvider - Migrate all API modules from static constants to dynamic config getters - Add trace tree visualization with SpanTreeNode and waterfall transformation - Enhance trace filtering with draft state, apply button, and attribute suggestions - Add pagination and advanced search to trace filters with click-outside detection - Fix TimeRangeFilter validation to prevent NaN timestamps - Fix Biome linting errors (variable ordering, React comment parsing) - Update Rust server to serve runtime configuration This establishes a proper configuration foundation and significantly improves the trace analysis experience with better filtering and tree visualization.
📝 WalkthroughWalkthroughReplaces static frontend config with a runtime ConfigProvider and module-scoped ConsoleConfig; updates API modules to derive base URLs at runtime; adds OpenTelemetry trace-tree support end-to-end (new handler, trigger, types, fetchTraceTree, treeToWaterfallData); backend exposes /api/config and bridge trace-tree handler. Changes
Sequence Diagram(s)sequenceDiagram
participant App as React App
participant CP as ConfigProvider
participant API as Server (/api/config)
participant Context as ConfigContext
participant Component as Consumer
App->>CP: Mount ConfigProvider
CP->>API: GET /api/config (with timeout/abort)
API-->>CP: 200 JSON config
CP->>CP: setConfig(...) & set loaded
CP->>Context: provide config
Component->>Context: useConfig()
Context-->>Component: ConsoleConfig
sequenceDiagram
participant UI as Trace Detail View
participant Hook as useTraceFilters
participant API as frontend fetchTraceTree
participant Backend as Server (/otel/traces/tree)
participant Transform as treeToWaterfallData
UI->>Hook: request apiParams / trigger fetch
UI->>API: fetchTraceTree(traceId)
API->>Backend: POST /_console/otel/traces/tree (traceId)
Backend-->>API: TraceTreeResponse (SpanTreeNode[] roots)
API-->>UI: TraceTreeResponse
UI->>Transform: treeToWaterfallData(roots)
Transform-->>UI: WaterfallData
UI->>UI: render waterfall
Estimated code review effort🎯 4 (Complex) | ⏱️ ~50 minutes Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing touches
🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
Actionable comments posted: 5
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
packages/console-frontend/src/api/observability/metrics.ts (1)
145-165:⚠️ Potential issue | 🟠 MajorRedundant fallback: both try and catch paths call the same API.
In
fetchRollups, both the try block (line 146) and the fallback (line 158) callgetManagementApi(). This appears to be a copy-paste error — the try block should likely usegetDevtoolsApi()to match the fallback pattern used in other functions likefetchDetailedMetrics.🐛 Proposed fix
try { - const res = await fetch(`${getManagementApi()}/rollups`, { + const res = await fetch(`${getDevtoolsApi()}/rollups`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(body), }) if (res.ok) { return unwrapResponse<RollupsResponse>(res) } } catch { - // Fall through to management API + // Fall through to management API }
🤖 Fix all issues with AI agents
In `@packages/console-frontend/src/api/config-provider.tsx`:
- Around line 60-87: The auto-retry useEffect can call setError, setConfig and
setConfigState after the component unmounts; add a cancellation guard and proper
cleanup: inside the effect create a boolean (e.g., isMounted or cancelled) and
set it to false in the cleanup, call controller.abort() and clear both timer and
timeout in cleanup, and before any state updates in the fetch handlers check the
flag (only call setError, setConfig, setConfigState when not cancelled). Ensure
you still use AbortController for the fetch and clear the request timeout
(timeout) when the request completes or is aborted to avoid leaked timers.
In `@packages/console-frontend/src/api/utils.ts`:
- Line 29: The current fallback retry uses getManagementApi() which returns the
same URL as getDevtoolsApi(), making the fallback useless; update the fetch
logic in the utility that calls getDevtoolsApi() (the request that assigns to
`res` and the subsequent fallback branch) to either call a truly distinct
endpoint from getManagementApi() (if intended) or remove the fallback/retry
entirely so the original error is surfaced. Locate the fetch call that uses
getDevtoolsApi() and the fallback branch that invokes getManagementApi(), then
either change getManagementApi() to return the correct alternate endpoint or
delete the fallback branch and propagate the initial fetch error.
In `@packages/console-frontend/src/components/traces/TraceFilters.tsx`:
- Around line 146-150: In handleDurationApply validate the parsed integers from
tempMinDuration and tempMaxDuration before calling onFilterChange: parse each
with Number.parseInt (or Number()) into local variables, check Number.isFinite
or !Number.isNaN, and only call onFilterChange('minDurationMs' /
'maxDurationMs', parsedValue) when valid otherwise pass null; keep
setOpenPopover(null) behavior. Ensure you reference the existing
handleDurationApply function, tempMinDuration/tempMaxDuration inputs, and
onFilterChange handler when making this change.
- Around line 99-103: The temporary input state (tempServiceName,
tempOperationName, tempMinDuration, tempMaxDuration) isn’t updated when the
filters prop changes, causing stale values; update these temp state values
whenever filters change or when the popover opens: either add a useEffect that
watches filters and calls setTempServiceName(filters.serviceName || ''),
setTempOperationName(filters.operationName || ''),
setTempMinDuration(filters.minDurationMs?.toString() || ''),
setTempMaxDuration(filters.maxDurationMs?.toString() || ''), or reset those
temps inside the existing togglePopover handler when opening a popover (check
openPopover !== popover) so inputs reflect the current filters before the user
edits them.
In `@packages/console-rust/src/server.rs`:
- Around line 134-144: The origins vector used to build the CorsLayer only
includes localhost/127.0.0.1 so requests from a configured host are blocked;
update the origins Vec (the variable origins used by
CorsLayer::new().allow_origin(...)) to also push formatted origins using
config.host and config.port (e.g. format!("http://{}:{}", config.host,
config.port) and the https variant) and handle the special case where
config.host is "0.0.0.0" by substituting a resolvable hostname such as
"localhost" or skipping adding that raw origin; ensure the new origins are
parsed into HeaderValue and included before calling .allow_origin(origins).
🧹 Nitpick comments (9)
packages/console-rust/src/main.rs (1)
33-36: LGTM! Consider logging the bridge port for operational visibility.The new
bridge_portCLI option correctly follows the existing pattern for port arguments and enables configurable bridge connectivity.However, the startup log at lines 78-81 only displays
engine_portandws_port. Consider addingbridge_portto the log output for better operational visibility:💡 Suggestion to improve operational logging
info!( - "Connecting to engine at {}:{} (WS: {})", - args.engine_host, args.engine_port, args.ws_port + "Connecting to engine at {}:{} (WS: {}, Bridge: {})", + args.engine_host, args.engine_port, args.ws_port, args.bridge_port );packages/console-frontend/src/hooks/useTraceFilters.ts (1)
215-217: Consider deriving warnings directly instead of syncing via effect.The
useEffectthat syncscomputedWarningstovalidationWarningsstate introduces an extra render cycle. SincecomputedWarningsis already memoized, you could either:
- Return
computedWarningsdirectly from the hook (renaming as needed)- Keep
validationWarningsstate only if external clearing viaclearValidationWarningsis requiredCurrent implementation is functionally correct but adds a minor render overhead.
♻️ Optional: Return computed warnings directly
- const [validationWarnings, setValidationWarnings] = useState<{ - durationSwapped?: boolean - timeRangeSwapped?: boolean - }>({}) + const [manuallyCleared, setManuallyCleared] = useState(false) ... - useEffect(() => { - setValidationWarnings(computedWarnings) - }, [computedWarnings]) + // Reset cleared state when filters change + useEffect(() => { + setManuallyCleared(false) + }, [filters]) + const validationWarnings = manuallyCleared ? {} : computedWarnings const clearValidationWarnings = useCallback(() => { - setValidationWarnings({}) + setManuallyCleared(true) }, [])packages/console-frontend/src/routes/streams.tsx (1)
177-181: Update stale comment to reflect composite key structure.The comment on line 179 states
Map<streamName, {groupId, subscriptionId}>, but the actual key is now a composite${streamName}:${groupId}. This discrepancy could confuse future maintainers.📝 Suggested comment fix
const subscriptionsRef = useRef<Map<string, { groupId: string; subscriptionId: string }>>( new Map(), - ) // Map<streamName, {groupId, subscriptionId}> + ) // Map<`${streamName}:${groupId}`, {groupId, subscriptionId}>packages/console-frontend/src/routes/handlers.tsx (1)
627-636: Consider cachinggetConfig()result to avoid redundant calls.Lines 627-628 call
getConfig()twice within the same JSX expression. While this works correctly, destructuring once improves readability and slight efficiency.💡 Optional: Destructure config once in the render scope
Since this is inside an IIFE that already has access to
triggerand other computed values, you could destructure once at the start of that block:{(() => { const trigger = getAssociatedTrigger(selectedFunction) const apiPath = getApiPath(selectedFunction) + const { engineHost, enginePort } = getConfig() + const baseUrl = `${window.location.protocol}//${engineHost}:${enginePort}` return ( <> {/* ... */} <code className="flex-1 text-xs font-mono bg-black/40 text-cyan-400 px-3 py-2 rounded border border-cyan-500/20"> - {getHttpMethod(selectedFunction)} {window.location.protocol}{'//'} - {getConfig().engineHost}:{getConfig().enginePort}/{apiPath} + {getHttpMethod(selectedFunction)} {baseUrl}/{apiPath} </code> <button onClick={() => { - const { engineHost, enginePort } = getConfig() copyToClipboard( - `${window.location.protocol}//${engineHost}:${enginePort}/${apiPath}`, + `${baseUrl}/${apiPath}`, 'endpoint', ) }}packages/console-frontend/src/components/traces/TraceFilters.tsx (3)
63-76: Consider stabilizing theuseClickOutsidecallback withuseCallback.The
onClickOutsidecallback passed touseClickOutsideis recreated on every render (e.g.,() => openPopover === 'status' && setOpenPopover(null)). This causes the effect to re-run on each render since it's in the dependency array.💡 Stabilize with useCallback or move condition inside the hook
Option 1: Move the condition inside the hook so consumers pass a stable setter:
-function useClickOutside(ref: React.RefObject<HTMLElement | null>, onClickOutside: () => void) { +function useClickOutside( + ref: React.RefObject<HTMLElement | null>, + onClickOutside: () => void, + enabled: boolean = true +) { useEffect(() => { function handleClickOutside(event: MouseEvent) { - if (ref.current && !ref.current.contains(event.target as Node)) { + if (enabled && ref.current && !ref.current.contains(event.target as Node)) { onClickOutside() } } // ... - }, [ref, onClickOutside]) + }, [ref, onClickOutside, enabled]) } // Usage: -useClickOutside(statusRef, () => openPopover === 'status' && setOpenPopover(null)) +useClickOutside(statusRef, () => setOpenPopover(null), openPopover === 'status')Option 2: Wrap callbacks in
useCallbackwhere they're defined.
78-83:formatDurationis duplicated intraces.tsx.This same function exists in
packages/console-frontend/src/routes/traces.tsx(lines 73-78). Consider extracting to a shared utility module (e.g.,@/lib/formattersor@/lib/traceTransform).
227-255: Consider memoizingactiveFiltersarray.The
activeFiltersarray is reconstructed on every render. While the array is small, wrapping it inuseMemowith appropriate dependencies would prevent unnecessary recalculations during frequent re-renders.packages/console-frontend/src/routes/traces.tsx (1)
110-111: Consider reducing the default limit or implementing lazy loading.A default limit of 10,000 traces could cause performance issues with memory usage and rendering time on the client. Consider:
- A lower default (e.g., 1000) with load-more functionality
- Server-side pagination
- Virtual scrolling for large lists
packages/console-frontend/src/api/config.ts (1)
27-37:getDevtoolsApiandgetManagementApireturn identical URLs despite different usage contexts.Both functions return
${protocol}//${c.engineHost}:${c.enginePort}/_console. While they're used across different modules (getDevtoolsApi more extensively, getManagementApi for specific operations), they produce the same result. If this semantic distinction is intentional, add a comment explaining the purpose. Otherwise, one could delegate to the other to avoid duplication.
…er and TraceFilters - Improve error handling in ConfigProvider to prevent state updates after component unmount - Synchronize temporary state in TraceFilters when external filters change - Refactor fetchWithFallback to simplify error handling and remove unused management API fetch
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Fix all issues with AI agents
In `@packages/console-frontend/src/api/utils.ts`:
- Around line 23-33: Rename the exported function fetchWithFallback to a clear
name like fetchFromDevtools and keep fetchWithFallback as a deprecated alias
that forwards to the new function for backward compatibility; remove the unused
_managementPath parameter from the new function signature and update internal
references to call unwrapResponse via the new function name, and mark the old
export (fetchWithFallback) with a deprecation comment and have it call
fetchFromDevtools so existing callers still work while signaling the new public
API.
In `@packages/console-frontend/src/components/traces/TraceFilters.tsx`:
- Around line 78-83: The function formatDuration treats 0 as falsy and returns
'-' for 0ms; change the initial falsy check to only detect undefined (or null)
so zero is handled correctly. In the formatDuration function replace the "if
(!ms) return '-'" check with a check for undefined (e.g., "if (ms === undefined)
return '-'") so formatDuration(0) returns "0ms" while preserving existing
behavior for undefined inputs.
🧹 Nitpick comments (3)
packages/console-frontend/src/api/utils.ts (1)
29-30: Consider including full URL in error message for easier debugging.Since the base URL is now dynamic, logging only the path may make debugging harder. Including the full URL would provide better context.
🔧 Proposed improvement
+ const url = `${getDevtoolsApi()}${devtoolsPath}` + const res = await fetch(url, options) - const res = await fetch(`${getDevtoolsApi()}${devtoolsPath}`, options) if (!res.ok) { - throw new Error(`Failed to fetch from ${devtoolsPath}: ${res.status}`) + throw new Error(`Failed to fetch from ${url}: ${res.status}`) }packages/console-frontend/src/components/traces/TraceFilters.tsx (2)
63-76:useClickOutsidere-registers listeners on every render due to inline callbacks.The hook includes
onClickOutsidein its dependency array. Since the callbacks passed on lines 121-126 are inline arrow functions, they're recreated on each render, causing the effect to repeatedly add/remove event listeners.Consider either memoizing the callbacks or restructuring the hook to accept the popover type and close action separately:
♻️ Option 1: Restructure hook to avoid inline callbacks
-function useClickOutside(ref: React.RefObject<HTMLElement | null>, onClickOutside: () => void) { +function useClickOutside( + ref: React.RefObject<HTMLElement | null>, + isActive: boolean, + onClickOutside: () => void +) { useEffect(() => { + if (!isActive) return + function handleClickOutside(event: MouseEvent) { if (ref.current && !ref.current.contains(event.target as Node)) { onClickOutside() } } document.addEventListener('mousedown', handleClickOutside) return () => { document.removeEventListener('mousedown', handleClickOutside) } - }, [ref, onClickOutside]) + }, [ref, isActive, onClickOutside]) }Then use a stable callback:
const closePopover = useCallback(() => setOpenPopover(null), []) useClickOutside(statusRef, openPopover === 'status', closePopover) useClickOutside(timeRangeRef, openPopover === 'timeRange', closePopover) // ...Also applies to: 121-126
338-353: Popovers lack keyboard accessibility (Escape to close).Users cannot close open popovers with the Escape key, which is a common accessibility expectation. Consider adding a keydown handler at the popover container level.
♿ Add Escape key handling
+ useEffect(() => { + const handleEscape = (e: KeyboardEvent) => { + if (e.key === 'Escape' && openPopover) { + setOpenPopover(null) + } + } + document.addEventListener('keydown', handleEscape) + return () => document.removeEventListener('keydown', handleEscape) + }, [openPopover])Add this effect near the other
useEffecthooks (around line 111).
| export async function fetchWithFallback<T>( | ||
| devtoolsPath: string, | ||
| managementPath: string, | ||
| _managementPath?: string, | ||
| options?: RequestInit, | ||
| ): Promise<T> { | ||
| try { | ||
| const res = await fetch(`${DEVTOOLS_API}${devtoolsPath}`, options) | ||
| if (res.ok) { | ||
| return await unwrapResponse<T>(res) | ||
| } | ||
| } catch { | ||
| // Fall through to management API | ||
| const res = await fetch(`${getDevtoolsApi()}${devtoolsPath}`, options) | ||
| if (!res.ok) { | ||
| throw new Error(`Failed to fetch from ${devtoolsPath}: ${res.status}`) | ||
| } | ||
|
|
||
| const res = await fetch(`${MANAGEMENT_API}${managementPath}`, options) | ||
| if (!res.ok) throw new Error(`Failed to fetch from ${managementPath}`) | ||
| return await unwrapResponse<T>(res) | ||
| } |
There was a problem hiding this comment.
🛠️ Refactor suggestion | 🟠 Major
🧩 Analysis chain
🏁 Script executed:
# Find all callers of fetchWithFallback outside utils.ts
rg -n 'fetchWithFallback' --type=ts -g '!**/utils.ts'Repository: MotiaDev/iii-console
Length of output: 170
🏁 Script executed:
# Also check imports of the function to understand how it's being used
rg -n 'import.*fetchWithFallback' --type=tsRepository: MotiaDev/iii-console
Length of output: 46
🏁 Script executed:
# Check if _managementPath is referenced anywhere in the codebase
rg -n '_managementPath' --type=tsRepository: MotiaDev/iii-console
Length of output: 137
🏁 Script executed:
# Check for test files that might call fetchWithFallback
rg -n 'fetchWithFallback' --type=tsRepository: MotiaDev/iii-console
Length of output: 260
🏁 Script executed:
# Check if there are calls to this function through string patterns or dynamic imports
rg 'fetchWithFallback' --type=ts -A 3Repository: MotiaDev/iii-console
Length of output: 633
🏁 Script executed:
# Verify the exact location and context of the export in index.ts
cat -n packages/console-frontend/src/api/index.ts | head -120 | tail -20Repository: MotiaDev/iii-console
Length of output: 720
Function name fetchWithFallback no longer reflects behavior, and the function is part of the public API.
The fallback logic has been removed (correctly addressing the previous review about identical endpoints), but the function name is now misleading since there's no fallback mechanism. Additionally, the _managementPath parameter is unused dead code that never appears elsewhere in the codebase.
Since this function is exported as part of the public API (via index.ts), renaming it with a deprecated alias for backward compatibility is the right approach. Consider renaming to fetchFromDevtools (or similar) and deprecating the old name rather than directly removing the parameter.
♻️ Proposed refactor
-export async function fetchWithFallback<T>(
- devtoolsPath: string,
- _managementPath?: string,
- options?: RequestInit,
-): Promise<T> {
+export async function fetchFromDevtools<T>(
+ devtoolsPath: string,
+ options?: RequestInit,
+): Promise<T> {
const res = await fetch(`${getDevtoolsApi()}${devtoolsPath}`, options)
if (!res.ok) {
throw new Error(`Failed to fetch from ${devtoolsPath}: ${res.status}`)
}
return await unwrapResponse<T>(res)
}
+
+/** `@deprecated` Use fetchFromDevtools instead */
+export const fetchWithFallback = fetchFromDevtools📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| export async function fetchWithFallback<T>( | |
| devtoolsPath: string, | |
| managementPath: string, | |
| _managementPath?: string, | |
| options?: RequestInit, | |
| ): Promise<T> { | |
| try { | |
| const res = await fetch(`${DEVTOOLS_API}${devtoolsPath}`, options) | |
| if (res.ok) { | |
| return await unwrapResponse<T>(res) | |
| } | |
| } catch { | |
| // Fall through to management API | |
| const res = await fetch(`${getDevtoolsApi()}${devtoolsPath}`, options) | |
| if (!res.ok) { | |
| throw new Error(`Failed to fetch from ${devtoolsPath}: ${res.status}`) | |
| } | |
| const res = await fetch(`${MANAGEMENT_API}${managementPath}`, options) | |
| if (!res.ok) throw new Error(`Failed to fetch from ${managementPath}`) | |
| return await unwrapResponse<T>(res) | |
| } | |
| export async function fetchFromDevtools<T>( | |
| devtoolsPath: string, | |
| options?: RequestInit, | |
| ): Promise<T> { | |
| const res = await fetch(`${getDevtoolsApi()}${devtoolsPath}`, options) | |
| if (!res.ok) { | |
| throw new Error(`Failed to fetch from ${devtoolsPath}: ${res.status}`) | |
| } | |
| return await unwrapResponse<T>(res) | |
| } | |
| /** `@deprecated` Use fetchFromDevtools instead */ | |
| export const fetchWithFallback = fetchFromDevtools |
🤖 Prompt for AI Agents
In `@packages/console-frontend/src/api/utils.ts` around lines 23 - 33, Rename the
exported function fetchWithFallback to a clear name like fetchFromDevtools and
keep fetchWithFallback as a deprecated alias that forwards to the new function
for backward compatibility; remove the unused _managementPath parameter from the
new function signature and update internal references to call unwrapResponse via
the new function name, and mark the old export (fetchWithFallback) with a
deprecation comment and have it call fetchFromDevtools so existing callers still
work while signaling the new public API.
| function formatDuration(ms: number | undefined): string { | ||
| if (!ms) return '-' | ||
| if (ms < 1) return '<1ms' | ||
| if (ms < 1000) return `${Math.round(ms)}ms` | ||
| return `${(ms / 1000).toFixed(2)}s` | ||
| } |
There was a problem hiding this comment.
formatDuration(0) returns '-' instead of '0ms'.
The falsy check !ms catches 0, returning '-'. If 0ms is a valid average duration (e.g., cached/instant responses), it should display as '0ms'.
🔧 Proposed fix
function formatDuration(ms: number | undefined): string {
- if (!ms) return '-'
+ if (ms === undefined || ms === null) return '-'
+ if (ms === 0) return '0ms'
if (ms < 1) return '<1ms'
if (ms < 1000) return `${Math.round(ms)}ms`
return `${(ms / 1000).toFixed(2)}s`
}📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| function formatDuration(ms: number | undefined): string { | |
| if (!ms) return '-' | |
| if (ms < 1) return '<1ms' | |
| if (ms < 1000) return `${Math.round(ms)}ms` | |
| return `${(ms / 1000).toFixed(2)}s` | |
| } | |
| function formatDuration(ms: number | undefined): string { | |
| if (ms === undefined || ms === null) return '-' | |
| if (ms === 0) return '0ms' | |
| if (ms < 1) return '<1ms' | |
| if (ms < 1000) return `${Math.round(ms)}ms` | |
| return `${(ms / 1000).toFixed(2)}s` | |
| } |
🤖 Prompt for AI Agents
In `@packages/console-frontend/src/components/traces/TraceFilters.tsx` around
lines 78 - 83, The function formatDuration treats 0 as falsy and returns '-' for
0ms; change the initial falsy check to only detect undefined (or null) so zero
is handled correctly. In the formatDuration function replace the "if (!ms)
return '-'" check with a check for undefined (e.g., "if (ms === undefined)
return '-'") so formatDuration(0) returns "0ms" while preserving existing
behavior for undefined inputs.
feat: add runtime configuration system and enhance trace filtering
Summary
ConfigProviderthat fetches/api/configfrom the Rust server. The frontend no longer relies onwindow.__CONSOLE_CONFIG__or build-time env vars for API base URLs. All API modules use getters (getDevtoolsApi(),getManagementApi(),getStreamsWs()) so URLs are correct in both dev and binary mode.SpanTreeNode,TraceTreeResponse,fetchTraceTree,otelTraceTreeQuery) for hierarchical trace data.TraceFilters.tsxand related components (e.g.AttributesFilter,useTraceFilters,traceTransform) were refactored and extended.GET /api/configthat returns engine host/port, WS port, console port, and version; proxy and config wiring updated so the embedded frontend receives config from the server..gitignoreupdated (e.g.AGENTS.md); bridge functions/triggers and route handlers aligned with new config and trace APIs.Type of Change
Checklist
Additional Context
ConfigProvidermounts first, fetches/api/config, callssetConfig(), then renders children. Loading and error states (spinner, retry with auto-retry) are handled in the provider. The Rust server serves/api/configwith data from CLI/env so the same binary works in different environments.fetchTracesnow accepts filter/sort params;fetchTraceTree(traceId)andotelTraceTreeQuery(traceId)support the new tree endpoint. Traces UI and filters were refactored to use the new API shape and filter state.DEVTOOLS_API,MANAGEMENT_API,STREAMS_WS,ENGINE_HOST, etc. must switch togetDevtoolsApi(),getManagementApi(),getStreamsWs(), orgetConfig(), and the app must be wrapped inConfigProvider(already done inmain.tsx).Summary by CodeRabbit
New Features
Bug Fixes
Improvements