Merge branch 'migrations/admin-users-filters' of github.com:strapi/strapi into migrations/admin-users-delete

This commit is contained in:
soupette 2021-09-02 13:20:57 +02:00
commit 99ba54cb43
12 changed files with 123 additions and 91 deletions

View File

@ -59,6 +59,7 @@ module.exports = {
'<rootDir>/test/config/front/test-bundler.js', '<rootDir>/test/config/front/test-bundler.js',
'<rootDir>/packages/admin-test-utils/lib/mocks/LocalStorageMock.js', '<rootDir>/packages/admin-test-utils/lib/mocks/LocalStorageMock.js',
'<rootDir>/packages/admin-test-utils/lib/mocks/IntersectionObserver.js', '<rootDir>/packages/admin-test-utils/lib/mocks/IntersectionObserver.js',
'<rootDir>/packages/admin-test-utils/lib/mocks/ResizeObserver.js',
], ],
testPathIgnorePatterns: [ testPathIgnorePatterns: [
'/node_modules/', '/node_modules/',

View File

@ -0,0 +1,11 @@
'use strict';
class ResizeObserverMock {
constructor() {
this.disconnect = () => null;
this.observe = () => null;
this.unobserve = () => null;
}
}
global.ResizeObserver = ResizeObserverMock;

View File

@ -1,10 +1,10 @@
import React from 'react'; import { Box, Row, TableLabel } from '@strapi/parts';
import { MultiSelectNested } from '@strapi/parts/Select';
import { upperFirst } from 'lodash';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import { Row, TableLabel } from '@strapi/parts'; import React from 'react';
import { useIntl } from 'react-intl'; import { useIntl } from 'react-intl';
import styled from 'styled-components'; import styled from 'styled-components';
// import ConditionsSelect from '../ConditionsSelect';
import { rowHeight } from '../../Permissions/utils/constants'; import { rowHeight } from '../../Permissions/utils/constants';
const RowWrapper = styled(Row)` const RowWrapper = styled(Row)`
@ -12,16 +12,46 @@ const RowWrapper = styled(Row)`
`; `;
const ActionRow = ({ const ActionRow = ({
// arrayOfOptionsGroupedByCategory, arrayOfOptionsGroupedByCategory,
// isFormDisabled, isFormDisabled,
isGrey, isGrey,
label, label,
// name, name,
// onCategoryChange, onChange,
// onChange, value,
// value,
}) => { }) => {
const { formatMessage } = useIntl(); 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);
};
return ( return (
<RowWrapper as="li" background={isGrey ? 'neutral100' : 'neutral0'}> <RowWrapper as="li" background={isGrey ? 'neutral100' : 'neutral0'}>
@ -56,26 +86,27 @@ const ActionRow = ({
})} })}
</TableLabel> </TableLabel>
</Row> </Row>
{/* <ConditionsSelect <Box style={{ maxWidth: 430, width: '100%' }}>
arrayOfOptionsGroupedByCategory={arrayOfOptionsGroupedByCategory} <MultiSelectNested
name={name} id={name}
isFormDisabled={isFormDisabled} customizeContent={values => `${values.length} currently selected`}
onCategoryChange={onCategoryChange} onChange={handleChange}
onChange={onChange} value={values}
value={value} options={options}
/> */} disabled={isFormDisabled}
/>
</Box>
</RowWrapper> </RowWrapper>
); );
}; };
ActionRow.propTypes = { ActionRow.propTypes = {
// arrayOfOptionsGroupedByCategory: PropTypes.array.isRequired, arrayOfOptionsGroupedByCategory: PropTypes.array.isRequired,
// isFormDisabled: PropTypes.bool.isRequired, isFormDisabled: PropTypes.bool.isRequired,
isGrey: PropTypes.bool.isRequired, isGrey: PropTypes.bool.isRequired,
label: PropTypes.string.isRequired, label: PropTypes.string.isRequired,
// name: PropTypes.string.isRequired, name: PropTypes.string.isRequired,
// value: PropTypes.object.isRequired, value: PropTypes.object.isRequired,
// onCategoryChange: PropTypes.func.isRequired, onChange: PropTypes.func.isRequired,
// onChange: PropTypes.func.isRequired,
}; };
export default ActionRow; export default ActionRow;

View File

@ -3,31 +3,24 @@ import {
Breadcrumbs, Breadcrumbs,
Button, Button,
Crumb, Crumb,
Divider,
H2, H2,
ModalFooter, ModalFooter,
ModalHeader, ModalHeader,
ModalLayout, ModalLayout,
Stack, Stack,
Text, Text,
Divider,
} from '@strapi/parts'; } from '@strapi/parts';
import { cloneDeep, get, groupBy, set, upperFirst } from 'lodash'; import produce from 'immer';
import { get, groupBy, 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 { useIntl } from 'react-intl'; import { useIntl } from 'react-intl';
import { usePermissionsDataManager } from '../../../hooks'; import { usePermissionsDataManager } from '../../../hooks';
import updateValues from '../Permissions/utils/updateValues';
import ActionRow from './ActionRow'; import ActionRow from './ActionRow';
import createDefaultConditionsForm from './utils/createDefaultConditionsForm'; import createDefaultConditionsForm from './utils/createDefaultConditionsForm';
const ConditionsModal = ({ const ConditionsModal = ({ actions, headerBreadCrumbs, isFormDisabled, onClosed, onToggle }) => {
actions,
headerBreadCrumbs,
isOpen,
isFormDisabled,
onClosed,
onToggle,
}) => {
const { formatMessage } = useIntl(); const { formatMessage } = useIntl();
const { availableConditions, modifiedData, onChangeConditions } = usePermissionsDataManager(); const { availableConditions, modifiedData, onChangeConditions } = usePermissionsDataManager();
@ -50,26 +43,20 @@ const ConditionsModal = ({
const [state, setState] = useState(initState); const [state, setState] = useState(initState);
const handleCategoryChange = ({ keys, value }) => { const handleChange = (name, values) => {
setState(prevState => { setState(
const updatedState = cloneDeep(prevState); produce(draft => {
const objToUpdate = get(prevState, keys, {}); if (!draft[name]) {
const updatedValues = updateValues(objToUpdate, value); draft[name] = {};
}
set(updatedState, keys, updatedValues); if (!draft[name].default) {
draft[name].default = {};
}
return updatedState; draft[name].default = values;
}); })
}; );
const handleChange = ({ keys, value }) => {
setState(prevState => {
const updatedState = cloneDeep(prevState);
set(updatedState, keys, value);
return updatedState;
});
}; };
const handleSubmit = () => { const handleSubmit = () => {
@ -89,8 +76,6 @@ const ConditionsModal = ({
onToggle(); onToggle();
}; };
if (!isOpen) return null;
return ( return (
<ModalLayout onClose={onClosed}> <ModalLayout onClose={onClosed}>
<ModalHeader> <ModalHeader>
@ -140,7 +125,6 @@ const ConditionsModal = ({
isFormDisabled={isFormDisabled} isFormDisabled={isFormDisabled}
isGrey={index % 2 === 0} isGrey={index % 2 === 0}
name={name} name={name}
onCategoryChange={handleCategoryChange}
onChange={handleChange} onChange={handleChange}
value={get(state, name, {})} value={get(state, name, {})}
/> />
@ -181,7 +165,6 @@ ConditionsModal.propTypes = {
}) })
).isRequired, ).isRequired,
headerBreadCrumbs: PropTypes.arrayOf(PropTypes.string).isRequired, headerBreadCrumbs: PropTypes.arrayOf(PropTypes.string).isRequired,
isOpen: PropTypes.bool.isRequired,
isFormDisabled: PropTypes.bool.isRequired, isFormDisabled: PropTypes.bool.isRequired,
onClosed: PropTypes.func.isRequired, onClosed: PropTypes.func.isRequired,
onToggle: PropTypes.func.isRequired, onToggle: PropTypes.func.isRequired,

View File

@ -228,14 +228,15 @@ const Collapse = ({
)} )}
</Row> </Row>
<Box style={{ width: 120 }} /> <Box style={{ width: 120 }} />
{isModalOpen && (
<ConditionsModal <ConditionsModal
headerBreadCrumbs={[label, 'app.components.LeftMenuLinkContainer.settings']} headerBreadCrumbs={[label, 'app.components.LeftMenuLinkContainer.settings']}
actions={checkboxesActions} actions={checkboxesActions}
isOpen={isModalOpen}
isFormDisabled={isFormDisabled} isFormDisabled={isFormDisabled}
onClosed={handleModalClose} onClosed={handleModalClose}
onToggle={handleToggleModalIsOpen} onToggle={handleToggleModalIsOpen}
/> />
)}
</Wrapper> </Wrapper>
<AbsoluteBox> <AbsoluteBox>
<ConditionsButton <ConditionsButton

View File

@ -130,14 +130,15 @@ const SubCategory = ({ categoryName, isFormDisabled, subCategoryName, actions, p
/> />
</Row> </Row>
</Box> </Box>
{isModalOpen && (
<ConditionsModal <ConditionsModal
headerBreadCrumbs={[categoryName, subCategoryName]} headerBreadCrumbs={[categoryName, subCategoryName]}
actions={formattedActions} actions={formattedActions}
isOpen={isModalOpen}
isFormDisabled={isFormDisabled} isFormDisabled={isFormDisabled}
onClosed={handleModalClose} onClosed={handleModalClose}
onToggle={handleToggleModalIsOpen} onToggle={handleToggleModalIsOpen}
/> />
)}
</> </>
); );
}; };

View File

@ -1,16 +1,16 @@
import { useEffect, useReducer } from 'react'; import { useEffect, useReducer } from 'react';
import { hasPermissions, useRBACProvider, useStrapiApp } from '@strapi/helper-plugin'; import { hasPermissions, useRBACProvider, useStrapiApp, useAppInfos } from '@strapi/helper-plugin';
import reducer, { initialState } from './reducer'; import reducer, { initialState } from './reducer';
import init from './init'; import init from './init';
const useSettingsMenu = (noCheck = false) => { const useSettingsMenu = (noCheck = false) => {
const { allPermissions: permissions } = useRBACProvider(); const { allPermissions: permissions } = useRBACProvider();
const { shouldUpdateStrapi } = useAppInfos();
const { settings } = useStrapiApp(); const { settings } = useStrapiApp();
const [{ isLoading, menu }, dispatch] = useReducer(reducer, initialState, () => const [{ isLoading, menu }, dispatch] = useReducer(reducer, initialState, () =>
init(initialState, settings) init(initialState, { settings, shouldUpdateStrapi })
); );
useEffect(() => { useEffect(() => {

View File

@ -4,11 +4,15 @@ import adminPermissions from '../../permissions';
import formatLinks from './utils/formatLinks'; import formatLinks from './utils/formatLinks';
import globalLinks from './utils/globalLinks'; import globalLinks from './utils/globalLinks';
const init = (initialState, settings) => { const init = (initialState, { settings, shouldUpdateStrapi }) => {
// Retrieve the links that will be injected into the global section // Retrieve the links that will be injected into the global section
const pluginsGlobalLinks = settings.global.links; const pluginsGlobalLinks = settings.global.links;
// Sort the links by name // Sort the links by name
const sortedGlobalLinks = sortLinks([...pluginsGlobalLinks, ...globalLinks]); const sortedGlobalLinks = sortLinks([...pluginsGlobalLinks, ...globalLinks]).map(link => ({
...link,
hasNotification: link.id === 'application-infos' && shouldUpdateStrapi,
}));
const otherSections = Object.values(omit(settings, 'global')); const otherSections = Object.values(omit(settings, 'global'));
const menu = [ const menu = [

View File

@ -38,7 +38,7 @@ const SettingsNav = ({ menu }) => {
{sections.map(section => ( {sections.map(section => (
<SubNavSection key={section.id} label={formatMessage(section.intlLabel)}> <SubNavSection key={section.id} label={formatMessage(section.intlLabel)}>
{section.links.map(link => ( {section.links.map(link => (
<SubNavLink to={link.to} key={link.id}> <SubNavLink withBullet={link.hasNotification} to={link.to} key={link.id}>
{formatMessage(link.intlLabel)} {formatMessage(link.intlLabel)}
</SubNavLink> </SubNavLink>
))} ))}

View File

@ -40,8 +40,8 @@
"@fortawesome/react-fontawesome": "^0.1.14", "@fortawesome/react-fontawesome": "^0.1.14",
"@strapi/babel-plugin-switch-ee-ce": "1.0.0", "@strapi/babel-plugin-switch-ee-ce": "1.0.0",
"@strapi/helper-plugin": "3.6.7", "@strapi/helper-plugin": "3.6.7",
"@strapi/icons": "0.0.1-alpha.18", "@strapi/icons": "0.0.1-alpha.19",
"@strapi/parts": "0.0.1-alpha.18", "@strapi/parts": "0.0.1-alpha.19",
"@strapi/utils": "3.6.7", "@strapi/utils": "3.6.7",
"axios": "^0.21.1", "axios": "^0.21.1",
"babel-loader": "8.2.2", "babel-loader": "8.2.2",

View File

@ -53,8 +53,8 @@
"@storybook/builder-webpack5": "^6.3.7", "@storybook/builder-webpack5": "^6.3.7",
"@storybook/manager-webpack5": "^6.3.7", "@storybook/manager-webpack5": "^6.3.7",
"@storybook/react": "^6.3.7", "@storybook/react": "^6.3.7",
"@strapi/icons": "0.0.1-alpha.18", "@strapi/icons": "0.0.1-alpha.19",
"@strapi/parts": "0.0.1-alpha.18", "@strapi/parts": "0.0.1-alpha.19",
"babel-loader": "^8.2.2", "babel-loader": "^8.2.2",
"enzyme": "^3.8.0", "enzyme": "^3.8.0",
"enzyme-adapter-react-16": "^1.15.6", "enzyme-adapter-react-16": "^1.15.6",

View File

@ -4915,15 +4915,15 @@
resolve-from "^5.0.0" resolve-from "^5.0.0"
store2 "^2.12.0" store2 "^2.12.0"
"@strapi/icons@0.0.1-alpha.18": "@strapi/icons@0.0.1-alpha.19":
version "0.0.1-alpha.18" version "0.0.1-alpha.19"
resolved "https://registry.yarnpkg.com/@strapi/icons/-/icons-0.0.1-alpha.18.tgz#c64ca4a896b965b1ea02b2863352391daa5406ff" resolved "https://registry.yarnpkg.com/@strapi/icons/-/icons-0.0.1-alpha.19.tgz#88153c77ff02deccfedffb1dc2e7f0f4cc2f830a"
integrity sha512-QDjCckoI5vGQc6eH/rgFxLMGrBkYqmbNsMAb7T5GOUhJxoSymPM4VPKOjqL36u6MRpi1xqYdw3GBiv48tnxZVw== integrity sha512-nFpT3Gsp6nQ4+FNd9DkbqhMZrX9KJbWXLQ6XFHhtYdNVA3n5vr2/0MFaqWrvYwxpnxMs3gn1xZOjG4+VzLBwbA==
"@strapi/parts@0.0.1-alpha.18": "@strapi/parts@0.0.1-alpha.19":
version "0.0.1-alpha.18" version "0.0.1-alpha.19"
resolved "https://registry.yarnpkg.com/@strapi/parts/-/parts-0.0.1-alpha.18.tgz#19306892ba98404f7554360760f1870a2e57e381" resolved "https://registry.yarnpkg.com/@strapi/parts/-/parts-0.0.1-alpha.19.tgz#e4c64c1f63256ab21f4ad643f684738a283c0efc"
integrity sha512-x0LcIounSdgFY7lVsOjinh6ksS9/Nw2/CHNDVW7ZZTuXS5QHODebNlZibrTyPVZNLSJniYqn8P0rxAtc+FcLjQ== integrity sha512-NzhwmCJnMNlCcRHpXTxILm0rVH+qLl2JoaCxx7XoMRnq4JZHHBaLjEiyTZHYJXRTdro+YUcWeayssL9kqEX8cw==
dependencies: dependencies:
"@internationalized/number" "^3.0.2" "@internationalized/number" "^3.0.2"
compute-scroll-into-view "^1.0.17" compute-scroll-into-view "^1.0.17"