Skip to content

Commit 5562ed2

Browse files
committed
feat(monitors): Add feature tour button using FeatureShowcase
Replace the old FeatureTourModal-based tour with the new FeatureShowcase compound component. The tour is now self-contained in the WorkflowEngineFeatureTourButton with 4 steps covering Monitors, Alerts, and how they connect together. Both the Alerts and Monitors list pages share the same tour. Also tweaks FeatureShowcase to use Stack instead of Container and adds size="sm" to the close button for better alignment.
1 parent ee4cb7c commit 5562ed2

File tree

8 files changed

+749
-105
lines changed

8 files changed

+749
-105
lines changed

static/app/components/featureShowcase.tsx

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import {
1010

1111
import {Button} from '@sentry/scraps/button';
1212
import {Image, type ImageProps} from '@sentry/scraps/image';
13-
import {Container, Flex, Stack} from '@sentry/scraps/layout';
13+
import {Flex, Stack} from '@sentry/scraps/layout';
1414
import {Heading, Text} from '@sentry/scraps/text';
1515

1616
import type {ModalRenderProps} from 'sentry/actionCreators/modal';
@@ -162,16 +162,21 @@ function FeatureShowcase({closeModal, children, onStepChange}: FeatureShowcasePr
162162
};
163163

164164
return (
165-
<Container data-test-id="feature-showcase">
165+
<Stack data-test-id="feature-showcase" gap="md">
166166
<Flex justify="end">
167-
<Button priority="transparent" onClick={closeModal} aria-label={t('Close tour')}>
167+
<Button
168+
priority="transparent"
169+
size="sm"
170+
onClick={closeModal}
171+
aria-label={t('Close tour')}
172+
>
168173
<IconClose size="xs" />
169174
</Button>
170175
</Flex>
171176
<ShowcaseContext.Provider value={contextValue}>
172177
{activeStep}
173178
</ShowcaseContext.Provider>
174-
</Container>
179+
</Stack>
175180
);
176181
}
177182

Lines changed: 168 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,176 @@
1+
import {useCallback} from 'react';
2+
import {css, type Theme} from '@emotion/react';
3+
4+
import monitorsTourAlertsImage from 'sentry-images/spot/monitors-tour-alerts.svg';
5+
import monitorsTourConnectingImage from 'sentry-images/spot/monitors-tour-connecting.svg';
6+
import monitorsTourIntroImage from 'sentry-images/spot/monitors-tour-intro.svg';
7+
import monitorsTourMonitorsImage from 'sentry-images/spot/monitors-tour-monitors.svg';
8+
19
import {Button} from '@sentry/scraps/button';
10+
import {Stack} from '@sentry/scraps/layout';
11+
import {ExternalLink} from '@sentry/scraps/link';
12+
import {Text} from '@sentry/scraps/text';
213

3-
import type {TourStep} from 'sentry/components/modals/featureTourModal';
4-
import {FeatureTourModal} from 'sentry/components/modals/featureTourModal';
14+
import {openModal} from 'sentry/actionCreators/modal';
15+
import {FeatureShowcase} from 'sentry/components/featureShowcase';
516
import {IconInfo} from 'sentry/icons';
6-
import {t} from 'sentry/locale';
17+
import {t, tct} from 'sentry/locale';
718

