Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
4 changes: 3 additions & 1 deletion static/app/types/group.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -700,7 +700,9 @@ interface GroupActivitySetPrivate extends GroupActivityBase {
}

interface GroupActivitySetByAge extends GroupActivityBase {
data: Record<string, any>;
data: {
age?: number | string;
};
type: GroupActivityType.SET_RESOLVED_BY_AGE;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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';

Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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 (
Expand Down
44 changes: 44 additions & 0 deletions static/app/views/issueDetails/activitySection/index.spec.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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(<ActivitySection group={autoResolvedGroup} />);

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');

Expand Down
Loading