mirror of
https://github.com/strapi/strapi.git
synced 2025-09-25 16:29:34 +00:00
Merge pull request #14784 from strapi/fix/settings-conditions-category
ConditionsModal: Fix selection of multiple items in different categories
This commit is contained in:
commit
c1de0e1f8d
@ -5,14 +5,9 @@ import { Box } from '@strapi/design-system/Box';
|
||||
import { Flex } from '@strapi/design-system/Flex';
|
||||
import { Typography } from '@strapi/design-system/Typography';
|
||||
import { MultiSelectNested } from '@strapi/design-system/Select';
|
||||
import upperFirst from 'lodash/upperFirst';
|
||||
import { useIntl } from 'react-intl';
|
||||
import styled from 'styled-components';
|
||||
import { rowHeight } from '../../Permissions/utils/constants';
|
||||
|
||||
const FlexWrapper = styled(Flex)`
|
||||
height: ${rowHeight};
|
||||
`;
|
||||
import { getNestedOptions, getSelectedValues, getNewStateFromChangedValues } from './utils/options';
|
||||
|
||||
const ActionRow = ({
|
||||
arrayOfOptionsGroupedByCategory,
|
||||
@ -24,40 +19,13 @@ const ActionRow = ({
|
||||
value,
|
||||
}) => {
|
||||
const { formatMessage } = useIntl();
|
||||
const options = arrayOfOptionsGroupedByCategory.reduce((arr, curr) => {
|
||||
const [label, children] = curr;
|
||||
const obj = {
|
||||
label: upperFirst(label),
|
||||
children: children.map((child) => ({
|
||||
label: child.displayName,
|
||||
value: child.id,
|
||||
})),
|
||||
};
|
||||
|
||||
return [...arr, obj];
|
||||
}, []);
|
||||
|
||||
// Output: ['value1', 'value2']
|
||||
const values = Object.values(value)
|
||||
.map((x) =>
|
||||
Object.entries(x)
|
||||
.filter(([, value]) => value)
|
||||
.map(([key]) => key)
|
||||
)
|
||||
.flat();
|
||||
|
||||
// ! Only expects arrayOfOpt to be [['default', obj]] - might break in future changes
|
||||
const handleChange = (val) => {
|
||||
const [[, values]] = arrayOfOptionsGroupedByCategory;
|
||||
const formattedValues = values.reduce(
|
||||
(acc, curr) => ({ [curr.id]: val.includes(curr.id), ...acc }),
|
||||
{}
|
||||
);
|
||||
onChange(name, formattedValues);
|
||||
onChange(name, getNewStateFromChangedValues(arrayOfOptionsGroupedByCategory, val));
|
||||
};
|
||||
|
||||
return (
|
||||
<FlexWrapper as="li" background={isGrey ? 'neutral100' : 'neutral0'}>
|
||||
<Flex as="li" background={isGrey ? 'neutral100' : 'neutral0'} paddingBottom={3} paddingTop={3}>
|
||||
<Flex paddingLeft={6} style={{ width: 180 }}>
|
||||
<Typography variant="sigma" textColor="neutral600">
|
||||
{formatMessage({
|
||||
@ -85,12 +53,12 @@ const ActionRow = ({
|
||||
id={name}
|
||||
customizeContent={(values) => `${values.length} currently selected`}
|
||||
onChange={handleChange}
|
||||
value={values}
|
||||
options={options}
|
||||
value={getSelectedValues(value)}
|
||||
options={getNestedOptions(arrayOfOptionsGroupedByCategory)}
|
||||
disabled={isFormDisabled || IS_DISABLED}
|
||||
/>
|
||||
</Box>
|
||||
</FlexWrapper>
|
||||
</Flex>
|
||||
);
|
||||
};
|
||||
|
||||
@ -103,4 +71,5 @@ ActionRow.propTypes = {
|
||||
value: PropTypes.object.isRequired,
|
||||
onChange: PropTypes.func.isRequired,
|
||||
};
|
||||
|
||||
export default ActionRow;
|
||||
|
@ -0,0 +1,31 @@
|
||||
import upperFirst from 'lodash/upperFirst';
|
||||
|
||||
const getSelectedValues = (rawValue) =>
|
||||
Object.values(rawValue)
|
||||
.map((x) =>
|
||||
Object.entries(x)
|
||||
.filter(([, value]) => value)
|
||||
.map(([key]) => key)
|
||||
)
|
||||
.flat();
|
||||
|
||||
const getNestedOptions = (options) =>
|
||||
options.reduce((acc, [label, children]) => {
|
||||
acc.push({
|
||||
label: upperFirst(label),
|
||||
children: children.map((child) => ({
|
||||
label: child.displayName,
|
||||
value: child.id,
|
||||
})),
|
||||
});
|
||||
|
||||
return acc;
|
||||
}, []);
|
||||
|
||||
const getNewStateFromChangedValues = (options, changedValues) =>
|
||||
options
|
||||
.map(([, values]) => values)
|
||||
.flat()
|
||||
.reduce((acc, curr) => ({ [curr.id]: changedValues.includes(curr.id), ...acc }), {});
|
||||
|
||||
export { getNestedOptions, getSelectedValues, getNewStateFromChangedValues };
|
@ -0,0 +1,145 @@
|
||||
import { getSelectedValues, getNestedOptions, getNewStateFromChangedValues } from '../options';
|
||||
|
||||
describe('ActionRow | utils | getSelectedValues', () => {
|
||||
test('should reduce the default values to a flat array', () => {
|
||||
const FIXTURE = {
|
||||
something: {
|
||||
'admin::billing-amount-under-10k': false,
|
||||
'admin::billing-amount-above-20k': true,
|
||||
},
|
||||
default: {
|
||||
'admin::is-creator': true,
|
||||
'admin::has-same-role-as-creator': false,
|
||||
},
|
||||
};
|
||||
|
||||
expect(getSelectedValues(FIXTURE)).toStrictEqual([
|
||||
'admin::billing-amount-above-20k',
|
||||
'admin::is-creator',
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('ActionRow | utils | getNestedOptions', () => {
|
||||
test('should reduce the default values to a flat array', () => {
|
||||
const FIXTURE = [
|
||||
[
|
||||
'default',
|
||||
[
|
||||
{
|
||||
id: 'default:id:1',
|
||||
displayName: 'default:displayName:1',
|
||||
category: 'default:category',
|
||||
},
|
||||
|
||||
{
|
||||
id: 'default:id:2',
|
||||
displayName: 'default:displayName:2',
|
||||
category: 'default:category',
|
||||
},
|
||||
],
|
||||
],
|
||||
|
||||
[
|
||||
'something',
|
||||
[
|
||||
{
|
||||
id: 'something:id:1',
|
||||
displayName: 'something:displayName:1',
|
||||
category: 'something:category',
|
||||
},
|
||||
],
|
||||
],
|
||||
];
|
||||
|
||||
expect(getNestedOptions(FIXTURE)).toStrictEqual([
|
||||
{
|
||||
label: 'Default',
|
||||
children: [
|
||||
{
|
||||
label: 'default:displayName:1',
|
||||
value: 'default:id:1',
|
||||
},
|
||||
|
||||
{
|
||||
label: 'default:displayName:2',
|
||||
value: 'default:id:2',
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
{
|
||||
label: 'Something',
|
||||
children: [
|
||||
{
|
||||
label: 'something:displayName:1',
|
||||
value: 'something:id:1',
|
||||
},
|
||||
],
|
||||
},
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('ActionRow | utils | getNewStateFromChangedValues', () => {
|
||||
const FIXTURE_OPTIONS = [
|
||||
[
|
||||
'default',
|
||||
[
|
||||
{
|
||||
id: 'default:id:1',
|
||||
displayName: 'default:displayName:1',
|
||||
category: 'default:category',
|
||||
},
|
||||
|
||||
{
|
||||
id: 'default:id:2',
|
||||
displayName: 'default:displayName:2',
|
||||
category: 'default:category',
|
||||
},
|
||||
],
|
||||
],
|
||||
|
||||
[
|
||||
'something',
|
||||
[
|
||||
{
|
||||
id: 'something:id:1',
|
||||
displayName: 'something:displayName:1',
|
||||
category: 'something:category',
|
||||
},
|
||||
],
|
||||
],
|
||||
];
|
||||
test('should generate false for all values if nothing was selected', () => {
|
||||
expect(getNewStateFromChangedValues(FIXTURE_OPTIONS, [])).toStrictEqual({
|
||||
'default:id:1': false,
|
||||
'default:id:2': false,
|
||||
'something:id:1': false,
|
||||
});
|
||||
});
|
||||
|
||||
test('should generate true for selected values', () => {
|
||||
expect(getNewStateFromChangedValues(FIXTURE_OPTIONS, ['default:id:1'])).toStrictEqual({
|
||||
'default:id:1': true,
|
||||
'default:id:2': false,
|
||||
'something:id:1': false,
|
||||
});
|
||||
|
||||
expect(
|
||||
getNewStateFromChangedValues(FIXTURE_OPTIONS, ['default:id:1', 'something:id:1'])
|
||||
).toStrictEqual({
|
||||
'default:id:1': true,
|
||||
'default:id:2': false,
|
||||
'something:id:1': true,
|
||||
});
|
||||
});
|
||||
|
||||
test('should ignore unknown values', () => {
|
||||
expect(getNewStateFromChangedValues(FIXTURE_OPTIONS, ['random:id:1'])).toStrictEqual({
|
||||
'default:id:1': false,
|
||||
'default:id:2': false,
|
||||
'something:id:1': false,
|
||||
});
|
||||
});
|
||||
});
|
Loading…
x
Reference in New Issue
Block a user