Skip to content

Commit 2bce2c7

Browse files
authored
feat(eap-alerts): UI deprecation of transaction alerts (#93096)
If the feature flag is enabled, all the aggregation based alerts point to span metrics instead of transactions. This is in preparation for transaction alert deprecation.
1 parent e8eff68 commit 2bce2c7

File tree

12 files changed

+400
-55
lines changed

12 files changed

+400
-55
lines changed

static/app/views/alerts/create.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,7 @@ function Create(props: Props) {
122122
let wizardAlertType: undefined | WizardAlertType;
123123
if (createFromWizard && alertType === AlertRuleType.METRIC) {
124124
wizardAlertType = wizardTemplate
125-
? getAlertTypeFromAggregateDataset(wizardTemplate)
125+
? getAlertTypeFromAggregateDataset({...wizardTemplate, organization})
126126
: 'issues';
127127
}
128128

static/app/views/alerts/rules/metric/constants.tsx

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -180,10 +180,11 @@ export function getWizardAlertFieldConfig(
180180
return errorFieldConfig;
181181
}
182182
// If user selected apdex we must include that in the OptionConfig as it has a user specified column
183-
const aggregations =
184-
alertType === 'apdex' || alertType === 'custom_transactions'
185-
? allAggregations
186-
: commonAggregations;
183+
const aggregations = ['apdex', 'trace_item_apdex', 'custom_transactions'].includes(
184+
alertType
185+
)
186+
? allAggregations
187+
: commonAggregations;
187188

188189
const config: OptionConfig = {
189190
aggregations,

static/app/views/alerts/rules/metric/details/metricChart.tsx

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,10 @@ import {makeDefaultCta} from 'sentry/views/alerts/rules/metric/metricRulePresets
5656
import type {MetricRule} from 'sentry/views/alerts/rules/metric/types';
5757
import {AlertRuleTriggerType, Dataset} from 'sentry/views/alerts/rules/metric/types';
5858
import {isCrashFreeAlert} from 'sentry/views/alerts/rules/metric/utils/isCrashFreeAlert';
59-
import {shouldUseErrorsDiscoverDataset} from 'sentry/views/alerts/rules/utils';
59+
import {
60+
isEapAlertType,
61+
shouldUseErrorsDiscoverDataset,
62+
} from 'sentry/views/alerts/rules/utils';
6063
import type {Anomaly, Incident} from 'sentry/views/alerts/types';
6164
import {
6265
alertDetailsLink,
@@ -284,7 +287,7 @@ export default function MetricChart({
284287
</Fragment>
285288
</StyledInlineContainer>
286289
{!isSessionAggregate(rule.aggregate) &&
287-
(getAlertTypeFromAggregateDataset(rule) === 'eap_metrics' ? (
290+
(isEapAlertType(getAlertTypeFromAggregateDataset(rule)) ? (
288291
<Feature features="visibility-explore-view">
289292
<LinkButton size="sm" {...props}>
290293
{buttonText}

static/app/views/alerts/rules/metric/ruleForm.spec.tsx

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,10 @@ describe('Incident Rules Form', () => {
8181
url: '/organizations/org-slug/events-meta/',
8282
body: {count: 5},
8383
});
84+
MockApiClient.addMockResponse({
85+
url: '/organizations/org-slug/trace-items/attributes/',
86+
body: [],
87+
});
8488
MockApiClient.addMockResponse({
8589
url: '/organizations/org-slug/events/',
8690
body: {},
@@ -413,6 +417,57 @@ describe('Incident Rules Form', () => {
413417
);
414418
expect(metric.startSpan).toHaveBeenCalledWith({name: 'saveAlertRule'});
415419
});
420+
421+
it('switches to failure rate with eap data with the right feature flag', async () => {
422+
organization.features = [
423+
...organization.features,
424+
'performance-view',
425+
'visibility-explore-view',
426+
'performance-transaction-deprecation-alerts',
427+
];
428+
const rule = MetricRuleFixture();
429+
createWrapper({
430+
rule: {
431+
...rule,
432+
id: undefined,
433+
eventTypes: [],
434+
aggregate: 'count(span.duration)',
435+
dataset: Dataset.EVENTS_ANALYTICS_PLATFORM,
436+
},
437+
});
438+
439+
await userEvent.click(screen.getAllByText('Throughput')[1]!);
440+
await userEvent.click(await screen.findByText('Failure Rate'));
441+
442+
await userEvent.click(screen.getByLabelText('Save Rule'));
443+
444+
expect(createRule).toHaveBeenLastCalledWith(
445+
expect.anything(),
446+
expect.objectContaining({
447+
data: expect.objectContaining({
448+
aggregate: 'failure_rate()',
449+
alertType: 'trace_item_failure_rate',
450+
comparisonDelta: null,
451+
dataset: 'events_analytics_platform',
452+
detectionType: 'static',
453+
environment: null,
454+
eventTypes: ['trace_item_span'],
455+
id: undefined,
456+
name: 'My Incident Rule',
457+
owner: undefined,
458+
projectId: '2',
459+
projects: ['project-slug'],
460+
query: '',
461+
queryType: 1,
462+
resolveThreshold: 36,
463+
status: 0,
464+
thresholdPeriod: 1,
465+
thresholdType: 0,
466+
timeWindow: 60,
467+
}),
468+
})
469+
);
470+
});
416471
});
417472

418473
describe('Editing a rule', () => {

static/app/views/alerts/rules/metric/ruleForm.tsx

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@ import {isEventsStats} from 'sentry/views/dashboards/utils/isEventsStats';
7070
import type {TimeSeries} from 'sentry/views/dashboards/widgets/common/types';
7171
import {combineConfidenceForSeries} from 'sentry/views/explore/utils';
7272
import {convertEventsStatsToTimeSeriesData} from 'sentry/views/insights/common/queries/useSortedTimeSeries';
73+
import {deprecateTransactionAlerts} from 'sentry/views/insights/common/utils/hasEAPAlerts';
7374
import {ProjectPermissionAlert} from 'sentry/views/settings/project/projectPermissionAlert';
7475

7576
import {isCrashFreeAlert} from './utils/isCrashFreeAlert';
@@ -200,7 +201,7 @@ class RuleFormContainer extends DeprecatedAsyncComponent<Props, State> {
200201
}
201202

202203
getDefaultState(): State {
203-
const {rule, location} = this.props;
204+
const {rule, location, organization} = this.props;
204205
const triggersClone = [...rule.triggers];
205206
const {
206207
aggregate: _aggregate,
@@ -225,6 +226,12 @@ class RuleFormContainer extends DeprecatedAsyncComponent<Props, State> {
225226
? `is:unresolved ${rule.query ?? ''}`
226227
: (rule.query ?? '');
227228

229+
const alertType = getAlertTypeFromAggregateDataset({
230+
aggregate,
231+
dataset,
232+
organization,
233+
});
234+
228235
return {
229236
...super.getDefaultState(),
230237
currentData: [],
@@ -255,7 +262,7 @@ class RuleFormContainer extends DeprecatedAsyncComponent<Props, State> {
255262
: AlertRuleComparisonType.COUNT,
256263
project: this.props.project,
257264
owner: rule.owner,
258-
alertType: getAlertTypeFromAggregateDataset({aggregate, dataset}),
265+
alertType,
259266
};
260267
}
261268

@@ -547,7 +554,7 @@ class RuleFormContainer extends DeprecatedAsyncComponent<Props, State> {
547554
}
548555

549556
handleFieldChange = (name: string, value: unknown) => {
550-
const {projects} = this.props;
557+
const {projects, organization} = this.props;
551558
const {timeWindow, chartError} = this.state;
552559
if (chartError) {
553560
this.setState({chartError: false, chartErrorMessage: undefined});
@@ -600,9 +607,24 @@ class RuleFormContainer extends DeprecatedAsyncComponent<Props, State> {
600607
this.state.query
601608
);
602609

610+
if (deprecateTransactionAlerts(organization)) {
611+
const newAlertType = getAlertTypeFromAggregateDataset({
612+
aggregate: name === 'aggregate' ? (value as string) : aggregate,
613+
dataset,
614+
organization,
615+
});
616+
617+
return {
618+
[name]: value,
619+
alertType: newAlertType,
620+
dataset,
621+
};
622+
}
623+
603624
const newAlertType = getAlertTypeFromAggregateDataset({
604625
aggregate,
605626
dataset,
627+
organization,
606628
});
607629

608630
return {

static/app/views/alerts/rules/metric/wizardField.tsx

Lines changed: 70 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,10 @@ import {
2121
import {QueryField} from 'sentry/views/discover/table/queryField';
2222
import {FieldValueKind} from 'sentry/views/discover/table/types';
2323
import {generateFieldOptions} from 'sentry/views/discover/utils';
24-
import {hasEAPAlerts} from 'sentry/views/insights/common/utils/hasEAPAlerts';
24+
import {
25+
deprecateTransactionAlerts,
26+
hasEAPAlerts,
27+
} from 'sentry/views/insights/common/utils/hasEAPAlerts';
2528

2629
import {getFieldOptionConfig} from './metricField';
2730

@@ -37,6 +40,7 @@ type Props = Omit<FormFieldProps, 'children'> & {
3740
*/
3841
columnWidth?: number;
3942
inFieldLabels?: boolean;
43+
isEditing?: boolean;
4044
};
4145

4246
export default function WizardField({
@@ -46,6 +50,68 @@ export default function WizardField({
4650
alertType,
4751
...fieldProps
4852
}: Props) {
53+
const deprecatedTransactionAggregationOptions: MenuOption[] = [
54+
{
55+
label: AlertWizardAlertNames.throughput,
56+
value: 'throughput',
57+
},
58+
{
59+
label: AlertWizardAlertNames.trans_duration,
60+
value: 'trans_duration',
61+
},
62+
{
63+
label: AlertWizardAlertNames.apdex,
64+
value: 'apdex',
65+
},
66+
{
67+
label: AlertWizardAlertNames.failure_rate,
68+
value: 'failure_rate',
69+
},
70+
{
71+
label: AlertWizardAlertNames.lcp,
72+
value: 'lcp',
73+
},
74+
{
75+
label: AlertWizardAlertNames.fid,
76+
value: 'fid',
77+
},
78+
{
79+
label: AlertWizardAlertNames.cls,
80+
value: 'cls',
81+
},
82+
];
83+
84+
const traceItemAggregationOptions: MenuOption[] = [
85+
{
86+
label: AlertWizardAlertNames.trace_item_throughput,
87+
value: 'trace_item_throughput',
88+
},
89+
{
90+
label: AlertWizardAlertNames.trace_item_duration,
91+
value: 'trace_item_duration',
92+
},
93+
{
94+
label: AlertWizardAlertNames.trace_item_apdex,
95+
value: 'trace_item_apdex',
96+
},
97+
{
98+
label: AlertWizardAlertNames.trace_item_failure_rate,
99+
value: 'trace_item_failure_rate',
100+
},
101+
{
102+
label: AlertWizardAlertNames.trace_item_lcp,
103+
value: 'trace_item_lcp',
104+
},
105+
{
106+
label: AlertWizardAlertNames.trace_item_fid,
107+
value: 'trace_item_fid',
108+
},
109+
{
110+
label: AlertWizardAlertNames.trace_item_cls,
111+
value: 'trace_item_cls',
112+
},
113+
];
114+
49115
const menuOptions: GroupedMenuOption[] = [
50116
{
51117
label: t('ERRORS'),
@@ -80,34 +146,9 @@ export default function WizardField({
80146
{
81147
label: t('PERFORMANCE'),
82148
options: [
83-
{
84-
label: AlertWizardAlertNames.throughput,
85-
value: 'throughput',
86-
},
87-
{
88-
label: AlertWizardAlertNames.trans_duration,
89-
value: 'trans_duration',
90-
},
91-
{
92-
label: AlertWizardAlertNames.apdex,
93-
value: 'apdex',
94-
},
95-
{
96-
label: AlertWizardAlertNames.failure_rate,
97-
value: 'failure_rate',
98-
},
99-
{
100-
label: AlertWizardAlertNames.lcp,
101-
value: 'lcp',
102-
},
103-
{
104-
label: AlertWizardAlertNames.fid,
105-
value: 'fid',
106-
},
107-
{
108-
label: AlertWizardAlertNames.cls,
109-
value: 'cls',
110-
},
149+
...(deprecateTransactionAlerts(organization)
150+
? traceItemAggregationOptions
151+
: deprecatedTransactionAggregationOptions),
111152

112153
...(hasEAPAlerts(organization)
113154
? [

static/app/views/alerts/rules/utils.tsx

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -168,5 +168,14 @@ export function isEapAlertType(alertType?: AlertType) {
168168
if (!defined(alertType)) {
169169
return false;
170170
}
171-
return alertType === 'eap_metrics';
171+
return [
172+
'eap_metrics',
173+
'trace_item_throughput',
174+
'trace_item_duration',
175+
'trace_item_apdex',
176+
'trace_item_failure_rate',
177+
'trace_item_lcp',
178+
'trace_item_fid',
179+
'trace_item_cls',
180+
].includes(alertType);
172181
}

0 commit comments

Comments
 (0)