Skip to content

Commit 50bffdd

Browse files
authored
feat(aci): Add edit detector page for error type (#96482)
1 parent 41c7df7 commit 50bffdd

File tree

6 files changed

+523
-237
lines changed

6 files changed

+523
-237
lines changed

static/app/types/workflowEngine/detectors.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,7 @@ export interface BaseDetectorUpdatePayload {
175175
name: string;
176176
owner: Detector['owner'];
177177
projectId: Detector['projectId'];
178+
type: Detector['type'];
178179
workflowIds: string[];
179180
}
180181

static/app/views/detectors/components/details/error/index.spec.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ describe('ErrorDetectorDetails', function () {
3232
render(<ErrorDetectorDetails {...defaultProps} />);
3333

3434
expect(
35-
await screen.findByText('Auto-resolve after 30 days of inactivity')
35+
await screen.findByText('Auto-resolve after 30 days of inactivity.')
3636
).toBeInTheDocument();
3737
});
3838

@@ -41,7 +41,7 @@ describe('ErrorDetectorDetails', function () {
4141

4242
render(<ErrorDetectorDetails {...defaultProps} project={project} />);
4343

44-
expect(await screen.findByText('Auto-resolution disabled')).toBeInTheDocument();
44+
expect(await screen.findByText('Auto-resolution disabled.')).toBeInTheDocument();
4545
});
4646
});
4747
});

static/app/views/detectors/components/details/error/index.tsx

