Skip to content

feat(ui): Add ESLint with plugins for react/hooks, prettier, flow#25716

Closed
johallar wants to merge 8 commits intoprestodb:masterfrom
johallar:eslint_with_flow
Closed

feat(ui): Add ESLint with plugins for react/hooks, prettier, flow#25716
johallar wants to merge 8 commits intoprestodb:masterfrom
johallar:eslint_with_flow

Conversation

@johallar
Copy link
Contributor

@johallar johallar commented Aug 7, 2025

Description

For developer + codebase life improvements, adding ESLint with prettier, react + react hooks, and flow plugins.

Motivation and Context

Impact

  • There will be a large number of line changes once all files are linted, but no functional impact.

Note: All lint rules are up for discussion if folks on the project have strong feelings about tab spacing, semicolons, etc. This mostly implements the "recommended" rules for react, hooks, prettier formatting, and flow

  • Only impacts dev dependencies
  • Adds commands to package.json to lint, lint fix, and use prettier formatter
  • Adds // @flow annotations to files that use flow so prettier/eslint know about it

Follow up

Test Plan

For now this simply adds the dependencies, and implements an eslint/prettier configuration that works. No files have been linted or formatted yet. I plan to do this in a follow up to keep this PR manageable, first draft of linting all files here: #25726

Test the eslint config by running yarn run lint for eslint changes, or yarn run format for just prettier formatting changes

Contributor checklist

  • Please make sure your submission complies with our contributing guide, in particular code style and commit standards.
  • PR description addresses the issue accurately and concisely. If the change is non-trivial, a GitHub Issue is referenced.
  • Documented new properties (with its default value), SQL syntax, functions, or other functionality.
  • If release notes are required, they follow the release notes guidelines.
  • Adequate tests were added if applicable.
  • CI passed.

Release Notes

Please follow release notes guidelines and fill in the release notes below.

== NO RELEASE NOTE ==

@johallar johallar mentioned this pull request Aug 8, 2025
6 tasks
@johallar johallar changed the title [ui] Add ESLint with plugins for react/hooks, prettier, flow feat(ui): add ESLint with plugins for react/hooks, prettier, flow Oct 1, 2025
@johallar johallar changed the title feat(ui): add ESLint with plugins for react/hooks, prettier, flow feat(ui): Add ESLint with plugins for react/hooks, prettier, flow Oct 1, 2025
@johallar johallar force-pushed the eslint_with_flow branch 2 times, most recently from 2f48ab6 to fe77f47 Compare October 3, 2025 16:01
@johallar johallar marked this pull request as ready for review October 7, 2025 20:09
@johallar johallar requested review from a team and yhwang as code owners October 7, 2025 20:09
@sourcery-ai
Copy link
Contributor

sourcery-ai bot commented Oct 7, 2025

Reviewer's Guide

This PR integrates ESLint with Prettier, React/React Hooks, and Flow plugins into the UI codebase by adding devDependencies, npm scripts, a new ESLint config file, and initial Flow annotations, without altering any runtime behavior.

Class diagram for ESLint configuration structure

classDiagram
  class ESLintConfig {
    +ignores: string[]
    +languageOptions: object
    +plugins: object
    +settings: object
    +rules: object
    +files: string[]
  }
  class PrettierPlugin {
    +recommended: object
  }
  class ReactPlugin {
    +recommended: object
    +rules: object
  }
  class ReactHooksPlugin {
    +recommended-latest: object
  }
  class FtFlowPlugin {
    +recommended: object
  }
  class HermesParser {}
  ESLintConfig --> PrettierPlugin
  ESLintConfig --> ReactPlugin
  ESLintConfig --> ReactHooksPlugin
  ESLintConfig --> FtFlowPlugin
  ESLintConfig --> HermesParser
Loading

File-Level Changes

Change Details Files
Introduce ESLint, Prettier, and related tooling as dev dependencies and npm scripts
  • Added ESLint, eslint-config-prettier, eslint-plugin-prettier, react, react-hooks, ft-flow, flow-bin, hermes-eslint, globals, and prettier to devDependencies
  • Defined npm scripts: lint, lint:fix, format, format:fix alongside existing build tasks
