diff --git a/static/app/types/group.tsx b/static/app/types/group.tsx index a82ca6f4475cf5..6cd883d9acb942 100644 --- a/static/app/types/group.tsx +++ b/static/app/types/group.tsx @@ -700,7 +700,9 @@ interface GroupActivitySetPrivate extends GroupActivityBase { } interface GroupActivitySetByAge extends GroupActivityBase { - data: Record; + data: { + age?: number | string; + }; type: GroupActivityType.SET_RESOLVED_BY_AGE; } diff --git a/static/app/views/issueDetails/activitySection/groupActivityItem.tsx b/static/app/views/issueDetails/activitySection/groupActivityItem.tsx index cbc5f6c60b177d..90496ae037bab1 100644 --- a/static/app/views/issueDetails/activitySection/groupActivityItem.tsx +++ b/static/app/views/issueDetails/activitySection/groupActivityItem.tsx @@ -22,6 +22,7 @@ import {GroupActivityType, IssueCategory as IssueCategoryEnum} from 'sentry/type import type {Organization, Team} from 'sentry/types/organization'; import type {Project} from 'sentry/types/project'; import type {User} from 'sentry/types/user'; +import {formatDuration} from 'sentry/utils/duration/formatDuration'; import {useOrganization} from 'sentry/utils/useOrganization'; import {isSemverRelease} from 'sentry/utils/versions/isSemverRelease'; @@ -287,13 +288,20 @@ export function getGroupActivityItem( message: resolvedMessage, }; } - case GroupActivityType.SET_RESOLVED_BY_AGE: + case GroupActivityType.SET_RESOLVED_BY_AGE: { + const duration = formatAutoResolveAge(activity.data.age); return { title: t('Resolved'), - message: tct('by [author] due to inactivity', { - author, - }), + message: duration + ? tct('by [author] after [duration] of inactivity', { + author, + duration, + }) + : tct('by [author] due to inactivity', { + author, + }), }; + } case GroupActivityType.SET_RESOLVED_IN_RELEASE: { const hasIntegration = 'integration_id' in activity.data && activity.data.integration_id; @@ -786,6 +794,22 @@ export function getGroupActivityItem( return renderContent(); } +function formatAutoResolveAge(age: number | string | undefined) { + const resolveAge = Number(age); + if (!Number.isFinite(resolveAge) || resolveAge <= 0) { + return null; + } + + const precision = resolveAge > 23 && resolveAge % 24 === 0 ? 'day' : 'hour'; + const count = Number( + formatDuration({duration: [resolveAge, 'hour'], precision, style: 'count'}) + ); + + return precision === 'day' + ? tn('%s day', '%s days', count) + : tn('%s hour', '%s hours', count); +} + function ActivityRelease({project, version}: {project: Project; version: string}) { const organization = useOrganization(); return ( diff --git a/static/app/views/issueDetails/activitySection/index.spec.tsx b/static/app/views/issueDetails/activitySection/index.spec.tsx index 96e219538c8e9c..3f2ff2e6c68b26 100644 --- a/static/app/views/issueDetails/activitySection/index.spec.tsx +++ b/static/app/views/issueDetails/activitySection/index.spec.tsx @@ -346,6 +346,50 @@ describe('ActivitySection', () => { expect(screen.getByText('Linked external issue')).toBeInTheDocument(); }); + it('renders auto-resolved activity age as an inactivity duration', async () => { + const autoResolvedGroup = GroupFixture({ + id: '1347', + activity: [ + { + type: GroupActivityType.SET_RESOLVED_BY_AGE, + id: 'set-resolved-by-age-1', + dateCreated: '2020-01-01T00:00:00', + data: {age: 504}, + user: null, + }, + { + type: GroupActivityType.SET_RESOLVED_BY_AGE, + id: 'set-resolved-by-age-2', + dateCreated: '2020-01-02T00:00:00', + data: {age: 11}, + user: null, + }, + { + type: GroupActivityType.SET_RESOLVED_BY_AGE, + id: 'set-resolved-by-age-3', + dateCreated: '2020-01-03T00:00:00', + data: {age: 30}, + user: null, + }, + { + type: GroupActivityType.SET_RESOLVED_BY_AGE, + id: 'set-resolved-by-age-4', + dateCreated: '2020-01-04T00:00:00', + data: {age: '48'}, + user: null, + }, + ], + project, + }); + + render(); + + expect(await screen.findByText(/after 21 days of inactivity/)).toBeInTheDocument(); + expect(screen.getByText(/after 11 hours of inactivity/)).toBeInTheDocument(); + expect(screen.getByText(/after 30 hours of inactivity/)).toBeInTheDocument(); + expect(screen.getByText(/after 2 days of inactivity/)).toBeInTheDocument(); + }); + it('renders note and allows for edit', async () => { jest.spyOn(indicators, 'addSuccessMessage');