Skip to content

[ADR-0006] Phase 3: Side Panel Container and Span Selection#3569

Merged
yurishkuro merged 10 commits into
jaegertracing:mainfrom
yurishkuro:adr-6/phase-3
Mar 7, 2026
Merged

[ADR-0006] Phase 3: Side Panel Container and Span Selection#3569
yurishkuro merged 10 commits into
jaegertracing:mainfrom
yurishkuro:adr-6/phase-3

Conversation

@yurishkuro
Copy link
Copy Markdown
Member

@yurishkuro yurishkuro commented Mar 6, 2026

Implements Phase 3 of ADR-0006: the side panel container and span selection, plus post-review polish from Phases 1 and 2.

Summary

  • Side panel component (SpanDetailSidePanel): when side-panel mode is active, clicking a span shows its details in a fixed right-side panel that scrolls independently of the trace timeline. Only one span is shown at a time; the panel falls back to the root span when nothing is explicitly selected.
  • Selection highlight: the selected span is visually highlighted in the timeline row.
  • Width constraints: spanNameColumnWidth, timeline bars, and sidePanelWidth are kept mutually consistent at all times — in reducers, at initialisation (including a new sanity check for side-panel mode), and in the resizer drag bounds.
  • Permanent column dividers: the vertical lines between name/timeline columns and between main/side-panel are always visible, not only on hover.
  • Design token migration: hardcoded colours in SpanBarRow.css and index.css replaced with CSS variables.
  • Prop rename: columnDivisionnameColumnWidth across SpanBarRow, SpanDetailRow, and VirtualizedTraceView.

AI Usage in this PR (choose one)

See AI Usage Policy.

  • None: No AI tools were used in creating this PR
  • Light: AI provided minor assistance (formatting, simple suggestions)
  • Moderate: AI helped with code generation or debugging specific parts
  • Heavy: AI generated most or all of the code changes

Screenshots

Side panel

image

Original view

image

Side panel without timeline

image

@yurishkuro yurishkuro requested a review from a team as a code owner March 6, 2026 18:54
Copilot AI review requested due to automatic review settings March 6, 2026 18:54
@yurishkuro yurishkuro added the changelog:experimental Experimental feature, may not be stable label Mar 6, 2026

This comment was marked as outdated.

@codecov
Copy link
Copy Markdown

codecov Bot commented Mar 6, 2026

Codecov Report

❌ Patch coverage is 98.97959% with 1 line in your changes missing coverage. Please review.
✅ Project coverage is 89.13%. Comparing base (4713873) to head (74ef69a).
⚠️ Report is 1 commits behind head on main.

Files with missing lines Patch % Lines
...c/components/TracePage/TraceTimelineViewer/duck.ts 97.22% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #3569      +/-   ##
==========================================
+ Coverage   89.04%   89.13%   +0.09%     
==========================================
  Files         302      303       +1     
  Lines        9613     9685      +72     
  Branches     2547     2576      +29     
==========================================
+ Hits         8560     8633      +73     
+ Misses       1050     1049       -1     
  Partials        3        3              

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Copilot AI review requested due to automatic review settings March 6, 2026 20:14

This comment was marked as outdated.

Comment thread packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/duck.ts Outdated
Comment thread packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/SpanBarRow.css Outdated
Copilot AI review requested due to automatic review settings March 6, 2026 21:20

This comment was marked as outdated.

Copilot AI review requested due to automatic review settings March 6, 2026 21:59

This comment was marked as outdated.

Signed-off-by: Yuri Shkuro <[email protected]>
Copilot AI review requested due to automatic review settings March 6, 2026 22:48

This comment was marked as outdated.

Signed-off-by: Yuri Shkuro <[email protected]>

This comment was marked as outdated.

This comment was marked as outdated.

Signed-off-by: Yuri Shkuro <[email protected]>
Signed-off-by: Yuri Shkuro <[email protected]>
Copilot AI review requested due to automatic review settings March 7, 2026 05:00

This comment was marked as outdated.

Signed-off-by: Yuri Shkuro <[email protected]>

This comment was marked as outdated.

Signed-off-by: Yuri Shkuro <[email protected]>

This comment was marked as outdated.

Signed-off-by: Yuri Shkuro <[email protected]>

This comment was marked as outdated.

Signed-off-by: Yuri Shkuro <[email protected]>
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 24 out of 24 changed files in this pull request and generated 2 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

You can also share your feedback on Copilot code review. Take the survey.