presto-ui/src/package.json
Add a dedicated ESLint configuration file with recommended rule sets
  • Imported and applied base JS, Prettier, React, React Hooks, and Flow plugin configurations
  • Configured hermes-eslint parser for Flow and enforced flow annotations-only rules
  • Set global browser and jQuery globals, and ignore patterns for vendor, node_modules, and config files
presto-ui/src/eslint.config.mjs
Annotate source files for Flow type checking
  • Added // @flow header to React component files and utility modules to opt them into Flow
presto-ui/src/components/QueryPlanView.jsx
presto-ui/src/components/QuerySplitsView.jsx
presto-ui/src/components/SQLClient.jsx
presto-ui/src/components/SQLInput.jsx
presto-ui/src/components/Splits.jsx
presto-ui/src/d3utils.js
presto-ui/src/lazy.jsx
Update lockfile to capture new dev dependencies
  • Regenerated yarn.lock to include versions for ESLint, Prettier, Flow, and plugin packages
presto-ui/src/yarn.lock

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

Copy link
Contributor

@sourcery-ai sourcery-ai bot left a comment

Choose a reason for hiding this comment

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

Hey there - I've reviewed your changes - here's some feedback:

  • Consider adding the lint step to your CI pipeline now so that this new ESLint/prettier configuration is applied and validated automatically rather than as a separate follow-up.
  • Renaming eslint.config.mjs to a more common config filename (like .eslintrc.cjs or .eslintrc.js) can help editors and tooling detect your ESLint settings out of the box.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- Consider adding the lint step to your CI pipeline now so that this new ESLint/prettier configuration is applied and validated automatically rather than as a separate follow-up.
- Renaming eslint.config.mjs to a more common config filename (like .eslintrc.cjs or .eslintrc.js) can help editors and tooling detect your ESLint settings out of the box.

## Individual Comments

### Comment 1
<location> `presto-ui/src/components/QuerySplitsView.jsx:122-126` </location>
<code_context>
+    updateTimeline();
+  }

