Skip to content

Fixes #39505 - Update OrderableSelect to PF5#11018

Open
tlabaj wants to merge 10 commits into
theforeman:developfrom
tlabaj:spike
Open

Fixes #39505 - Update OrderableSelect to PF5#11018
tlabaj wants to merge 10 commits into
theforeman:developfrom
tlabaj:spike

Conversation

@tlabaj

@tlabaj tlabaj commented Jun 10, 2026

Copy link
Copy Markdown
Contributor

Fixes #39505 - Update OrderableSelect to PF5

Summary

Replaces the legacy PF3 OrderableSelect (typeahead + react-dnd tokens) with a PF5 composable dual list for ordered multi-value form fields.

The only current consumer is VMware VM Boot order (orderable_select_f on the new VM form). The form contract is unchanged: multiple hidden inputs with the same name, values submitted in boot order.

Intentional UX change (PF3 → PF5)

Before (PF3) After (PF5)
Typeahead to search/add options Dual list: available pane + chosen pane
Selected items shown as draggable tokens Chosen items in an ordered list with PF5 DragDrop
Add via typeahead search Add/remove via dual list controls (+ optional multi-select + move)

This is an intentional structural change, not a 1:1 PF component swap. A dual list matches existing Foreman/Satellite patterns and was preferred over keeping the typeahead token UI. User-visible outcome is the same: users can select boot devices and control their order.

Implementation

  • OrderableDualListSelector — reusable PF5 dual list in common/ (controlled API, drag-and-drop on chosen pane, tooltips, dedup on move). Intended for reuse by plugins (e.g. foreman_ansible).
  • OrderableDualList — thin form wrapper (initial state, hidden inputs, onChange).
  • orderable_select_f continues to register orderableSelect in InputFactory; no parallel helper added.
  • OrderableSelect/helpers.js kept and deprecated for plugin compatibility (orderable HOC still used by foreman_ansible/katello until they migrate).
image

@github-actions github-actions Bot added the UI label Jun 10, 2026
@tlabaj tlabaj changed the title Spike: Boot order Dual list selector with drag drop Fixes #39505 - Update OrderableSelect to PF5 Jul 8, 2026
@tlabaj
tlabaj marked this pull request as ready for review July 8, 2026 12:50

@Lukshio Lukshio 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.

Hi, I went thru the PR and have some notes. Also we have something similar in our plugin, that leads me to the idea of creating reusable component. So could you please create new component from this PR?

Check also this PR so you can better design the new component. theforeman/foreman_ansible#796

Please also take a look at our PF guide.

https://github.com/theforeman/foreman/blob/develop/developer_docs/pf3-to-pf5-migration-guide.asciidoc

Comment thread locale/foreman.pot

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.

Do not include locale changes, they are updated in a bulk in a separate PR

Comment thread app/helpers/form_helper.rb Outdated
tlabaj and others added 10 commits July 14, 2026 16:15
Move Draggable inside DualListOptionItem so PF5 receives a single list
item element, and guard option normalization for form field usage.

Co-authored-by: Cursor <cursoragent@cursor.com>
foreman_ansible and katello still import the orderable HOC from
foremanReact; keep helpers exported while the form input uses PF5.

Co-authored-by: Cursor <cursoragent@cursor.com>

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.

Please add test for reordering and onDrop handling

deprecate(
'forms/OrderableSelect/helpers',
'OrderableDualListSelector from foremanReact/components/common/OrderableDualListSelector/OrderableDualListSelector',
'3.21'

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.

Suggested change
'3.21'
'5.1'

Comment on lines +20 to +29
const newRemoveFrom = removeFrom.filter(
option => !selectedValues.includes(String(option.value))
);
const moved = selectedValues
.map(value =>
removeFrom.find(option => String(option.value) === String(value))
)
.filter(Boolean);

return [newRemoveFrom, appendUniqueOptions(addTo, moved)];

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.

Converting array to set and then using .has instead of .includes will reduce time complexity

};

const isItemSelected = stateName => value =>
selectState[stateName].includes(String(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.

Creating helper Set for available and selected and then use .has instead of .include will also reduce time complexity.

Comment on lines +32 to +38
const listOptionType = PropTypes.oneOfType([
PropTypes.string,
PropTypes.shape({
label: PropTypes.string.isRequired,
value: PropTypes.oneOfType([PropTypes.string, PropTypes.number]).isRequired,
}),
]);

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.

This can be inlined

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.

2 participants