Skip to content

feat(search): Make default lookback configurable; reconstruct lookback from URL timestamps#3973

Merged
yurishkuro merged 17 commits into
jaegertracing:mainfrom
yurishkuro:feat/configurable-default-lookback
May 27, 2026
Merged

feat(search): Make default lookback configurable; reconstruct lookback from URL timestamps#3973
yurishkuro merged 17 commits into
jaegertracing:mainfrom
yurishkuro:feat/configurable-default-lookback

Conversation

@yurishkuro

@yurishkuro yurishkuro commented May 27, 2026

Copy link
Copy Markdown
Member

Which problem is this PR solving?

The Lookback dropdown in the Search form has two related issues:

  1. The default value always hardcodes 1h regardless of deployment context. Some deployments (e.g. high-cardinality environments, short-retention backends) want a shorter default like 15m to avoid overwhelming the backend on every page load.

  2. When a URL is shared without a lookback param (e.g. from an external system or manually crafted link), the form previously hardcoded '1h' as the selected option, misrepresenting the actual time range that was searched.

maxLookback is already configurable but only controls the upper bound, not the pre-selected default.

Description of the changes

1. Configurable default lookback

Adds search.defaultLookback to the UI config object. When set to a recognized option, it overrides the hardcoded '1h' default used when the lookback cannot be derived from the URL. Invalid values are silently ignored and fall back to '1h'.

Example jaeger-ui.json:

{
  "search": {
    "defaultLookback": "15m"
  }
}

Valid values: "5m", "15m", "30m", "1h", "2h", "3h", "6h", "12h", "24h", "2d", "3d", "5d", "7d", "2w", "3w", "4w", "custom".

2. Reconstruct lookback from URL timestamps

When lookback is absent or invalid in the URL but valid start/end timestamps are present, the lookback is now reconstructed by rounding up to the smallest standard option that covers the full range (or 'custom' when the range exceeds all standard options). The config default is applied only when timestamps are absent or invalid too.

This logic lives in lookbackFromUrlState() in url.ts and is shared by both searchQueryFromUrl() and mapStateToProps via the public lookbackFromUrl() wrapper.

Files changed

  • types/config.ts — adds defaultLookback?: string to the search section
  • utils/time-range-options.ts — adds asValidLookback() (validates + accepts 'custom') and lookbackFromDuration() helpers; moved from constants/ to utils/
  • SearchForm.tsx — reads search.defaultLookback via lookbackFromUrl() + asValidLookback() fallback chain; removes lookback from queryString.parse destructure
  • url.ts — adds lookbackFromUrlState() (shared core logic), lookbackFromUrl() (public string wrapper); searchQueryFromUrl delegates to lookbackFromUrlState to avoid double-parsing

How was this change tested?

  • time-range-options.test.ts: 4 new tests for lookbackFromDuration
  • url.test.js: 5 new tests for searchQueryFromUrl lookback reconstruction
  • SearchForm.test.jsx: 2 new tests for mapStateToProps — config default used when no URL lookback, URL lookback takes precedence

Checklist

AI Usage in this PR

  • Moderate: AI helped with code generation

🤖 Generated with Claude Code

Copilot AI review requested due to automatic review settings May 27, 2026 04:11
@yurishkuro yurishkuro requested a review from a team as a code owner May 27, 2026 04:11
@codecov

codecov Bot commented May 27, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 91.13%. Comparing base (cb50cc4) to head (104c1bc).

Additional details and impacted files
@@            Coverage Diff             @@
##             main    #3973      +/-   ##
==========================================
+ Coverage   91.11%   91.13%   +0.01%     
==========================================
  Files         342      342              
  Lines       10702    10723      +21     
  Branches     2819     2823       +4     
==========================================
+ Hits         9751     9772      +21     
  Misses        826      826              
  Partials      125      125              

☔ 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 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Adds a UI configuration knob to control the default Lookback selection in the Search form, allowing deployments to choose a less expensive default time range than the current hardcoded 1h.

Changes:

  • Extends the UI Config type with search.defaultLookback?: string (documented as a Lookback dropdown value).
  • Applies search.defaultLookback in SearchForm for initial form values and the Lookback dropdown default.
  • Adds unit tests verifying config default behavior and URL precedence, and documents why url.ts retains a hardcoded fallback.

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated no comments.

File Description
packages/jaeger-ui/src/types/config.ts Adds search.defaultLookback to the typed UI config with documentation.
packages/jaeger-ui/src/components/SearchTracePage/url.ts Documents why URL parsing still falls back to '1h' when lookback is absent.
packages/jaeger-ui/src/components/SearchTracePage/SearchForm.tsx Reads search.defaultLookback to influence Lookback defaults and initial form state.
packages/jaeger-ui/src/components/SearchTracePage/SearchForm.test.jsx Adds tests for config-driven default lookback and URL precedence.
Comments suppressed due to low confidence (1)

packages/jaeger-ui/src/components/SearchTracePage/SearchForm.tsx:367

  • search.defaultLookback is consumed directly as the Select default/initial value, but it is not validated against the allowed lookbackOptions (and can also be inconsistent with search.maxLookback). If it’s misconfigured (typo, unsupported unit, or a value filtered out by optionsWithinMaxLookback()), AntD Select can render an empty value and submitForm() will compute timestamps from an invalid lookback. Consider normalizing/clamping the configured value: if it’s not in the allowed set (and within the maxLookback range), fall back to DEFAULT_LOOKBACK (or to searchMaxLookback.value).
  const { useOpenTelemetryTerms: useOtelTerms, search } = useConfig();
  const searchMaxLookback: ILookbackOption | undefined = search?.maxLookback;
  const searchAdjustEndTime: string | undefined = search?.adjustEndTime;
  const defaultLookback: string = search?.defaultLookback ?? DEFAULT_LOOKBACK;
  const [formData, setFormData] = useState<Partial<ISearchFormFields>>(() => ({
    service: initialValues?.service,
    operation: initialValues?.operation,
    tags: initialValues?.tags,
    lookback: initialValues?.lookback,
    startDate: initialValues?.startDate,

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

@yurishkuro yurishkuro added the changelog:bugfix-or-minor-feature 🐞 Bug fixes, Minor Improvements label May 27, 2026
…okback

Add search.defaultLookback to the UI config so operators can change
the pre-selected Lookback dropdown value (e.g. '15m') without having
to set maxLookback. When not set, falls back to the existing '1h' default.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: Yuri Shkuro <github@ysh.us>
@yurishkuro yurishkuro force-pushed the feat/configurable-default-lookback branch from ac25afe to 05cc4ee Compare May 27, 2026 17:24
Add lookbackFromDuration() to time-range-options.ts: given a duration
in milliseconds, returns the lookback string of the smallest standard
option whose window covers that duration, or 'custom' if it exceeds
the largest option (4 weeks).

Use it in searchQueryFromUrl: when lookback is absent from the URL but
start/end timestamps are present (shared link, external link), snap the
time-range duration up to the nearest standard bucket instead of
hardcoding '1h'. This keeps the dropdown in sync with the actual time
range that was searched and avoids misleading the user.

When neither timestamps nor lookback are present, return '' so that
mapStateToProps can apply the configured defaultLookback instead.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: Yuri Shkuro <github@ysh.us>
Copilot AI review requested due to automatic review settings May 27, 2026 17:29

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

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 7 out of 7 changed files in this pull request and generated 3 comments.

Comment thread packages/jaeger-ui/src/components/SearchTracePage/SearchForm.tsx
Comment thread packages/jaeger-ui/src/components/SearchTracePage/url.ts Outdated
Comment thread packages/jaeger-ui/src/components/SearchTracePage/url.ts Outdated
- isValidLookback() in time-range-options.ts validates config-supplied
  defaultLookback values; falls back to DEFAULT_LOOKBACK when invalid
- Guard in searchQueryFromUrl changed from endUs > 0 to endUs > startUs
  to avoid negative duration when timestamps are inverted in the URL

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: Yuri Shkuro <github@ysh.us>
@yurishkuro yurishkuro changed the title feat(search): Make default lookback configurable feat(search): Make default lookback configurable; reconstruct lookback from URL timestamps May 27, 2026
@yurishkuro yurishkuro requested a review from Copilot May 27, 2026 18:06
yurishkuro and others added 3 commits May 27, 2026 14:08
Avoids ambiguity with the `search` URL string param used elsewhere
in the same file.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: Yuri Shkuro <github@ysh.us>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: Yuri Shkuro <github@ysh.us>
…nfig

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: Yuri Shkuro <github@ysh.us>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

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 7 out of 7 changed files in this pull request and generated 2 comments.

Comment thread packages/jaeger-ui/src/components/SearchTracePage/SearchForm.tsx Outdated
Comment thread packages/jaeger-ui/src/types/config.ts
yurishkuro and others added 2 commits May 27, 2026 14:13
The module now contains functions (isValidLookback, lookbackFromDuration)
in addition to constants, so utils/ is a more appropriate home.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: Yuri Shkuro <github@ysh.us>
Returns the value itself (or undefined) instead of boolean, eliminating
the repeated guard pattern at every call site.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: Yuri Shkuro <github@ysh.us>
Copilot AI review requested due to automatic review settings May 27, 2026 18:15
mapStateToProps already seeds initialValues.lookback with the config
default, making the Select's defaultValue prop dead code (controlled
components ignore defaultValue anyway).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: Yuri Shkuro <github@ysh.us>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

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 10 out of 10 changed files in this pull request and generated 2 comments.

Comment thread packages/jaeger-ui/src/components/SearchTracePage/SearchForm.tsx
Comment thread packages/jaeger-ui/src/components/SearchTracePage/SearchForm.tsx
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: Yuri Shkuro <github@ysh.us>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

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 10 out of 10 changed files in this pull request and generated 2 comments.

Comments suppressed due to low confidence (1)

packages/jaeger-ui/src/utils/time-range-options.ts:113

  • The PR description lists constants/time-range-options.ts, but the helpers are added in src/utils/time-range-options.ts (and there is no constants/time-range-options.ts in this package). Updating the description/file list would avoid confusion for reviewers and future archeology.

Comment thread packages/jaeger-ui/src/components/SearchTracePage/SearchForm.tsx
Comment thread packages/jaeger-ui/src/components/SearchTracePage/SearchForm.tsx
When lookback is absent but start/end are present in the URL,
mapStateToProps now derives the lookback from the timestamp range
(same logic as searchQueryFromUrl), rather than falling back to
the configured default. This ensures the form's dropdown reflects
the actual searched window for shared/external links.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: Yuri Shkuro <github@ysh.us>
yurishkuro and others added 2 commits May 27, 2026 15:14
URL input is external and should not be trusted blindly. An invalid
lookback value in the URL now falls through to timestamp reconstruction
or the configured default, same as an absent value.

asValidLookback now also accepts 'custom' since that is a valid
Select option rendered alongside TIME_RANGE_OPTIONS entries.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: Yuri Shkuro <github@ysh.us>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: Yuri Shkuro <github@ysh.us>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

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 10 out of 10 changed files in this pull request and generated 1 comment.

Comment thread packages/jaeger-ui/src/components/SearchTracePage/SearchForm.tsx Outdated
mapStateToProps was duplicating the same lookback-derivation logic as
searchQueryFromUrl. Extracted into lookbackFromUrl() in url.ts so both
callers share a single implementation.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: Yuri Shkuro <github@ysh.us>
Copilot AI review requested due to automatic review settings May 27, 2026 19:18

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

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 10 out of 10 changed files in this pull request and generated 3 comments.

Comment thread packages/jaeger-ui/src/components/SearchTracePage/url.ts Outdated
Comment thread packages/jaeger-ui/src/components/SearchTracePage/url.ts Outdated
Comment thread packages/jaeger-ui/src/components/SearchTracePage/SearchForm.tsx
yurishkuro and others added 2 commits May 27, 2026 15:28
Extract lookbackFromUrlState() that operates on the already-parsed
TUrlState; searchQueryFromUrl reuses the q it already holds.
lookbackFromUrl() is a thin public wrapper for callers that only
have the raw search string.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: Yuri Shkuro <github@ysh.us>
An invalid lookback string in the URL now falls through to timestamp
reconstruction, the same way an absent value does.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: Yuri Shkuro <github@ysh.us>
Copilot AI review requested due to automatic review settings May 27, 2026 19:31

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

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 10 out of 10 changed files in this pull request and generated 3 comments.

Comment thread packages/jaeger-ui/src/components/SearchTracePage/SearchForm.tsx
Comment thread packages/jaeger-ui/src/types/config.ts
Comment thread packages/jaeger-ui/src/components/SearchTracePage/url.ts
Add asValidConfigLookback() which only accepts TIME_RANGE_OPTIONS
entries (no 'custom'). Config validation now uses this stricter
function; asValidLookback() (accepting 'custom') remains for URL
param validation where 'custom' is a legitimate user selection.

Also fix JSDoc placement: lookbackFromUrl gets a short summary that
refers to lookbackFromUrlState; the full doc block sits above
searchQueryFromUrl where it belongs.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: Yuri Shkuro <github@ysh.us>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

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 10 out of 10 changed files in this pull request and generated no new comments.

@yurishkuro yurishkuro merged commit f69aa56 into jaegertracing:main May 27, 2026
15 checks passed
@yurishkuro yurishkuro deleted the feat/configurable-default-lookback branch May 27, 2026 21:09
Harizz076 pushed a commit to Harizz076/jaeger-ui that referenced this pull request Jul 4, 2026
…k from URL timestamps (jaegertracing#3973)

## Which problem is this PR solving?

The Lookback dropdown in the Search form has two related issues:

1. The default value always hardcodes **1h** regardless of deployment
context. Some deployments (e.g. high-cardinality environments,
short-retention backends) want a shorter default like **15m** to avoid
overwhelming the backend on every page load.

2. When a URL is shared without a `lookback` param (e.g. from an
external system or manually crafted link), the form previously hardcoded
`'1h'` as the selected option, misrepresenting the actual time range
that was searched.

`maxLookback` is already configurable but only controls the upper bound,
not the pre-selected default.

## Description of the changes

### 1. Configurable default lookback

Adds `search.defaultLookback` to the UI config object. When set to a
recognized option, it overrides the hardcoded `'1h'` default used when
the lookback cannot be derived from the URL. Invalid values are silently
ignored and fall back to `'1h'`.

**Example `jaeger-ui.json`:**
```json
{
  "search": {
    "defaultLookback": "15m"
  }
}
```

Valid values: `"5m"`, `"15m"`, `"30m"`, `"1h"`, `"2h"`, `"3h"`, `"6h"`,
`"12h"`, `"24h"`, `"2d"`, `"3d"`, `"5d"`, `"7d"`, `"2w"`, `"3w"`,
`"4w"`, `"custom"`.

### 2. Reconstruct lookback from URL timestamps

When `lookback` is absent or invalid in the URL but valid `start`/`end`
timestamps are present, the lookback is now reconstructed by rounding up
to the smallest standard option that covers the full range (or
`'custom'` when the range exceeds all standard options). The config
default is applied only when timestamps are absent or invalid too.

This logic lives in `lookbackFromUrlState()` in `url.ts` and is shared
by both `searchQueryFromUrl()` and `mapStateToProps` via the public
`lookbackFromUrl()` wrapper.

### Files changed

- `types/config.ts` — adds `defaultLookback?: string` to the `search`
section
- `utils/time-range-options.ts` — adds `asValidLookback()` (validates +
accepts `'custom'`) and `lookbackFromDuration()` helpers; moved from
`constants/` to `utils/`
- `SearchForm.tsx` — reads `search.defaultLookback` via
`lookbackFromUrl()` + `asValidLookback()` fallback chain; removes
`lookback` from `queryString.parse` destructure
- `url.ts` — adds `lookbackFromUrlState()` (shared core logic),
`lookbackFromUrl()` (public string wrapper); `searchQueryFromUrl`
delegates to `lookbackFromUrlState` to avoid double-parsing

## How was this change tested?

- `time-range-options.test.ts`: 4 new tests for `lookbackFromDuration`
- `url.test.js`: 5 new tests for `searchQueryFromUrl` lookback
reconstruction
- `SearchForm.test.jsx`: 2 new tests for `mapStateToProps` — config
default used when no URL lookback, URL lookback takes precedence

## Checklist
- [x] I have read
https://github.com/jaegertracing/jaeger/blob/main/CONTRIBUTING_GUIDELINES.md
- [x] I have signed all commits
- [x] I have added unit tests for the new functionality
- [x] I have run lint and test steps successfully: `make lint test`

## AI Usage in this PR
- [x] **Moderate**: AI helped with code generation

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Signed-off-by: Yuri Shkuro <github@ysh.us>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

changelog:bugfix-or-minor-feature 🐞 Bug fixes, Minor Improvements

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants