Wizard: Switch from deprecated select in ActivationKeys

This replaces a deprecated select in `ActivationKeys` for a non-deprecated one.
This commit is contained in:
regexowl 2025-03-19 11:58:49 +01:00 committed by Klara Simickova
parent a34d5895d9
commit 0431ac98dc
4 changed files with 108 additions and 38 deletions

View file

@ -4,14 +4,16 @@ import {
Alert,
FormGroup,
Spinner,
Select,
SelectList,
SelectOption,
Text,
TextContent,
MenuToggleElement,
MenuToggle,
TextInputGroup,
TextInputGroupMain,
} from '@patternfly/react-core';
import {
Select,
SelectOption,
SelectVariant,
} from '@patternfly/react-core/deprecated';
import { addNotification } from '@redhat-cloud-services/frontend-components-notifications/redux';
import ManageKeysButton from './components/ManageKeysButton';
@ -43,6 +45,8 @@ const ActivationKeysList = () => {
const { isProd } = useGetEnvironment();
const [isOpen, setIsOpen] = useState(false);
const [inputValue, setInputValue] = useState<string>('');
const [filterValue, setFilterValue] = useState<string>('');
const {
data: activationKeys,
@ -69,6 +73,36 @@ const ActivationKeysList = () => {
}
}, [dispatch, isProd]);
const [selectOptions, setSelectOptions] = useState<(string | undefined)[]>(
activationKeys?.body ? activationKeys.body.map((key) => key.name) : []
);
useEffect(() => {
let filteredKeys = activationKeys?.body?.map((key) => key.name);
if (filterValue) {
filteredKeys = activationKeys?.body
?.map((key) => key.name)
.filter((keyName: string) =>
String(keyName).toLowerCase().includes(filterValue.toLowerCase())
);
if (filteredKeys && !filteredKeys.length) {
filteredKeys = [`No results found for "${filterValue}"`];
}
if (!isOpen) {
setIsOpen(true);
}
}
if (filteredKeys) {
setSelectOptions(filteredKeys);
}
// This useEffect hook should run *only* on when the filter value changes.
// eslint's exhaustive-deps rule does not support this use.
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [filterValue]);
const setActivationKey = (
_event: React.MouseEvent<Element, MouseEvent>,
selection: string
@ -136,18 +170,33 @@ const ActivationKeysList = () => {
}
}, [isSuccessActivationKeys]);
const setSelectOptions = () => {
const selectOptions = [];
const onTextInputChange = (_event: React.FormEvent, value: string) => {
setInputValue(value);
setFilterValue(value);
if (value !== activationKey) {
dispatch(changeActivationKey(''));
}
};
const prepareSelectOptions = () => {
const selectOptionsElement = [];
if (isSuccessActivationKeys) {
activationKeys?.body?.map((key, index) =>
selectOptions.push(<SelectOption key={index} value={key.name} />)
selectOptions.map((key, index) =>
selectOptionsElement.push(
<SelectOption key={index} value={key}>
{key}
</SelectOption>
)
);
}
if (!isSuccessActivationKeys && isFetchingActivationKeys) {
selectOptions.push(
selectOptionsElement.push(
<SelectOption
key={'Fetching'}
isNoResultsOption={true}
key="Fetching"
value="loader"
data-testid="activation-keys-loading"
>
<Spinner size="md" />
@ -155,9 +204,40 @@ const ActivationKeysList = () => {
);
}
return selectOptions;
return selectOptionsElement;
};
const toggle = (toggleRef: React.Ref<MenuToggleElement>) => (
<MenuToggle
ref={toggleRef}
variant="typeahead"
onClick={handleToggle}
isExpanded={isOpen}
data-testid="activation-key-select"
isDisabled={
!isSuccessActivationKeys || registrationType === 'register-later'
}
ouiaId="activation_key_select"
>
<TextInputGroup isPlain>
<TextInputGroupMain
value={
activationKey
? registrationType === 'register-later'
? ''
: activationKey
: inputValue
}
onClick={handleToggle}
onChange={onTextInputChange}
autoComplete="off"
placeholder="Select activation key"
isExpanded={isOpen}
/>
</TextInputGroup>
</MenuToggle>
);
return (
<>
<FormGroup
@ -169,21 +249,15 @@ const ActivationKeysList = () => {
data-testid="subscription-activation-key"
>
<Select
ouiaId="activation_key_select"
variant={SelectVariant.typeahead}
onToggle={handleToggle}
onSelect={setActivationKey}
selections={
registrationType === 'register-later' ? '' : activationKey
}
isScrollable
isOpen={isOpen}
placeholderText="Select activation key"
typeAheadAriaLabel="Select activation key"
isDisabled={
!isSuccessActivationKeys || registrationType === 'register-later'
}
selected={activationKey}
onSelect={setActivationKey}
onOpenChange={handleToggle}
toggle={toggle}
shouldFocusFirstItemOnOpen={false}
>
{setSelectOptions()}
<SelectList>{prepareSelectOptions()}</SelectList>
</Select>
<TextContent>
<Text>

View file

@ -411,9 +411,7 @@ describe('Import modal', () => {
'automatically-register-radio'
);
expect(registrationCheckbox).toHaveFocus();
await screen.findByRole('textbox', {
name: 'Select activation key',
});
await screen.findByPlaceholderText('Select activation key');
// OpenScap
await clickNext();

View file

@ -144,9 +144,7 @@ describe('Keyboard accessibility', () => {
'automatically-register-radio'
);
expect(registrationCheckbox).toHaveFocus();
await screen.findByRole('textbox', {
name: 'Select activation key',
});
await screen.findByPlaceholderText('Select activation key');
await clickNext();
// TODO: Focus on textbox on OpenSCAP step

View file

@ -73,9 +73,9 @@ const deselectPredictiveAnalytics = async () => {
const openActivationKeyDropdown = async () => {
const user = userEvent.setup();
const activationKeyDropdown = await screen.findByRole('textbox', {
name: 'Select activation key',
});
const activationKeyDropdown = await screen.findByPlaceholderText(
'Select activation key'
);
user.click(activationKeyDropdown);
};
@ -197,9 +197,9 @@ describe('Step Registration', () => {
).not.toBeInTheDocument()
);
await waitFor(async () =>
expect(
await screen.findByRole('button', { name: /options menu/i })
).toBeDisabled()
expect(await screen.findByTestId('activation-key-select')).toHaveClass(
'pf-m-disabled'
)
);
await goToReviewStep();
await screen.findByText('Register the system later');