Skip to content

fix(uptime): Allow typing intermediate values in status code input#106487

Merged
jaydgoss merged 15 commits intomasterfrom
jaygoss/new-698-status-code-assertion-field-is-not-easily-editable-in-actual
Jan 21, 2026
Merged

fix(uptime): Allow typing intermediate values in status code input#106487
jaydgoss merged 15 commits intomasterfrom
jaygoss/new-698-status-code-assertion-field-is-not-easily-editable-in-actual

Conversation

@jaydgoss
Copy link
Copy Markdown
Member

@jaydgoss jaydgoss commented Jan 16, 2026

Summary

  • Fix status code input that was clamping values on every keystroke, making it impossible to type codes like "504"
  • Changed from type="number" to type="text" with inputMode="numeric" to allow intermediate values during typing
  • Added form-level normalization to handle edge cases like submitting with empty/NaN values

Problem

The onChange handler was running clamping logic on every keystroke. When typing "5" to start "504", it would immediately clamp to 100, making the field unusable.

Additionally, if a user cleared the input and submitted the form (e.g., via ENTER key) before the blur handler fired, NaN values could be sent to the API.

Solution

Input Handling

  • Use type="text" with inputMode="numeric" and pattern="[0-9]*" for mobile keyboard support
  • Allow any digits during typing (up to 3 characters)
  • Clamp to valid range (100-599) immediately when user enters a complete 3-digit code (e.g., "700" → "599")
  • Clamp to valid range on blur for partial values (e.g., "50" → "100")
  • Reset to default (200) if field is empty on blur

Form Submission Normalization

  • Added normalizeAssertion() function in UptimeAssertionsField to ensure valid values at submission time
  • Uses getValue prop (not getData) to transform field values - this is important because getData only works for save-on-blur scenarios, while getValue is used by getTransformedData() during full form submission via saveForm()
  • Added getValue to FormFieldProps type definition - the prop was already supported by the form model but was missing from the TypeScript interface
  • Handles NaN values (defaults to 200) and clamps to valid HTTP range (100-599)
  • Centralized in the shared UptimeAssertionsField component so it works for both:
    • Alerts UI (/issues/alerts/new/uptime/)
    • Detectors UI (/monitors/new/settings/?detectorType=uptime_domain_failure)

Detector Form Fix

  • Fixed detector form submit hooks (useCreateDetectorFormSubmit, useEditDetectorFormSubmit) to use formModel.getTransformedData() instead of raw data parameter
  • The raw data parameter is getData() which bypasses field-level getValue transformations
  • This aligns with how the Form component works when no custom onSubmit is provided

Test Plan

  • Updated tests to use userEvent instead of deprecated fireEvent
  • Added tests for immediate 3-digit clamping behavior
  • Added StatefulWrapper for tests that need controlled component state updates
  • Added unit tests for normalizeAssertion() function covering NaN handling and recursive normalization
  • Added integration tests verifying getValue normalization works via model.getTransformedData() on form submission

Fixes NEW-698

@linear
Copy link
Copy Markdown

linear Bot commented Jan 16, 2026

@github-actions github-actions Bot added the Scope: Frontend Automatically applied to PRs that change frontend components label Jan 16, 2026
The status code input was clamping values on every keystroke, making it
impossible to type codes like "504" because typing "5" would immediately
clamp to 100. Changed from type="number" to type="text" with numeric
input mode, allowing users to clear the field and type any 3-digit value.
Clamping to valid HTTP range (100-599) now only happens on blur.
@jaydgoss jaydgoss force-pushed the jaygoss/new-698-status-code-assertion-field-is-not-easily-editable-in-actual branch from eaa99cc to 4355cd3 Compare January 17, 2026 00:11
…t race condition

When a user types a complete 3-digit status code (like "700"), immediately
clamp it to the valid HTTP range (100-599). This prevents a race condition
where clicking "Create Monitor" before the blur event could submit an
unclamped invalid value.

The blur handler remains as a fallback for 1-2 digit values like "50".
Add normalizeAssertion function that recursively clamps status code
values to the valid HTTP range (100-599) in onPreSubmit. This ensures
invalid values can never be submitted, regardless of input length or
blur timing.

This complements the 3-digit immediate clamping in the input component
by providing a safety net at the form submission level.

