Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(issue-details): Display the resolution/archival reason on new UI #83555

Merged
merged 3 commits into from
Jan 16, 2025
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
127 changes: 65 additions & 62 deletions static/app/components/archivedBox.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,76 +12,79 @@ interface ArchivedBoxProps {
organization: Organization;
statusDetails: IgnoredStatusDetails;
substatus: Group['substatus'];
hasStreamlinedUI?: boolean;
}

function ArchivedBox({substatus, statusDetails, organization}: ArchivedBoxProps) {
function trackDocsClick() {
trackAnalytics('issue_details.issue_status_docs_clicked', {
organization,
});
}

function renderReason() {
const {ignoreUntil, ignoreCount, ignoreWindow, ignoreUserCount, ignoreUserWindow} =
statusDetails;
export function renderArchiveReason({
substatus,
statusDetails,
organization,
hasStreamlinedUI = false,
}: ArchivedBoxProps) {
const {ignoreUntil, ignoreCount, ignoreWindow, ignoreUserCount, ignoreUserWindow} =
statusDetails;

if (substatus === GroupSubstatus.ARCHIVED_UNTIL_ESCALATING) {
return t(
"This issue has been archived. It'll return to your inbox if it escalates. To learn more, %s",
<ExternalLink
href="https://docs.sentry.io/product/issues/states-triage/#archive"
onClick={trackDocsClick}
>
{t('read the docs')}
</ExternalLink>
);
}
if (ignoreUntil) {
return t(
'This issue has been archived until %s.',
<strong>
<DateTime date={ignoreUntil} />
</strong>
);
}
if (ignoreCount && ignoreWindow) {
return t(
'This issue has been archived until it occurs %s time(s) in %s.',
<strong>{ignoreCount.toLocaleString()}</strong>,
<strong>
<Duration seconds={ignoreWindow * 60} />
</strong>
);
}
if (ignoreCount) {
return t(
'This issue has been archived until it occurs %s more time(s).',
<strong>{ignoreCount.toLocaleString()}</strong>
);
}
if (ignoreUserCount && ignoreUserWindow) {
return t(
'This issue has been archived until it affects %s user(s) in %s.',
<strong>{ignoreUserCount.toLocaleString()}</strong>,
<strong>
<Duration seconds={ignoreUserWindow * 60} />
</strong>
);
}
if (ignoreUserCount) {
return t(
'This issue has been archived until it affects %s more user(s).',
<strong>{ignoreUserCount.toLocaleString()}</strong>
);
}

return t('This issue has been archived forever.');
if (substatus === GroupSubstatus.ARCHIVED_UNTIL_ESCALATING) {
return hasStreamlinedUI
? t('This issue has been archived until it escalates.')
: t(
"This issue has been archived. It'll return to your inbox if it escalates. To learn more, %s",
<ExternalLink
href="https://docs.sentry.io/product/issues/states-triage/#archive"
onClick={() =>
trackAnalytics('issue_details.issue_status_docs_clicked', {organization})
}
>
{t('read the docs')}
</ExternalLink>
);
}
if (ignoreUntil) {
return t(
'This issue has been archived until %s.',
<strong>
<DateTime date={ignoreUntil} />
</strong>
);
}
if (ignoreCount && ignoreWindow) {
return t(
'This issue has been archived until it occurs %s time(s) in %s.',
<strong>{ignoreCount.toLocaleString()}</strong>,
<strong>
<Duration seconds={ignoreWindow * 60} />
</strong>
);
}
if (ignoreCount) {
return t(
'This issue has been archived until it occurs %s more time(s).',
<strong>{ignoreCount.toLocaleString()}</strong>
);
}
if (ignoreUserCount && ignoreUserWindow) {
return t(
'This issue has been archived until it affects %s user(s) in %s.',
<strong>{ignoreUserCount.toLocaleString()}</strong>,
<strong>
<Duration seconds={ignoreUserWindow * 60} />
</strong>
);
}
if (ignoreUserCount) {
return t(
'This issue has been archived until it affects %s more user(s).',
<strong>{ignoreUserCount.toLocaleString()}</strong>
);
}

return t('This issue has been archived forever.');
}
function ArchivedBox({substatus, statusDetails, organization}: ArchivedBoxProps) {
return (
<BannerContainer priority="default">
<BannerSummary>
<span>{renderReason()}</span>
<span>{renderArchiveReason({substatus, statusDetails, organization})}</span>
</BannerSummary>
</BannerContainer>
);
Expand Down
79 changes: 64 additions & 15 deletions static/app/components/resolutionBox.spec.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import {CommitFixture} from 'sentry-fixture/commit';
import {OrganizationFixture} from 'sentry-fixture/organization';
import {ProjectFixture} from 'sentry-fixture/project';
import {ReleaseFixture} from 'sentry-fixture/release';
import {UserFixture} from 'sentry-fixture/user';

import {render} from 'sentry-test/reactTestingLibrary';
Expand All @@ -9,13 +11,42 @@ import {GroupActivityType} from 'sentry/types/group';
import ResolutionBox from './resolutionBox';

describe('ResolutionBox', function () {
const organization = OrganizationFixture();
const project = ProjectFixture();
const release = ReleaseFixture({version: '1.0'});

beforeEach(() => {
MockApiClient.clearMockResponses();
MockApiClient.addMockResponse({
url: `/organizations/${organization.slug}/repos/`,
method: 'GET',
body: [],
});
MockApiClient.addMockResponse({
url: `/projects/${organization.slug}/${project.slug}/releases/${release.version}/`,
method: 'GET',
body: [],
});
MockApiClient.addMockResponse({
url: `/organizations/${organization.slug}/releases/${release.version}/deploys/`,
method: 'GET',
body: [],
});
});

it('handles default', function () {
const {container} = render(<ResolutionBox statusDetails={{}} projectId="1" />);
const {container} = render(
<ResolutionBox statusDetails={{}} project={project} organization={organization} />
);
expect(container).toHaveTextContent('This issue has been marked as resolved.');
});
it('handles inNextRelease', function () {
const {container} = render(
<ResolutionBox statusDetails={{inNextRelease: true}} projectId="1" />
<ResolutionBox
statusDetails={{inNextRelease: true}}
project={project}
organization={organization}
/>
);
expect(container).toHaveTextContent(
'This issue has been marked as resolved in the upcoming release.'
Expand All @@ -34,56 +65,71 @@ describe('ResolutionBox', function () {
email: '[email protected]',
},
}}
projectId="1"
project={project}
organization={organization}
/>
);
expect(container).toHaveTextContent(
'David Cramer marked this issue as resolved in the upcoming release.'
);
});
it('handles in next release (semver current_release_version)', function () {
const currentReleaseVersion = '1.2.0';
MockApiClient.addMockResponse({
url: `/projects/${organization.slug}/${project.slug}/releases/${currentReleaseVersion}/`,
method: 'GET',
body: [],
});
MockApiClient.addMockResponse({
url: `/organizations/${organization.slug}/releases/${currentReleaseVersion}/deploys/`,
method: 'GET',
body: [],
});

const {container} = render(
<ResolutionBox
statusDetails={{
inNextRelease: true,
actor: UserFixture(),
}}
projectId="1"
project={project}
organization={organization}
activities={[
{
id: '1',
type: GroupActivityType.SET_RESOLVED_IN_RELEASE,
data: {
current_release_version: '[email protected]',
current_release_version: currentReleaseVersion,
},
dateCreated: new Date().toISOString(),
project: ProjectFixture(),
project,
},
]}
/>
);
expect(container).toHaveTextContent(
'Foo Bar marked this issue as resolved in versions greater than 1.0.0'
'Foo Bar marked this issue as resolved in versions greater than 1.2.0'
);
});
it('handles inRelease', function () {
const {container} = render(
<ResolutionBox
statusDetails={{
inRelease: '1.0',
inRelease: release.version,
}}
projectId="1"
project={project}
organization={organization}
/>
);
expect(container).toHaveTextContent(
'This issue has been marked as resolved in version 1.0.'
`This issue has been marked as resolved in version ${release.version}.`
);
});
it('handles inRelease with actor', function () {
const {container} = render(
<ResolutionBox
statusDetails={{
inRelease: '1.0',
inRelease: release.version,
actor: {
id: '111',
name: 'David Cramer',
Expand All @@ -92,11 +138,12 @@ describe('ResolutionBox', function () {
email: '[email protected]',
},
}}
projectId="1"
project={project}
organization={organization}
/>
);
expect(container).toHaveTextContent(
'David Cramer marked this issue as resolved in version 1.0.'
`David Cramer marked this issue as resolved in version ${release.version}.`
);
});
it('handles inCommit', function () {
Expand All @@ -105,7 +152,8 @@ describe('ResolutionBox', function () {
statusDetails={{
inCommit: CommitFixture(),
}}
projectId="1"
project={project}
organization={organization}
/>
);
expect(container).toHaveTextContent(
Expand All @@ -126,7 +174,8 @@ describe('ResolutionBox', function () {
email: '[email protected]',
},
}}
projectId="1"
project={project}
organization={organization}
/>
);
expect(container).toHaveTextContent(
Expand Down
Loading
Loading