Lines changed: 36 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
import ExternalLink from 'sentry/components/links/externalLink';
1+
import {ExternalLink, Link} from 'sentry/components/core/link';
2+
import {Text} from 'sentry/components/core/text';
23
import Placeholder from 'sentry/components/placeholder';
34
import DetailLayout from 'sentry/components/workflowEngine/layout/detail';
45
import Section from 'sentry/components/workflowEngine/ui/section';
@@ -7,7 +8,6 @@ import type {Project} from 'sentry/types/project';
78
import type {Detector} from 'sentry/types/workflowEngine/detectors';
89
import {useDetailedProject} from 'sentry/utils/useDetailedProject';
910
import useOrganization from 'sentry/utils/useOrganization';
10-
import {DetectorDetailsAssignee} from 'sentry/views/detectors/components/details/common/assignee';
1111
import {DetectorDetailsAutomations} from 'sentry/views/detectors/components/details/common/automations';
1212
import {DetectorExtraDetails} from 'sentry/views/detectors/components/details/common/extraDetails';
1313
import {DetectorDetailsHeader} from 'sentry/views/detectors/components/details/common/header';
@@ -20,19 +20,19 @@ type ErrorDetectorDetailsProps = {
2020

2121
const formatResolveAge = (resolveAge: number) => {
2222
if (!resolveAge) {
23-
return t('Auto-resolution disabled');
23+
return t('Auto-resolution disabled.');
2424
}
2525

2626
if (resolveAge < 24 || resolveAge % 24 !== 0) {
2727
return tn(
28-
'Auto-resolve after %s hour of inactivity',
28+
'Auto-resolve after %s hour of inactivity.',
2929
'Auto-resolve after %s hours of inactivity',
3030
resolveAge
3131
);
3232
}
3333
return tn(
34-
'Auto-resolve after %s day of inactivity',
35-
'Auto-resolve after %s days of inactivity',
34+
'Auto-resolve after %s day of inactivity.',
35+
'Auto-resolve after %s days of inactivity.',
3636
resolveAge / 24
3737
);
3838
};
@@ -62,6 +62,8 @@ function ResolveSection({project}: {project: Project}) {
6262
}
6363

6464
export function ErrorDetectorDetails({detector, project}: ErrorDetectorDetailsProps) {
65+
const organization = useOrganization();
66+
6567
return (
6668
<DetailLayout>
6769
<DetectorDetailsHeader detector={detector} project={project} />
@@ -72,7 +74,7 @@ export function ErrorDetectorDetails({detector, project}: ErrorDetectorDetailsPr
7274
</DetailLayout.Main>
7375
<DetailLayout.Sidebar>
7476
<Section title={t('Detect')}>
75-
<p>
77+
<Text as="p">
7678
{tct(
7779
'All events have a fingerprint. Events with the same fingerprint are grouped together into an issue. To learn more about issue grouping, [link:read the docs].',
7880
{
@@ -81,9 +83,34 @@ export function ErrorDetectorDetails({detector, project}: ErrorDetectorDetailsPr
8183
),
8284
}
8385
)}
84-
</p>
86+
</Text>
87+
</Section>
88+
<Section title={t('Assign')}>
89+
<Text as="p">
90+
{tct(
91+
'Sentry will attempt to autotmatically assign new issues based on [link:Ownership Rules].',
92+
{
93+
link: (
94+
<Link
95+
to={`/settings/${organization.slug}/projects/${project?.slug}/ownership/`}
96+
/>
97+
),
98+
}
99+
)}
100+
</Text>
101+
</Section>
102+
<Section title={t('Prioritize')}>
103+
<Text as="p">
104+
{tct(
105+
'New error issues are prioritized based on log level. [link:Learn more about Issue Priority].',
106+
{
107+
link: (
108+
<ExternalLink href="https://docs.sentry.io/product/issues/issue-priority/" />
109+
),
110+
}
111+
)}
112+
</Text>
85113
</Section>
86-
<DetectorDetailsAssignee owner={detector.owner} />
87114
<ResolveSection project={project} />
88115
<DetectorExtraDetails>
89116
<DetectorExtraDetails.DateCreated detector={detector} />
Lines changed: 165 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,165 @@
1+
import {Link} from 'react-router-dom';
2+
import styled from '@emotion/styled';
3+
4+
import {Button} from 'sentry/components/core/button';
5+
import {ButtonBar} from 'sentry/components/core/button/buttonBar';
6+
import {ExternalLink} from 'sentry/components/core/link';
7+
import {Text} from 'sentry/components/core/text';
8+
import * as Layout from 'sentry/components/layouts/thirds';
9+
import LoadingError from 'sentry/components/loadingError';
10+
import EditLayout from 'sentry/components/workflowEngine/layout/edit';
11+
import {Container} from 'sentry/components/workflowEngine/ui/container';
12+
import Section from 'sentry/components/workflowEngine/ui/section';
13+
import {t, tct} from 'sentry/locale';
14+
import {space} from 'sentry/styles/space';
15+
import type {ErrorDetector} from 'sentry/types/workflowEngine/detectors';
16+
import useOrganization from 'sentry/utils/useOrganization';
17+
import useProjectFromId from 'sentry/utils/useProjectFromId';
18+
import {AutomateSection} from 'sentry/views/detectors/components/forms/automateSection';
19+
import {EditDetectorBreadcrumbs} from 'sentry/views/detectors/components/forms/common/breadcrumbs';
20+
import {useEditDetectorFormSubmit} from 'sentry/views/detectors/hooks/useEditDetectorFormSubmit';
21+
22+
type ErrorDetectorFormData = {
23+
workflowIds: string[];
24+
};
25+
26+
function ErrorDetectorForm({detector}: {detector: ErrorDetector}) {
27+
const organization = useOrganization();
28+
const project = useProjectFromId({project_id: detector.projectId});
29+
30+
return (
31+
<FormStack>
32+
<Container>
33+
<Section title={t('Detect')}>
34+
<Text as="p">
35+
{tct(
36+
'An error issue will be created when a new issue group is detected. [link:Manage Grouping Rules]',
37+
{
38+
link: (
39+
<Link
40+
to={`/settings/${organization.slug}/projects/${project?.slug}/issue-grouping/`}
41+
/>
42+
),
43+
}
44+
)}
45+
</Text>
46+
</Section>
47+
</Container>
48+
<Container>
49+
<Section title={t('Assign')}>
50+
<Text as="p">
51+
{tct(
52+
'Sentry will attempt to autotmatically assign new issues based on [link:Ownership Rules].',
53+
{
54+
link: (
55+
<Link
56+
to={`/settings/${organization.slug}/projects/${project?.slug}/ownership/`}
57+
/>
58+
),
59+
}
60+
)}
61+
</Text>
62+
</Section>
63+
</Container>
64+
<Container>
65+
<Section title={t('Prioritize')}>
66+
<Text as="p">
67+
{tct(
68+
'New error issues are prioritized based on log level. [link:Learn more about Issue Priority]',
69+
{
70+
link: (
71+
<ExternalLink href="https://docs.sentry.io/product/issues/issue-priority/" />
72+
),
73+
}
74+
)}
75+
</Text>
76+
</Section>
77+
</Container>
78+
<Container>
79+
<Section title={t('Prioritize')}>
80+
<Text as="p">
81+
{tct(
82+
'Issues may be automatically resolved based on [link:Auto Resolve Settings].',
83+
{
84+
link: (
85+
<Link
86+
to={`/settings/${organization.slug}/projects/${project?.slug}/#resolveAge`}
87+
/>
88+
),
89+
}
90+
)}
91+
</Text>
92+
</Section>
93+
</Container>
94+
<AutomateSection />
95+
</FormStack>
96+
);
97+
}
98+
99+
export function NewErrorDetectorForm() {
100+
return (
101+
<Layout.Page>
102+
<Layout.Body>
103+
<Layout.Main fullWidth>
104+
<LoadingError message={t('Error detectors cannot be created')} />
105+
</Layout.Main>
106+
</Layout.Body>
107+
</Layout.Page>
108+
);
109+
}
110+
111+
export function EditExistingErrorDetectorForm({detector}: {detector: ErrorDetector}) {
112+
const project = useProjectFromId({project_id: detector.projectId});
113+
114+
const handleFormSubmit = useEditDetectorFormSubmit({
115+
detector,
116+
formDataToEndpointPayload: (data: ErrorDetectorFormData) => ({
117+
type: 'error',
118+
name: detector.name,
119+
owner: detector.owner,
120+
projectId: detector.projectId,
121+
workflowIds: data.workflowIds,
122+
dataSource: {},
123+
conditionGroup: {},
124+
}),
125+
});
126+
127+
return (
128+
<EditLayout
129+
formProps={{
130+
initialData: {
131+
workflowIds: detector.workflowIds,
132+
},
133+
onSubmit: handleFormSubmit,
134+
}}
135+
>
136+
<EditLayout.Header>
137+
<EditLayout.HeaderContent>
138+
<EditDetectorBreadcrumbs detector={detector} />
139+
<EditLayout.Title title={detector.name} project={project} />
140+
</EditLayout.HeaderContent>
141+
142+
<EditLayout.Actions>
143+
<div>
144+
<ButtonBar>
145+
<Button type="submit" priority="primary" size="sm">
146+
{t('Save')}
147+
</Button>
148+
</ButtonBar>
149+
</div>
150+
</EditLayout.Actions>
151+
</EditLayout.Header>
152+
153+
<EditLayout.Body>
154+
<ErrorDetectorForm detector={detector} />
155+
</EditLayout.Body>
156+
</EditLayout>
157+
);
158+
}
159+
160+
const FormStack = styled('div')`
161+
display: flex;
162+
flex-direction: column;
163+
gap: ${space(3)};
164+
max-width: ${p => p.theme.breakpoints.xl};
165+
`;

static/app/views/detectors/components/forms/index.tsx

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,10 @@ import LoadingError from 'sentry/components/loadingError';
33
import {t} from 'sentry/locale';
44
import type {Detector, DetectorType} from 'sentry/types/workflowEngine/detectors';
55
import {unreachable} from 'sentry/utils/unreachable';
6+
import {
7+
EditExistingErrorDetectorForm,
8+
NewErrorDetectorForm,
9+
} from 'sentry/views/detectors/components/forms/error';
610
import {
711
EditExistingMetricDetectorForm,
812
NewMetricDetectorForm,
@@ -31,7 +35,7 @@ export function NewDetectorForm({detectorType}: {detectorType: DetectorType}) {
3135
case 'uptime_domain_failure':
3236
return <NewUptimeDetectorForm />;
3337
case 'error':
34-
return <PlaceholderForm />;
38+
return <NewErrorDetectorForm />;
3539
case 'uptime_subscription':
3640
return <PlaceholderForm />;
3741
default:
@@ -48,7 +52,7 @@ export function EditExistingDetectorForm({detector}: {detector: Detector}) {
4852
case 'uptime_domain_failure':
4953
return <EditExistingUptimeDetectorForm detector={detector} />;
5054
case 'error':
51-
return <PlaceholderForm />;
55+
return <EditExistingErrorDetectorForm detector={detector} />;
5256
case 'uptime_subscription':
5357
return <PlaceholderForm />;
5458
default:

0 commit comments

Comments
 (0)