Comment on lines +145 to +169
useLayoutEffect(() => {
if (!sidePanelActive) return;
const measure = () => {
/* istanbul ignore next */
if (!layoutRef.current) return;
const { top } = layoutRef.current.getBoundingClientRect();
const headerHeight = parseInt(
getComputedStyle(document.documentElement).getPropertyValue('--timeline-header-row-height'),
10
);
setPanelTop(top + window.scrollY + headerHeight);
};
measure();
window.addEventListener('resize', measure);
// ResizeObserver catches layout shifts that window resize misses (e.g. slim-header toggle,
// archive notifier appearing), which would change the layout container's document offset.
/* istanbul ignore next */
const resizeObserver = new ResizeObserver(measure);
/* istanbul ignore next */
if (layoutRef.current) resizeObserver.observe(layoutRef.current);
return () => {
window.removeEventListener('resize', measure);
/* istanbul ignore next */
resizeObserver.disconnect();
};
Copy link

Copilot AI Mar 7, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The side-panel measurement effect uses new ResizeObserver(...) unconditionally and assumes the CSS var --timeline-header-row-height parses to a finite number. In environments without ResizeObserver (older browsers / non-DOM contexts) this will throw, and if the CSS var is missing/empty parseInt() yields NaN, causing invalid top/height styles. Consider guarding ResizeObserver (as done elsewhere in the repo) and falling back to a sane default header height when parsing fails.

Copilot uses AI. Check for mistakes.
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we'll live with this

Comment on lines +175 to +177
/** Returns the currently selected span ID in side-panel mode (first key of detailStates), or null. */
export function getSelectedSpanID(detailStates: Map<string, DetailState | TNil>): string | null {
return detailStates.size > 0 ? (detailStates.keys().next().value as string) : null;
Copy link

Copilot AI Mar 7, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

getSelectedSpanID() derives selection from the first key in detailStates. In side-panel mode this assumes detailStates always contains at most one entry, but other reducers (notably focusUiFindMatches(), which can add many matches) can populate multiple entries. That can lead to inconsistent selection/highlighting and can also make detailToggle behave unexpectedly (clicking a span that is present but not the “selected” one may clear selection). Consider enforcing single-entry detailStates whenever detailPanelMode === 'sidepanel' (including in focusUiFindMatches) or splitting “selected span” into its own state field.

Suggested change
/** Returns the currently selected span ID in side-panel mode (first key of detailStates), or null. */
export function getSelectedSpanID(detailStates: Map<string, DetailState | TNil>): string | null {
return detailStates.size > 0 ? (detailStates.keys().next().value as string) : null;
/** Returns the currently selected span ID in side-panel mode if and only if detailStates has exactly one entry; otherwise null. */
export function getSelectedSpanID(detailStates: Map<string, DetailState | TNil>): string | null {
return detailStates.size === 1 ? (detailStates.keys().next().value as string) : null;

Copilot uses AI. Check for mistakes.
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we'll live with this

@yurishkuro yurishkuro merged commit 6fbd735 into jaegertracing:main Mar 7, 2026
19 checks passed
@yurishkuro yurishkuro deleted the adr-6/phase-3 branch March 7, 2026 18:37
yurishkuro added a commit that referenced this pull request Mar 7, 2026
Closes out the ADR-0006 implementation (side panel span details +
tree-only mode).
Previous phases: [Phase 1
#3558](#3558), [Phase 2
#3562](#3562), [Phase 3
#3569](#3569), [Phase 4
#3576](#3576).

## What changed

### Analytics tracking (`duck.track.ts`)

Three new Redux actions are now tracked:

| Action | Category | Tracked value |
|---|---|---|
| `SET_DETAIL_PANEL_MODE` | `jaeger/ux/trace/timeline/panel-mode` | mode
string (`'inline'` / `'sidepanel'`) |
| `SET_TIMELINE_BARS_VISIBLE` |
`jaeger/ux/trace/timeline/timeline-visible` | `'true'` / `'false'` |
| `SET_SIDE_PANEL_WIDTH` | `jaeger/ux/trace/timeline/column` | width ×
1000 (integer), same pattern as `SET_SPAN_NAME_COLUMN_WIDTH` |

### Test coverage (`index.test.js`)

Added a `describe('layout combinations')` block that renders
`TraceTimelineViewerImpl` for all four `{detailPanelMode,
timelineBarsVisible}` combinations and asserts:
- Side panel container is present/absent as expected
- `VerticalResizer` is present only when `detailPanelMode='sidepanel'`
**and** `timelineBarsVisible=true`
- `VirtualizedTraceView` is always rendered

### ADR

`docs/adr/0006-side-panel-span-details.md` status updated to
**Implemented**; Phase 5 marked complete.

## Testing

```bash
npm run prettier
npm run lint
npm test
npm run build
```

All 2560 tests pass.

### Manual testing of all four layout combinations

Enable the side panel feature flag in `default-config.ts`
(`enableSidePanel: true`) or via query param, then verify each
combination:

| `detailPanelMode` | `timelineBarsVisible` | Expected |
|---|---|---|
| `inline` | `true` | Default behavior — inline expand, timeline bars
visible |
| `inline` | `false` | Tree-only — inline expand, no timeline bars |
| `sidepanel` | `true` | Side panel on right, `VerticalResizer` divider
visible |
| `sidepanel` | `false` | Side panel fills remaining width, no resizer |

To test in embedded mode, append `?uiEmbed=v0` (optionally with
`uiTimelineCollapseTitle=1`, `uiTimelineHideMinimap=1`,
`uiTimelineHideSummary=1`) to a trace URL and verify the side panel and
settings gear work normally.

## AI Usage in this PR (choose one)
See [AI Usage
Policy](https://github.com/jaegertracing/jaeger/blob/main/CONTRIBUTING_GUIDELINES.md#ai-usage-policy).
- [ ] **None**: No AI tools were used in creating this PR
- [ ] **Light**: AI provided minor assistance (formatting, simple
suggestions)
- [ ] **Moderate**: AI helped with code generation or debugging specific
parts
- [x] **Heavy**: AI generated most or all of the code changes

---------

Signed-off-by: Yuri Shkuro <[email protected]>
yurishkuro added a commit that referenced this pull request Mar 7, 2026
)

## Description of the changes
- Enables displaying span details in a side panel as an option
- Default view is still inline span details, can be changed via
`traceTimeline.defaultDetailPanelMode="sidepanel"` config option.

<img width="1920" height="964" alt="image"
src="https://github.com/user-attachments/assets/c71a9f98-e30d-4030-8947-6dc8e5b6bd0c"
/>

Previous phases: [Phase 1
#3558](#3558), [Phase 2
#3562](#3562), [Phase 3
#3569](#3569), [Phase 4
#3576](#3576), [Phase 5
#3577](#3577).

---------

Signed-off-by: Yuri Shkuro <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

changelog:experimental Experimental feature, may not be stable

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants