From 8f897c9725024c9d346cee6730eb4b5e348bf722 Mon Sep 17 00:00:00 2001 From: Evan Purkhiser Date: Fri, 22 Nov 2024 15:20:31 -0500 Subject: [PATCH] feat(uptime): Add timeout configuration (#81201) Looks like this clipboard.png --- .../alerts/rules/uptime/uptimeAlertForm.spec.tsx | 12 +++++++++++- .../alerts/rules/uptime/uptimeAlertForm.tsx | 16 +++++++++++++++- 2 files changed, 26 insertions(+), 2 deletions(-) diff --git a/static/app/views/alerts/rules/uptime/uptimeAlertForm.spec.tsx b/static/app/views/alerts/rules/uptime/uptimeAlertForm.spec.tsx index 9d8979b96d8026..3c8b22b78b333c 100644 --- a/static/app/views/alerts/rules/uptime/uptimeAlertForm.spec.tsx +++ b/static/app/views/alerts/rules/uptime/uptimeAlertForm.spec.tsx @@ -5,7 +5,7 @@ import {ProjectFixture} from 'sentry-fixture/project'; import {TeamFixture} from 'sentry-fixture/team'; import {UptimeRuleFixture} from 'sentry-fixture/uptimeRule'; -import {render, screen, userEvent} from 'sentry-test/reactTestingLibrary'; +import {fireEvent, render, screen, userEvent} from 'sentry-test/reactTestingLibrary'; import selectEvent from 'sentry-test/selectEvent'; import OrganizationStore from 'sentry/stores/organizationStore'; @@ -42,6 +42,9 @@ describe('Uptime Alert Form', function () { await selectEvent.select(input('Environment'), 'prod'); + const timeout = screen.getByRole('slider', {name: 'Timeout'}); + fireEvent.change(timeout, {target: {value: '10000'}}); + await userEvent.clear(input('URL')); await userEvent.type(input('URL'), 'http://example.com'); @@ -82,6 +85,7 @@ describe('Uptime Alert Form', function () { body: '{"key": "value"}', traceSampling: true, intervalSeconds: 60, + timeoutMs: 10_000, }), }) ); @@ -100,6 +104,7 @@ describe('Uptime Alert Form', function () { ], body: '{"key": "value"}', traceSampling: true, + timeoutMs: 7500, owner: ActorFixture(), }); render( @@ -120,6 +125,7 @@ describe('Uptime Alert Form', function () { await selectEvent.openMenu(input('Environment')); expect(screen.getByRole('menuitemradio', {name: 'prod'})).toBeChecked(); expect(screen.getByRole('checkbox', {name: 'Allow Sampling'})).toBeChecked(); + expect(screen.getByRole('slider', {name: 'Timeout'})).toHaveValue('7500'); }); it('handles simple edits', async function () { @@ -179,6 +185,9 @@ describe('Uptime Alert Form', function () { await selectEvent.select(input('Interval'), 'Every 10 minutes'); await selectEvent.select(input('Environment'), 'dev'); + const timeout = screen.getByRole('slider', {name: 'Timeout'}); + fireEvent.change(timeout, {target: {value: '7500'}}); + await userEvent.clear(input('URL')); await userEvent.type(input('URL'), 'http://another-url.com'); @@ -225,6 +234,7 @@ describe('Uptime Alert Form', function () { body: '{"different": "value"}', intervalSeconds: 60 * 10, traceSampling: true, + timeoutMs: 7500, }), }) ); diff --git a/static/app/views/alerts/rules/uptime/uptimeAlertForm.tsx b/static/app/views/alerts/rules/uptime/uptimeAlertForm.tsx index 1f8b2cc25973b4..5a0371b73a4a5c 100644 --- a/static/app/views/alerts/rules/uptime/uptimeAlertForm.tsx +++ b/static/app/views/alerts/rules/uptime/uptimeAlertForm.tsx @@ -8,6 +8,7 @@ import Confirm from 'sentry/components/confirm'; import FieldWrapper from 'sentry/components/forms/fieldGroup/fieldWrapper'; import BooleanField from 'sentry/components/forms/fields/booleanField'; import HiddenField from 'sentry/components/forms/fields/hiddenField'; +import RangeField from 'sentry/components/forms/fields/rangeField'; import SelectField from 'sentry/components/forms/fields/selectField'; import SentryMemberTeamSelectorField from 'sentry/components/forms/fields/sentryMemberTeamSelectorField'; import SentryProjectSelectorField from 'sentry/components/forms/fields/sentryProjectSelectorField'; @@ -63,6 +64,7 @@ function getFormDataFromRule(rule: UptimeRule) { body: rule.body, headers: rule.headers, intervalSeconds: rule.intervalSeconds, + timeoutMs: rule.timeoutMs, traceSampling: rule.traceSampling, owner: rule.owner ? `${rule.owner.type}:${rule.owner.id}` : null, }; @@ -193,7 +195,19 @@ export function UptimeAlertForm({project, handleDelete, rule}: Props) { flexibleControlStateSize required /> - + getDuration((value || 0) / 1000, 2, true)} + flexibleControlStateSize + required + />