-    useEffect(() => {
-        if (data && show) {
-            calculateItemsGroups();
-        }
-    }, [data, show]);
+  useEffect(() => {
+    if (data && show) {
</code_context>

<issue_to_address>
**suggestion:** Consider guarding against null containerRef in useEffect.

Add a check to ensure containerRef.current is not null before calling calculateItemsGroups to prevent timeline initialization errors.
</issue_to_address>

### Comment 2
<location> `presto-ui/src/d3utils.js:21-26` </location>
<code_context>
-    return new dagreD3.graphlib.Graph({compound: true})
-        .setGraph({rankdir: 'BT'})
-        .setDefaultEdgeLabel(function () { return {}; });
+export function initializeGraph() {
+  return new dagreD3.graphlib.Graph({ compound: true })
+    .setGraph({ rankdir: "BT" })
+    .setDefaultEdgeLabel(function () {
+      return {};
+    });
 }

</code_context>

<issue_to_address>
**nitpick:** Return type annotation for initializeGraph is missing.

Please add a Flow return type annotation to initializeGraph for better type safety.
</issue_to_address>

### Comment 3
<location> `presto-ui/src/components/QueryPlanView.jsx:119` </location>
<code_context>
    const svg = widgets.current.svg;

</code_context>

<issue_to_address>
**suggestion (code-quality):** Prefer object destructuring when accessing and using properties. ([`use-object-destructuring`](https://docs.sourcery.ai/Reference/Rules-and-In-Line-Suggestions/JavaScript/Default-Rules/use-object-destructuring))

```suggestion
    const {svg} = widgets.current;
```

<br/><details><summary>Explanation</summary>Object destructuring can often remove an unnecessary temporary reference, as well as making your code more succinct.

From the [Airbnb Javascript Style Guide](https://airbnb.io/javascript/#destructuring--object)
</details>
</issue_to_address>

### Comment 4
<location> `presto-ui/src/components/QuerySplitsView.jsx:24-122` </location>
<code_context>

</code_context>

<issue_to_address>
**issue (code-quality):** Avoid function declarations, favouring function assignment expressions, inside blocks. ([`avoid-function-declarations-in-blocks`](https://docs.sourcery.ai/Reference/Rules-and-In-Line-Suggestions/JavaScript/Default-Rules/avoid-function-declarations-in-blocks))

<details><summary>Explanation</summary>Function declarations may be hoisted in Javascript, but the behaviour is inconsistent between browsers.
Hoisting is generally confusing and should be avoided. Rather than using function declarations inside blocks, you
should use function expressions, which create functions in-scope.
</details>
</issue_to_address>

### Comment 5
<location> `presto-ui/src/components/SQLInput.jsx:103-107` </location>
<code_context>

</code_context>

<issue_to_address>
**issue (code-quality):** Avoid function declarations, favouring function assignment expressions, inside blocks. ([`avoid-function-declarations-in-blocks`](https://docs.sourcery.ai/Reference/Rules-and-In-Line-Suggestions/JavaScript/Default-Rules/avoid-function-declarations-in-blocks))

<details><summary>Explanation</summary>Function declarations may be hoisted in Javascript, but the behaviour is inconsistent between browsers.
Hoisting is generally confusing and should be avoided. Rather than using function declarations inside blocks, you
should use function expressions, which create functions in-scope.
</details>
</issue_to_address>

### Comment 6
<location> `presto-ui/src/components/SQLInput.jsx:212-226` </location>
<code_context>

</code_context>

<issue_to_address>
**issue (code-quality):** Avoid function declarations, favouring function assignment expressions, inside blocks. ([`avoid-function-declarations-in-blocks`](https://docs.sourcery.ai/Reference/Rules-and-In-Line-Suggestions/JavaScript/Default-Rules/avoid-function-declarations-in-blocks))

<details><summary>Explanation</summary>Function declarations may be hoisted in Javascript, but the behaviour is inconsistent between browsers.
Hoisting is generally confusing and should be avoided. Rather than using function declarations inside blocks, you
should use function expressions, which create functions in-scope.
</details>
</issue_to_address>

### Comment 7
<location> `presto-ui/src/components/SQLInput.jsx:233-242` </location>
<code_context>

</code_context>

<issue_to_address>
**issue (code-quality):** Avoid function declarations, favouring function assignment expressions, inside blocks. ([`avoid-function-declarations-in-blocks`](https://docs.sourcery.ai/Reference/Rules-and-In-Line-Suggestions/JavaScript/Default-Rules/avoid-function-declarations-in-blocks))

<details><summary>Explanation</summary>Function declarations may be hoisted in Javascript, but the behaviour is inconsistent between browsers.
Hoisting is generally confusing and should be avoided. Rather than using function declarations inside blocks, you
should use function expressions, which create functions in-scope.
</details>
</issue_to_address>

### Comment 8
<location> `presto-ui/src/components/Splits.jsx:31-143` </location>
<code_context>

</code_context>

<issue_to_address>
**issue (code-quality):** Avoid function declarations, favouring function assignment expressions, inside blocks. ([`avoid-function-declarations-in-blocks`](https://docs.sourcery.ai/Reference/Rules-and-In-Line-Suggestions/JavaScript/Default-Rules/avoid-function-declarations-in-blocks))

<details><summary>Explanation</summary>Function declarations may be hoisted in Javascript, but the behaviour is inconsistent between browsers.
Hoisting is generally confusing and should be avoided. Rather than using function declarations inside blocks, you
should use function expressions, which create functions in-scope.
</details>
</issue_to_address>

### Comment 9
<location> `presto-ui/src/components/Splits.jsx:145-161` </location>
<code_context>

</code_context>

<issue_to_address>
**issue (code-quality):** Avoid function declarations, favouring function assignment expressions, inside blocks. ([`avoid-function-declarations-in-blocks`](https://docs.sourcery.ai/Reference/Rules-and-In-Line-Suggestions/JavaScript/Default-Rules/avoid-function-declarations-in-blocks))

<details><summary>Explanation</summary>Function declarations may be hoisted in Javascript, but the behaviour is inconsistent between browsers.
Hoisting is generally confusing and should be avoided. Rather than using function declarations inside blocks, you
should use function expressions, which create functions in-scope.
</details>
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

Comment on lines 122 to 126
}

useEffect(() => {
if (data && show) {
calculateItemsGroups();
}
}, [data, show]);
useEffect(() => {
if (data && show) {
calculateItemsGroups();
Copy link
Contributor

Choose a reason for hiding this comment

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

suggestion: Consider guarding against null containerRef in useEffect.

Add a check to ensure containerRef.current is not null before calling calculateItemsGroups to prevent timeline initialization errors.

Comment on lines 21 to 26
export function initializeGraph() {
return new dagreD3.graphlib.Graph({ compound: true })
.setGraph({ rankdir: "BT" })
.setDefaultEdgeLabel(function () {
return {};
});
Copy link
Contributor

Choose a reason for hiding this comment

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

nitpick: Return type annotation for initializeGraph is missing.

Please add a Flow return type annotation to initializeGraph for better type safety.

@tdcmeehan tdcmeehan requested a review from unidevel October 7, 2025 20:11
@johallar johallar marked this pull request as draft October 7, 2025 20:12
@johallar
Copy link
Contributor Author

johallar commented Oct 7, 2025

Sorry folks, accidentally committed some formatting changes... fix incoming shortly.

@johallar johallar marked this pull request as ready for review October 7, 2025 20:17
Copy link
Contributor

@sourcery-ai sourcery-ai bot left a comment

Choose a reason for hiding this comment

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

Hey there - I've reviewed your changes and they look great!

Prompt for AI Agents
Please address the comments from this code review:

## Individual Comments

### Comment 1
<location> `presto-ui/src/package.json:59-60` </location>
<code_context>
+    "analyze": "webpack --env=production --config webpack.config.js --profile --json > stats.json && mv stats.json ../target/webapp/ && npx webpack-bundle-analyzer ../target/webapp/stats.json",
+    "lint": "eslint . --ext .js,.jsx",
+    "lint:fix": "eslint . --ext .js,.jsx --fix",
+    "format": "prettier .",
+    "format:fix": "prettier --write ."
   },
   "resolutions": {
</code_context>

<issue_to_address>
**suggestion:** Consider specifying file extensions for Prettier scripts to avoid formatting unintended files.

Using '.' as the target for Prettier may format files outside your intended scope. Limit formatting to specific extensions to avoid affecting non-source files.

```suggestion
    "format": "prettier \"**/*.{js,jsx,json,css,md}\"",
    "format:fix": "prettier --write \"**/*.{js,jsx,json,css,md}\""
```
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

Comment on lines +59 to +60
"format": "prettier .",
"format:fix": "prettier --write ."
Copy link
Contributor

Choose a reason for hiding this comment

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

suggestion: Consider specifying file extensions for Prettier scripts to avoid formatting unintended files.

Using '.' as the target for Prettier may format files outside your intended scope. Limit formatting to specific extensions to avoid affecting non-source files.

Suggested change
"format": "prettier .",
"format:fix": "prettier --write ."
"format": "prettier \"**/*.{js,jsx,json,css,md}\"",
"format:fix": "prettier --write \"**/*.{js,jsx,json,css,md}\""

@johallar
Copy link
Contributor Author

johallar commented Oct 7, 2025

OK, I'll have to remove the flow flags again, didn't realize it was all or nothing.

It'll break prettier formatting for now, but will get through CI. I can complete flow annotations (or remove from files with minimal type annotations) in #25726 if that's acceptable.

@yhwang
Copy link
Member

yhwang commented Oct 9, 2025

Hi @johallar, thanks for the work. I am thinking separate the flow and prettier if that's possible. I believe prettier won't break the CI, however, it would contain a large change. (but we know it's just reformatting). And when you put the prettier change, you can also update the build to run prettier and make sure it is enforced afterwards.

Then the other PR could only contain flow change, including enabling the flow annotation and fixing the errors.

@johallar
Copy link
Contributor Author

johallar commented Oct 9, 2025

Hi @johallar, thanks for the work. I am thinking separate the flow and prettier if that's possible. I believe prettier won't break the CI, however, it would contain a large change. (but we know it's just reformatting). And when you put the prettier change, you can also update the build to run prettier and make sure it is enforced afterwards.

Then the other PR could only contain flow change, including enabling the flow annotation and fixing the errors.

Yeah, I can split it that way, i'll plan to do 2 PRs then:

  1. Fix flow problems (add flow flag to files that use it, fix/complete flow annotations for files that have // @flow flag)
  2. Add ESLint + Flow + Prettier configs + code fixes + add step to build to enforce it

Let me know if you were thinking a different split @yhwang (eg. adding eslint + flow pieces in PR 1)

@yhwang
Copy link
Member

yhwang commented Oct 9, 2025

Yes, separating the flow from others is great! Let’s do it.

@johallar
Copy link
Contributor Author

Yes, separating the flow from others is great! Let’s do it.

Side note @yhwang @tdcmeehan: How committed is presto to flow? I know it's a meta library, but support + tooling is much better for typescript, as well as compatibility with 3rd party libraries.

With how limited the flow usage is now in the presto UI I don't see the conversion being too hard, and much better to do now if that's something we might want to do going forward.

@yhwang
Copy link
Member

yhwang commented Oct 10, 2025

@johallar

How committed is presto to flow?

This is a good question, and I guess you probably could guess why flow is used at the Presto UI. And I totally understand your points and 100% agree with you. Here are my thoughts:

  1. TypeScript + ESLint would be a must-have for the long-term goal
  2. Apply testing to Presto UI. We missed this at the beginning
  3. Flow won't be necessary once we move to TypeScript

I believe wrapping up those PRs that refactor class components into function components would benefit us with TypeScript conversion. I am fine if you want to repurpose this PR to only apply ESLint and prettier, since we agreed to separate flow from ESLint.

How do you think?

@johallar
Copy link
Contributor Author

Agree that eslint + ts is a great long term goal. If we're all in alignment on that I think we should do this in separate steps:

  1. Repurpose this PR to add ESLint + prettier config/packages
  2. Format all UI files, add eslint to build process
  3. Convert flow -> typescript, add typescript-eslint
  4. Group spike to boost UI test coverage?

@yhwang
Copy link
Member

yhwang commented Oct 10, 2025

Sounds like a great plan to me!

@johallar
Copy link
Contributor Author

Closing this one, replaced by #26281

@johallar johallar closed this Oct 10, 2025
yhwang pushed a commit that referenced this pull request Nov 18, 2025
## Description
<!---Describe your changes in detail-->

This removes flow, and replaces it with typescript, and is the next step
in the plan laid out in
#25716 (comment)

## Motivation and Context
<!---Why is this change required? What problem does it solve?-->
<!---If it fixes an open issue, please link to the issue here.-->
Typescript has better tooling, and has a bigger community around it so
this will be another QOL improvement for developers.

Big # line changes is mostly yarn-lock changes, the code diff relatively
small

## Impact
<!---Describe any public API or user-facing feature change or any
performance impact-->

## Test Plan
<!---Please fill in how you tested your change-->
CI passes, there should be no user facing changes

## Contributor checklist

- [ ] Please make sure your submission complies with our [contributing
guide](https://github.com/prestodb/presto/blob/master/CONTRIBUTING.md),
in particular [code
style](https://github.com/prestodb/presto/blob/master/CONTRIBUTING.md#code-style)
and [commit
standards](https://github.com/prestodb/presto/blob/master/CONTRIBUTING.md#commit-standards).
- [ ] PR description addresses the issue accurately and concisely. If
the change is non-trivial, a GitHub Issue is referenced.
- [ ] Documented new properties (with its default value), SQL syntax,
functions, or other functionality.
- [ ] If release notes are required, they follow the [release notes
guidelines](https://github.com/prestodb/presto/wiki/Release-Notes-Guidelines).
- [ ] Adequate tests were added if applicable.
- [ ] CI passed.
- [ ] If adding new dependencies, verified they have an [OpenSSF
Scorecard](https://securityscorecards.dev/#the-checks) score of 5.0 or
higher (or obtained explicit TSC approval for lower scores).

## Release Notes
Please follow [release notes
guidelines](https://github.com/prestodb/presto/wiki/Release-Notes-Guidelines)
and fill in the release notes below.

```
== NO RELEASE NOTE ==
```
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants