Skip to content

Commit

Permalink
fix(RHINENG-13682): Update eligible filter to single select
Browse files Browse the repository at this point in the history
This PR updates the system eligibility filter in the select systems modal for a task from radio buttons to a single select dropdown. The functionality should remain the same.

Go to the Available tab on the Tasks app and click the Select systems button on a task to load the system modal and select the eligibility filter.
  • Loading branch information
Michael Johnson authored and johnsonm325 committed Jan 8, 2025
1 parent 10ab6a6 commit 729bef8
Show file tree
Hide file tree
Showing 5 changed files with 176 additions and 22 deletions.
74 changes: 74 additions & 0 deletions src/SmartComponents/SystemTable/SelectCustomFilter.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
import React, { useState } from 'react';
import propTypes from 'prop-types';
import {
MenuToggle,
Select,
SelectList,
SelectOption,
} from '@patternfly/react-core';
import { findFilterData } from './helpers';

const SelectCustomFilter = ({
filterId,
options,
selectedValue,
setFilterData,
}) => {
const [isOpen, setOpen] = useState(false);

const handleSelectChange = (value) => {
setFilterData(findFilterData(value, options));
};

const toggle = (toggleRef) => (
<MenuToggle
ref={toggleRef}
onClick={() => setOpen(!isOpen)}
isExpanded={isOpen}
style={{
width: 'auto',
}}
>
{options.find((item) => item.value === selectedValue.value)?.label}
</MenuToggle>
);

return (
<div
className="pf-v5-c-select pf-v5-u-mr-sm pf-v5-u-mb-sm"
style={{ width: 'auto' }}
>
<Select
aria-label="Select Input"
isOpen={isOpen}
key={filterId}
onSelect={(event, optionName) => handleSelectChange(optionName)}
onOpenChange={(isOpen) => setOpen(isOpen)}
selected={selectedValue.label}
toggle={toggle}
shouldFocusToggleOnSelect
>
<SelectList>
{options.map((item) => (
<SelectOption
width="100%"
key={filterId + item.label}
value={item.label}
>
{item.label}
</SelectOption>
))}
</SelectList>
</Select>
</div>
);
};

SelectCustomFilter.propTypes = {
filterId: propTypes.string,
options: propTypes.array,
setFilterData: propTypes.func,
selectedValue: propTypes.object,
};

