mirror of
https://github.com/strapi/strapi.git
synced 2025-09-19 21:38:05 +00:00
Migrate AllowedTypesSelect
Signed-off-by: soupette <cyril@strapi.io>
This commit is contained in:
parent
548cc9a88e
commit
7148972f00
@ -1,115 +0,0 @@
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { components } from 'react-select';
|
||||
import { useIntl } from 'react-intl';
|
||||
import { CheckboxWrapper, Label } from '@buffetjs/styles';
|
||||
import getTrad from '../../utils/getTrad';
|
||||
import SelectCheckbox from '../SelectCheckbox';
|
||||
import SubUl from '../SelectMenuSubUl';
|
||||
import UpperFirst from '../UpperFirst';
|
||||
import Ul from '../SelectMenuUl';
|
||||
import Text from './Text';
|
||||
|
||||
const MenuList = ({ selectProps: { changeMediaAllowedTypes, value }, ...rest }) => {
|
||||
const { formatMessage } = useIntl();
|
||||
const Component = components.MenuList;
|
||||
const areAllAllowedTypesSelected = value.value && value.value.length === 3;
|
||||
const someChecked = value.value && !areAllAllowedTypesSelected && value.value.length > 0;
|
||||
const options = [
|
||||
{
|
||||
name: 'images',
|
||||
infos: '(JPEG, PNG, GIF, SVG, TIFF, ICO, DVU)',
|
||||
},
|
||||
{
|
||||
name: 'videos',
|
||||
infos: '(MPEG, MP4, Quicktime, WMV, AVI, FLV)',
|
||||
},
|
||||
|
||||
{
|
||||
name: 'files',
|
||||
infos: '(CSV, ZIP, MP3, PDF, Excel, JSON, ...)',
|
||||
},
|
||||
];
|
||||
|
||||
return (
|
||||
<Component {...rest}>
|
||||
<Ul>
|
||||
<li className="li-multi-menu">
|
||||
<div style={{ marginTop: 3 }}>
|
||||
<CheckboxWrapper>
|
||||
<Label
|
||||
htmlFor="overrideReactSelectBehavior"
|
||||
onClick={() => {
|
||||
changeMediaAllowedTypes({
|
||||
target: { name: 'all', value: !areAllAllowedTypesSelected },
|
||||
});
|
||||
}}
|
||||
>
|
||||
<SelectCheckbox
|
||||
id="checkAll"
|
||||
checked={areAllAllowedTypesSelected}
|
||||
someChecked={someChecked}
|
||||
name="all"
|
||||
onChange={() => {}}
|
||||
/>
|
||||
<UpperFirst content="All" />
|
||||
</Label>
|
||||
</CheckboxWrapper>
|
||||
</div>
|
||||
<SubUl tad="ul" isOpen>
|
||||
{options.map(({ name, infos }) => {
|
||||
const isChecked = value.value && value.value.includes(name);
|
||||
const target = { name, value: !isChecked };
|
||||
|
||||
return (
|
||||
<li key={name}>
|
||||
<CheckboxWrapper>
|
||||
<Label
|
||||
htmlFor={name}
|
||||
onClick={() => {
|
||||
changeMediaAllowedTypes({ target });
|
||||
}}
|
||||
>
|
||||
<SelectCheckbox
|
||||
id="check"
|
||||
name={name}
|
||||
// Remove the handler
|
||||
onChange={() => {}}
|
||||
checked={isChecked}
|
||||
/>
|
||||
<Text>
|
||||
<UpperFirst
|
||||
content={formatMessage({
|
||||
id: getTrad(`form.attribute.media.allowed-types.option-${name}`),
|
||||
})}
|
||||
/>
|
||||
</Text>
|
||||
<Text fontSize="sm" color="#B3B5B9" textTransform="italic">
|
||||
{infos}
|
||||
</Text>
|
||||
</Label>
|
||||
</CheckboxWrapper>
|
||||
</li>
|
||||
);
|
||||
})}
|
||||
</SubUl>
|
||||
</li>
|
||||
</Ul>
|
||||
</Component>
|
||||
);
|
||||
};
|
||||
|
||||
MenuList.defaultProps = {
|
||||
selectProps: {
|
||||
value: {},
|
||||
},
|
||||
};
|
||||
|
||||
MenuList.propTypes = {
|
||||
selectProps: PropTypes.shape({
|
||||
changeMediaAllowedTypes: PropTypes.func.isRequired,
|
||||
value: PropTypes.object,
|
||||
}),
|
||||
};
|
||||
|
||||
export default MenuList;
|
@ -1,26 +0,0 @@
|
||||
import styled from 'styled-components';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
const Text = styled.p`
|
||||
display: contents;
|
||||
color: ${({ theme, color }) => theme.main.colors[color] || color};
|
||||
font-size: ${({ theme, fontSize }) => theme.main.sizes.fonts[fontSize]};
|
||||
font-weight: ${({ theme, fontWeight }) => theme.main.fontWeights[fontWeight]};
|
||||
text-transform: ${({ textTransform }) => textTransform};
|
||||
`;
|
||||
|
||||
Text.defaultProps = {
|
||||
color: 'black',
|
||||
fontSize: 'md',
|
||||
fontWeight: 'regular',
|
||||
textTransform: 'none',
|
||||
};
|
||||
|
||||
Text.propTypes = {
|
||||
color: PropTypes.string,
|
||||
fontSize: PropTypes.string,
|
||||
fontWeight: PropTypes.string,
|
||||
textTransform: PropTypes.string,
|
||||
};
|
||||
|
||||
export default Text;
|
@ -1,18 +1,23 @@
|
||||
import React, { useRef } from 'react';
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import Select from 'react-select';
|
||||
import { useIntl } from 'react-intl';
|
||||
import { MultiSelectNested } from '@strapi/parts/Select';
|
||||
import upperFirst from 'lodash/upperFirst';
|
||||
import MenuList from './MenuList';
|
||||
import getTrad from '../../utils/getTrad';
|
||||
|
||||
const AllowedTypesSelect = ({ name, changeMediaAllowedTypes, styles, value }) => {
|
||||
const options = [
|
||||
{
|
||||
label: 'All',
|
||||
children: [
|
||||
{ label: 'images (JPEG, PNG, GIF, SVG, TIFF, ICO, DVU)', value: 'images' },
|
||||
{ label: 'videos (MPEG, MP4, Quicktime, WMV, AVI, FLV)', value: 'videos' },
|
||||
{ label: 'files (CSV, ZIP, MP3, PDF, Excel, JSON, ...)', value: 'files' },
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
const AllowedTypesSelect = ({ intlLabel, name, onChange, value }) => {
|
||||
const { formatMessage } = useIntl();
|
||||
// Create a ref in order to access the StateManager
|
||||
// So we can close the menu after clicking on a menu item
|
||||
// This allows us to get rid of the menuIsOpen state management
|
||||
// So we let the custom components taking care of it
|
||||
const ref = useRef();
|
||||
|
||||
/* eslint-disable indent */
|
||||
|
||||
@ -26,17 +31,24 @@ const AllowedTypesSelect = ({ name, changeMediaAllowedTypes, styles, value }) =>
|
||||
|
||||
/* eslint-enable indent */
|
||||
|
||||
const label = intlLabel.id
|
||||
? formatMessage({ id: intlLabel.id, defaultMessage: intlLabel.defaultMessage })
|
||||
: name;
|
||||
|
||||
return (
|
||||
<Select
|
||||
components={{ MenuList }}
|
||||
isClearable={false}
|
||||
isSearchable={false}
|
||||
name={name}
|
||||
changeMediaAllowedTypes={changeMediaAllowedTypes}
|
||||
ref={ref}
|
||||
refState={ref}
|
||||
styles={styles}
|
||||
value={{ label: displayedValue, value: value || '' }}
|
||||
<MultiSelectNested
|
||||
id="select1"
|
||||
label={label}
|
||||
customizeContent={() => displayedValue}
|
||||
onChange={values => {
|
||||
if (values.length > 0) {
|
||||
onChange({ target: { name, value: values, type: 'allowed-types-select' } });
|
||||
} else {
|
||||
onChange({ target: { name, value: null, type: 'allowed-types-select' } });
|
||||
}
|
||||
}}
|
||||
options={options}
|
||||
value={value || []}
|
||||
/>
|
||||
);
|
||||
};
|
||||
@ -46,9 +58,13 @@ AllowedTypesSelect.defaultProps = {
|
||||
};
|
||||
|
||||
AllowedTypesSelect.propTypes = {
|
||||
changeMediaAllowedTypes: PropTypes.func.isRequired,
|
||||
intlLabel: PropTypes.shape({
|
||||
id: PropTypes.string.isRequired,
|
||||
defaultMessage: PropTypes.string.isRequired,
|
||||
values: PropTypes.object,
|
||||
}).isRequired,
|
||||
name: PropTypes.string.isRequired,
|
||||
styles: PropTypes.object.isRequired,
|
||||
onChange: PropTypes.func.isRequired,
|
||||
value: PropTypes.oneOfType([PropTypes.object, PropTypes.array]),
|
||||
};
|
||||
|
||||
|
@ -239,7 +239,8 @@ const advancedForm = {
|
||||
defaultMessage: 'Select allowed types of media',
|
||||
},
|
||||
name: 'allowedTypes',
|
||||
type: 'allowedTypesSelect',
|
||||
type: 'allowed-types-select',
|
||||
size: 7,
|
||||
value: '',
|
||||
validations: {},
|
||||
},
|
||||
|
@ -1,7 +1,6 @@
|
||||
export const ADD_COMPONENTS_TO_DYNAMIC_ZONE =
|
||||
'ContentTypeBuilder/FormModal/ADD_COMPONENTS_TO_DYNAMIC_ZONE';
|
||||
export const ON_CHANGE = 'ContentTypeBuilder/FormModal/ON_CHANGE';
|
||||
export const ON_CHANGE_ALLOWED_TYPE = 'ContentTypeBuilder/FormModal/ON_CHANGE_ALLOWED_TYPE';
|
||||
export const ON_CHANGE_RELATION_TARGET = 'ContentTypeBuilder/FormModal/ON_CHANGE_RELATION_TARGET';
|
||||
export const ON_CHANGE_RELATION_TYPE = 'ContentTypeBuilder/FormModal/ON_CHANGE_RELATION_TYPE';
|
||||
export const RESET_PROPS = 'ContentTypeBuilder/FormModal/RESET_PROPS';
|
||||
|
@ -25,6 +25,7 @@ import { Stack } from '@strapi/parts/Stack';
|
||||
import pluginId from '../../pluginId';
|
||||
import useDataManager from '../../hooks/useDataManager';
|
||||
// New compos
|
||||
import AllowedTypesSelect from '../AllowedTypesSelect';
|
||||
import AttributeOptions from '../AttributeOptions';
|
||||
import DraftAndPublishToggle from '../DraftAndPublishToggle';
|
||||
import FormModalHeader from '../FormModalHeader';
|
||||
@ -57,7 +58,6 @@ import {
|
||||
SET_DYNAMIC_ZONE_DATA_SCHEMA,
|
||||
SET_ATTRIBUTE_DATA_SCHEMA,
|
||||
// ADD_COMPONENTS_TO_DYNAMIC_ZONE,
|
||||
// ON_CHANGE_ALLOWED_TYPE,
|
||||
SET_ERRORS,
|
||||
ON_CHANGE,
|
||||
RESET_PROPS_AND_SET_THE_FORM_FOR_ADDING_A_COMPO_TO_A_DZ,
|
||||
@ -564,14 +564,6 @@ const FormModal = () => {
|
||||
// });
|
||||
// };
|
||||
|
||||
// const handleChangeMediaAllowedTypes = ({ target: { name, value } }) => {
|
||||
// dispatch({
|
||||
// type: ON_CHANGE_ALLOWED_TYPE,
|
||||
// name,
|
||||
// value,
|
||||
// });
|
||||
// };
|
||||
|
||||
const handleChange = useCallback(
|
||||
({ target: { name, value, type, ...rest } }) => {
|
||||
const namesThatCanResetToNullValue = [
|
||||
@ -1095,6 +1087,7 @@ const FormModal = () => {
|
||||
|
||||
const genericInputProps = {
|
||||
customInputs: {
|
||||
'allowed-types-select': AllowedTypesSelect,
|
||||
'checkbox-with-number-field': CheckboxWithNumberField,
|
||||
'select-default-boolean': BooleanDefaultValueSelect,
|
||||
'radio-group': CustomRadioGroup,
|
||||
|
@ -183,40 +183,7 @@ const reducer = (state = initialState, action) =>
|
||||
|
||||
break;
|
||||
}
|
||||
case actions.ON_CHANGE_ALLOWED_TYPE: {
|
||||
if (action.name === 'all') {
|
||||
if (action.value) {
|
||||
set(draftState, ['modifiedData', 'allowedTypes'], ['images', 'videos', 'files']);
|
||||
break;
|
||||
}
|
||||
|
||||
set(draftState, ['modifiedData', 'allowedTypes'], null);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
const currentList = state.modifiedData.allowedTypes || [];
|
||||
let updatedList = [...currentList];
|
||||
|
||||
if (currentList.includes(action.name)) {
|
||||
updatedList = updatedList.filter(v => v !== action.name);
|
||||
|
||||
if (updatedList.length === 0) {
|
||||
set(draftState, ['modifiedData', 'allowedTypes'], null);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
set(draftState, ['modifiedData', 'allowedTypes'], updatedList);
|
||||
break;
|
||||
}
|
||||
|
||||
updatedList.push(action.name);
|
||||
|
||||
set(draftState, ['modifiedData', 'allowedTypes'], updatedList);
|
||||
|
||||
break;
|
||||
}
|
||||
case actions.RESET_PROPS:
|
||||
return initialState;
|
||||
case actions.RESET_PROPS_AND_SET_FORM_FOR_ADDING_AN_EXISTING_COMPO: {
|
||||
|
@ -141,124 +141,6 @@ describe('CTB | components | FormModal | reducer | actions', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('ON_CHANGE_ALLOWED_TYPE', () => {
|
||||
it('Should add the missing types', () => {
|
||||
const state = {
|
||||
...initialState,
|
||||
modifiedData: {
|
||||
allowedTypes: ['images', 'videos'],
|
||||
},
|
||||
};
|
||||
const action = {
|
||||
name: 'all',
|
||||
value: true,
|
||||
type: actions.ON_CHANGE_ALLOWED_TYPE,
|
||||
};
|
||||
|
||||
const expected = {
|
||||
...initialState,
|
||||
modifiedData: {
|
||||
allowedTypes: ['images', 'videos', 'files'],
|
||||
},
|
||||
};
|
||||
|
||||
expect(reducer(state, action)).toEqual(expected);
|
||||
});
|
||||
|
||||
it('Should remove the missing types', () => {
|
||||
const state = {
|
||||
...initialState,
|
||||
modifiedData: {
|
||||
allowedTypes: ['images', 'videos', 'files'],
|
||||
},
|
||||
};
|
||||
const action = {
|
||||
name: 'all',
|
||||
value: false,
|
||||
type: actions.ON_CHANGE_ALLOWED_TYPE,
|
||||
};
|
||||
|
||||
const expected = {
|
||||
...initialState,
|
||||
modifiedData: {
|
||||
allowedTypes: null,
|
||||
},
|
||||
};
|
||||
|
||||
expect(reducer(state, action)).toEqual(expected);
|
||||
});
|
||||
|
||||
it('Shoul add the missing type', () => {
|
||||
const state = {
|
||||
...initialState,
|
||||
modifiedData: {
|
||||
allowedTypes: ['videos', 'files'],
|
||||
},
|
||||
};
|
||||
|
||||
const action = {
|
||||
name: 'images',
|
||||
value: null,
|
||||
type: actions.ON_CHANGE_ALLOWED_TYPE,
|
||||
};
|
||||
|
||||
const expected = {
|
||||
...initialState,
|
||||
modifiedData: {
|
||||
allowedTypes: ['videos', 'files', 'images'],
|
||||
},
|
||||
};
|
||||
|
||||
expect(reducer(state, action)).toEqual(expected);
|
||||
});
|
||||
|
||||
it('Should remove the type', () => {
|
||||
const state = {
|
||||
...initialState,
|
||||
modifiedData: {
|
||||
allowedTypes: ['videos', 'images', 'files'],
|
||||
},
|
||||
};
|
||||
|
||||
const action = {
|
||||
name: 'images',
|
||||
value: null,
|
||||
type: actions.ON_CHANGE_ALLOWED_TYPE,
|
||||
};
|
||||
|
||||
const expected = {
|
||||
...initialState,
|
||||
modifiedData: {
|
||||
allowedTypes: ['videos', 'files'],
|
||||
},
|
||||
};
|
||||
|
||||
expect(reducer(state, action)).toEqual(expected);
|
||||
});
|
||||
|
||||
it('Should remove set the allowedTypes to null if removing the last type', () => {
|
||||
const state = {
|
||||
...initialState,
|
||||
modifiedData: {
|
||||
allowedTypes: ['videos'],
|
||||
},
|
||||
};
|
||||
const action = {
|
||||
name: 'videos',
|
||||
value: null,
|
||||
type: actions.ON_CHANGE_ALLOWED_TYPE,
|
||||
};
|
||||
const expected = {
|
||||
...initialState,
|
||||
modifiedData: {
|
||||
allowedTypes: null,
|
||||
},
|
||||
};
|
||||
|
||||
expect(reducer(state, action)).toEqual(expected);
|
||||
});
|
||||
});
|
||||
|
||||
describe('ON_CHANGE_RELATION_TARGET', () => {
|
||||
it('Should handle the target change correctly for a one side relation (oneWay, manyWay)', () => {
|
||||
const state = {
|
||||
|
Loading…
x
Reference in New Issue
Block a user