Skip to content

Commit 92ef772

Browse files
committed
feat(issue-progress): Add actions to issue preview
1 parent 5be84a6 commit 92ef772

2 files changed

Lines changed: 128 additions & 2 deletions

File tree

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
import {GroupFixture} from 'sentry-fixture/group';
2+
import {OrganizationFixture} from 'sentry-fixture/organization';
3+
import {ProjectFixture} from 'sentry-fixture/project';
4+
import {TeamFixture} from 'sentry-fixture/team';
5+
import {UserFixture} from 'sentry-fixture/user';
6+
7+
import {render, screen, userEvent, waitFor} from 'sentry-test/reactTestingLibrary';
8+
9+
import {ConfigStore} from 'sentry/stores/configStore';
10+
import {ProjectsStore} from 'sentry/stores/projectsStore';
11+
import {IssueCategory} from 'sentry/types/group';
12+
import {IssuePreviewDrawer} from 'sentry/views/issueDetails/issuePreview/issuePreviewDrawer';
13+
14+
const organization = OrganizationFixture({id: '4660', slug: 'org'});
15+
16+
const project = ProjectFixture({
17+
id: '2448',
18+
name: 'project name',
19+
slug: 'project',
20+
teams: [TeamFixture({id: '3', slug: 'frontend', name: 'Frontend'})],
21+
});
22+
23+
const group = GroupFixture({
24+
id: '1337',
25+
issueCategory: IssueCategory.ERROR,
26+
project,
27+
});
28+
29+
describe('IssuePreviewDrawer', () => {
30+
beforeEach(() => {
31+
ConfigStore.init();
32+
ConfigStore.set('user', UserFixture());
33+
ProjectsStore.reset();
34+
ProjectsStore.loadInitialData([project]);
35+
36+
MockApiClient.addMockResponse({
37+
url: `/organizations/${organization.slug}/issues/${group.id}/`,
38+
body: group,
39+
});
40+
MockApiClient.addMockResponse({
41+
url: `/organizations/${organization.slug}/users/`,
42+
body: [],
43+
});
44+
MockApiClient.addMockResponse({
45+
url: `/organizations/${organization.slug}/issues/${group.id}/autofix/setup/`,
46+
body: {
47+
billing: null,
48+
integration: {ok: false, reason: null},
49+
seerReposLinked: false,
50+
githubWriteIntegration: null,
51+
},
52+
});
53+
MockApiClient.addMockResponse({
54+
url: `/organizations/${organization.slug}/integrations/coding-agents/`,
55+
body: {integrations: []},
56+
});
57+
MockApiClient.addMockResponse({
58+
url: `/organizations/${organization.slug}/replay-count/`,
59+
body: {},
60+
});
61+
MockApiClient.addMockResponse({
62+
url: `/organizations/${organization.slug}/issues/${group.id}/attachments/`,
63+
body: [],
64+
});
65+
});
66+
67+
afterEach(() => {
68+
MockApiClient.clearMockResponses();
69+
jest.clearAllMocks();
70+
});
71+
72+
it('resolves the issue', async () => {
73+
const updateRequest = MockApiClient.addMockResponse({
74+
url: `/projects/${organization.slug}/${project.slug}/issues/`,
75+
method: 'PUT',
76+
body: {...group, status: 'resolved'},
77+
});
78+
79+
render(<IssuePreviewDrawer groupId={group.id} />, {organization});
80+
81+
const resolveButton = await screen.findByRole('button', {name: 'Resolve'});
82+
83+
// The drawer refetches the group after the update; return the resolved group.
84+
MockApiClient.addMockResponse({
85+
url: `/organizations/${organization.slug}/issues/${group.id}/`,
86+
body: {...group, status: 'resolved'},
87+
});
88+
89+
await userEvent.click(resolveButton);
90+
91+
await waitFor(() => {
92+
expect(updateRequest).toHaveBeenCalledWith(
93+
`/projects/${organization.slug}/${project.slug}/issues/`,
94+
expect.objectContaining({
95+
data: {status: 'resolved', statusDetails: {}, substatus: null},
96+
})
97+
);
98+
});
99+
100+
expect(await screen.findAllByText('Resolved')).not.toHaveLength(0);
101+
});
102+
});

static/app/views/issueDetails/issuePreview/issuePreviewDrawer.tsx

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import {Fragment} from 'react';
33
import {LinkButton} from '@sentry/scraps/button';
44
import {DrawerBody, DrawerHeader} from '@sentry/scraps/drawer';
55
import {Container, Flex} from '@sentry/scraps/layout';
6-
import {Heading} from '@sentry/scraps/text';
6+
import {Heading, Text} from '@sentry/scraps/text';
77
import {Tooltip} from '@sentry/scraps/tooltip';
88

99
import {ErrorBoundary} from 'sentry/components/errorBoundary';
@@ -18,6 +18,8 @@ import {normalizeUrl} from 'sentry/utils/url/normalizeUrl';
1818
import {useOrganization} from 'sentry/utils/useOrganization';
1919
import {useProjects} from 'sentry/utils/useProjects';
2020
import {GroupActions} from 'sentry/views/issueDetails/actions/index';
21+
import {GroupPriority} from 'sentry/views/issueDetails/groupPriority';
22+
import {GroupHeaderAssigneeSelector} from 'sentry/views/issueDetails/header/assigneeSelector';
2123
import {GroupStatusSubtitle} from 'sentry/views/issueDetails/header/groupStatusSubtitle';
2224
import {IssueIdBreadcrumb} from 'sentry/views/issueDetails/header/issueIdBreadcrumb';
2325
import {useGroup} from 'sentry/views/issueDetails/useGroup';
@@ -99,8 +101,30 @@ function IssuePreviewContent({
99101
<GroupStatusSubtitle group={group} project={project} />
100102
</Flex>
101103
</Container>
102-
<Flex paddingTop="lg" align="center" wrap="wrap" gap="xs">
104+
<Flex
105+
paddingTop="lg"
106+
paddingBottom="lg"
107+
borderBottom="muted"
108+
justify="between"
109+
align="center"
110+
wrap="wrap"
111+
gap="md"
112+
>
103113
<GroupActions group={group} project={project} disabled={false} event={null} />
114+
<Flex align="center" wrap="wrap" gap="lg">
115+
<Flex align="center" gap="xs">
116+
<Text size="sm" variant="muted">
117+
{t('Priority')}
118+
</Text>
119+
<GroupPriority group={group} />
120+
</Flex>
121+
<Flex align="center" gap="xs">
122+
<Text size="sm" variant="muted">
123+
{t('Assignee')}
124+
</Text>
125+
<GroupHeaderAssigneeSelector group={group} project={project} event={null} />
126+
</Flex>
127+
</Flex>
104128
</Flex>
105129
</Fragment>
106130
);

0 commit comments

Comments
 (0)