Skip to content

Commit 392ff41

Browse files
committed
add in banners and warnings for old alerts UI
1 parent 88d2f92 commit 392ff41

File tree

3 files changed

+182
-42
lines changed

3 files changed

+182
-42
lines changed

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

Lines changed: 88 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -21,13 +21,15 @@ import {shouldShowOnDemandMetricAlertUI} from 'sentry/utils/onDemandMetrics/feat
2121
import {useLocation} from 'sentry/utils/useLocation';
2222
import {useNavigate} from 'sentry/utils/useNavigate';
2323
import useOrganization from 'sentry/utils/useOrganization';
24+
import {makeAlertsPathname} from 'sentry/views/alerts/pathnames';
2425
import AnomalyDetectionFeedbackBanner from 'sentry/views/alerts/rules/metric/details/anomalyDetectionFeedbackBanner';
2526
import {ErrorMigrationWarning} from 'sentry/views/alerts/rules/metric/details/errorMigrationWarning';
2627
import MetricHistory from 'sentry/views/alerts/rules/metric/details/metricHistory';
2728
import type {MetricRule} from 'sentry/views/alerts/rules/metric/types';
2829
import {
2930
AlertRuleComparisonType,
3031
Dataset,
32+
ExtrapolationMode,
3133
TimePeriod,
3234
} from 'sentry/views/alerts/rules/metric/types';
3335
import {extractEventTypeFilterFromRule} from 'sentry/views/alerts/rules/metric/utils/getEventTypeFilter';
@@ -69,10 +71,6 @@ export default function MetricDetailsBody({
6971
const organization = useOrganization();
7072
const location = useLocation();
7173
const navigate = useNavigate();
72-
const [showTransactionsDeprecationAlert, setShowTransactionsDeprecationAlert] =
73-
useState(
74-
organization.features.includes('performance-transaction-deprecation-banner')
75-
);
7674

7775
const handleTimePeriodChange = (datetime: ChangeData) => {
7876
const {start, end, relative} = datetime;
@@ -146,6 +144,13 @@ export default function MetricDetailsBody({
146144
const deprecateTransactionsAlertsWarning =
147145
ruleType && DEPRECATED_TRANSACTION_ALERTS.includes(ruleType);
148146

147+
const showExtrapolationModeWarning = !!(
148+
rule.dataset === Dataset.EVENTS_ANALYTICS_PLATFORM &&
149+
rule.extrapolationMode &&
150+
(rule.extrapolationMode === ExtrapolationMode.SERVER_WEIGHTED ||
151+
rule.extrapolationMode === ExtrapolationMode.NONE)
152+
);
153+
149154
return (
150155
<Fragment>
151156
{selectedIncident?.alertRule.status === AlertRuleStatus.SNAPSHOT && (
@@ -173,33 +178,12 @@ export default function MetricDetailsBody({
173178
)}
174179
</Alert.Container>
175180
)}
176-
{deprecateTransactionsAlertsWarning && showTransactionsDeprecationAlert && (
177-
<Alert.Container>
178-
<Alert
179-
type="warning"
180-
trailingItems={
181-
<StyledCloseButton
182-
icon={<IconClose size="sm" />}
183-
aria-label={t('Close')}
184-
onClick={() => {
185-
setShowTransactionsDeprecationAlert(false);
186-
}}
187-
size="zero"
188-
borderless
189-
/>
190-
}
191-
>
192-
{tctCode(
193-
'The transaction dataset is being deprecated. Please use Span alerts instead. Spans are a superset of transactions, you can isolate transactions by using the [code:is_transaction:true] filter. Please read these [FAQLink:FAQs] for more information.',
194-
{
195-
FAQLink: (
196-
<ExternalLink href="https://sentry.zendesk.com/hc/en-us/articles/40366087871515-FAQ-Transactions-Spans-Migration" />
197-
),
198-
}
199-
)}
200-
</Alert>
201-
</Alert.Container>
202-
)}
181+
<TransactionsDeprecationAlert isEnabled={deprecateTransactionsAlertsWarning} />
182+
<MigratedAlertWarning
183+
isEnabled={showExtrapolationModeWarning}
184+
rule={rule}
185+
project={project}
186+
/>
203187
<StyledSubHeader>
204188
<StyledTimeRangeSelector
205189
relative={timePeriod.period ?? ''}
@@ -301,6 +285,79 @@ export default function MetricDetailsBody({
301285
);
302286
}
303287

288+
function TransactionsDeprecationAlert({isEnabled}: {isEnabled: boolean}) {
289+
const organization = useOrganization();
290+
const [showTransactionsDeprecationAlert, setShowTransactionsDeprecationAlert] =
291+
useState(
292+
organization.features.includes('performance-transaction-deprecation-banner')
293+
);
294+
295+
if (isEnabled && showTransactionsDeprecationAlert) {
296+
return (
297+
<Alert.Container>
298+
<Alert
299+
type="warning"
300+
trailingItems={
301+
<StyledCloseButton
302+
icon={<IconClose size="sm" />}
303+
aria-label={t('Close')}
304+
onClick={() => {
305+
setShowTransactionsDeprecationAlert(false);
306+
}}
307+
size="zero"
308+
borderless
309+
/>
310+
}
311+
>
312+
{tctCode(
313+
'The transaction dataset is being deprecated. Please use Span alerts instead. Spans are a superset of transactions, you can isolate transactions by using the [code:is_transaction:true] filter. Please read these [FAQLink:FAQs] for more information.',
314+
{
315+
FAQLink: (
316+
<ExternalLink href="https://sentry.zendesk.com/hc/en-us/articles/40366087871515-FAQ-Transactions-Spans-Migration" />
317+
),
318+
}
319+
)}
320+
</Alert>
321+
</Alert.Container>
322+
);
323+
}
324+
return null;
325+
}
326+
327+
function MigratedAlertWarning({
328+
isEnabled,
329+
rule,
330+
project,
331+
}: {
332+
isEnabled: boolean;
333+
rule: MetricRule;
334+
project?: Project;
335+
}) {
336+
const organization = useOrganization();
337+
const editLink = rule
338+
? makeAlertsPathname({
339+
path: `/metric-rules/${project?.slug ?? rule?.projects?.[0]}/${rule.id}/`,
340+
organization,
341+
})
342+
: '#';
343+
344+
if (isEnabled) {
345+
return (
346+
<Alert.Container>
347+
<Alert type="warning">
348+
{tctCode(
349+
'This alert has been migrated from a transaction-based alert to a span-based alert. We have set a different extrapolation mode to mimic the previous alert behavior but this mode will be deprecated. Please [editLink:edit] the thresholds to match the regular extrapolation mode.',
350+
{
351+
editLink: <Link to={editLink} />,
352+
}
353+
)}
354+
</Alert>
355+
</Alert.Container>
356+
);
357+
}
358+
return null;
359+
}
360+
304361
const DetailWrapper = styled('div')`
305362
display: flex;
306363
flex: 1;

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

Lines changed: 41 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ import {css} from '@emotion/react';
33
import styled from '@emotion/styled';
44
import omit from 'lodash/omit';
55

6+
import {Button} from '@sentry/scraps/button/button';
7+
68
import {addErrorMessage} from 'sentry/actionCreators/indicator';
79
import {fetchTagValues} from 'sentry/actionCreators/tags';
810
import type {Client} from 'sentry/api';
@@ -83,8 +85,13 @@ import {
8385
DEFAULT_TRANSACTION_AGGREGATE,
8486
getTimeWindowOptions,
8587
} from './constants';
86-
import type {EventTypes} from './types';
87-
import {AlertRuleComparisonType, Dataset, Datasource} from './types';
88+
import {
89+
AlertRuleComparisonType,
90+
Dataset,
91+
Datasource,
92+
ExtrapolationMode,
93+
type EventTypes,
94+
} from './types';
8895

8996
type Props = {
9097
aggregate: string;
@@ -109,6 +116,7 @@ type Props = {
109116
allowChangeEventTypes?: boolean;
110117
comparisonDelta?: number;
111118
disableProjectSelector?: boolean;
119+
extrapolationMode?: ExtrapolationMode;
112120
isErrorMigration?: boolean;
113121
isExtrapolatedChartData?: boolean;
114122
isLowConfidenceChartData?: boolean;
@@ -554,6 +562,7 @@ class RuleConditionsForm extends PureComponent<Props, State> {
554562
isLowConfidenceChartData,
555563
isOnDemandLimitReached,
556564
eventTypes,
565+
extrapolationMode,
557566
} = this.props;
558567

559568
const {environments, filterKeys} = this.state;
@@ -574,6 +583,13 @@ class RuleConditionsForm extends PureComponent<Props, State> {
574583
organization.features.includes('performance-transaction-deprecation-banner') &&
575584
DEPRECATED_TRANSACTION_ALERTS.includes(alertType);
576585

586+
const showExtrapolationModeChangeWarning = !!(
587+
dataset === Dataset.EVENTS_ANALYTICS_PLATFORM &&
588+
extrapolationMode &&
589+
(extrapolationMode === ExtrapolationMode.SERVER_WEIGHTED ||
590+
extrapolationMode === ExtrapolationMode.NONE)
591+
);
592+
577593
return (
578594
<Fragment>
579595
{deprecateTransactionsAlertsWarning && (
@@ -590,6 +606,29 @@ class RuleConditionsForm extends PureComponent<Props, State> {
590606
</Alert>
591607
</Alert.Container>
592608
)}
609+
{showExtrapolationModeChangeWarning && (
610+
<Alert.Container>
611+
<Alert type="info">
612+
{tct(
613+
'This chart may look different from the alert details chart. This is expected as the extrapolation mode has been changed. Once the alert has been saved, your alert will be switched to use the extrapolation mode represented here. To be alerted correctly, please edit your [thresholdsLink:thresholds]. For more information, check out this FAQ!',
614+
{
615+
thresholdsLink: (
616+
<Button
617+
priority="link"
618+
aria-label="Go to thresholds"
619+
onClick={() => {
620+
document
621+
.getElementById('thresholds-warning-icon')
622+
?.scrollIntoView({behavior: 'smooth'});
623+
}}
624+
/>
625+
),
626+
}
627+
)}
628+
</Alert>
629+
</Alert.Container>
630+
)}
631+
593632
<ChartPanel>
594633
<StyledPanelBody>{this.props.thresholdChart}</StyledPanelBody>
595634
</ChartPanel>

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

Lines changed: 53 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ import type {Theme} from '@emotion/react';
33
import styled from '@emotion/styled';
44
import * as Sentry from '@sentry/react';
55

6+
import {Tooltip} from '@sentry/scraps/tooltip/tooltip';
7+
68
import type {Indicator} from 'sentry/actionCreators/indicator';
79
import {
810
addErrorMessage,
@@ -23,8 +25,10 @@ import FormModel from 'sentry/components/forms/model';
2325
import * as Layout from 'sentry/components/layouts/thirds';
2426
import List from 'sentry/components/list';
2527
import ListItem from 'sentry/components/list/listItem';
28+
import {IconWarning} from 'sentry/icons';
2629
import {t, tct} from 'sentry/locale';
2730
import IndicatorStore from 'sentry/stores/indicatorStore';
31+
import {pulse} from 'sentry/styles/animations';
2832
import {space} from 'sentry/styles/space';
2933
import type {PlainRoute, RouteComponentProps} from 'sentry/types/legacyReactRouter';
3034
import type {
@@ -87,22 +91,20 @@ import {
8791
getTimeWindowOptions,
8892
} from './constants';
8993
import RuleConditionsForm from './ruleConditionsForm';
90-
import type {
91-
EventTypes,
92-
ExtrapolationMode,
93-
MetricActionTemplate,
94-
MetricRule,
95-
Trigger,
96-
UnsavedMetricRule,
97-
} from './types';
9894
import {
9995
AlertRuleComparisonType,
10096
AlertRuleSeasonality,
10197
AlertRuleSensitivity,
10298
AlertRuleThresholdType,
10399
AlertRuleTriggerType,
104100
Dataset,
101+
ExtrapolationMode,
105102
TimeWindow,
103+
type EventTypes,
104+
type MetricActionTemplate,
105+
type MetricRule,
106+
type Trigger,
107+
type UnsavedMetricRule,
106108
} from './types';
107109

108110
const POLLING_MAX_TIME_LIMIT = 3 * 60000;
@@ -1320,6 +1322,7 @@ class RuleFormContainer extends DeprecatedAsyncComponent<Props, State> {
13201322
alertType,
13211323
isExtrapolatedChartData,
13221324
triggersHaveChanged,
1325+
extrapolationMode,
13231326
} = this.state;
13241327

13251328
const wizardBuilderChart = this.renderTriggerChart();
@@ -1374,6 +1377,13 @@ class RuleFormContainer extends DeprecatedAsyncComponent<Props, State> {
13741377
const showErrorMigrationWarning =
13751378
!!ruleId && isMigration && ruleNeedsErrorMigration(rule);
13761379

1380+
const showExtrapolationModeChangeWarning = !!(
1381+
dataset === Dataset.EVENTS_ANALYTICS_PLATFORM &&
1382+
extrapolationMode &&
1383+
(extrapolationMode === ExtrapolationMode.SERVER_WEIGHTED ||
1384+
extrapolationMode === ExtrapolationMode.NONE)
1385+
);
1386+
13771387
// Rendering the main form body
13781388
return (
13791389
<Main width="full">
@@ -1471,8 +1481,24 @@ class RuleFormContainer extends DeprecatedAsyncComponent<Props, State> {
14711481
thresholdChart={wizardBuilderChart}
14721482
timeWindow={timeWindow}
14731483
eventTypes={eventTypes}
1484+
extrapolationMode={extrapolationMode}
14741485
/>
1475-
<AlertListItem>{t('Set thresholds')}</AlertListItem>
1486+
1487+
<AlertListItem>
1488+
{
1489+
<HeadingContainer>
1490+
{t('Set thresholds')}
1491+
{showExtrapolationModeChangeWarning && (
1492+
<WarningIcon
1493+
title={t(
1494+
'Your thresholds may need to be adjusted after the change in extrapolation mode'
1495+
)}
1496+
id="thresholds-warning-icon"
1497+
/>
1498+
)}
1499+
</HeadingContainer>
1500+
}
1501+
</AlertListItem>
14761502
{thresholdTypeForm(formDisabled)}
14771503
{showErrorMigrationWarning && (
14781504
<Alert.Container>
@@ -1527,6 +1553,14 @@ function getTimeWindowFromDataset(
15271553
return defaultWindow;
15281554
}
15291555

1556+
function WarningIcon({title, id}: {id: string; title: ReactNode}) {
1557+
return (
1558+
<Tooltip title={title} skipWrapper>
1559+
<StyledIconWarning id={id} size="md" color="warning" />
1560+
</Tooltip>
1561+
);
1562+
}
1563+
15301564
const Main = styled(Layout.Main)`
15311565
max-width: 1000px;
15321566
`;
@@ -1563,4 +1597,14 @@ const Aggregate = styled('span')`
15631597
margin-right: ${space(1)};
15641598
`;
15651599

1600+
const HeadingContainer = styled('div')`
1601+
display: flex;
1602+
align-items: center;
1603+
gap: ${p => p.theme.space.sm};
1604+
`;
1605+
1606+
const StyledIconWarning = styled(IconWarning)`
1607+
animation: ${() => pulse(1.15)} 1s ease infinite;
1608+
`;
1609+
15661610
export default withProjects(RuleFormContainer);

0 commit comments

Comments
 (0)