mirror of
https://github.com/strapi/strapi.git
synced 2025-11-14 17:19:01 +00:00
Merge branch 'migrations/admin-users-filters' of github.com:strapi/strapi into migrations/admin-users-delete
This commit is contained in:
commit
99ba54cb43
@ -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/',
|
||||||
|
|||||||
11
packages/admin-test-utils/lib/mocks/ResizeObserver.js
Normal file
11
packages/admin-test-utils/lib/mocks/ResizeObserver.js
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
class ResizeObserverMock {
|
||||||
|
constructor() {
|
||||||
|
this.disconnect = () => null;
|
||||||
|
this.observe = () => null;
|
||||||
|
this.unobserve = () => null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
global.ResizeObserver = ResizeObserverMock;
|
||||||
@ -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;
|
||||||
|
|||||||
@ -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,
|
||||||
|
|||||||
@ -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
|
||||||
|
|||||||
@ -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}
|
||||||
/>
|
/>
|
||||||
|
)}
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@ -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(() => {
|
||||||
|
|||||||
@ -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 = [
|
||||||
|
|||||||
@ -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>
|
||||||
))}
|
))}
|
||||||
|
|||||||
@ -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",
|
||||||
|
|||||||
@ -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",
|
||||||
|
|||||||
16
yarn.lock
16
yarn.lock
@ -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"
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user