8-
interface WorkflowEngineFeatureTourButtonProps {
9-
doneUrl: string;
10-
steps: TourStep[];
11-
}
19+
const DOCS_URL = 'https://docs.sentry.io/product/new-monitors-and-alerts/';
20+
21+
export function WorkflowEngineFeatureTourButton() {
22+
const handleClick = useCallback(() => {
23+
openModal(
24+
deps => (
25+
<FeatureShowcase {...deps}>
26+
<FeatureShowcase.Step>
27+
<FeatureShowcase.Image
28+
src={monitorsTourIntroImage}
29+
alt={t('Introducing Monitors and Alerts')}
30+
/>
31+
<FeatureShowcase.StepTitle>
32+
{t('Introducing Monitors & Alerts')}
33+
</FeatureShowcase.StepTitle>
34+
<FeatureShowcase.StepContent>
35+
{t(
36+
'Monitors detect problems and create issues. These issues trigger Alerts to notify your team.'
37+
)}
38+
</FeatureShowcase.StepContent>
39+
<FeatureShowcase.StepActions />
40+
</FeatureShowcase.Step>
41+
<FeatureShowcase.Step>
42+
<FeatureShowcase.Image
43+
src={monitorsTourMonitorsImage}
44+
alt={t('Monitors detect problems and create issues')}
45+
/>
46+
<FeatureShowcase.StepTitle>
47+
{t('Monitors detect problems and create issues')}
48+
</FeatureShowcase.StepTitle>
49+
<FeatureShowcase.StepContent>
50+
{t(
51+
'Set conditions across your data and when a threshold is breached, Sentry creates an issue.'
52+
)}
53+
</FeatureShowcase.StepContent>
54+
<Stack gap="sm">
55+
<Text bold>{t('Types of Monitors:')}</Text>
56+
<ul>
57+
<li>
58+
<Text>
59+
<Text bold as="span">
60+
{t('Metric')}
61+
</Text>
62+
{' — '}
63+
{t('count, attributes, tags, custom metrics, and more')}
64+
</Text>
65+
</li>
66+
<li>
67+
<Text>
68+
<Text bold as="span">
69+
{t('Error')}
70+
</Text>
71+
{' — '}
72+
{t('unhandled, recurring, or volume-based')}
73+
</Text>
74+
</li>
75+
<li>
76+
<Text>
77+
<Text bold as="span">
78+
{t('Uptime')}
79+
</Text>
80+
{' — '}
81+
{t('service availability and reliability')}
82+
</Text>
83+
</li>
84+
<li>
85+
<Text>
86+
<Text bold as="span">
87+
{t('Mobile Builds')}
88+
</Text>
89+
{' — '}
90+
{t('build size and regressions')}
91+
</Text>
92+
</li>
93+
<li>
94+
<Text>
95+
<Text bold as="span">
96+
{t('Cron')}
97+
</Text>
98+
{' — '}
99+
{t(
100+
'group incoming errors into issues based on your project settings'
101+
)}
102+
</Text>
103+
</li>
104+
</ul>
105+
</Stack>
106+
<FeatureShowcase.StepActions />
107+
</FeatureShowcase.Step>
108+
<FeatureShowcase.Step>
109+
<FeatureShowcase.Image
110+
src={monitorsTourAlertsImage}
111+
alt={t('Alerts notify your team')}
112+
/>
113+
<FeatureShowcase.StepTitle>
114+
{t('Alerts notify your team')}
115+
</FeatureShowcase.StepTitle>
116+
<FeatureShowcase.StepContent>
117+
{t(
118+
'Alerts notify your team. Define who gets paged, when, and how — via Slack, email, PagerDuty, and more.'
119+
)}
120+
</FeatureShowcase.StepContent>
121+
<FeatureShowcase.StepContent>
122+
{t(
123+
'Scale and connect to many monitors, projects, and issue types. Configure your routing so the right people get notified when it matters.'
124+
)}
125+
</FeatureShowcase.StepContent>
126+
<FeatureShowcase.StepActions />
127+
</FeatureShowcase.Step>
128+
<FeatureShowcase.Step>
129+
<FeatureShowcase.Image
130+
src={monitorsTourConnectingImage}
131+
alt={t('Connecting Alerts and Monitors')}
132+
/>
133+
<FeatureShowcase.StepTitle>
134+
{t('Connecting Alerts & Monitors')}
135+
</FeatureShowcase.StepTitle>
136+
<FeatureShowcase.StepContent>
137+
{t(
138+
'When creating a Monitor you have the option of setting up a new Alert or connecting to an existing Alert at the same time.'
139+
)}
140+
</FeatureShowcase.StepContent>
141+
<FeatureShowcase.StepContent>
142+
{t(
143+
'When creating or editing Alerts you can connect to existing routing without ever touching your Monitor logic.'
144+
)}
145+
</FeatureShowcase.StepContent>
146+
<FeatureShowcase.StepContent>
147+
{tct('For more information, [link:read the docs].', {
148+
link: <ExternalLink href={DOCS_URL} />,
149+
})}
150+
</FeatureShowcase.StepContent>
151+
<FeatureShowcase.StepActions />
152+
</FeatureShowcase.Step>
153+
</FeatureShowcase>
154+
),
155+
{
156+
modalCss: (theme: Theme) => css`
157+
width: 490px;
158+
159+
[role='document'] {
160+
padding: ${theme.space['2xl']};
161+
padding-top: ${theme.space.lg};
162+
}
163+
`,
164+
}
165+
);
166+
}, []);
12167

13-
export function WorkflowEngineFeatureTourButton({
14-
steps,
15-
doneUrl,
16-
}: WorkflowEngineFeatureTourButtonProps) {
17168
return (
18-
<FeatureTourModal steps={steps} doneUrl={doneUrl} doneText={t('Got it')}>
19-
{({showModal}) => (
20-
<Button
21-
size="sm"
22-
icon={<IconInfo />}
23-
onClick={showModal}
24-
aria-label={t('Feature tour')}
25-
/>
26-
)}
27-
</FeatureTourModal>
169+
<Button
170+
size="sm"
171+
icon={<IconInfo />}
172+
onClick={handleClick}
173+
aria-label={t('Feature tour')}
174+
/>
28175
);
29176
}

static/app/views/automations/list.tsx

Lines changed: 1 addition & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,6 @@ import {useCallback} from 'react';
33
import {LinkButton} from '@sentry/scraps/button';
44
import {Flex} from '@sentry/scraps/layout';
55

6-
import type {TourStep} from 'sentry/components/modals/featureTourModal';
7-
import {TourText} from 'sentry/components/modals/featureTourModal';
86
import {ProjectPageFilter} from 'sentry/components/pageFilters/project/projectPageFilter';
97
import {usePageFilters} from 'sentry/components/pageFilters/usePageFilters';
108
import {Pagination} from 'sentry/components/pagination';
@@ -21,42 +19,6 @@ import {useLocation} from 'sentry/utils/useLocation';
2119
import {useNavigate} from 'sentry/utils/useNavigate';
2220
import {useOrganization} from 'sentry/utils/useOrganization';
2321
import {AutomationFeedbackButton} from 'sentry/views/automations/components/automationFeedbackButton';
24-
25-
const AUTOMATION_DOCS_URL =
26-
'https://docs.sentry.io/product/new-monitors-and-alerts/alerts/';
27-
28-
const AUTOMATION_TOUR_STEPS: TourStep[] = [
29-
{
30-
title: t('What are Alerts?'),
31-
body: (
32-
<TourText>
33-
{t(
34-
'Alerts are triggered when issues change state, are created, or pass a threshold. They perform actions like sending notifications, creating tickets, or calling webhooks.'
35-
)}
36-
</TourText>
37-
),
38-
},
39-
{
40-
title: t('Creating an Alert'),
41-
body: (
42-
<TourText>
43-
{t(
44-
'Create alerts to define what happens when a monitor triggers. Connect them to monitors and configure actions like Slack notifications, PagerDuty incidents, or Jira tickets.'
45-
)}
46-
</TourText>
47-
),
48-
},
49-
{
50-
title: t('Managing Alerts'),
51-
body: (
52-
<TourText>
53-
{t(
54-
'Use this page to view, search, and manage all your alerts. You can filter by project and see which monitors are connected to each alert.'
55-
)}
56-
</TourText>
57-
),
58-
},
59-
];
6022
import {AutomationListTable} from 'sentry/views/automations/components/automationListTable';
6123
import {AutomationSearch} from 'sentry/views/automations/components/automationListTable/search';
6224
import {AUTOMATION_LIST_PAGE_LIMIT} from 'sentry/views/automations/constants';
@@ -190,10 +152,7 @@ function Actions() {
190152
const organization = useOrganization();
191153
return (
192154
<Flex gap="sm">
193-
<WorkflowEngineFeatureTourButton
194-
steps={AUTOMATION_TOUR_STEPS}
195-
doneUrl={AUTOMATION_DOCS_URL}
196-
/>
155+
<WorkflowEngineFeatureTourButton />
197156
<AutomationFeedbackButton />
198157
<LinkButton
199158
to={makeAutomationCreatePathname(organization.slug)}

static/app/views/detectors/list/common/detectorListActions.tsx

Lines changed: 1 addition & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
11
import {LinkButton} from '@sentry/scraps/button';
22
import {Flex} from '@sentry/scraps/layout';
33

4-
import type {TourStep} from 'sentry/components/modals/featureTourModal';
5-
import {TourText} from 'sentry/components/modals/featureTourModal';
64
import {ALL_ACCESS_PROJECTS} from 'sentry/components/pageFilters/constants';
75
import {usePageFilters} from 'sentry/components/pageFilters/usePageFilters';
86
import {WorkflowEngineFeatureTourButton} from 'sentry/components/workflowEngine/featureTourButton';
@@ -15,41 +13,6 @@ import {makeMonitorCreatePathname} from 'sentry/views/detectors/pathnames';
1513
import {getNoPermissionToCreateMonitorsTooltip} from 'sentry/views/detectors/utils/monitorAccessMessages';
1614
import {useCanCreateDetector} from 'sentry/views/detectors/utils/useCanCreateDetector';
1715

18-
const DOCS_URL = 'https://docs.sentry.io/product/new-monitors-and-alerts/monitors/';
19-
20-
const DETECTOR_TOUR_STEPS: TourStep[] = [
21-
{
22-
title: t('What are Monitors?'),
23-
body: (
24-
<TourText>
25-
{t(
26-
'Monitors detect changes in your application like new errors, performance regressions, and other anomalies, then create issues for your team to investigate.'
27-
)}
28-
</TourText>
29-
),
30-
},
31-
{
32-
title: t('Creating a Monitor'),
33-
body: (
34-
<TourText>
35-
{t(
36-
'Create monitors to track specific conditions such as error thresholds, uptime checks, or cron job failures. Each monitor can be connected to one or more alerts.'
37-
)}
38-
</TourText>
39-
),
40-
},
41-
{
42-
title: t('Managing Monitors'),
43-
body: (
44-
<TourText>
45-
{t(
46-
'Use this page to view, search, and manage all your monitors. You can filter by project and monitor type to find what you need.'
47-
)}
48-
</TourText>
49-
),
50-
},
51-
];
52-
5316
interface DetectorListActionsProps {
5417
children?: React.ReactNode;
5518
detectorType?: DetectorType;
@@ -64,7 +27,7 @@ export function DetectorListActions({children, detectorType}: DetectorListAction
6427

6528
return (
6629
<Flex gap="sm">
67-
<WorkflowEngineFeatureTourButton steps={DETECTOR_TOUR_STEPS} doneUrl={DOCS_URL} />
30+
<WorkflowEngineFeatureTourButton />
6831
{children}
6932
<MonitorFeedbackButton />
7033
<LinkButton

0 commit comments

Comments
 (0)