fleet/frontend/components/forms
Scott Gress 02c5026436
Allow ESCAPE in LIKE clauses to be valid SQL (#31222)
for #30109

# Details

This PR fixes an issue in our current SQL parsing library that was
causing queries like this to be marked invalid:

```
SELECT * FROM table_name WHERE column_name LIKE '\_%' ESCAPE '\'
```

This is valid in SQLite because the `\` is not considered an escape
character by default. From [the SQLite
docs](https://www.sqlite.org/lang_expr.html) (see section 3 "Literal
Values (Constants)"; emphasis mine):

> A string constant is formed by enclosing the string in single quotes
('). A single quote within the string can be encoded by putting two
single quotes in a row - as in Pascal. C-style escapes using the
backslash character are not supported because they are not standard SQL.

# Use of forked code

Part of the fix for this was [submitted as a PR to the node-sql-parser
library](https://github.com/taozhi8833998/node-sql-parser/pull/2496) we
now use, and merged. I then found that another fix was needed, which I
submitted as [a separate
PR](https://github.com/taozhi8833998/node-sql-parser/pull/2512). As
these fixes have yet to be made part of an official release of the
library, I made a fork off of the release we were using (5.3.10) and
bundled the necessary build artifacts with Fleet. We have an [ADR
proposing the use of submodules for this
purpose](https://github.com/fleetdm/fleet/pull/31079); I'm happy to
implement that instead if we approve that, although for a front-end
module with a build step it's a bit more complicated. Hopefully this
code will be released in `node-sql-parser` soon and we can revert back
to using the dependency.

Here is the [full set of
changes](https://github.com/taozhi8833998/node-sql-parser/compare/master...sgress454:node-sql-parser:5.3.10-plus).

# Checklist for submitter

- [X] Changes file added for user-visible changes in `changes/`,
`orbit/changes/` or `ee/fleetd-chrome/changes`.
See [Changes
files](https://github.com/fleetdm/fleet/blob/main/docs/Contributing/guides/committing-changes.md#changes-files)
for more information.
- [X] Manual QA for all new/changed functionality
2025-07-25 10:13:55 -05:00
..
ChangeEmailForm FE: Button renaming, better storybook view, remove unused code (#28245) 2025-04-16 09:56:09 -04:00
ChangePasswordForm FE: Button renaming, better storybook view, remove unused code (#28245) 2025-04-16 09:56:09 -04:00
ConfirmInviteForm FE: Button renaming, better storybook view, remove unused code (#28245) 2025-04-16 09:56:09 -04:00
ConfirmSSOInviteForm FE: Button renaming, better storybook view, remove unused code (#28245) 2025-04-16 09:56:09 -04:00
fields Fleet UI: Host details > Software > Library statuses clickable, add software button (#30318) 2025-06-30 13:26:01 -04:00
ForgotPasswordForm FE: Button renaming, better storybook view, remove unused code (#28245) 2025-04-16 09:56:09 -04:00
FormField Fleet UI: Filter software/version tables by vulnerability score and exploitability (#21278) 2024-08-20 09:41:49 -04:00
LoginForm FE: Button renaming, better storybook view, remove unused code (#28245) 2025-04-16 09:56:09 -04:00
packs FE: Button renaming, better storybook view, remove unused code (#28245) 2025-04-16 09:56:09 -04:00
RegistrationForm Apply starter library during new Fleet instance setup (#29564) 2025-05-30 16:27:33 -05:00
ResetPasswordForm FE: Button renaming, better storybook view, remove unused code (#28245) 2025-04-16 09:56:09 -04:00
UserSettingsForm FE: Button renaming, better storybook view, remove unused code (#28245) 2025-04-16 09:56:09 -04:00
validators Allow ESCAPE in LIKE clauses to be valid SQL (#31222) 2025-07-25 10:13:55 -05:00
_styles.scss Bring new style variables from teams into master (#707) 2021-04-30 17:32:50 -04:00
Form.jsx Client side search for tables no longer debounce (#2807) 2021-11-04 21:16:42 -07:00
README.md Replace uses of the term "Kolide" with "Fleet" (#1999) 2019-01-24 09:39:32 -08:00

Fleet Forms

Fleet Forms leverage the Form Higher Order Component to simplify implementation and state management. As a user fills out a form, the Form HOC collects the form data in state. When the form is submitted, the Form HOC calls the provided client-side validation function with the form data and, if valid, then calls the handleSubmit prop with the form data. If the client-side validation function returns errors, those errors are stored in the Form HOC state and displayed in the form input where the input name matches the error key.

The Form HOC takes 3 parameters:

  • Component Class: The Component Class is the individual form component. It is a React component that renders a form.
  • Options Hash: The Options Hash accepts 2 options:
    • fields: This option is an array of field name strings in the form.
    • validate: This option is a function that gets called with the form data to test validity of the form. The return value from the validate function is expected to be a Javascript object with a valid key that has a boolean value signifying whether or not the form is valid, and an errors key that has a Javascript object value containing the client side validation errors.
      type ValidateResponse = { valid: String, errors: Object };
      const validate Function = (formData: Object): ValidateResponse => { ... };
    

The Form HOC renders with Component Class with additional props. The added props to the form are:

  • fields: The fields prop is a Javascript object containing an object for each field string passed to the Form HOC in the fields array. Each field object contains the following:
    • error: A string containing client side validation errors from the validate function or from the serverErrors prop passed to the form.
    • name: The name of the form field.
    • onChange: A function used to handle change on a form field element. This function stores the value of the form field element in state, and then submits the form field element values when the form is submitted.
    • value: The value of the form field element.

Additionally, the Form HOC accepts the following props passed to the form instance:

  • serverErrors: A Javascript object containing errors returned by the server. The key should be the name of the form field and the value should be the error message string. (Defaults to {}).
  • formData: A Javascript object representing the entity that will populate the form with the entity's attributes. When updating an entity, pass the entity to the form as the formData prop.
  • handleSubmit: A function that is called when the form is submitted. The function will be called with the form data if the validate function is run without errors.
  • onChangeFunc: A function that is called when a form field is changed. It is passed 2 parameters, the form field name and value. This is useful for handling specific form field changes on the parent component.

Example:

// Defining the form

import Button from 'components/buttons/Button';
import Form from 'components/forms/Form';
import InputField from 'components/forms/fields/InputField';

class MyForm extends Component {
  render () {
    return (
      <form onSubmit={this.props.handleSubmit}>
        <InputField
          {...this.props.fields.first_name}
        />
        <InputField
          {...this.props.fields.last_name}
        />
        <Button type="submit" />
      </form>
    );
  }
}

export default Form(MyForm, {
  fields: ['first_name', 'last_name'],
  validate: (formData) => {
    return { errors: {}, valid: true };
  },
});


// Rendering the form
import MyForm from 'components/forms/MyForm';

class MyFormPage extends Component {
  handleSubmit = (formData) => {
    console.log(formData);
  }

  render () {
    return (
      <div>
        <MyForm handleSubmit={this.handleSubmit} />
      </div>
    );
  }
}

export default MyFormPage