Skip to content

Commit 41df9ad

Browse files
authored
feat(aci): redirect incidents to metric issue details (#104001)
redirects metric alert incidents to the appropriate metric issue. note we don't currently support passing a specific open period id to the UI, but we can easily add this to the redirect logic later.
1 parent a93dfcf commit 41df9ad

File tree

3 files changed

+141
-5
lines changed

3 files changed

+141
-5
lines changed

static/app/router/routes.tsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1669,7 +1669,9 @@ function buildRoutes(): RouteObject[] {
16691669
},
16701670
{
16711671
path: ':alertId/',
1672-
component: make(() => import('sentry/views/alerts/incidentRedirect')),
1672+
component: make(
1673+
() => import('sentry/views/alerts/workflowEngineRedirectWrappers/incident')
1674+
),
16731675
},
16741676
{
16751677
path: ':projectId/',
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
import {lazy} from 'react';
2+
3+
import {withOpenPeriodRedirect} from 'sentry/views/alerts/workflowEngineRedirects';
4+
5+
const AlertWizardProjectProvider = lazy(
6+
() => import('sentry/views/alerts/incidentRedirect')
7+
);
8+
9+
export default withOpenPeriodRedirect(AlertWizardProjectProvider);

static/app/views/alerts/workflowEngineRedirects.tsx

Lines changed: 129 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import LoadingIndicator from 'sentry/components/loadingIndicator';
22
import Redirect from 'sentry/components/redirect';
33
import {useApiQuery} from 'sentry/utils/queryClient';
4+
import {useLocation} from 'sentry/utils/useLocation';
45
import useOrganization from 'sentry/utils/useOrganization';
56
import {useParams} from 'sentry/utils/useParams';
67
import {useUser} from 'sentry/utils/useUser';
@@ -26,6 +27,13 @@ interface AlertRuleDetector {
2627
ruleId: string | null;
2728
}
2829

30+
interface IncidentGroupOpenPeriod {
31+
groupId: string;
32+
incidentId: string | null;
33+
incidentIdentifier: string;
34+
openPeriodId: string;
35+
}
36+
2937
/**
3038
* HoC that wraps a component to handle workflow engine
3139
* redirects for issue alert rules. Fetches workflow data if needed and
@@ -137,10 +145,86 @@ export const withAutomationEditRedirect = <P extends Record<string, any>>(
137145

138146
export const withDetectorDetailsRedirect = <P extends Record<string, any>>(
139147
Component: React.ComponentType<P>
140-
) =>
141-
withAlertRuleRedirect(Component, (detectorId, orgSlug) =>
142-
makeMonitorDetailsPathname(orgSlug, detectorId)
143-
);
148+
) => {
149+
return function WorkflowEngineRedirectWrapper(props: P) {
150+
const user = useUser();
151+
const organization = useOrganization();
152+
const {ruleId, detectorId} = useParams();
153+
const location = useLocation();
154+
const alertId = location.query.alert as string | undefined;
155+
156+
const shouldRedirect =
157+
!user.isStaff && organization.features.includes('workflow-engine-ui');
158+
159+
// Check for incident open period if alertId is present
160+
const {data: incidentGroupOpenPeriod, isPending: isOpenPeriodPending} =
161+
useApiQuery<IncidentGroupOpenPeriod>(
162+
[
163+
`/organizations/${organization.slug}/incident-groupopenperiod/`,
164+
{query: {incident_identifier: alertId}},
165+
],
166+
{
167+
staleTime: 0,
168+
enabled: shouldRedirect && !!alertId,
169+
retry: false,
170+
}
171+
);
172+
173+
// Check for detector if no alertId
174+
const {data: alertRuleDetector, isPending: isDetectorPending} =
175+
useApiQuery<AlertRuleDetector>(
176+
[
177+
`/organizations/${organization.slug}/alert-rule-detector/`,
178+
{query: {alert_rule_id: ruleId}},
179+
],
180+
{
181+
staleTime: 0,
182+
enabled: shouldRedirect && !!ruleId && !detectorId && !alertId,
183+
retry: false,
184+
}
185+
);
186+
187+
if (shouldRedirect) {
188+
// If alertId is provided, redirect to metric issue
189+
if (alertId) {
190+
if (isOpenPeriodPending) {
191+
return <LoadingIndicator />;
192+
}
193+
if (incidentGroupOpenPeriod) {
194+
return (
195+
<Redirect
196+
to={`/organizations/${organization.slug}/issues/${incidentGroupOpenPeriod.groupId}/`}
197+
/>
198+
);
199+
}
200+
}
201+
202+
// If detectorId is provided, redirect to monitor details
203+
if (detectorId) {
204+
return (
205+
<Redirect to={makeMonitorDetailsPathname(organization.slug, detectorId)} />
206+
);
207+
}
208+
209+
// If alertRuleId is provided, fetch detector and redirect
210+
if (isDetectorPending) {
211+
return <LoadingIndicator />;
212+
}
213+
if (alertRuleDetector) {
214+
return (
215+
<Redirect
216+
to={makeMonitorDetailsPathname(
217+
organization.slug,
218+
alertRuleDetector.detectorId
219+
)}
220+
/>
221+
);
222+
}
223+
}
224+
225+
return <Component {...(props as any)} />;
226+
};
227+
};
144228

145229
export const withDetectorEditRedirect = <P extends Record<string, any>>(
146230
Component: React.ComponentType<P>
@@ -183,3 +267,44 @@ export function withDetectorCreateRedirect<P extends Record<string, any>>(
183267
return <Component {...(props as any)} />;
184268
};
185269
}
270+
271+
export function withOpenPeriodRedirect<P extends Record<string, any>>(
272+
Component: React.ComponentType<P>
273+
) {
274+
return function OpenPeriodRedirectWrapper(props: P) {
275+
const user = useUser();
276+
const organization = useOrganization();
277+
const {alertId} = useParams();
278+
279+
const shouldRedirect =
280+
!user.isStaff && organization.features.includes('workflow-engine-ui');
281+
282+
const {data: incidentGroupOpenPeriod, isPending} =
283+
useApiQuery<IncidentGroupOpenPeriod>(
284+
[
285+
`/organizations/${organization.slug}/incident-groupopenperiod/`,
286+
{query: {incident_identifier: alertId}},
287+
],
288+
{
289+
staleTime: 0,
290+
enabled: shouldRedirect && !!alertId,
291+
retry: false,
292+
}
293+
);
294+
295+
if (shouldRedirect) {
296+
if (isPending) {
297+
return <LoadingIndicator />;
298+
}
299+
if (incidentGroupOpenPeriod) {
300+
return (
301+
<Redirect
302+
to={`/organizations/${organization.slug}/issues/${incidentGroupOpenPeriod.groupId}/`}
303+
/>
304+
);
305+
}
306+
}
307+
308+
return <Component {...(props as any)} />;
309+
};
310+
}

0 commit comments

Comments
 (0)