Skip to content

Conversation

@ofedoren
Copy link
Member

InputFactory seems to be used by FormField (which is not commonly used and probably will have adjustments or removal) and by Tags::ReactInput via react_form_input.

react_form_input seems to cover any usages by either passing registered component name (such as autocomplete) or using a component directly instead of using InputFactory (such as textarea).

Given that I think we don't even need a fallback component, which previously was a simple input wrapped with FormControl. But to replace it, I went with TextInput since it's quite general component, even though not as flexible as input with type={type}.

I've tried to make this backwards compatible, but please verify if it's enough. Also, tried to replace snap tests with normal ones, but not sure if they are enough as well.

Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull Request Overview

This PR replaces the legacy FormControl component from patternfly-react with the modern TextInput component from @patternfly/react-core in the InputFactory component. The change modernizes the component while maintaining backwards compatibility for custom registered input components.

Key Changes:

  • Replaced FormControl with TextInput as the default fallback component
  • Updated prop mapping to use PatternFly 4 conventions (isDisabled, isRequired)
  • Migrated tests from snapshot-based to behavior-based testing with React Testing Library

Reviewed Changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 1 comment.

File Description
InputFactory.js Replaced FormControl with TextInput, updated prop handling and onChange signature
InputFactory.test.js Replaced snapshot tests with comprehensive behavior-based tests using React Testing Library
InputFactory.test.js.snap Removed snapshot file as tests no longer use snapshots

Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.

isDisabled={disabled}
isRequired={required}
className={className}
onChange={(_event, value) => onChange(value)}
Copy link

Copilot AI Oct 21, 2025

Choose a reason for hiding this comment

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

The onChange handler should check if onChange exists before calling it. While defaultProps defines onChange as noop, if a parent component explicitly passes undefined or null, this will throw a runtime error.

Suggested change
onChange={(_event, value) => onChange(value)}
onChange={(_event, value) => typeof onChange === 'function' && onChange(value)}

Copilot uses AI. Check for mistakes.
Copy link
Member

@MariaAga MariaAga left a comment

Choose a reason for hiding this comment

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

Needs a lint and tests fix, also

I've tried to make this backwards compatible, but please verify if it's enough.

Could you please share where its used?

Comment on lines 84 to 93
it('should render MemoryAllocationInput for type="memory"', () => {
render(<InputFactory type="memory" name="test" id="test-memory" />);
expect(screen.getByRole('spinbutton')).toBeInTheDocument();
});

it('should render CounterInput for type="counter"', () => {
render(<InputFactory type="counter" name="test" id="test-counter" />);
expect(screen.getByRole('spinbutton')).toBeInTheDocument();
});

Copy link
Member

Choose a reason for hiding this comment

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

These test the same output

Comment on lines 94 to 106
it('should pass setError and setWarning to custom components', () => {
const setError = jest.fn();
const setWarning = jest.fn();

render(
<InputFactory
{...selectProps}
setError={setError}
setWarning={setWarning}
/>
);

expect(screen.getByText('Grouped select')).toBeInTheDocument();
Copy link
Member

Choose a reason for hiding this comment

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

How does it test it?

type={type}
{...validations}
{...controlProps}
<TextInput
Copy link
Member

Choose a reason for hiding this comment

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

I got this error when rendering it: Text input: Text input requires either an id or aria-label to be specified Error Component Stack

@ogajduse
Copy link
Member

This PR has a target version set to 3.17, so we'd likely want to cherry-pick it to 3.17-stable

@MariaAga
Copy link
Member

Thanks, I dont think we have to have it in 3.17

Copy link
Member Author

@ofedoren ofedoren left a comment

Choose a reason for hiding this comment

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

Thanks, @MariaAga, updated.

Could you please share where its used?

IIUC, currently the whole InputFactory is used only for FormField, which also seems to be used only in foreman_webhooks. I think potentially we can just drop both 🤷

Anyway, InputFactory's fallback (TextInput now) seems to be used in foreman_webhooks ForemanFormikField (https://github.com/theforeman/foreman_webhooks/blob/master/webpack/ForemanWebhooks/Routes/Webhooks/Components/WebhookForm/Components/ForemanFormikField.js#L108), but the actual content will still be custom. I've checked if webhook forms still work with these changes and it seems so, but given how UI sometimes weird to me, I'd ask to re-test that.

@ofedoren ofedoren force-pushed the feat-38842-pf5-input-factory branch from 283bfec to badbc33 Compare November 13, 2025 14:14
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull Request Overview

Copilot reviewed 5 out of 5 changed files in this pull request and generated 4 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

onChange={(_event, val) => onChange(val)}
validated={validated}
ouiaId={`input-factory-text-input-${id}`}
aria-label={`text-input-${id}`}
Copy link

Copilot AI Nov 13, 2025

Choose a reason for hiding this comment

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

The aria-label will produce invalid values like "text-input-null" or "text-input-undefined" when id is null or undefined. Based on the FormField test snapshots, id can indeed be null.

Consider making aria-label conditional or providing a fallback:

aria-label={id ? `text-input-${id}` : 'text-input'}

Alternatively, only include aria-label when id is provided, or use a more descriptive fallback based on the input's purpose.

Suggested change
aria-label={`text-input-${id}`}
aria-label={id ? `text-input-${id}` : 'text-input'}

Copilot uses AI. Check for mistakes.
className={className}
onChange={(_event, val) => onChange(val)}
validated={validated}
ouiaId={`input-factory-text-input-${id}`}
Copy link

Copilot AI Nov 13, 2025

Choose a reason for hiding this comment

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

The ouiaId will produce invalid values like "input-factory-text-input-null" or "input-factory-text-input-undefined" when id is null or undefined. Based on the FormField test snapshots, id can indeed be null.

Consider making ouiaId conditional:

ouiaId={id ? `input-factory-text-input-${id}` : undefined}

OUIA IDs should be meaningful identifiers; having null or undefined in them defeats their purpose.

Suggested change
ouiaId={`input-factory-text-input-${id}`}
ouiaId={id ? `input-factory-text-input-${id}` : undefined}

Copilot uses AI. Check for mistakes.
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

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

Copilot encountered an error and was unable to review this pull request. You can try again by re-requesting a review.

"useKeyShortcuts": false,
}
}
id={null}
Copy link
Contributor

@kfamilonidis kfamilonidis Nov 14, 2025

Choose a reason for hiding this comment

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

why these are null ? Don't we need to remove this file altogether ?

Copy link
Member Author

Choose a reason for hiding this comment

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

These are null, because they are not being provided via fixtures props. Some fixtures do provide them though, see below.

Copy link
Contributor

@kfamilonidis kfamilonidis left a comment

Choose a reason for hiding this comment

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

The snap files are preventing testing. Please remove them. [/FormField.test.js.snap]‎(https://github.com/theforeman/foreman/pull/10729/files#diff-78eb07ad74cba7f7b5be93c011a04c294006aa76157dd671f22fcd2794901981) is needed to be connected with the input

Copy link
Member Author

@ofedoren ofedoren left a comment

Choose a reason for hiding this comment

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

The snap files are preventing testing.

How exactly? I've removed the snap which is directly related to the component I'm changing, since that snap is now covered by react-test lib tests.

I can't just remove snap for FormField component, since I don't almost change it nor re-writing into PF5 nor I change the test suite from snap-based into react-test-based. That's kinda out of scope for this PR.

"useKeyShortcuts": false,
}
}
id={null}
Copy link
Member Author

Choose a reason for hiding this comment

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

These are null, because they are not being provided via fixtures props. Some fixtures do provide them though, see below.

Copy link
Member

@MariaAga MariaAga left a comment

Choose a reason for hiding this comment

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

I dont think its used anywhere, anyway I tested it with packit to make sure in webhooks that use InputFactory and report generate that also uses it for the date.
I replaced a place where text_f was used with react_form_input(nil, f, attr, options) and it works well on new and edit.
The only issue, that might be out of the scope of the PR as this was a bug before as well :

Warning: `value` prop on `input` should not be null. Consider using an empty string to clear the component or `undefined` for uncontrolled components.

@ofedoren
Copy link
Member Author

ofedoren commented Nov 26, 2025

Yeah, I'm afraid that bug is not related to this PR or should be dealt with in since here we pass what's provided and if value is null instead of undefined it should be fixed in the component that's passing this in. We already have here some expectations: https://github.com/theforeman/foreman/pull/10729/files#diff-ff434a0e57df48e0aa222e0ef65e260a875b88a7934563b572f26976779e11ffL48-L53

Copy link
Member

@MariaAga MariaAga left a comment

Choose a reason for hiding this comment

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

LGTM, I opened https://issues.redhat.com/browse/SAT-40642 to track it

@MariaAga MariaAga merged commit 0b71365 into theforeman:develop Nov 26, 2025
46 checks passed
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.

4 participants