diff --git a/static/app/views/detectors/components/forms/uptime/formatUptimeUrl.spec.ts b/static/app/views/detectors/components/forms/uptime/formatUptimeUrl.spec.ts new file mode 100644 index 00000000000000..216839011e4805 --- /dev/null +++ b/static/app/views/detectors/components/forms/uptime/formatUptimeUrl.spec.ts @@ -0,0 +1,17 @@ +import {formatUptimeUrl} from 'sentry/views/detectors/components/forms/uptime/formatUptimeUrl'; + +describe('formatUptimeUrl', () => { + it('returns the host when the URL has no path', () => { + expect(formatUptimeUrl('https://example.com')).toBe('example.com'); + }); + + it('includes the path and strips a trailing slash', () => { + expect(formatUptimeUrl('https://example.com/health/check/')).toBe( + 'example.com/health/check' + ); + }); + + it('returns null for invalid URLs', () => { + expect(formatUptimeUrl('not-a-url')).toBeNull(); + }); +}); diff --git a/static/app/views/detectors/components/forms/uptime/formatUptimeUrl.ts b/static/app/views/detectors/components/forms/uptime/formatUptimeUrl.ts new file mode 100644 index 00000000000000..a46287d0d2d339 --- /dev/null +++ b/static/app/views/detectors/components/forms/uptime/formatUptimeUrl.ts @@ -0,0 +1,15 @@ +/** + * Takes a full URL used by the uptime detector and formats it nicely for display purposes + * + * https://example.com/health/check/ -> example.com/health/check + */ +export function formatUptimeUrl(url: string): string | null { + const parsedUrl = URL.parse(url); + if (!parsedUrl?.hostname) { + return null; + } + + const path = parsedUrl.pathname === '/' ? '' : parsedUrl.pathname; + + return `${parsedUrl.hostname}${path}`.replace(/\/$/, ''); +} diff --git a/static/app/views/detectors/components/forms/uptime/index.tsx b/static/app/views/detectors/components/forms/uptime/index.tsx index 8cc3a603631564..f572af43fddf11 100644 --- a/static/app/views/detectors/components/forms/uptime/index.tsx +++ b/static/app/views/detectors/components/forms/uptime/index.tsx @@ -27,9 +27,11 @@ import { uptimeFormDataToEndpointPayload, uptimeSavedDetectorToFormData, } from 'sentry/views/detectors/components/forms/uptime/fields'; +import {formatUptimeUrl} from 'sentry/views/detectors/components/forms/uptime/formatUptimeUrl'; import {PreviewSection} from 'sentry/views/detectors/components/forms/uptime/previewSection'; import {UptimeRegionWarning} from 'sentry/views/detectors/components/forms/uptime/regionWarning'; import {UptimeDetectorResolveSection} from 'sentry/views/detectors/components/forms/uptime/resolve'; +import {UptimeIssuePreview} from 'sentry/views/detectors/components/forms/uptime/uptimeIssuePreview'; import {UptimeDetectorVerificationSection} from 'sentry/views/detectors/components/forms/uptime/verification'; const ENVIRONMENT_CONFIG: EnvironmentConfig = { @@ -49,14 +51,11 @@ function UptimeDetectorForm() { return null; } - const parsedUrl = URL.parse(url); - if (!parsedUrl) { + const urlName = formatUptimeUrl(url); + if (!urlName) { return null; } - const path = parsedUrl.pathname === '/' ? '' : parsedUrl.pathname; - const urlName = `${parsedUrl.hostname}${path}`.replace(/\/$/, ''); - return t('Uptime check for %s', urlName); }); @@ -70,6 +69,7 @@ function UptimeDetectorForm() { + ); diff --git a/static/app/views/detectors/components/forms/uptime/uptimeIssuePreview.tsx b/static/app/views/detectors/components/forms/uptime/uptimeIssuePreview.tsx new file mode 100644 index 00000000000000..414aaabeccee43 --- /dev/null +++ b/static/app/views/detectors/components/forms/uptime/uptimeIssuePreview.tsx @@ -0,0 +1,43 @@ +import {t} from 'sentry/locale'; +import {DetectorIssuePreview} from 'sentry/views/detectors/components/forms/common/detectorIssuePreview'; +import {IssuePreviewSection} from 'sentry/views/detectors/components/forms/common/issuePreviewSection'; +import {ownerToActor} from 'sentry/views/detectors/components/forms/common/ownerToActor'; +import {useDetectorFormContext} from 'sentry/views/detectors/components/forms/context'; +import {useUptimeDetectorFormField} from 'sentry/views/detectors/components/forms/uptime/fields'; +import {formatUptimeUrl} from 'sentry/views/detectors/components/forms/uptime/formatUptimeUrl'; + +const FALLBACK_ISSUE_TITLE = t('Downtime detected for …'); +const SUBTITLE = t('Your monitored domain is down'); + +function useUptimeIssueTitle() { + const url = useUptimeDetectorFormField('url'); + + if (!url) { + return FALLBACK_ISSUE_TITLE; + } + + const displayUrl = formatUptimeUrl(url); + if (!displayUrl) { + return FALLBACK_ISSUE_TITLE; + } + + return t('Downtime detected for %s', displayUrl); +} + +export function UptimeIssuePreview({step}: {step?: number}) { + const owner = useUptimeDetectorFormField('owner'); + const issueTitle = useUptimeIssueTitle(); + const assignee = ownerToActor(owner); + const {project} = useDetectorFormContext(); + + return ( + + + + ); +} diff --git a/static/app/views/detectors/new-setting.spec.tsx b/static/app/views/detectors/new-setting.spec.tsx index 434f16d58d952c..4432582039ba67 100644 --- a/static/app/views/detectors/new-setting.spec.tsx +++ b/static/app/views/detectors/new-setting.spec.tsx @@ -930,6 +930,11 @@ describe('DetectorEdit', () => { await userEvent.click(bodyInput); await userEvent.paste('{"test": "data"}'); + // Issue preview reflects the URL + expect( + screen.getByText('Downtime detected for uptime.example.com') + ).toBeInTheDocument(); + await selectEvent.openMenu(screen.getByLabelText('Select Environment')); expect( screen.queryByRole('menuitemradio', {name: 'All Environments'})