mirror of
https://github.com/strapi/strapi.git
synced 2025-07-25 18:05:07 +00:00
Fix a11y issues
This commit is contained in:
parent
9a042610ea
commit
3c9e92a2c4
@ -18,7 +18,7 @@ const Wrapper = styled.div`
|
|||||||
left: -10px;
|
left: -10px;
|
||||||
width: 6px;
|
width: 6px;
|
||||||
height: 6px;
|
height: 6px;
|
||||||
border-radius: 20px;
|
border-radius: ${20 / 16}rem;;
|
||||||
background: ${disabled ? theme.colors.neutral100 : theme.colors.primary600};
|
background: ${disabled ? theme.colors.neutral100 : theme.colors.primary600};
|
||||||
}
|
}
|
||||||
`}
|
`}
|
||||||
|
@ -7,7 +7,7 @@ import styled from 'styled-components';
|
|||||||
import ConditionsSelect from '../ConditionsSelect';
|
import ConditionsSelect from '../ConditionsSelect';
|
||||||
|
|
||||||
const RowWrapper = styled(Row)`
|
const RowWrapper = styled(Row)`
|
||||||
height: 52px;
|
height: ${52 / 16}rem;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const ActionRow = ({
|
const ActionRow = ({
|
||||||
@ -23,9 +23,9 @@ const ActionRow = ({
|
|||||||
const { formatMessage } = useIntl();
|
const { formatMessage } = useIntl();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<RowWrapper background={isGrey ? 'neutral100' : 'neutral0'}>
|
<RowWrapper as="li" background={isGrey ? 'neutral100' : 'neutral0'}>
|
||||||
<Row paddingLeft={6} style={{ width: 180 }}>
|
<Row paddingLeft={6} style={{ width: 180 }}>
|
||||||
<TableLabel textColor="neutral500">
|
<TableLabel textColor="neutral600">
|
||||||
{formatMessage({
|
{formatMessage({
|
||||||
id: 'Settings.permissions.conditions.can',
|
id: 'Settings.permissions.conditions.can',
|
||||||
defaultMessage: 'Can',
|
defaultMessage: 'Can',
|
||||||
@ -47,7 +47,7 @@ const ActionRow = ({
|
|||||||
defaultMessage: label,
|
defaultMessage: label,
|
||||||
})}
|
})}
|
||||||
</TableLabel>
|
</TableLabel>
|
||||||
<TableLabel textColor="neutral500">
|
<TableLabel textColor="neutral600">
|
||||||
|
|
||||||
{formatMessage({
|
{formatMessage({
|
||||||
id: 'Settings.permissions.conditions.when',
|
id: 'Settings.permissions.conditions.when',
|
||||||
|
@ -1,39 +1,25 @@
|
|||||||
import { After } from '@strapi/icons';
|
|
||||||
import {
|
import {
|
||||||
Box,
|
Box,
|
||||||
|
Breadcrumbs,
|
||||||
Button,
|
Button,
|
||||||
|
Crumb,
|
||||||
H2,
|
H2,
|
||||||
ModalFooter,
|
ModalFooter,
|
||||||
ModalHeader,
|
ModalHeader,
|
||||||
ModalLayout,
|
ModalLayout,
|
||||||
Stack,
|
Stack,
|
||||||
Text,
|
Text,
|
||||||
TextButton,
|
Divider,
|
||||||
} from '@strapi/parts';
|
} from '@strapi/parts';
|
||||||
import { cloneDeep, get, groupBy, set, upperFirst } from 'lodash';
|
import { cloneDeep, get, groupBy, set, upperFirst } from 'lodash';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import React, { useMemo, useState } from 'react';
|
import React, { useMemo, useState } from 'react';
|
||||||
import { FormattedMessage, useIntl } from 'react-intl';
|
import { useIntl } from 'react-intl';
|
||||||
import styled from 'styled-components';
|
|
||||||
import { usePermissionsDataManager } from '../../../hooks';
|
import { usePermissionsDataManager } from '../../../hooks';
|
||||||
import updateValues from '../Permissions/utils/updateValues';
|
import updateValues from '../Permissions/utils/updateValues';
|
||||||
import ActionRow from './ActionRow';
|
import ActionRow from './ActionRow';
|
||||||
import createDefaultConditionsForm from './utils/createDefaultConditionsForm';
|
import createDefaultConditionsForm from './utils/createDefaultConditionsForm';
|
||||||
|
|
||||||
// ! Something needs to be done in the DS parts to avoid doing this
|
|
||||||
const Icon = styled(Box)`
|
|
||||||
svg {
|
|
||||||
width: 6px;
|
|
||||||
}
|
|
||||||
* {
|
|
||||||
fill: ${({ theme }) => theme.colors.neutral300};
|
|
||||||
}
|
|
||||||
`;
|
|
||||||
|
|
||||||
const Separator = styled.div`
|
|
||||||
border-bottom: 1px solid ${({ theme }) => theme.main.colors.brightGrey};
|
|
||||||
`;
|
|
||||||
|
|
||||||
const ConditionsModal = ({
|
const ConditionsModal = ({
|
||||||
actions,
|
actions,
|
||||||
headerBreadCrumbs,
|
headerBreadCrumbs,
|
||||||
@ -45,11 +31,6 @@ const ConditionsModal = ({
|
|||||||
const { formatMessage } = useIntl();
|
const { formatMessage } = useIntl();
|
||||||
const { availableConditions, modifiedData, onChangeConditions } = usePermissionsDataManager();
|
const { availableConditions, modifiedData, onChangeConditions } = usePermissionsDataManager();
|
||||||
|
|
||||||
const translatedHeaders = headerBreadCrumbs.map(headerTrad => ({
|
|
||||||
key: headerTrad,
|
|
||||||
element: <FormattedMessage id={headerTrad} defaultMessage={upperFirst(headerTrad)} />,
|
|
||||||
}));
|
|
||||||
|
|
||||||
const arrayOfOptionsGroupedByCategory = useMemo(() => {
|
const arrayOfOptionsGroupedByCategory = useMemo(() => {
|
||||||
return Object.entries(groupBy(availableConditions, 'category'));
|
return Object.entries(groupBy(availableConditions, 'category'));
|
||||||
}, [availableConditions]);
|
}, [availableConditions]);
|
||||||
@ -113,22 +94,18 @@ const ConditionsModal = ({
|
|||||||
return (
|
return (
|
||||||
<ModalLayout onClose={onClosed}>
|
<ModalLayout onClose={onClosed}>
|
||||||
<ModalHeader>
|
<ModalHeader>
|
||||||
<Stack horizontal size={3}>
|
<Breadcrumbs label={headerBreadCrumbs.join(', ')}>
|
||||||
{translatedHeaders.map(({ key, element }, index) => {
|
{headerBreadCrumbs.map(label => (
|
||||||
const shouldDisplayChevron = index < translatedHeaders.length - 1;
|
<Crumb key={label}>
|
||||||
|
{upperFirst(
|
||||||
return (
|
formatMessage({
|
||||||
<React.Fragment key={key}>
|
id: label,
|
||||||
<TextButton textColor="neutral800">{element}</TextButton>
|
defaultMessage: label,
|
||||||
{shouldDisplayChevron && (
|
})
|
||||||
<Icon>
|
)}
|
||||||
<After />
|
</Crumb>
|
||||||
</Icon>
|
))}
|
||||||
)}
|
</Breadcrumbs>
|
||||||
</React.Fragment>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
</Stack>
|
|
||||||
</ModalHeader>
|
</ModalHeader>
|
||||||
<Box padding={8}>
|
<Box padding={8}>
|
||||||
<Stack size={6}>
|
<Stack size={6}>
|
||||||
@ -138,7 +115,8 @@ const ConditionsModal = ({
|
|||||||
defaultMessage: 'Define conditions',
|
defaultMessage: 'Define conditions',
|
||||||
})}
|
})}
|
||||||
</H2>
|
</H2>
|
||||||
<Separator />
|
{/* ! Need to force margin here - Remove this when Divider is updated in parts */}
|
||||||
|
<Divider style={{ marginTop: `${24 / 16}rem` }} />
|
||||||
<Box>
|
<Box>
|
||||||
{actionsToDisplay.length === 0 && (
|
{actionsToDisplay.length === 0 && (
|
||||||
<Text>
|
<Text>
|
||||||
@ -149,23 +127,25 @@ const ConditionsModal = ({
|
|||||||
})}
|
})}
|
||||||
</Text>
|
</Text>
|
||||||
)}
|
)}
|
||||||
{actionsToDisplay.map(({ actionId, label, pathToConditionsObject }, index) => {
|
<ul>
|
||||||
const name = pathToConditionsObject.join('..');
|
{actionsToDisplay.map(({ actionId, label, pathToConditionsObject }, index) => {
|
||||||
|
const name = pathToConditionsObject.join('..');
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ActionRow
|
<ActionRow
|
||||||
key={actionId}
|
key={actionId}
|
||||||
arrayOfOptionsGroupedByCategory={arrayOfOptionsGroupedByCategory}
|
arrayOfOptionsGroupedByCategory={arrayOfOptionsGroupedByCategory}
|
||||||
label={label}
|
label={label}
|
||||||
isFormDisabled={isFormDisabled}
|
isFormDisabled={isFormDisabled}
|
||||||
isGrey={index % 2 === 0}
|
isGrey={index % 2 === 0}
|
||||||
name={name}
|
name={name}
|
||||||
onCategoryChange={handleCategoryChange}
|
onCategoryChange={handleCategoryChange}
|
||||||
onChange={handleChange}
|
onChange={handleChange}
|
||||||
value={get(state, name, {})}
|
value={get(state, name, {})}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
|
</ul>
|
||||||
</Box>
|
</Box>
|
||||||
</Stack>
|
</Stack>
|
||||||
</Box>
|
</Box>
|
||||||
|
@ -34,7 +34,7 @@ const activeRowStyle = (theme, isActive, isClicked) => `
|
|||||||
const Wrapper = styled.div`
|
const Wrapper = styled.div`
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
height: 52px;
|
height: ${52 / 16}rem;
|
||||||
background-color: ${({ isGrey, theme }) =>
|
background-color: ${({ isGrey, theme }) =>
|
||||||
isGrey ? theme.colors.neutral100 : theme.colors.neutral0};
|
isGrey ? theme.colors.neutral100 : theme.colors.neutral0};
|
||||||
border: 1px solid transparent;
|
border: 1px solid transparent;
|
||||||
@ -45,6 +45,10 @@ const Wrapper = styled.div`
|
|||||||
&:hover {
|
&:hover {
|
||||||
${({ theme, isActive }) => activeRowStyle(theme, isActive)}
|
${({ theme, isActive }) => activeRowStyle(theme, isActive)}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&:focus-within {
|
||||||
|
${({ theme, isActive }) => activeRowStyle(theme, isActive)}
|
||||||
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const Cell = styled(Row)`
|
const Cell = styled(Row)`
|
||||||
@ -81,7 +85,7 @@ const Collapse = ({
|
|||||||
onClickToggle,
|
onClickToggle,
|
||||||
pathToData,
|
pathToData,
|
||||||
}) => {
|
}) => {
|
||||||
const [modalState, setModalState] = useState({ isOpen: false, isMounted: false });
|
const [isModalOpen, setModalOpen] = useState(false);
|
||||||
const {
|
const {
|
||||||
modifiedData,
|
modifiedData,
|
||||||
onChangeParentCheckbox,
|
onChangeParentCheckbox,
|
||||||
@ -89,11 +93,11 @@ const Collapse = ({
|
|||||||
} = usePermissionsDataManager();
|
} = usePermissionsDataManager();
|
||||||
|
|
||||||
const handleToggleModalIsOpen = () => {
|
const handleToggleModalIsOpen = () => {
|
||||||
setModalState(prevState => ({ isMounted: true, isOpen: !prevState.isOpen }));
|
setModalOpen(s => !s);
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleModalClose = () => {
|
const handleModalClose = () => {
|
||||||
setModalState(prevState => ({ ...prevState, isMounted: false }));
|
setModalOpen(false);
|
||||||
};
|
};
|
||||||
|
|
||||||
// This corresponds to the data related to the CT left checkbox
|
// This corresponds to the data related to the CT left checkbox
|
||||||
@ -133,6 +137,7 @@ const Collapse = ({
|
|||||||
onClick={onClickToggle}
|
onClick={onClickToggle}
|
||||||
someChecked={hasSomeActionsSelected}
|
someChecked={hasSomeActionsSelected}
|
||||||
value={hasAllActionsSelected}
|
value={hasAllActionsSelected}
|
||||||
|
isActive={isActive}
|
||||||
>
|
>
|
||||||
<Chevron paddingLeft={2}>{isActive ? <Up /> : <Down />}</Chevron>
|
<Chevron paddingLeft={2}>{isActive ? <Up /> : <Down />}</Chevron>
|
||||||
</RowLabelWithCheckbox>
|
</RowLabelWithCheckbox>
|
||||||
@ -159,6 +164,7 @@ const Collapse = ({
|
|||||||
<Checkbox
|
<Checkbox
|
||||||
disabled={isFormDisabled || IS_DISABLED}
|
disabled={isFormDisabled || IS_DISABLED}
|
||||||
name={checkboxName}
|
name={checkboxName}
|
||||||
|
aria-label={checkboxName}
|
||||||
// Keep same signature as packages/core/admin/admin/src/components/Roles/Permissions/index.js l.91
|
// Keep same signature as packages/core/admin/admin/src/components/Roles/Permissions/index.js l.91
|
||||||
onValueChange={value =>
|
onValueChange={value =>
|
||||||
onChangeParentCheckbox({
|
onChangeParentCheckbox({
|
||||||
@ -202,16 +208,14 @@ const Collapse = ({
|
|||||||
hasConditions={doesConditionButtonHasConditions}
|
hasConditions={doesConditionButtonHasConditions}
|
||||||
/>
|
/>
|
||||||
</Box>
|
</Box>
|
||||||
{modalState.isMounted && (
|
<ConditionsModal
|
||||||
<ConditionsModal
|
headerBreadCrumbs={[label, 'app.components.LeftMenuLinkContainer.settings']}
|
||||||
headerBreadCrumbs={[label, 'app.components.LeftMenuLinkContainer.settings']}
|
actions={checkboxesActions}
|
||||||
actions={checkboxesActions}
|
isOpen={isModalOpen}
|
||||||
isOpen={modalState.isOpen}
|
isFormDisabled={isFormDisabled}
|
||||||
isFormDisabled={isFormDisabled}
|
onClosed={handleModalClose}
|
||||||
onClosed={handleModalClose}
|
onToggle={handleToggleModalIsOpen}
|
||||||
onToggle={handleToggleModalIsOpen}
|
/>
|
||||||
/>
|
|
||||||
)}
|
|
||||||
</Wrapper>
|
</Wrapper>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -27,7 +27,7 @@ const Cell = styled(Box)`
|
|||||||
const Chevron = styled(Box)`
|
const Chevron = styled(Box)`
|
||||||
display: none;
|
display: none;
|
||||||
svg {
|
svg {
|
||||||
width: 11px;
|
width: ${11 / 16}rem;
|
||||||
}
|
}
|
||||||
* {
|
* {
|
||||||
fill: ${({ theme }) => theme.colors.primary600};
|
fill: ${({ theme }) => theme.colors.primary600};
|
||||||
@ -39,7 +39,7 @@ const Wrapper = styled(Row)`
|
|||||||
flex: 1;
|
flex: 1;
|
||||||
background: ${({ theme, isOdd }) => theme.colors[isOdd ? 'neutral100' : 'neutral0']};
|
background: ${({ theme, isOdd }) => theme.colors[isOdd ? 'neutral100' : 'neutral0']};
|
||||||
${Chevron} {
|
${Chevron} {
|
||||||
width: 13px;
|
width: ${13 / 16}rem;
|
||||||
}
|
}
|
||||||
${({ isCollapsable, theme }) =>
|
${({ isCollapsable, theme }) =>
|
||||||
isCollapsable &&
|
isCollapsable &&
|
||||||
@ -118,6 +118,7 @@ const ActionRow = ({
|
|||||||
label={label}
|
label={label}
|
||||||
someChecked={hasSomeActionsSelected}
|
someChecked={hasSomeActionsSelected}
|
||||||
value={hasAllActionsSelected}
|
value={hasAllActionsSelected}
|
||||||
|
isActive={isActive}
|
||||||
>
|
>
|
||||||
{required && <RequiredSign />}
|
{required && <RequiredSign />}
|
||||||
<Chevron paddingLeft={2}>{isActive ? <Up /> : <Down />}</Chevron>
|
<Chevron paddingLeft={2}>{isActive ? <Up /> : <Down />}</Chevron>
|
||||||
@ -144,6 +145,7 @@ const ActionRow = ({
|
|||||||
<Checkbox
|
<Checkbox
|
||||||
disabled={isFormDisabled || IS_DISABLED}
|
disabled={isFormDisabled || IS_DISABLED}
|
||||||
name={checkboxName.join('..')}
|
name={checkboxName.join('..')}
|
||||||
|
aria-label={checkboxName.join('..')}
|
||||||
// Keep same signature as packages/core/admin/admin/src/components/Roles/Permissions/index.js l.91
|
// Keep same signature as packages/core/admin/admin/src/components/Roles/Permissions/index.js l.91
|
||||||
onValueChange={value =>
|
onValueChange={value =>
|
||||||
onChangeSimpleCheckbox({
|
onChangeSimpleCheckbox({
|
||||||
|
@ -1,29 +1,16 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import { useIntl } from 'react-intl';
|
import { useIntl } from 'react-intl';
|
||||||
import { Row, Box } from '@strapi/parts';
|
import { Row, TableLabel } from '@strapi/parts';
|
||||||
import styled from 'styled-components';
|
import styled from 'styled-components';
|
||||||
import { cellWidth, firstRowWidth } from '../../../Permissions/utils/constants';
|
import { cellWidth, firstRowWidth } from '../../../Permissions/utils/constants';
|
||||||
// Those styles are very specific.
|
|
||||||
// so it is not a big problem to use custom paddings and widths.
|
const HeaderLabel = styled(Row)`
|
||||||
const HeaderLabel = styled.div`
|
|
||||||
justify-content: center;
|
|
||||||
display: flex;
|
|
||||||
width: ${cellWidth};
|
width: ${cellWidth};
|
||||||
`;
|
`;
|
||||||
const PropertyLabelWrapper = styled.div`
|
const PropertyLabelWrapper = styled(Row)`
|
||||||
width: ${firstRowWidth};
|
width: ${firstRowWidth};
|
||||||
display: flex;
|
height: ${52 / 16}rem;
|
||||||
align-items: center;
|
|
||||||
padding-left: ${({ theme }) => theme.spaces[6]};
|
|
||||||
height: 52px;
|
|
||||||
`;
|
|
||||||
|
|
||||||
const Label = styled(Box)`
|
|
||||||
font-size: ${11 / 16}rem;
|
|
||||||
text-transform: uppercase;
|
|
||||||
color: ${({ theme }) => theme.colors.neutral500};
|
|
||||||
font-weight: bold;
|
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const Header = ({ headers, label }) => {
|
const Header = ({ headers, label }) => {
|
||||||
@ -38,8 +25,8 @@ const Header = ({ headers, label }) => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<Row>
|
<Row>
|
||||||
<PropertyLabelWrapper>
|
<PropertyLabelWrapper alignItems="center" paddingLeft={6}>
|
||||||
<Label>{translatedLabel}</Label>
|
<TableLabel textColor="neutral500">{translatedLabel}</TableLabel>
|
||||||
</PropertyLabelWrapper>
|
</PropertyLabelWrapper>
|
||||||
{headers.map(header => {
|
{headers.map(header => {
|
||||||
if (!header.isActionRelatedToCurrentProperty) {
|
if (!header.isActionRelatedToCurrentProperty) {
|
||||||
@ -47,13 +34,13 @@ const Header = ({ headers, label }) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<HeaderLabel key={header.label}>
|
<HeaderLabel justifyContent="center" key={header.label}>
|
||||||
<Label>
|
<TableLabel textColor="neutral500">
|
||||||
{formatMessage({
|
{formatMessage({
|
||||||
id: `Settings.roles.form.permissions.${header.label.toLowerCase()}`,
|
id: `Settings.roles.form.permissions.${header.label.toLowerCase()}`,
|
||||||
defaultMessage: header.label,
|
defaultMessage: header.label,
|
||||||
})}
|
})}
|
||||||
</Label>
|
</TableLabel>
|
||||||
</HeaderLabel>
|
</HeaderLabel>
|
||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
|
@ -16,7 +16,6 @@ const Wrapper = styled.div`
|
|||||||
|
|
||||||
return `none`;
|
return `none`;
|
||||||
}};
|
}};
|
||||||
border-radius: 0px 0px 2px 2px;
|
|
||||||
`;
|
`;
|
||||||
|
|
||||||
Wrapper.defaultProps = {
|
Wrapper.defaultProps = {
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { Checkbox, Stack, TableLabel } from '@strapi/parts';
|
import { Checkbox, Stack, TableLabel, Box } from '@strapi/parts';
|
||||||
import IS_DISABLED from 'ee_else_ce/components/Roles/GlobalActions/utils/constants';
|
import IS_DISABLED from 'ee_else_ce/components/Roles/GlobalActions/utils/constants';
|
||||||
import { get } from 'lodash';
|
import { get } from 'lodash';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
@ -15,21 +15,6 @@ const CenteredStack = styled(Stack)`
|
|||||||
width: ${cellWidth};
|
width: ${cellWidth};
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const Wrapper = styled.div`
|
|
||||||
padding-left: ${firstRowWidth};
|
|
||||||
padding-bottom: ${({ theme }) => theme.spaces[4]};
|
|
||||||
padding-top: ${({ theme }) => theme.spaces[6]};
|
|
||||||
${({ disabled, theme }) =>
|
|
||||||
`
|
|
||||||
input[type='checkbox'] {
|
|
||||||
&:after {
|
|
||||||
color: ${!disabled ? theme.main.colors.mediumBlue : theme.main.colors.grey};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
cursor: initial;
|
|
||||||
`}
|
|
||||||
`;
|
|
||||||
|
|
||||||
const GlobalActions = ({ actions, isFormDisabled, kind }) => {
|
const GlobalActions = ({ actions, isFormDisabled, kind }) => {
|
||||||
const { formatMessage } = useIntl();
|
const { formatMessage } = useIntl();
|
||||||
const { modifiedData, onChangeCollectionTypeGlobalActionCheckbox } = usePermissionsDataManager();
|
const { modifiedData, onChangeCollectionTypeGlobalActionCheckbox } = usePermissionsDataManager();
|
||||||
@ -43,7 +28,7 @@ const GlobalActions = ({ actions, isFormDisabled, kind }) => {
|
|||||||
}, [modifiedData, displayedActions, kind]);
|
}, [modifiedData, displayedActions, kind]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Wrapper disabled={isFormDisabled}>
|
<Box paddingBottom={4} paddingTop={6} style={{ paddingLeft: firstRowWidth }}>
|
||||||
<Stack horizontal>
|
<Stack horizontal>
|
||||||
{displayedActions.map(({ label, actionId }) => {
|
{displayedActions.map(({ label, actionId }) => {
|
||||||
return (
|
return (
|
||||||
@ -60,6 +45,7 @@ const GlobalActions = ({ actions, isFormDisabled, kind }) => {
|
|||||||
onChangeCollectionTypeGlobalActionCheckbox(kind, actionId, value);
|
onChangeCollectionTypeGlobalActionCheckbox(kind, actionId, value);
|
||||||
}}
|
}}
|
||||||
name={actionId}
|
name={actionId}
|
||||||
|
aria-label={actionId}
|
||||||
value={get(checkboxesState, [actionId, 'hasAllActionsSelected'], false)}
|
value={get(checkboxesState, [actionId, 'hasAllActionsSelected'], false)}
|
||||||
indeterminate={get(checkboxesState, [actionId, 'hasSomeActionsSelected'], false)}
|
indeterminate={get(checkboxesState, [actionId, 'hasSomeActionsSelected'], false)}
|
||||||
/>
|
/>
|
||||||
@ -67,7 +53,7 @@ const GlobalActions = ({ actions, isFormDisabled, kind }) => {
|
|||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
</Stack>
|
</Stack>
|
||||||
</Wrapper>
|
</Box>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1,2 +1,2 @@
|
|||||||
export const cellWidth = '120px';
|
export const cellWidth = `${120 / 16}rem`;
|
||||||
export const firstRowWidth = '200px';
|
export const firstRowWidth = `${200 / 16}rem`;
|
||||||
|
@ -26,18 +26,18 @@ const CheckboxWrapper = styled.div`
|
|||||||
&:before {
|
&:before {
|
||||||
content: '';
|
content: '';
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: -4px;
|
top: ${-4 / 16}rem;
|
||||||
left: -8px;
|
left: ${-8 / 16}rem;
|
||||||
width: 6px;
|
width: ${6 / 16}rem;
|
||||||
height: 6px;
|
height: ${6 / 16}rem;
|
||||||
border-radius: 20px;
|
border-radius: ${20 / 16}rem;
|
||||||
background: ${disabled ? theme.colors.neutral100 : theme.colors.primary600};
|
background: ${disabled ? theme.colors.neutral100 : theme.colors.primary600};
|
||||||
}
|
}
|
||||||
`}
|
`}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const SubCategory = ({ categoryName, isFormDisabled, subCategoryName, actions, pathToData }) => {
|
const SubCategory = ({ categoryName, isFormDisabled, subCategoryName, actions, pathToData }) => {
|
||||||
const [modalState, setModalState] = useState({ isOpen: false, isMounted: false });
|
const [isModalOpen, setModalOpen] = useState(false);
|
||||||
const {
|
const {
|
||||||
modifiedData,
|
modifiedData,
|
||||||
onChangeParentCheckbox,
|
onChangeParentCheckbox,
|
||||||
@ -57,13 +57,12 @@ const SubCategory = ({ categoryName, isFormDisabled, subCategoryName, actions, p
|
|||||||
const { hasAllActionsSelected, hasSomeActionsSelected } = getCheckboxState(dataWithoutCondition);
|
const { hasAllActionsSelected, hasSomeActionsSelected } = getCheckboxState(dataWithoutCondition);
|
||||||
|
|
||||||
const handleToggleModalIsOpen = () => {
|
const handleToggleModalIsOpen = () => {
|
||||||
setModalState(prevState => ({ isMounted: true, isOpen: !prevState.isOpen }));
|
setModalOpen(s => !s);
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleModalClose = () => {
|
const handleModalClose = () => {
|
||||||
setModalState(prevState => ({ ...prevState, isMounted: false }));
|
setModalOpen(false);
|
||||||
};
|
};
|
||||||
|
|
||||||
// We need to format the actions so it matches the shape of the ConditionsModal actions props
|
// We need to format the actions so it matches the shape of the ConditionsModal actions props
|
||||||
const formattedActions = formatActions(actions, modifiedData, pathToData);
|
const formattedActions = formatActions(actions, modifiedData, pathToData);
|
||||||
const doesButtonHasCondition = getConditionsButtonState(get(modifiedData, [...pathToData], {}));
|
const doesButtonHasCondition = getConditionsButtonState(get(modifiedData, [...pathToData], {}));
|
||||||
@ -79,6 +78,7 @@ const SubCategory = ({ categoryName, isFormDisabled, subCategoryName, actions, p
|
|||||||
<Box paddingLeft={4}>
|
<Box paddingLeft={4}>
|
||||||
<Checkbox
|
<Checkbox
|
||||||
name={pathToData.join('..')}
|
name={pathToData.join('..')}
|
||||||
|
aria-label={pathToData.join('..')}
|
||||||
disabled={isFormDisabled || IS_DISABLED}
|
disabled={isFormDisabled || IS_DISABLED}
|
||||||
// Keep same signature as packages/core/admin/admin/src/components/Roles/Permissions/index.js l.91
|
// Keep same signature as packages/core/admin/admin/src/components/Roles/Permissions/index.js l.91
|
||||||
onValueChange={value =>
|
onValueChange={value =>
|
||||||
@ -131,16 +131,14 @@ const SubCategory = ({ categoryName, isFormDisabled, subCategoryName, actions, p
|
|||||||
/>
|
/>
|
||||||
</Row>
|
</Row>
|
||||||
</Box>
|
</Box>
|
||||||
{modalState.isMounted && (
|
<ConditionsModal
|
||||||
<ConditionsModal
|
headerBreadCrumbs={[categoryName, subCategoryName]}
|
||||||
headerBreadCrumbs={[categoryName, subCategoryName]}
|
actions={formattedActions}
|
||||||
actions={formattedActions}
|
isOpen={isModalOpen}
|
||||||
isOpen={modalState.isOpen}
|
isFormDisabled={isFormDisabled}
|
||||||
isFormDisabled={isFormDisabled}
|
onClosed={handleModalClose}
|
||||||
onClosed={handleModalClose}
|
onToggle={handleToggleModalIsOpen}
|
||||||
onToggle={handleToggleModalIsOpen}
|
/>
|
||||||
/>
|
|
||||||
)}
|
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { Box, Checkbox, Text } from '@strapi/parts';
|
import { Row, Checkbox, Text } from '@strapi/parts';
|
||||||
import upperFirst from 'lodash/upperFirst';
|
import upperFirst from 'lodash/upperFirst';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import React, { memo } from 'react';
|
import React, { memo } from 'react';
|
||||||
@ -6,24 +6,6 @@ import styled from 'styled-components';
|
|||||||
import CollapseLabel from '../CollapseLabel';
|
import CollapseLabel from '../CollapseLabel';
|
||||||
import { firstRowWidth } from '../Permissions/utils/constants';
|
import { firstRowWidth } from '../Permissions/utils/constants';
|
||||||
|
|
||||||
const Wrapper = styled(Box)`
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
width: ${firstRowWidth};
|
|
||||||
padding-left: ${({ theme }) => theme.spaces[6]};
|
|
||||||
|
|
||||||
${({ disabled, theme }) =>
|
|
||||||
disabled &&
|
|
||||||
`
|
|
||||||
input[type='checkbox'] {
|
|
||||||
cursor: not-allowed;
|
|
||||||
&:after {
|
|
||||||
color: ${theme.main.colors.grey};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
`};
|
|
||||||
`;
|
|
||||||
|
|
||||||
// ! REMOVE THIS WHEN DS IS UPDATED WITH ELLIPSIS PROP
|
// ! REMOVE THIS WHEN DS IS UPDATED WITH ELLIPSIS PROP
|
||||||
const StyledText = styled(Text)`
|
const StyledText = styled(Text)`
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
@ -34,6 +16,7 @@ const StyledText = styled(Text)`
|
|||||||
const RowLabelWithCheckbox = ({
|
const RowLabelWithCheckbox = ({
|
||||||
children,
|
children,
|
||||||
isCollapsable,
|
isCollapsable,
|
||||||
|
isActive,
|
||||||
isFormDisabled,
|
isFormDisabled,
|
||||||
label,
|
label,
|
||||||
onChange,
|
onChange,
|
||||||
@ -43,9 +26,10 @@ const RowLabelWithCheckbox = ({
|
|||||||
value,
|
value,
|
||||||
}) => {
|
}) => {
|
||||||
return (
|
return (
|
||||||
<Wrapper disabled={isFormDisabled}>
|
<Row alignItems="center" paddingLeft={6} style={{ width: firstRowWidth }}>
|
||||||
<Checkbox
|
<Checkbox
|
||||||
name={checkboxName}
|
name={checkboxName}
|
||||||
|
aria-label={checkboxName}
|
||||||
disabled={isFormDisabled}
|
disabled={isFormDisabled}
|
||||||
// Keep same signature as packages/core/admin/admin/src/components/Roles/Permissions/index.js l.91
|
// Keep same signature as packages/core/admin/admin/src/components/Roles/Permissions/index.js l.91
|
||||||
onValueChange={value =>
|
onValueChange={value =>
|
||||||
@ -64,6 +48,7 @@ const RowLabelWithCheckbox = ({
|
|||||||
isCollapsable={isCollapsable}
|
isCollapsable={isCollapsable}
|
||||||
{...(isCollapsable && {
|
{...(isCollapsable && {
|
||||||
onClick,
|
onClick,
|
||||||
|
'aria-expanded': isActive,
|
||||||
onKeyDown: ({ key }) => (key === 'Enter' || key === ' ') && onClick(),
|
onKeyDown: ({ key }) => (key === 'Enter' || key === ' ') && onClick(),
|
||||||
tabIndex: 0,
|
tabIndex: 0,
|
||||||
role: 'button',
|
role: 'button',
|
||||||
@ -72,7 +57,7 @@ const RowLabelWithCheckbox = ({
|
|||||||
<StyledText>{upperFirst(label)}</StyledText>
|
<StyledText>{upperFirst(label)}</StyledText>
|
||||||
{children}
|
{children}
|
||||||
</CollapseLabel>
|
</CollapseLabel>
|
||||||
</Wrapper>
|
</Row>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -95,6 +80,7 @@ RowLabelWithCheckbox.propTypes = {
|
|||||||
onClick: PropTypes.func.isRequired,
|
onClick: PropTypes.func.isRequired,
|
||||||
someChecked: PropTypes.bool,
|
someChecked: PropTypes.bool,
|
||||||
value: PropTypes.bool,
|
value: PropTypes.bool,
|
||||||
|
isActive: PropTypes.bool.isRequired,
|
||||||
};
|
};
|
||||||
|
|
||||||
export default memo(RowLabelWithCheckbox);
|
export default memo(RowLabelWithCheckbox);
|
||||||
|
@ -132,6 +132,7 @@ const Login = ({ onSubmit, schema, children }) => {
|
|||||||
handleChange({ target: { value: checked, name: 'rememberMe' } });
|
handleChange({ target: { value: checked, name: 'rememberMe' } });
|
||||||
}}
|
}}
|
||||||
value={values.rememberMe}
|
value={values.rememberMe}
|
||||||
|
aria-label="rememberMe"
|
||||||
name="rememberMe"
|
name="rememberMe"
|
||||||
>
|
>
|
||||||
{formatMessage({
|
{formatMessage({
|
||||||
|
@ -280,6 +280,7 @@ const Register = ({ fieldsToDisable, noSignin, onSubmit, schema }) => {
|
|||||||
}}
|
}}
|
||||||
value={values.news}
|
value={values.news}
|
||||||
name="news"
|
name="news"
|
||||||
|
aria-label="news"
|
||||||
>
|
>
|
||||||
{formatMessage(
|
{formatMessage(
|
||||||
{
|
{
|
||||||
|
@ -4,6 +4,7 @@ import {
|
|||||||
useNotification,
|
useNotification,
|
||||||
useOverlayBlocker,
|
useOverlayBlocker,
|
||||||
useTracking,
|
useTracking,
|
||||||
|
Form,
|
||||||
} from '@strapi/helper-plugin';
|
} from '@strapi/helper-plugin';
|
||||||
import {
|
import {
|
||||||
Box,
|
Box,
|
||||||
@ -124,8 +125,8 @@ const CreatePage = () => {
|
|||||||
validationSchema={schema}
|
validationSchema={schema}
|
||||||
validateOnChange={false}
|
validateOnChange={false}
|
||||||
>
|
>
|
||||||
{({ handleSubmit, values, errors, handleReset, handleChange, handleBlur }) => (
|
{({ handleSubmit, values, errors, handleReset, handleChange }) => (
|
||||||
<form onSubmit={handleSubmit}>
|
<Form noValidate>
|
||||||
<>
|
<>
|
||||||
<HeaderLayout
|
<HeaderLayout
|
||||||
id="title"
|
id="title"
|
||||||
@ -162,87 +163,86 @@ const CreatePage = () => {
|
|||||||
as="h1"
|
as="h1"
|
||||||
/>
|
/>
|
||||||
<ContentLayout>
|
<ContentLayout>
|
||||||
<Box background="neutral0" padding={6} shadow="filterShadow" hasRadius>
|
<Stack size={6}>
|
||||||
<Stack size={4}>
|
<Box background="neutral0" padding={6} shadow="filterShadow" hasRadius>
|
||||||
<Row justifyContent="space-between">
|
<Stack size={4}>
|
||||||
<Box>
|
<Row justifyContent="space-between">
|
||||||
<Box>
|
<Box>
|
||||||
<Text highlighted>
|
<Box>
|
||||||
{formatMessage({
|
<Text highlighted>
|
||||||
id: 'Settings.roles.form.title',
|
{formatMessage({
|
||||||
defaultMessage: 'Details',
|
id: 'Settings.roles.form.title',
|
||||||
})}
|
defaultMessage: 'Details',
|
||||||
</Text>
|
})}
|
||||||
|
</Text>
|
||||||
|
</Box>
|
||||||
|
<Box>
|
||||||
|
<Text textColor="neutral600" small>
|
||||||
|
{formatMessage({
|
||||||
|
id: 'Settings.roles.form.description',
|
||||||
|
defaultMessage: 'Name and description of the role',
|
||||||
|
})}
|
||||||
|
</Text>
|
||||||
|
</Box>
|
||||||
</Box>
|
</Box>
|
||||||
<Box>
|
<UsersRoleNumber>
|
||||||
<Text textColor="neutral500" small>
|
{formatMessage(
|
||||||
{formatMessage({
|
{
|
||||||
id: 'Settings.roles.form.description',
|
id: 'Settings.roles.form.button.users-with-role',
|
||||||
defaultMessage: 'Name and description of the role',
|
defaultMessage:
|
||||||
|
'{number, plural, =0 {# users} one {# user} other {# users}} with this role',
|
||||||
|
},
|
||||||
|
{ number: 0 }
|
||||||
|
)}
|
||||||
|
</UsersRoleNumber>
|
||||||
|
</Row>
|
||||||
|
<Grid gap={4}>
|
||||||
|
<GridItem col={6}>
|
||||||
|
<TextInput
|
||||||
|
name="name"
|
||||||
|
error={errors.name && formatMessage({ id: errors.name })}
|
||||||
|
label={formatMessage({
|
||||||
|
id: 'Settings.roles.form.input.name',
|
||||||
|
defaultMessage: 'Name',
|
||||||
})}
|
})}
|
||||||
</Text>
|
onChange={handleChange}
|
||||||
</Box>
|
value={values.name}
|
||||||
</Box>
|
/>
|
||||||
<UsersRoleNumber>
|
</GridItem>
|
||||||
{formatMessage(
|
<GridItem col={6}>
|
||||||
{
|
<Textarea
|
||||||
id: 'Settings.roles.form.button.users-with-role',
|
label={formatMessage({
|
||||||
defaultMessage:
|
id: 'Settings.roles.form.input.description',
|
||||||
'{number, plural, =0 {# users} one {# user} other {# users}} with this role',
|
defaultMessage: 'Description',
|
||||||
},
|
})}
|
||||||
{ number: 0 }
|
name="description"
|
||||||
)}
|
error={errors.name && formatMessage({ id: errors.name })}
|
||||||
</UsersRoleNumber>
|
onChange={handleChange}
|
||||||
</Row>
|
>
|
||||||
<Grid gap={4}>
|
{values.description}
|
||||||
<GridItem col={6}>
|
</Textarea>
|
||||||
<TextInput
|
</GridItem>
|
||||||
name="name"
|
</Grid>
|
||||||
error={errors.name && formatMessage({ id: errors.name })}
|
</Stack>
|
||||||
label={formatMessage({
|
|
||||||
id: 'Settings.roles.form.input.name',
|
|
||||||
defaultMessage: 'Name',
|
|
||||||
})}
|
|
||||||
onChange={handleChange}
|
|
||||||
onBlur={handleBlur}
|
|
||||||
value={values.name}
|
|
||||||
/>
|
|
||||||
</GridItem>
|
|
||||||
<GridItem col={6}>
|
|
||||||
<Textarea
|
|
||||||
label={formatMessage({
|
|
||||||
id: 'Settings.roles.form.input.description',
|
|
||||||
defaultMessage: 'Description',
|
|
||||||
})}
|
|
||||||
name="description"
|
|
||||||
error={errors.name && formatMessage({ id: errors.name })}
|
|
||||||
onChange={handleChange}
|
|
||||||
onBlur={handleBlur}
|
|
||||||
>
|
|
||||||
{values.description}
|
|
||||||
</Textarea>
|
|
||||||
</GridItem>
|
|
||||||
</Grid>
|
|
||||||
</Stack>
|
|
||||||
</Box>
|
|
||||||
{!isLayoutLoading && !isRoleLoading ? (
|
|
||||||
<Box paddingTop={6} paddingBottom={6}>
|
|
||||||
<Permissions
|
|
||||||
isFormDisabled={false}
|
|
||||||
ref={permissionsRef}
|
|
||||||
permissions={rolePermissions}
|
|
||||||
layout={permissionsLayout}
|
|
||||||
/>
|
|
||||||
</Box>
|
</Box>
|
||||||
) : (
|
{!isLayoutLoading && !isRoleLoading ? (
|
||||||
// ! TODO : Switch to the DS component when done
|
<Box shadow="filterShadow" hasRadius>
|
||||||
<Row alignItems="center" justifyContent="center" padding={11}>
|
<Permissions
|
||||||
<Loader />
|
isFormDisabled={false}
|
||||||
</Row>
|
ref={permissionsRef}
|
||||||
)}
|
permissions={rolePermissions}
|
||||||
|
layout={permissionsLayout}
|
||||||
|
/>
|
||||||
|
</Box>
|
||||||
|
) : (
|
||||||
|
<Row alignItems="center" justifyContent="center" padding={11}>
|
||||||
|
<Loader />
|
||||||
|
</Row>
|
||||||
|
)}
|
||||||
|
</Stack>
|
||||||
</ContentLayout>
|
</ContentLayout>
|
||||||
</>
|
</>
|
||||||
</form>
|
</Form>
|
||||||
)}
|
)}
|
||||||
</Formik>
|
</Formik>
|
||||||
</Main>
|
</Main>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user