#11584
## What changed
Updated `CorrelatedLogsTable.vue` to load key fields from the service
correlation configuration and use them as default visible columns
alongside `_timestamp`. Added 5 new test cases covering key field
matching, fallback behavior, and user customization preservation.
## Why
The correlated logs table was only showing `_timestamp` by default,
missing relevant log fields that should appear as columns. Key fields
defined in the service correlation config (e.g., `field1`, `field2`)
were not being surfaced unless the user manually customized columns.
## Approach
- Imported `useServiceCorrelation` composable and its `loadKeyFields`
method
- On mount, fetch key fields config and store in `defaultLogFields` ref
- Added `initializeVisibleColumns()` that creates a default set from
`_timestamp` + any key fields present in the available fields
- Updated the `availableFields` watcher to check `visibleColumns.size <=
1` (instead of `=== 0`) — accounts for `_timestamp` being persisted in
localStorage
- Added a separate `watch` on `defaultLogFields` to re-initialize when
key fields arrive after `availableFields`
- Both watchers skip re-initialization if the user has already
customized columns (more than just `_timestamp`)
## Risk
Medium. The column initialization logic now runs in two watchers
(`availableFields` and `defaultLogFields`). If `defaultLogFields` loads
before `availableFields`, the first watcher applies (with an empty key
fields list) and the second watcher skips because `visibleColumns.size`
is already `> 1`. Reviewers should verify that the ordering of these
watchers doesn't leave key fields unapplied in edge cases.
Design at: ui/traces/trace-details/
#11581
## What changed
Added an "Error" tab to the trace details sidebar, extracted
error-detection logic from the sidebar into a dedicated
`useTraceDetails` composable, and moved the error/exception UI into a
new `TraceErrorTab` component. Active tab management was changed from
internal sidebar state to a parent-controlled prop with two-way binding.
Hover state (`hoveredSpanId`) was added to `TraceDetails` and
`TraceTree` — when set, hovered spans take visual priority over
`selectedSpanId`. A missing `hoveredSpanId` prop declaration was added
to `TraceTree.vue`. The `error` i18n key was added across all 12
languages. Test coverage spans 84 composable tests, 55 error-tab tests,
and updates to all three existing spec files.
## Why
Trace detail spans can fail for reasons beyond HTTP status codes (gRPC
errors, exception events, process exit codes, DB response codes).
Previously, there was no dedicated, consistently surfaced view for these
errors — they were either buried in the attributes tab or shown as
inline exception tables in the sidebar. The new error tab provides a
centralized home for all error indicators.
## Approach
Extracted error detection (HTTP status, gRPC status/name/message,
exception events, error type, DB response status, process exit code)
into `useTraceDetails` composable so it can be reused across sidebar and
error tab without duplication. Moved the error/exception UI into
`TraceErrorTab.vue`, keeping the sidebar as the orchestrator. Made
`activeTab` parent-controlled so `TraceDetails` can auto-select the
preview tab for LLM spans without conflicting with sidebar internal
state.
## Risk
The refactored active tab logic (parent-controlled via prop+emit instead
of internal state) could affect tab selection behavior in edge cases —
particularly the LLM preview auto-selection and the correlated-metrics
tab watch. The `hoveredSpanId` added to `TraceTree` was previously
undeclared as a prop (referenced but never defined), so adding it is an
unambiguous fix, not a behavioral risk. All 5 spec files pass with 357
total tests.
---------
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
## What changed
Fixed `addFieldTerm` in `SearchBar.vue` so that include/exclude search
terms are inserted at the correct position in SQL aggregation queries.
Previously the code checked for `ORDER BY` before `GROUP BY`, causing
the injected `WHERE` clause to land after `GROUP BY` (invalid SQL). The
fix scans all terminating clauses (`GROUP BY`, `HAVING`, `ORDER BY`,
`LIMIT`) and inserts `WHERE` before whichever appears earliest. The
remaining diff is Prettier-driven reformatting with no logic changes.
## Why
The old sequential `if/else if` checked `ORDER BY` first. On a query
containing both `GROUP BY` and `ORDER BY`, it would split at `ORDER BY`
and produce `… WHERE <filter> ORDER BY … GROUP BY …` — structurally
invalid SQL. The fix enforces correct SQL clause ordering (`FROM → WHERE
→ GROUP BY → HAVING → ORDER BY → LIMIT`).
## Approach
The new algorithm iterates over all four terminating clauses, records
the index of each that is present, picks the one with the smallest index
(`firstClause`), then uses the existing `queryIndexSplit` utility to
splice the `WHERE <filter>` token in before it. If no terminating clause
exists the filter is appended. The spec file was extended with 14 new
unit tests covering the core bug scenario (GROUP BY + ORDER BY
together), each individual clause in isolation, all-clauses-present,
AND-append paths, and edge cases (case-insensitive matching, column
names containing clause keywords, special characters in filter values).
## Risk
The logic change is isolated to the `else` branch of `addFieldTerm` that
handles queries with no existing `WHERE` clause. Queries that already
have a `WHERE` clause follow a separate code path and are unaffected.
Reviewers should confirm the `queryIndexSplit` utility is
case-insensitive-safe (the fix lowercases only for the index scan, then
splits the original string) and verify the preserved trailing
`afterClause` string includes the space/newline that was previously part
of the `" order by"` / `" group by"` literals.
## What changed
Replaced `VueJsonPretty` (`vue-json-pretty`) with `CodeQueryEditor.vue`
(Monaco-based) for JSON rendering in `LLMContentRenderer.vue`. Inlined
the `MessageItem` sub-component directly into the template with
`CodeQueryEditor` for JSON message content. Added `showLineNumbers` and
`stickyScroll` props to `CodeQueryEditor`. Removed the unused
`vue-json-pretty` dependency from `package.json`. Passed unique editor
IDs from `TraceDetailsSidebar` via a new `instanceId` prop to prevent
Monaco editor ID collisions.
## Why
`vue-json-pretty` formats the entire JSON tree on initial render,
causing lag on long JSON payloads. Monaco (via `CodeQueryEditor`)
renders only visible viewport lines, making performance O(visible)
instead of O(total).
## Approach
- Replaced all 7 `VueJsonPretty` instances in `LLMContentRenderer.vue`
with `<CodeQueryEditor>` in read-only mode (`:read-only="true"`,
`:show-line-numbers="false"`, `:sticky-scroll="false"`)
- Inlined the `MessageItem` sub-component as a `v-for` block with
`CodeQueryEditor` for JSON message content and the existing `v-html`
markdown renderer for non-JSON content
- Converted the component to `<script setup lang="ts">` with
`defineAsyncComponent` for `CodeQueryEditor`
- Added `showLineNumbers` and `stickyScroll` props (both default `true`)
to `CodeQueryEditor.vue` to support the JSON viewer use case
- Added a `watch` on `showLineNumbers` to dynamically toggle line
numbers in Monaco
- Passed `instanceId` from `TraceDetailsSidebar` down to
`LLMContentRenderer` to generate unique editor IDs like
`trace-id-msg-json-editor-0`
## Considered & rejected
- **Render function approach with synchronous import of
CodeQueryEditor** — rejected because it forced manual editor height
computation and module-level counters for editor IDs. Inlining
`MessageItem` as a template component was cleaner and consistent with
the other 5 template `CodeQueryEditor` locations.
- **Retaining `MessageItem` as a separate component with render
function** — rejected because the render function approach was
over-engineering for what is now a simple `v-for` with conditional
`CodeQueryEditor` / markdown branching.
## Risk
Medium. Monaco editor initialization has non-trivial overhead; rendering
multiple editors on one page (e.g., many messages in a conversation)
could impact initial render time. Reviewers should check that the
`instanceId` prop is correctly wired from `TraceDetailsSidebar` to avoid
duplicate Monaco editor IDs, and that the `tw:h-full` class application
on content-wrapper divs doesn't break non-JSON (plain text / markdown)
layouts.
## What changed
Removed the `label` property from important field entries pushed into
`selectedStreamFields` in the traces `extractFields()` function.
## Why
The `label` field was redundant — it duplicated the `name` property —
and caused display issues in the traces fields sidebar where both `name`
and `label` were shown. The data model already uses `name` as the
display key.
## Approach
Stripped the `label: rowName` assignment from the important fields
branch in `extractFields()`.
## Risk
The field removal changes the object shape pushed to
`selectedStreamFields` for important fields. Verify that no downstream
code (field grouping, semantic matching, search building) depends on
`field.label` being present.
**Problem:**
Backend sent cumulative `took` per partition (monotonically increasing:
69, 130, 192...ms). Frontend summed all values → O(n²) inflation (e.g.
23s displayed vs 1.4s actual).
**Fix:**
- Backend: timer now created independently per partition → each
partition reports only its own processing time
**Result:** `took = search + histogram` sums correctly. Verified against
SSE data for both no-cache and cache flows