Skip to content
Draft
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,9 @@ describe('EventDetailsHeader', () => {

expect(screen.getByRole('button', {name: 'All Envs'})).toBeInTheDocument();
// Date selection is based on first seen unless selected by the user
expect(screen.getByRole('button', {name: 'Since First Seen'})).toBeInTheDocument();
expect(
screen.getByRole('button', {name: 'Since First Seen (19d)'})
).toBeInTheDocument();
expect(screen.getByPlaceholderText('Filter events\u2026')).toBeInTheDocument();
expect(
screen.getByRole('button', {
Expand Down
15 changes: 11 additions & 4 deletions static/app/views/issueDetails/streamline/eventDetailsHeader.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import {
} from 'sentry/components/timeRangeSelector';
import {getRelativeSummary} from 'sentry/components/timeRangeSelector/utils';
import {TourElement} from 'sentry/components/tours/components';
import {t} from 'sentry/locale';
import {t, tct} from 'sentry/locale';
import type {Event} from 'sentry/types/event';
import type {Group} from 'sentry/types/group';
import type {Project} from 'sentry/types/project';
Expand All @@ -38,7 +38,10 @@ import {IssueUptimeCheckTimeline} from 'sentry/views/issueDetails/streamline/iss
import {OccurrenceSummary} from 'sentry/views/issueDetails/streamline/occurrenceSummary';
import {getDetectorDetails} from 'sentry/views/issueDetails/streamline/sidebar/detectorSection';
import {ToggleSidebar} from 'sentry/views/issueDetails/streamline/sidebar/toggleSidebar';
import {useGroupDefaultStatsPeriod} from 'sentry/views/issueDetails/useGroupDefaultStatsPeriod';
import {
getFirstSeenDuration,
useGroupDefaultStatsPeriod,
} from 'sentry/views/issueDetails/useGroupDefaultStatsPeriod';
import {
getGroupReprocessingStatus,
ReprocessingStatus,
Comment thread
sentry[bot] marked this conversation as resolved.
Expand Down Expand Up @@ -148,7 +151,9 @@ export function EventDetailsHeader({group, event, project}: EventDetailsHeaderPr
? {
[defaultStatsPeriod.statsPeriod]: t(
'%s (since first seen)',
getRelativeSummary(defaultStatsPeriod.statsPeriod)
getRelativeSummary(
getFirstSeenDuration(group.firstSeen)
)
),
Comment thread
sentry[bot] marked this conversation as resolved.
}
: {}),
Comment on lines 150 to 159
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.

Bug: The custom "since first seen" dropdown label is overwritten by default options when an issue's age matches a standard period like 7d, 14d, or 30d.
Severity: LOW

Suggested Fix

To fix the label overwrite, move the ...props.defaultOptions spread before the custom "since first seen" option is defined within the relativeOptions callback. This will ensure that the custom label takes precedence over the default one for matching time periods, while still allowing other default options to be available.

Prompt for AI Agent
Review the code at the location below. A potential bug has been identified by an AI
agent. Verify if this is a real issue. If it is, propose a fix; if not, explain why it's
not valid.

Location: static/app/views/issueDetails/streamline/eventDetailsHeader.tsx#L153-L162

Potential issue: When an issue's age aligns with a standard relative period (e.g., 7,
14, or 30 days), the custom "Since First Seen" label in the stats period dropdown is
overwritten. This happens because the `...props.defaultOptions` spread, containing
generic labels like "Last 7 days", is applied after the custom option is defined,
replacing it. This results in a UI inconsistency where the dropdown's trigger button
correctly shows "Since First Seen", but the selected option within the dropdown displays
the generic label, creating a confusing user experience.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

known issue, will need another ticket to address this

Expand Down Expand Up @@ -181,7 +186,9 @@ export function EventDetailsHeader({group, event, project}: EventDetailsHeaderPr
{period === defaultStatsPeriod &&
!defaultStatsPeriod.isMaxRetention &&
shouldShowSinceFirstSeenOption
? t('Since First Seen')
? tct('Since First Seen ([period])', {
Comment thread
shashjar marked this conversation as resolved.
period: getFirstSeenDuration(group.firstSeen),
})
: triggerProps.children}
</TimeRangeSelectTrigger>
)}
Expand Down
15 changes: 15 additions & 0 deletions static/app/views/issueDetails/useGroupDefaultStatsPeriod.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -71,3 +71,18 @@ export function useGroupDefaultStatsPeriod(

return {statsPeriod: `${clampedRetentionDays}d`, isMaxRetention};
}

/**
* Returns a short-form duration string (e.g. "19d", "3h") without converting to larger units like weeks, matching the sidebar's TimeSince display.
Copy link
Copy Markdown
Member

@shashjar shashjar May 19, 2026

Choose a reason for hiding this comment

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

Seems like the TimeSince display in the sidebar does use larger units, e.g. on this issue:

Image Image

Is it possible to just reuse the "2 months" that gets calculated for the sidebar? If that's difficult, I'm fine with always using days (or hours if less than 1 day)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

yup, i can reuse the calculation from the sidebar

*/
export function getFirstSeenDuration(firstSeen: string): string {
const MS_PER_HOUR = 60 * 60 * 1000;
const MS_PER_DAY = 24 * MS_PER_HOUR;
const ms = Date.now() - new Date(firstSeen).getTime();
const days = Math.round(ms / MS_PER_DAY);

if (days >= 1) {
return `${days}d`;
}
Comment thread
cursor[bot] marked this conversation as resolved.
Outdated
return `${Math.max(1, Math.round(ms / MS_PER_HOUR))}h`;
Comment thread
amy-chen23 marked this conversation as resolved.
Outdated
}
Comment thread
cursor[bot] marked this conversation as resolved.
Outdated
Loading