Includes unit tests for the normalizeAssertion function covering:
- Clamping values above range (700 -> 599)
- Clamping values below range (50 -> 100)
- Preserving valid values (404)
- Recursive normalization of nested and/or/not operations
- Passthrough of non-status-code operations
Remove normalizeAssertion function and tests since blur always fires
before form submission, making the onPreSubmit normalization redundant.
The input-level clamping (on blur and 3-digit input) is sufficient.
@jaydgoss jaydgoss marked this pull request as ready for review January 20, 2026 17:01
@jaydgoss jaydgoss requested a review from a team as a code owner January 20, 2026 17:01
@jaydgoss jaydgoss requested a review from a team January 20, 2026 17:02
cursor[bot]

This comment was marked as outdated.

Update test selectors from 'spinbutton' (number input) to 'textbox' (text
input) and change numeric value assertions to string values to match the
input type change in opStatusCode.tsx.
type="text"
inputMode="numeric"
pattern="[0-9]*"
value={isNaN(value.value) ? '' : value.value}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would this fallback to a default for ''? If not it should to 200 right?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Otherwise looks good to me

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah the fallback to default is actually happening onBlur as opposed to onChange, I wrote it this way to allow the user to completely clear the field (with the delete key), otherwise the onChange clamp would prevent that behavior.

I made a couple additional changes here:

  • if value is '' (or NaN) on blur, fallback to 200 (previously was 100 via clamp)
  • added comment explaining the fallback logic of the value prop.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Change the fallback value from 100 to 200 when the status code input
is cleared and blurred. This is consistent with the default value used
when adding a new status code assertion.

Also adds a comment explaining why the value prop displays an empty
string during editing (when value is NaN) and clarifies that the
actual default is applied on blur.
Comment thread static/app/views/alerts/rules/uptime/assertions/opStatusCode.tsx
Re-add normalizeAssertion function to handle edge case where user
clears the status code input and submits via ENTER without blurring.
This ensures NaN values are converted to 200 (the default) and
out-of-range values are clamped before form submission.

The normalization:
- Defaults NaN to 200 (matches the default when adding new assertion)
- Clamps values to valid HTTP range (100-599)
- Recursively handles nested assertions in and/or/not groups
@Abdkhan14 Abdkhan14 self-requested a review January 21, 2026 17:43
Move normalizeAssertion from uptimeAlertForm.tsx to field.tsx and apply
it via the getData prop on FormField. This ensures assertion values are
normalized before submission for both:
- Alerts form (/issues/alerts/new/uptime/)
- Detectors form (/monitors/new/)

The normalization handles NaN values (from cleared inputs) by defaulting
to 200, and clamps values to the valid HTTP status code range (100-599).
Comment thread static/app/views/alerts/rules/uptime/assertions/opStatusCode.tsx
Copy link
Copy Markdown
Contributor

@cursor cursor Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Bugbot Autofix is OFF. To automatically fix reported issues with Cloud Agents, enable Autofix in the Cursor dashboard.

Comment thread static/app/views/alerts/rules/uptime/assertions/field.tsx
getData only works for save-on-blur scenarios. getValue is the correct
prop to use for transforming field values at form submission time, as it
is used by getTransformedData() which is called during saveForm().
The getValue prop was already supported by the form model for
transforming field values at submission time, but was missing from
the FormFieldProps interface, causing TypeScript errors when used
directly on FormField components.
…m submission

Tests verify that:
- NaN values are normalized to 200 via getTransformedData()
- Out-of-range values are clamped to valid HTTP range (100-599)
The detector form submit hooks were using raw getData() which bypasses
field-level getValue transformations. Changed to use getTransformedData()
so that assertion normalization (and any future getValue transformations)
are applied at submission time.

This aligns with how the Form component works when no custom onSubmit
is provided - it calls saveForm() which uses getTransformedData().
@jaydgoss jaydgoss merged commit 9844450 into master Jan 21, 2026
54 checks passed
@jaydgoss jaydgoss deleted the jaygoss/new-698-status-code-assertion-field-is-not-easily-editable-in-actual branch January 21, 2026 21:26
@github-actions github-actions Bot locked and limited conversation to collaborators Feb 6, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

Scope: Frontend Automatically applied to PRs that change frontend components

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants