diff --git a/knip.config.ts b/knip.config.ts
index 9738a41948b52a..2f44be83fb3186 100644
--- a/knip.config.ts
+++ b/knip.config.ts
@@ -25,8 +25,6 @@ const productionEntryPoints = [
'static/app/components/pipeline/**/*.{js,ts,tsx}',
// TODO: Remove when used
'static/app/views/seerExplorer/contexts/**/*.{js,ts,tsx}',
- // TODO: Remove when used
- 'static/app/components/featureShowcase.tsx',
];
const testingEntryPoints = [
diff --git a/static/app/components/featureShowcase.tsx b/static/app/components/featureShowcase.tsx
index 2335c76df8aed9..16353633ce8911 100644
--- a/static/app/components/featureShowcase.tsx
+++ b/static/app/components/featureShowcase.tsx
@@ -10,7 +10,7 @@ import {
import {Button} from '@sentry/scraps/button';
import {Image, type ImageProps} from '@sentry/scraps/image';
-import {Container, Flex, Stack} from '@sentry/scraps/layout';
+import {Flex, Stack} from '@sentry/scraps/layout';
import {Heading, Text} from '@sentry/scraps/text';
import type {ModalRenderProps} from 'sentry/actionCreators/modal';
@@ -62,7 +62,7 @@ function StepTitle({children}: {children: ReactNode}) {
}
function StepContent({children}: {children: ReactNode}) {
- return {children};
+ return {children};
}
/**
@@ -162,16 +162,21 @@ function FeatureShowcase({closeModal, children, onStepChange}: FeatureShowcasePr
};
return (
-
+
-
{activeStep}
-
+
);
}
diff --git a/static/app/components/workflowEngine/alertsMonitorsShowcaseButton.tsx b/static/app/components/workflowEngine/alertsMonitorsShowcaseButton.tsx
new file mode 100644
index 00000000000000..c4bb694fda8fc2
--- /dev/null
+++ b/static/app/components/workflowEngine/alertsMonitorsShowcaseButton.tsx
@@ -0,0 +1,196 @@
+import {useCallback} from 'react';
+import {css, type Theme} from '@emotion/react';
+
+import monitorsTourAlertsImage from 'sentry-images/spot/monitors-tour-alerts.svg';
+import monitorsTourConnectingImage from 'sentry-images/spot/monitors-tour-connecting.svg';
+import monitorsTourIntroImage from 'sentry-images/spot/monitors-tour-intro.svg';
+import monitorsTourMonitorsImage from 'sentry-images/spot/monitors-tour-monitors.svg';
+
+import {Button} from '@sentry/scraps/button';
+import {Stack} from '@sentry/scraps/layout';
+import {ExternalLink} from '@sentry/scraps/link';
+import {Text} from '@sentry/scraps/text';
+
+import {openModal} from 'sentry/actionCreators/modal';
+import {FeatureShowcase} from 'sentry/components/featureShowcase';
+import {IconInfo} from 'sentry/icons';
+import {t, tct} from 'sentry/locale';
+import {trackAnalytics} from 'sentry/utils/analytics';
+import {useOrganization} from 'sentry/utils/useOrganization';
+
+const DOCS_URL = 'https://docs.sentry.io/product/new-monitors-and-alerts/';
+
+export function AlertsMonitorsShowcaseButton() {
+ const organization = useOrganization();
+
+ const handleClick = useCallback(() => {
+ trackAnalytics('monitors.onboarding_modal_viewed', {organization, step: 0});
+ openModal(
+ deps => (
+ {
+ trackAnalytics('monitors.onboarding_modal_viewed', {
+ organization,
+ step,
+ });
+ }}
+ >
+
+
+
+ {t('Introducing Monitors & Alerts')}
+
+
+ {t(
+ 'Monitors detect problems and create issues. These issues trigger Alerts to notify your team.'
+ )}
+
+
+
+
+
+
+ {t('Monitors detect problems and create issues')}
+
+
+
+ {t(
+ 'Set conditions across your data and when a threshold is breached, Sentry creates an issue.'
+ )}
+
+
+ {t('Types of Monitors:')}
+
+ -
+
+
+ {t('Metric')}
+
+ {' — '}
+ {t('span attributes, logs, custom metrics, and more')}
+
+
+ -
+
+
+ {t('Cron')}
+
+ {' — '}
+ {t('scheduled, recurring job health')}
+
+
+ -
+
+
+ {t('Uptime')}
+
+ {' — '}
+ {t('service availability and reliability')}
+
+
+ -
+
+
+ {t('Mobile Builds')}
+
+ {' — '}
+ {t('build size and regressions')}
+
+
+ -
+
+
+ {t('Error')}
+ {' '}
+ {t('(managed by Sentry)')}
+ {' — '}
+ {t(
+ 'groups incoming errors into issues based on your project settings'
+ )}
+
+
+
+
+
+
+
+
+
+
+ {t('Alerts notify your team')}
+
+
+
+ {t(
+ 'Alerts notify your team. Define who gets paged, when, and how — via Slack, email, PagerDuty, and more.'
+ )}
+
+
+ {t(
+ 'Scale and connect to many monitors, projects, and issue types. Configure your routing so the right people get notified when it matters.'
+ )}
+
+
+
+
+
+
+
+ {t('Connecting Alerts & Monitors')}
+
+
+
+ {t(
+ 'When creating a Monitor you have the option of setting up a new Alert or connecting to an existing Alert at the same time.'
+ )}
+
+
+ {t(
+ 'When creating or editing Alerts you can connect to existing routing without ever touching your Monitor logic.'
+ )}
+
+
+ {tct('For more information, [link:read the docs].', {
+ link: ,
+ })}
+
+
+
+
+
+ ),
+ {
+ modalCss: (theme: Theme) => css`
+ width: 490px;
+
+ [role='document'] {
+ padding: ${theme.space['2xl']};
+ padding-top: ${theme.space.lg};
+ }
+ `,
+ }
+ );
+ }, [organization]);
+
+ return (
+ }
+ onClick={handleClick}
+ aria-label={t('Feature tour')}
+ />
+ );
+}
diff --git a/static/app/utils/analytics/monitorsAnalyticsEvents.tsx b/static/app/utils/analytics/monitorsAnalyticsEvents.tsx
index 55d3ac0f76a304..d5ff8748df1054 100644
--- a/static/app/utils/analytics/monitorsAnalyticsEvents.tsx
+++ b/static/app/utils/analytics/monitorsAnalyticsEvents.tsx
@@ -28,6 +28,7 @@ export type MonitorsEventParameters = {
};
'monitor.created': DetectorCreateAnalyticsEventPayload;
'monitor.updated': DetectorAnalyticsEventPayload;
+ 'monitors.onboarding_modal_viewed': {step: number};
};
type MonitorsAnalyticsKey = keyof MonitorsEventParameters;
@@ -38,4 +39,5 @@ export const monitorsEventMap: Record = {
'monitor.updated': 'Detectors: Updated',
'automation.created': 'Automations: Created',
'automation.updated': 'Automations: Updated',
+ 'monitors.onboarding_modal_viewed': 'Monitors: Onboarding Modal Viewed',
};
diff --git a/static/app/views/automations/list.tsx b/static/app/views/automations/list.tsx
index 7f9554dfda4e0e..1e3a17552c7a20 100644
--- a/static/app/views/automations/list.tsx
+++ b/static/app/views/automations/list.tsx
@@ -7,6 +7,7 @@ import {ProjectPageFilter} from 'sentry/components/pageFilters/project/projectPa
import {usePageFilters} from 'sentry/components/pageFilters/usePageFilters';
import {Pagination} from 'sentry/components/pagination';
import {SentryDocumentTitle} from 'sentry/components/sentryDocumentTitle';
+import {AlertsMonitorsShowcaseButton} from 'sentry/components/workflowEngine/alertsMonitorsShowcaseButton';
import {WorkflowEngineListLayout as ListLayout} from 'sentry/components/workflowEngine/layout/list';
import {IconAdd} from 'sentry/icons';
import {t} from 'sentry/locale';
@@ -151,6 +152,7 @@ function Actions() {
const organization = useOrganization();
return (
+
+
{children}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/static/images/spot/monitors-tour-connecting.svg b/static/images/spot/monitors-tour-connecting.svg
new file mode 100644
index 00000000000000..99fdc4f4cf1637
--- /dev/null
+++ b/static/images/spot/monitors-tour-connecting.svg
@@ -0,0 +1,116 @@
+
diff --git a/static/images/spot/monitors-tour-intro.svg b/static/images/spot/monitors-tour-intro.svg
new file mode 100644
index 00000000000000..bee8d9f266a707
--- /dev/null
+++ b/static/images/spot/monitors-tour-intro.svg
@@ -0,0 +1,76 @@
+
\ No newline at end of file
diff --git a/static/images/spot/monitors-tour-monitors.svg b/static/images/spot/monitors-tour-monitors.svg
new file mode 100644
index 00000000000000..716302b16e7d27
--- /dev/null
+++ b/static/images/spot/monitors-tour-monitors.svg
@@ -0,0 +1,172 @@
+
\ No newline at end of file