export default SelectCustomFilter;
39 changes: 23 additions & 16 deletions src/SmartComponents/SystemTable/SystemTable.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ import React, { useContext, useEffect, useRef, useState } from 'react';
import { useSelector } from 'react-redux';
import propTypes from 'prop-types';
import {
ELIGIBLE_SYSTEMS,
ALL_SYSTEMS,
ELIGIBLE_SYSTEMS_VALUE,
ALL_SYSTEMS_VALUE,
API_MAX_SYSTEMS,
eligibilityFilterItems,
defaultOnLoad,
Expand All @@ -21,6 +21,7 @@ import { conditionalFilterType } from '@redhat-cloud-services/frontend-component
import usePromiseQueue from '../../Utilities/hooks/usePromiseQueue';
import { NoCentOsEmptyState } from './NoCentOsEmptyState';
import { CENTOS_CONVERSION_SLUGS } from '../AvailableTasks/QuickstartButton';
import SelectCustomFilter from './SelectCustomFilter';

const SystemTable = ({
bulkSelectIds,
Expand All @@ -32,7 +33,7 @@ const SystemTable = ({
}) => {
const [items, setItems] = useState([]);
const [total, setTotal] = useState(0);
const [eligibility, setEligibility] = useState(ELIGIBLE_SYSTEMS);
const [eligibility, setEligibility] = useState(eligibilityFilterItems[0]);
const inventory = useRef(null);
const { getRegistry } = useContext(RegistryContext);
const dispatch = useDispatch();
Expand Down Expand Up @@ -95,17 +96,23 @@ const SystemTable = ({
};
});

const setEligibilityData = (value) => {
setEligibility(value);
setShowEligibilityAlert(value === ELIGIBLE_SYSTEMS_VALUE);
};

const eligibilityFilter = {
label: 'Task Eligibility',
type: conditionalFilterType.radio,
type: conditionalFilterType.custom,
filterValues: {
onChange: (event, value) => {
setEligibility(value);
setShowEligibilityAlert(value === ELIGIBLE_SYSTEMS);
},
items: eligibilityFilterItems,
value: eligibility,
placeholder: 'Filter Eligible Systems',
children: (
<SelectCustomFilter
filterId="task-eligibility"
options={eligibilityFilterItems}
selectedValue={eligibility}
setFilterData={setEligibilityData}
/>
),
},
};

Expand All @@ -114,21 +121,21 @@ const SystemTable = ({
{
id: 'Task eligibility',
category: 'Task eligibility',
chips: [{ name: eligibility, value: eligibility }],
chips: [{ name: eligibility.label, value: eligibility.value }],
},
],
onDelete: (event, itemsToRemove, isAll) => {
if (isAll) {
setEligibility(ELIGIBLE_SYSTEMS);
setEligibility(eligibilityFilterItems[0]);
setShowEligibilityAlert(true);
} else {
itemsToRemove.map((item) => {
if (item.category === 'Task eligibility') {
if (eligibility === ALL_SYSTEMS) {
setEligibility(ELIGIBLE_SYSTEMS);
if (eligibility.value === ALL_SYSTEMS_VALUE) {
setEligibility(eligibilityFilterItems[0]);
setShowEligibilityAlert(true);
} else {
setEligibility(ALL_SYSTEMS);
setEligibility(eligibilityFilterItems[1]);
setShowEligibilityAlert(false);
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
import React from 'react';
import userEvent from '@testing-library/user-event';
import SelectCustomFilter from '../SelectCustomFilter';
import { render, screen, waitFor, within } from '@testing-library/react';

const options = [
{ value: 'op1', label: 'option 1' },
{ value: 'op2', label: 'option 2' },
{ value: 'op3', label: 'option 3' },
];
const filterId = 'my-filter';
const setFilterData = jest.fn();

describe('SelectCustomFilter component', () => {
it('Should handle select values', async () => {
const selectedValue = { value: 'op1', label: 'option 1' };

render(
<SelectCustomFilter
selectedValue={selectedValue}
setFilterData={setFilterData}
options={options}
filterId={filterId}
/>
);

await waitFor(() =>
userEvent.click(
screen.getByRole('button', {
name: /option 1/i,
})
)
);

const option1 = screen.getByRole('option', {
name: /option 1/i,
});
const option2 = screen.getByRole('option', {
name: /option 2/i,
});
const option3 = screen.getByRole('option', {
name: /option 3/i,
});

expect(
within(option1).getByRole('img', {
hidden: true,
})
).toBeTruthy();
expect(
within(option2).queryByRole('img', {
hidden: true,
})
).toBeFalsy();
expect(
within(option3).queryByRole('img', {
hidden: true,
})
).toBeFalsy();

await waitFor(() => userEvent.click(option2));

expect(setFilterData).toHaveBeenCalledWith(options[1]);
});
});
10 changes: 6 additions & 4 deletions src/SmartComponents/SystemTable/constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -56,11 +56,13 @@ export const defaultOnLoad = (columns, getRegistry) => {
});
};

export const ELIGIBLE_SYSTEMS = 'Eligible Systems';
export const ALL_SYSTEMS = 'All Systems';
const ELIGIBLE_SYSTEMS = 'Eligible Systems';
export const ELIGIBLE_SYSTEMS_VALUE = 'eligible-systems';
const ALL_SYSTEMS = 'All Systems';
export const ALL_SYSTEMS_VALUE = 'all-systems';
export const eligibilityFilterItems = [
{ label: ELIGIBLE_SYSTEMS, value: ELIGIBLE_SYSTEMS },
{ label: ALL_SYSTEMS, value: ALL_SYSTEMS },
{ label: ELIGIBLE_SYSTEMS, value: ELIGIBLE_SYSTEMS_VALUE },
{ label: ALL_SYSTEMS, value: ALL_SYSTEMS_VALUE },
];

// Max systems we can ask for from the API, otherwise the connected status
Expand Down
10 changes: 8 additions & 2 deletions src/SmartComponents/SystemTable/helpers.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { ALL_SYSTEMS } from './constants';
import { ALL_SYSTEMS_VALUE } from './constants';

const buildSortString = (orderBy, orderDirection) => {
let sortString = orderBy ? '&sort=' : '';
Expand Down Expand Up @@ -87,7 +87,9 @@ const buildWorkloadFiltersString = (filters) => {
};

const buildEligibilityFilterString = ({ filters }) => {
return filters[0]?.chips[0]?.value === ALL_SYSTEMS ? '&all_systems=true' : '';
return filters[0]?.chips[0]?.value === ALL_SYSTEMS_VALUE
? '&all_systems=true'
: '';
};

// TODO this should be based on a URLSearchParams object and use its toString() function
Expand Down Expand Up @@ -120,3 +122,7 @@ export const findCheckedValue = (total, selected) => {
return false;
}
};

export const findFilterData = (optionName, options) => {
return options.find((item) => item.label === optionName);
};

0 comments on commit 729bef8

Please sign in to comment.