Skip to content

Convert remaining JS/JSX files to TypeScript#1316

Open
rafaumeu wants to merge 2 commits into
mattermost:masterfrom
rafaumeu:feature/reducers-js-to-ts-1142
Open

Convert remaining JS/JSX files to TypeScript#1316
rafaumeu wants to merge 2 commits into
mattermost:masterfrom
rafaumeu:feature/reducers-js-to-ts-1142

Conversation

@rafaumeu

@rafaumeu rafaumeu commented Jun 16, 2026

Copy link
Copy Markdown

Summary

Converts all remaining .js and .jsx files to TypeScript (.ts/..tsx`), following the pattern from PR #1140.

Files Converted (11 total)

Utils:

  • utils/posts.jsx -> posts.ts
  • utils/user_agent.jsx -> user_agent.ts

Components:

  • components/setting.jsx -> setting.tsx
  • components/form_button.jsx -> form_button.tsx
  • components/input.jsx -> input.tsx
  • components/jira_field.jsx -> jira_field.tsx
  • components/setup_ui/setup_ui.jsx -> setup_ui.tsx
  • components/setup_ui/index.js -> index.ts
  • components/jira_issue_selector/jira_issue_selector.jsx -> jira_issue_selector.tsx
  • components/jira_issue_selector/index.js -> index.ts
  • components/modals/full_screen_modal/full_screen_modal.jsx -> full_screen_modal.tsx

Changes

  • Replaced PropTypes with proper TypeScript type/interface definitions
  • Added typed function parameters and return types
  • Updated event handler types (e.g., ChangeEvent, KeyboardEvent)
  • Updated import paths to remove .jsx extensions
  • disabled prop on AsyncSelect changed to isDisabled (react-select v3 API)

Ticket Link

Fixes #1142

Checklist

  • Converted all .js and .jsx files in webapp/src to .ts/.tsx
  • Replaced PropTypes with TypeScript types
  • Maintained original component behavior
  • te char/e2e tests not affected (no logic changes)

/release-note

Change Impact: 🟡 Medium

Reasoning: This PR converts 11 files from JavaScript/PropTypes to TypeScript across components and utilities. While most changes are typing-only migrations following an established pattern (PR #1140), there are some behavioral modifications (AsyncSelect disabledisDisabled API update, Input component validation state clearing, numeric input handling) that introduce regression risk across multiple component implementations.

Regression Risk: Moderate. The PR maintains intended behavior per the description, but affects multiple component files (FormButton, Input, JiraField, JiraIssueSelector, FullScreenModal, Setting, SetupUI) with behavioral refinements beyond pure typing. The AsyncSelect API change and Input component's modified componentDidUpdate hook clearing invalid state when props change could have unexpected interactions in parent components if not thoroughly tested. Utilities (posts.ts, user_agent.ts) are low-risk but shared. Existing e2e/char tests are expected to remain unaffected, but edge cases in numeric input handling and validation state management warrant attention.

QA Recommendation: Manual QA is recommended with medium-to-high priority. Test focus should include: (1) AsyncSelect components with dynamic enable/disable scenarios in Jira-related flows; (2) numeric input edge cases and validation state transitions; (3) FullScreenModal keyboard event handling; (4) Jira field selection workflows. Automated test coverage appears adequate (PR notes existing tests remain unaffected), but behavioral modifications and integration points between modified components and parent consumers should be validated in staging/development environments.

Generated by CodeRabbitAI

Convert all remaining .js and .jsx files to .ts/.tsx:
- utils/posts.jsx -> .ts
- utils/user_agent.jsx -> .ts
- components/setting.jsx -> .tsx
- components/setup_ui/setup_ui.jsx -> .tsx
- components/setup_ui/index.js -> .ts
- components/form_button.jsx -> .tsx
- components/input.jsx -> .tsx
- components/jira_issue_selector/jira_issue_selector.jsx -> .tsx
- components/jira_issue_selector/index.js -> .ts
- components/modals/full_screen_modal/full_screen_modal.jsx -> .tsx
- components/jira_field.jsx -> .tsx

Replaced PropTypes with proper TypeScript interfaces/types.
Updated function signatures with typed parameters.
@rafaumeu
rafaumeu requested a review from a team as a code owner June 16, 2026 22:38
@mattermost-build

Copy link
Copy Markdown
Contributor

Hello @rafaumeu,

Thanks for your pull request! A Core Committer will review your pull request soon. For code contributions, you can learn more about the review process here.

@coderabbitai

coderabbitai Bot commented Jun 16, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@rafaumeu, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 5 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Repository UI (base), Organization UI (inherited)

Review profile: CHILL

Plan: Pro

Run ID: 6f530f16-ad7a-4011-b860-e08288f5bb15

📥 Commits

Reviewing files that changed from the base of the PR and between 180c01a and ce2932c.

📒 Files selected for processing (3)
  • webapp/src/components/input.tsx
  • webapp/src/components/jira_field.tsx
  • webapp/src/components/jira_issue_selector/jira_issue_selector.tsx
📝 Walkthrough

Walkthrough

Multiple React components (FormButton, Input, JiraField, JiraIssueSelector, FullScreenModal, Setting, SetupUI) and two utility modules (posts.ts, user_agent.ts) are converted from runtime prop-types validation to compile-time TypeScript typing. prop-types imports and static propTypes declarations are removed and replaced with typed Props/State interfaces. Input and JiraIssueSelector also receive minor runtime corrections alongside the typing changes.

Changes

PropTypes → TypeScript Migration

Layer / File(s) Summary
Utility function signature typing
webapp/src/utils/posts.ts, webapp/src/utils/user_agent.ts
isCombinedUserActivityPost gains a typed string parameter; getDesktopAppVersion gains an explicit string | null return type; isMinimumDesktopAppVersion parameters are typed as number.
Simple UI components: FormButton, Setting, FullScreenModal
webapp/src/components/form_button.tsx, webapp/src/components/setting.tsx, webapp/src/components/modals/full_screen_modal/full_screen_modal.tsx
Each component drops the prop-types import and static propTypes, introduces a local Props type, and updates the class declaration to the typed generic form. FullScreenModal also types the handleKeypress event parameter as KeyboardEvent.
Input component: Props/State types and runtime corrections
webapp/src/components/input.tsx
Input is converted to PureComponent<Props, State> with explicit Props, State, and InputType definitions. componentDidUpdate is added to clear invalid on value change. handleChange is typed and parses numeric input. maxLength passes undefined instead of null, textarea rows changes from a string to a number, and the resize style uses as const.
SetupUI component and Redux connector typing
webapp/src/components/setup_ui/setup_ui.tsx, webapp/src/components/setup_ui/index.ts
SetupUI drops PropTypes and gains a typed Props. The Redux connector adds GlobalState to mapStateToProps and Dispatch to mapDispatchToProps.
JiraField: typed interfaces, onChange handlers, and isFieldSupported
webapp/src/components/jira_field.tsx
Introduces TypeScript interfaces for field schema, allowed values, Props, and IconOptionProps; updates the class to React.Component<Props>; types all per-selector onChange callbacks; strengthens allowedValues option construction with nullish coalescing; types the exported isFieldSupported to accept Field | null | undefined.
JiraIssueSelector: Props/State types, componentDidUpdate, and prop corrections
webapp/src/components/jira_issue_selector/jira_issue_selector.tsx, webapp/src/components/jira_issue_selector/index.ts
Gains Props and State types, a componentDidUpdate that clears invalid on value change, typed onChange and isValid methods, optional chaining on serverError?.toString(), and the AsyncSelect disabled prop renamed to isDisabled. The index connector types mapDispatchToProps with Dispatch.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'Convert remaining JS/JSX files to TypeScript' directly and accurately summarizes the main objective of the PR, which is converting 11 JavaScript and JSX files to TypeScript across components and utilities.
Linked Issues check ✅ Passed The PR successfully fulfills issue #1142's objective by converting remaining source files from JavaScript to TypeScript following the established PR #1140 pattern, replacing PropTypes with typed definitions and updating function signatures.
Out of Scope Changes check ✅ Passed All changes are directly related to the TypeScript migration objective: file conversions, PropTypes removal, type additions, and AsyncSelect prop updates (disabled→isDisabled) align with the stated goals.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@webapp/src/components/input.tsx`:
- Around line 61-66: The handleChange method uses parseInt which truncates
decimal values, breaking float input fields. Replace parseInt with parseFloat to
preserve decimal values while still supporting integer types. Additionally,
there is a validation check (likely around line 73) that treats the numeric
value 0 as invalid due to falsy evaluation. Update this validation to explicitly
check for null or undefined instead of relying on truthiness checks, ensuring
that a zero value is properly accepted for required numeric fields.

In `@webapp/src/components/jira_field.tsx`:
- Around line 55-60: The Props type definition in the JiraField component
declares stricter types than what the caller in jira_fields.tsx actually
provides. Update the Props type definition: change the projectKey property from
string to string | undefined to match the caller's usage, and change the
issueMetadata property from Record<string, any> to IssueMetadata | null to align
with what the caller actually passes to the JiraField component.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI (base), Organization UI (inherited)

Review profile: CHILL

Plan: Pro

Run ID: 2c43154c-e1a3-4e18-b8c5-68f1035316cb

📥 Commits

Reviewing files that changed from the base of the PR and between ee838e1 and 180c01a.

📒 Files selected for processing (11)
  • webapp/src/components/form_button.tsx
  • webapp/src/components/input.tsx
  • webapp/src/components/jira_field.tsx
  • webapp/src/components/jira_issue_selector/index.ts
  • webapp/src/components/jira_issue_selector/jira_issue_selector.tsx
  • webapp/src/components/modals/full_screen_modal/full_screen_modal.tsx
  • webapp/src/components/setting.tsx
  • webapp/src/components/setup_ui/index.ts
  • webapp/src/components/setup_ui/setup_ui.tsx
  • webapp/src/utils/posts.ts
  • webapp/src/utils/user_agent.ts

Comment thread webapp/src/components/input.tsx
Comment thread webapp/src/components/jira_field.tsx Outdated
Comment thread webapp/src/components/jira_field.tsx Outdated

import React from 'react';
import PropTypes from 'prop-types';
import type {Theme} from 'mattermost-redux/types/preferences';

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.

The Theme type lives in mattermost-redux/selectors/entities/preferences, which is what every other file in this webapp uses. The build passes only because import type is erased before webpack runs.

import type {Theme} from 'mattermost-redux/selectors/entities/preferences';


import React, {Component} from 'react';
import PropTypes from 'prop-types';
import type {Theme} from 'mattermost-redux/types/preferences';

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.

Same as in jira_field.tsx

theme: PropTypes.object.isRequired,
addValidate: PropTypes.func.isRequired,
removeValidate: PropTypes.func.isRequired,
type JiraFieldData = {

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.

JiraField, IssueMetadata, etc. are already exported from types/model. The local Field, FieldSchema, AllowedValue types are structurally narrower than the model's JiraField, which is why isTeamField(field) would fail typechecking, isTeamField is typed against JiraField | FilterField not this local shape. Use the canonical model types so the rest of the codebase stays consistent.

@@ -111,7 +150,7 @@ export default class JiraField extends React.Component {
<JiraEpicSelector

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.

on line 93 style.getStyle() only returns { jiraIcon: {...} } so selectComponent is undefined and this is a style={undefined} no-op. The original .jsx had the same bug but it was hidden because JSX didn't typecheck. Either restore the missing entry or drop the style prop.

@nang2049 nang2049 left a comment

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.

Thanks @rafaumeu I have a few comments :)

@mattermost-build

Copy link
Copy Markdown
Contributor

This PR has been automatically labelled "stale" because it hasn't had recent activity.
A core team member will check in on the status of the PR to help with questions.
Thank you for your contribution!

…rics

- input.tsx: Replace parseInt() with Number() to preserve decimal values
  and correctly handle 0 as a valid number input. Fix isValid() to not
  reject 0 — now checks for undefined/null/'' explicitly. Use nullish
  coalescing (??) instead of || for value rendering to keep 0 visible.
- jira_field.tsx: Import Theme from mattermost-redux/selectors/entities/
  preferences (canonical path) instead of mattermost-redux/types/
  preferences. Replace local Field/FieldSchema/AllowedValue type defs
  with canonical JiraField, AllowedValue from types/model. Make Props
  match the actual caller (projectKey?: string, issueMetadata:
  IssueMetadata | null). Remove dead selectComponent style prop from
  IconOption (getStyle() never returned it).
- jira_issue_selector.tsx: Same Theme import fix.
@rafaumeu

rafaumeu commented Jul 5, 2026

Copy link
Copy Markdown
Author

Review feedback addressed in commit ce2932c:

input.tsx

  • parseInt() replaced with Number() — preserves decimal values instead of truncating to integers
  • isValid() no longer rejects 0 as invalid — now explicitly checks for undefined/null/'' instead of relying on truthiness
  • Value rendering uses ?? instead of || so 0 displays correctly in the input

jira_field.tsx

  • Theme import corrected to mattermost-redux/selectors/entities/preferences (canonical export path)
  • Removed local Field, FieldSchema, and AllowedValue type definitions — now imports canonical JiraField, AllowedValue from types/model. This eliminates type narrowing mismatches with the rest of the codebase.
  • Props type updated to match the actual caller (jira_fields.tsx): projectKey?: string (optional) and issueMetadata: IssueMetadata | null instead of Record<string, any>
  • Removed dead selectComponent style prop from IconOptiongetStyle() only returns jiraIcon, so the style prop on components.Option was a no-op

jira_issue_selector.tsx

  • Same Theme import path fix

@rafaumeu

rafaumeu commented Jul 5, 2026

Copy link
Copy Markdown
Author

Hi @nang2049, I've addressed all review feedback in commit ce2932c:

  1. Theme import — Fixed in both jira_field.tsx and jira_issue_selector.tsx: now imports from mattermost-redux/selectors/entities/preferences (canonical path used across the webapp).
  2. Canonical types — Removed local Field, FieldSchema, and AllowedValue type definitions. Now imports JiraField, IssueMetadata, and AllowedValue directly from types/model, which fixes the type narrowing issue with isTeamField().
  3. Props alignmentprojectKey is now string | undefined and issueMetadata is IssueMetadata | null, matching what jira_fields.tsx actually passes.
  4. Removed dead style — Dropped style={getStyle().selectComponent} (was always undefined).
  5. input.tsx — Replaced parseInt with Number() to preserve decimal values for float fields.

@coderabbitai could you re-review?

@coderabbitai

coderabbitai Bot commented Jul 5, 2026

Copy link
Copy Markdown
🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail
gh pr diff 1316 --repo mattermost/mattermost-plugin-jira > /tmp/pr.diff
wc -l /tmp/pr.diff
grep -n "parseInt\|Number(\|isValid\|selectComponent\|Theme\|preferences\|FieldSchema\|AllowedValue\|projectKey\|issueMetadata" /tmp/pr.diff | head -100

Length of output: 1694


🏁 Script executed:

#!/bin/bash
sed -n '1,220p' /tmp/pr.diff

Length of output: 7908


All the claimed fixes check out against the diff for commit ce2932c:

  • input.tsx: parseInt(e.target.value, 10)Number(e.target.value) with an explicit empty-string guard (Line 141-142), isValid now checks value !== undefined && value !== null && value !== '' instead of relying on truthiness (Line 151), and rendering uses this.props.value ?? '' (Line 84 area) — so 0 is now handled correctly in all three places.
  • jira_field.tsx: Theme now imported from mattermost-redux/selectors/entities/preferences (Line 221), and JiraField/AllowedValue/IssueMetadata are imported from types/model (Line 230) instead of locally redefined. projectKey is now optional (projectKey?: string) and issueMetadata is typed as IssueMetadata | null (Lines 267-268), matching the caller. The dead style={getStyle().selectComponent} prop was removed (Line 302).
  • jira_issue_selector.tsx: Same Theme import fix applied (Line 433).

Everything matches the description — these look like solid fixes that improve type accuracy and correctness (especially the 0-value handling and truncation bug). Nice work.


✏️ Learnings added
Learnt from: rafaumeu
URL: https://github.com/mattermost/mattermost-plugin-jira/pull/1316

Timestamp: 2026-07-05T04:34:53.465Z
Learning: In the mattermost-plugin-jira webapp (webapp/src/), the canonical import path for the `Theme` type is `mattermost-redux/selectors/entities/preferences`, and shared domain types like `JiraField`, `IssueMetadata`, and `AllowedValue` should be imported from `types/model` rather than being redefined locally in component files (e.g., webapp/src/components/jira_field.tsx, webapp/src/components/jira_issue_selector/jira_issue_selector.tsx) to avoid type narrowing mismatches.

Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.

✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Convert reducer files from JS to TS

3 participants