mirror of
https://github.com/strapi/strapi.git
synced 2025-09-26 17:00:55 +00:00
Merge pull request #10873 from strapi/migration/rbac-delete
Migration/rbac delete
This commit is contained in:
commit
070d7d64ea
@ -1,9 +1,9 @@
|
|||||||
import { Box, Row, Td, Text, Tr, IconButton, BaseCheckbox } from '@strapi/parts';
|
import { Box, Row, Td, Text, Tr, IconButton } from '@strapi/parts';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { useIntl } from 'react-intl';
|
import { useIntl } from 'react-intl';
|
||||||
|
|
||||||
const RoleRow = ({ onToggle, id, name, description, usersCount, isChecked, icons }) => {
|
const RoleRow = ({ id, name, description, usersCount, icons }) => {
|
||||||
const { formatMessage } = useIntl();
|
const { formatMessage } = useIntl();
|
||||||
|
|
||||||
const usersCountText = formatMessage(
|
const usersCountText = formatMessage(
|
||||||
@ -16,19 +16,6 @@ const RoleRow = ({ onToggle, id, name, description, usersCount, isChecked, icons
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<Tr key={id}>
|
<Tr key={id}>
|
||||||
{Boolean(onToggle) && (
|
|
||||||
<Td>
|
|
||||||
<BaseCheckbox
|
|
||||||
name="role-checkbox"
|
|
||||||
onValueChange={() => onToggle(id)}
|
|
||||||
value={isChecked}
|
|
||||||
aria-label={formatMessage(
|
|
||||||
{ id: `Roles.RoleRow.select-all`, defaultMessage: 'Select {name} for bulk actions' },
|
|
||||||
{ name }
|
|
||||||
)}
|
|
||||||
/>
|
|
||||||
</Td>
|
|
||||||
)}
|
|
||||||
<Td>
|
<Td>
|
||||||
<Text textColor="neutral800">{name}</Text>
|
<Text textColor="neutral800">{name}</Text>
|
||||||
</Td>
|
</Td>
|
||||||
@ -53,19 +40,12 @@ const RoleRow = ({ onToggle, id, name, description, usersCount, isChecked, icons
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
RoleRow.defaultProps = {
|
|
||||||
onToggle: undefined,
|
|
||||||
isChecked: undefined,
|
|
||||||
};
|
|
||||||
|
|
||||||
RoleRow.propTypes = {
|
RoleRow.propTypes = {
|
||||||
id: PropTypes.number.isRequired,
|
id: PropTypes.number.isRequired,
|
||||||
name: PropTypes.string.isRequired,
|
name: PropTypes.string.isRequired,
|
||||||
description: PropTypes.string.isRequired,
|
description: PropTypes.string.isRequired,
|
||||||
usersCount: PropTypes.number.isRequired,
|
usersCount: PropTypes.number.isRequired,
|
||||||
icons: PropTypes.array.isRequired,
|
icons: PropTypes.array.isRequired,
|
||||||
onToggle: PropTypes.func,
|
|
||||||
isChecked: PropTypes.bool,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export default RoleRow;
|
export default RoleRow;
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import { useEffect, useReducer, useCallback } from 'react';
|
import { useEffect, useReducer, useCallback } from 'react';
|
||||||
import { request, useNotification } from '@strapi/helper-plugin';
|
import { useNotification } from '@strapi/helper-plugin';
|
||||||
import { get } from 'lodash';
|
import get from 'lodash/get';
|
||||||
|
import { axiosInstance } from '../../core/utils';
|
||||||
import init from './init';
|
import init from './init';
|
||||||
import reducer, { initialState } from './reducer';
|
import reducer, { initialState } from './reducer';
|
||||||
|
|
||||||
@ -23,7 +24,9 @@ const useRolesList = (shouldFetchData = true) => {
|
|||||||
type: 'GET_DATA',
|
type: 'GET_DATA',
|
||||||
});
|
});
|
||||||
|
|
||||||
const { data } = await request('/admin/roles', { method: 'GET' });
|
const {
|
||||||
|
data: { data },
|
||||||
|
} = await axiosInstance.get('/admin/roles');
|
||||||
|
|
||||||
dispatch({
|
dispatch({
|
||||||
type: 'GET_DATA_SUCCEEDED',
|
type: 'GET_DATA_SUCCEEDED',
|
||||||
|
@ -1,8 +1,9 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import {
|
import {
|
||||||
CustomContentLayout,
|
CustomContentLayout,
|
||||||
useRBAC,
|
Search,
|
||||||
SettingsPageTitle,
|
SettingsPageTitle,
|
||||||
|
useRBAC,
|
||||||
useNotification,
|
useNotification,
|
||||||
useFocusWhenNavigate,
|
useFocusWhenNavigate,
|
||||||
} from '@strapi/helper-plugin';
|
} from '@strapi/helper-plugin';
|
||||||
@ -15,7 +16,6 @@ import get from 'lodash/get';
|
|||||||
import adminPermissions from '../../../permissions';
|
import adminPermissions from '../../../permissions';
|
||||||
import DynamicTable from './DynamicTable';
|
import DynamicTable from './DynamicTable';
|
||||||
import Filters from './Filters';
|
import Filters from './Filters';
|
||||||
import Search from './Search';
|
|
||||||
import PaginationFooter from './PaginationFooter';
|
import PaginationFooter from './PaginationFooter';
|
||||||
import { deleteData, fetchData } from './utils/api';
|
import { deleteData, fetchData } from './utils/api';
|
||||||
import displayedFilters from './utils/displayedFilters';
|
import displayedFilters from './utils/displayedFilters';
|
||||||
|
@ -699,46 +699,6 @@ describe('ADMIN | Pages | USERS | ListPage', () => {
|
|||||||
height: 0.25rem;
|
height: 0.25rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.c13 {
|
|
||||||
padding-right: 56px;
|
|
||||||
padding-left: 56px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.c36 tr:last-of-type {
|
|
||||||
border-bottom: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.c37 {
|
|
||||||
border-bottom: 1px solid #eaeaef;
|
|
||||||
}
|
|
||||||
|
|
||||||
.c37 td,
|
|
||||||
.c37 th {
|
|
||||||
padding: 16px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.c37 td:first-of-type,
|
|
||||||
.c37 th:first-of-type {
|
|
||||||
padding: 0 4px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.c38 {
|
|
||||||
vertical-align: middle;
|
|
||||||
text-align: left;
|
|
||||||
color: #666687;
|
|
||||||
outline-offset: -4px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.c38 input {
|
|
||||||
vertical-align: sub;
|
|
||||||
}
|
|
||||||
|
|
||||||
.c34 {
|
|
||||||
-webkit-transform: rotate(0deg);
|
|
||||||
-ms-transform: rotate(0deg);
|
|
||||||
transform: rotate(0deg);
|
|
||||||
}
|
|
||||||
|
|
||||||
.c15 {
|
.c15 {
|
||||||
display: -webkit-box;
|
display: -webkit-box;
|
||||||
display: -webkit-flex;
|
display: -webkit-flex;
|
||||||
@ -788,6 +748,46 @@ describe('ADMIN | Pages | USERS | ListPage', () => {
|
|||||||
fill: #666687;
|
fill: #666687;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.c13 {
|
||||||
|
padding-right: 56px;
|
||||||
|
padding-left: 56px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.c36 tr:last-of-type {
|
||||||
|
border-bottom: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.c37 {
|
||||||
|
border-bottom: 1px solid #eaeaef;
|
||||||
|
}
|
||||||
|
|
||||||
|
.c37 td,
|
||||||
|
.c37 th {
|
||||||
|
padding: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.c37 td:first-of-type,
|
||||||
|
.c37 th:first-of-type {
|
||||||
|
padding: 0 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.c38 {
|
||||||
|
vertical-align: middle;
|
||||||
|
text-align: left;
|
||||||
|
color: #666687;
|
||||||
|
outline-offset: -4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.c38 input {
|
||||||
|
vertical-align: sub;
|
||||||
|
}
|
||||||
|
|
||||||
|
.c34 {
|
||||||
|
-webkit-transform: rotate(0deg);
|
||||||
|
-ms-transform: rotate(0deg);
|
||||||
|
transform: rotate(0deg);
|
||||||
|
}
|
||||||
|
|
||||||
<main
|
<main
|
||||||
aria-labelledby="title"
|
aria-labelledby="title"
|
||||||
class="c0"
|
class="c0"
|
||||||
|
@ -1,10 +1,11 @@
|
|||||||
|
import React, { useCallback, useEffect, useReducer, useState } from 'react';
|
||||||
import {
|
import {
|
||||||
|
ConfirmDialog,
|
||||||
LoadingIndicatorPage,
|
LoadingIndicatorPage,
|
||||||
PopUpWarning,
|
Search,
|
||||||
SettingsPageTitle,
|
SettingsPageTitle,
|
||||||
request,
|
|
||||||
useNotification,
|
useNotification,
|
||||||
useQuery,
|
useQueryParams,
|
||||||
useRBAC,
|
useRBAC,
|
||||||
} from '@strapi/helper-plugin';
|
} from '@strapi/helper-plugin';
|
||||||
import { AddIcon, DeleteIcon, Duplicate, EditIcon } from '@strapi/icons';
|
import { AddIcon, DeleteIcon, Duplicate, EditIcon } from '@strapi/icons';
|
||||||
@ -20,14 +21,14 @@ import {
|
|||||||
Tr,
|
Tr,
|
||||||
TableLabel,
|
TableLabel,
|
||||||
VisuallyHidden,
|
VisuallyHidden,
|
||||||
BaseCheckbox,
|
|
||||||
Main,
|
Main,
|
||||||
|
ActionLayout,
|
||||||
} from '@strapi/parts';
|
} from '@strapi/parts';
|
||||||
import { get } from 'lodash';
|
import { get } from 'lodash';
|
||||||
import matchSorter from 'match-sorter';
|
import matchSorter from 'match-sorter';
|
||||||
import React, { useCallback, useEffect, useReducer, useState } from 'react';
|
|
||||||
import { useIntl } from 'react-intl';
|
import { useIntl } from 'react-intl';
|
||||||
import { useHistory } from 'react-router-dom';
|
import { useHistory } from 'react-router-dom';
|
||||||
|
import { axiosInstance } from '../../../../../admin/src/core/utils';
|
||||||
import { EmptyRole, RoleRow as BaseRoleRow } from '../../../../../admin/src/components/Roles';
|
import { EmptyRole, RoleRow as BaseRoleRow } from '../../../../../admin/src/components/Roles';
|
||||||
import { useRolesList } from '../../../../../admin/src/hooks';
|
import { useRolesList } from '../../../../../admin/src/hooks';
|
||||||
import adminPermissions from '../../../../../admin/src/permissions';
|
import adminPermissions from '../../../../../admin/src/permissions';
|
||||||
@ -40,8 +41,8 @@ const useSortedRoles = () => {
|
|||||||
} = useRBAC(adminPermissions.settings.roles);
|
} = useRBAC(adminPermissions.settings.roles);
|
||||||
|
|
||||||
const { getData, roles, isLoading } = useRolesList(false);
|
const { getData, roles, isLoading } = useRolesList(false);
|
||||||
const query = useQuery();
|
const [{ query }] = useQueryParams();
|
||||||
const _q = decodeURIComponent(query.get('_q') || '');
|
const _q = query?._q || '';
|
||||||
const sortedRoles = matchSorter(roles, _q, { keys: ['name', 'description'] });
|
const sortedRoles = matchSorter(roles, _q, { keys: ['name', 'description'] });
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@ -63,62 +64,33 @@ const useSortedRoles = () => {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
const useRoleActions = ({ getData, canCreate, canDelete, canUpdate, roles, sortedRoles }) => {
|
const useRoleActions = ({ getData, canCreate, canDelete, canUpdate }) => {
|
||||||
const { formatMessage } = useIntl();
|
const { formatMessage } = useIntl();
|
||||||
|
|
||||||
const toggleNotification = useNotification();
|
const toggleNotification = useNotification();
|
||||||
const [isWarningDeleteAllOpened, setIsWarningDeleteAllOpenend] = useState(false);
|
const [isWarningDeleteAllOpened, setIsWarningDeleteAllOpenend] = useState(false);
|
||||||
const { push } = useHistory();
|
const { push } = useHistory();
|
||||||
const [
|
const [{ selectedRoles, showModalConfirmButtonLoading, roleToDelete }, dispatch] = useReducer(
|
||||||
{ selectedRoles, showModalConfirmButtonLoading, shouldRefetchData },
|
reducer,
|
||||||
dispatch,
|
initialState
|
||||||
] = useReducer(reducer, initialState);
|
);
|
||||||
|
|
||||||
const handleClosedModal = () => {
|
const handleDeleteData = async () => {
|
||||||
if (shouldRefetchData) {
|
|
||||||
getData();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Empty the selected ids when the modal closes
|
|
||||||
dispatch({
|
|
||||||
type: 'RESET_DATA_TO_DELETE',
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleConfirmDeleteData = async () => {
|
|
||||||
try {
|
try {
|
||||||
dispatch({
|
dispatch({
|
||||||
type: 'ON_REMOVE_ROLES',
|
type: 'ON_REMOVE_ROLES',
|
||||||
});
|
});
|
||||||
const filteredRoles = selectedRoles.filter(currentId => {
|
|
||||||
const currentRole = roles.find(role => role.id === currentId);
|
|
||||||
|
|
||||||
return currentRole.usersCount === 0;
|
await axiosInstance.post('/admin/roles/batch-delete', {
|
||||||
|
ids: [roleToDelete],
|
||||||
});
|
});
|
||||||
|
|
||||||
if (selectedRoles.length !== filteredRoles.length) {
|
await getData();
|
||||||
toggleNotification({
|
|
||||||
type: 'info',
|
|
||||||
message: { id: 'Roles.ListPage.notification.delete-all-not-allowed' },
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if (filteredRoles.length) {
|
|
||||||
await request('/admin/roles/batch-delete', {
|
|
||||||
method: 'POST',
|
|
||||||
body: {
|
|
||||||
ids: filteredRoles,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
// Empty the selectedRolesId and set the shouldRefetchData to true so the
|
|
||||||
// list is updated when closing the modal
|
|
||||||
dispatch({
|
dispatch({
|
||||||
type: 'ON_REMOVE_ROLES_SUCCEEDED',
|
type: 'RESET_DATA_TO_DELETE',
|
||||||
});
|
});
|
||||||
}
|
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error(err);
|
|
||||||
const errorIds = get(err, ['response', 'payload', 'data', 'ids'], null);
|
const errorIds = get(err, ['response', 'payload', 'data', 'ids'], null);
|
||||||
|
|
||||||
if (errorIds && Array.isArray(errorIds)) {
|
if (errorIds && Array.isArray(errorIds)) {
|
||||||
@ -133,9 +105,8 @@ const useRoleActions = ({ getData, canCreate, canDelete, canUpdate, roles, sorte
|
|||||||
message: { id: 'notification.error' },
|
message: { id: 'notification.error' },
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
} finally {
|
|
||||||
handleToggleModal();
|
|
||||||
}
|
}
|
||||||
|
handleToggleModal();
|
||||||
};
|
};
|
||||||
|
|
||||||
const onRoleDuplicate = useCallback(
|
const onRoleDuplicate = useCallback(
|
||||||
@ -156,19 +127,6 @@ const useRoleActions = ({ getData, canCreate, canDelete, canUpdate, roles, sorte
|
|||||||
handleToggleModal();
|
handleToggleModal();
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const onRoleToggle = roleId => {
|
|
||||||
dispatch({
|
|
||||||
type: 'ON_SELECTION',
|
|
||||||
id: roleId,
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
const onAllRolesToggle = () =>
|
|
||||||
dispatch({
|
|
||||||
type: 'TOGGLE_ALL',
|
|
||||||
ids: sortedRoles.map(r => r.id),
|
|
||||||
});
|
|
||||||
|
|
||||||
const handleToggleModal = () => setIsWarningDeleteAllOpenend(prev => !prev);
|
const handleToggleModal = () => setIsWarningDeleteAllOpenend(prev => !prev);
|
||||||
|
|
||||||
const handleGoTo = useCallback(
|
const handleGoTo = useCallback(
|
||||||
@ -246,16 +204,13 @@ const useRoleActions = ({ getData, canCreate, canDelete, canUpdate, roles, sorte
|
|||||||
);
|
);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
handleClosedModal,
|
|
||||||
handleConfirmDeleteData,
|
|
||||||
handleNewRoleClick,
|
handleNewRoleClick,
|
||||||
onRoleToggle,
|
|
||||||
onAllRolesToggle,
|
|
||||||
getIcons,
|
getIcons,
|
||||||
selectedRoles,
|
selectedRoles,
|
||||||
isWarningDeleteAllOpened,
|
isWarningDeleteAllOpened,
|
||||||
showModalConfirmButtonLoading,
|
showModalConfirmButtonLoading,
|
||||||
handleToggleModal,
|
handleToggleModal,
|
||||||
|
handleDeleteData,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -271,21 +226,16 @@ const RoleListPage = () => {
|
|||||||
isLoading,
|
isLoading,
|
||||||
getData,
|
getData,
|
||||||
sortedRoles,
|
sortedRoles,
|
||||||
roles,
|
|
||||||
} = useSortedRoles();
|
} = useSortedRoles();
|
||||||
|
|
||||||
const {
|
const {
|
||||||
handleClosedModal,
|
|
||||||
handleConfirmDeleteData,
|
|
||||||
handleNewRoleClick,
|
handleNewRoleClick,
|
||||||
onRoleToggle,
|
|
||||||
onAllRolesToggle,
|
|
||||||
getIcons,
|
getIcons,
|
||||||
selectedRoles,
|
|
||||||
isWarningDeleteAllOpened,
|
isWarningDeleteAllOpened,
|
||||||
showModalConfirmButtonLoading,
|
showModalConfirmButtonLoading,
|
||||||
handleToggleModal,
|
handleToggleModal,
|
||||||
} = useRoleActions({ getData, canCreate, canDelete, canUpdate, roles, sortedRoles });
|
handleDeleteData,
|
||||||
|
} = useRoleActions({ getData, canCreate, canDelete, canUpdate });
|
||||||
|
|
||||||
// ! TODO - Show the search bar only if the user is allowed to read - add the search input
|
// ! TODO - Show the search bar only if the user is allowed to read - add the search input
|
||||||
// canRead
|
// canRead
|
||||||
@ -293,11 +243,6 @@ const RoleListPage = () => {
|
|||||||
const rowCount = sortedRoles.length + 1;
|
const rowCount = sortedRoles.length + 1;
|
||||||
const colCount = 6;
|
const colCount = 6;
|
||||||
|
|
||||||
const isAllEntriesIndeterminate = selectedRoles.length
|
|
||||||
? selectedRoles.length !== rowCount
|
|
||||||
: false;
|
|
||||||
const isAllChecked = selectedRoles.length ? selectedRoles.length === rowCount : false;
|
|
||||||
|
|
||||||
if (isLoadingForPermissions) {
|
if (isLoadingForPermissions) {
|
||||||
return <LoadingIndicatorPage />;
|
return <LoadingIndicatorPage />;
|
||||||
}
|
}
|
||||||
@ -327,6 +272,7 @@ const RoleListPage = () => {
|
|||||||
})}
|
})}
|
||||||
as="h2"
|
as="h2"
|
||||||
/>
|
/>
|
||||||
|
{canRead && <ActionLayout startActions={<Search />} />}
|
||||||
{canRead && (
|
{canRead && (
|
||||||
<ContentLayout>
|
<ContentLayout>
|
||||||
<Table
|
<Table
|
||||||
@ -345,16 +291,6 @@ const RoleListPage = () => {
|
|||||||
>
|
>
|
||||||
<Thead>
|
<Thead>
|
||||||
<Tr>
|
<Tr>
|
||||||
{!!onRoleToggle && (
|
|
||||||
<Th>
|
|
||||||
<BaseCheckbox
|
|
||||||
aria-label="Select all entries"
|
|
||||||
indeterminate={isAllEntriesIndeterminate}
|
|
||||||
value={isAllChecked}
|
|
||||||
onChange={onAllRolesToggle}
|
|
||||||
/>
|
|
||||||
</Th>
|
|
||||||
)}
|
|
||||||
<Th>
|
<Th>
|
||||||
<TableLabel>
|
<TableLabel>
|
||||||
{formatMessage({
|
{formatMessage({
|
||||||
@ -394,10 +330,6 @@ const RoleListPage = () => {
|
|||||||
<BaseRoleRow
|
<BaseRoleRow
|
||||||
key={role.id}
|
key={role.id}
|
||||||
id={role.id}
|
id={role.id}
|
||||||
onToggle={onRoleToggle}
|
|
||||||
isChecked={
|
|
||||||
selectedRoles.findIndex(selectedRoleId => selectedRoleId === role.id) !== -1
|
|
||||||
}
|
|
||||||
name={role.name}
|
name={role.name}
|
||||||
description={role.description}
|
description={role.description}
|
||||||
usersCount={role.usersCount}
|
usersCount={role.usersCount}
|
||||||
@ -409,12 +341,11 @@ const RoleListPage = () => {
|
|||||||
{!rowCount && !isLoading && <EmptyRole />}
|
{!rowCount && !isLoading && <EmptyRole />}
|
||||||
</ContentLayout>
|
</ContentLayout>
|
||||||
)}
|
)}
|
||||||
<PopUpWarning
|
<ConfirmDialog
|
||||||
isOpen={isWarningDeleteAllOpened}
|
isVisible={isWarningDeleteAllOpened}
|
||||||
onClosed={handleClosedModal}
|
onConfirm={handleDeleteData}
|
||||||
onConfirm={handleConfirmDeleteData}
|
|
||||||
toggleModal={handleToggleModal}
|
|
||||||
isConfirmButtonLoading={showModalConfirmButtonLoading}
|
isConfirmButtonLoading={showModalConfirmButtonLoading}
|
||||||
|
onToggleDialog={handleToggleModal}
|
||||||
/>
|
/>
|
||||||
</Main>
|
</Main>
|
||||||
);
|
);
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
import produce from 'immer';
|
import produce from 'immer';
|
||||||
|
|
||||||
export const initialState = {
|
export const initialState = {
|
||||||
selectedRoles: [],
|
roleToDelete: null,
|
||||||
showModalConfirmButtonLoading: false,
|
showModalConfirmButtonLoading: false,
|
||||||
shouldRefetchData: false,
|
shouldRefetchData: false,
|
||||||
};
|
};
|
||||||
@ -10,57 +10,26 @@ export const initialState = {
|
|||||||
const reducer = (state, action) =>
|
const reducer = (state, action) =>
|
||||||
produce(state, draftState => {
|
produce(state, draftState => {
|
||||||
switch (action.type) {
|
switch (action.type) {
|
||||||
case 'ON_SELECTION': {
|
|
||||||
const { id } = action;
|
|
||||||
const roleIndex = state.selectedRoles.findIndex(roleId => roleId === id);
|
|
||||||
|
|
||||||
if (roleIndex === -1) {
|
|
||||||
draftState.selectedRoles.push(id);
|
|
||||||
} else {
|
|
||||||
draftState.selectedRoles = state.selectedRoles.filter(roleId => roleId !== id);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case 'TOGGLE_ALL': {
|
|
||||||
if (state.selectedRoles.length) {
|
|
||||||
draftState.selectedRoles = [];
|
|
||||||
} else {
|
|
||||||
const { ids } = action;
|
|
||||||
draftState.selectedRoles = ids;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case 'ON_REMOVE_ROLES': {
|
case 'ON_REMOVE_ROLES': {
|
||||||
draftState.showModalConfirmButtonLoading = true;
|
draftState.showModalConfirmButtonLoading = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 'ON_REMOVE_ROLES_SUCCEEDED': {
|
case 'ON_REMOVE_ROLES_SUCCEEDED': {
|
||||||
draftState.shouldRefetchData = true;
|
draftState.shouldRefetchData = true;
|
||||||
|
draftState.roleToDelete = null;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 'RESET_DATA_TO_DELETE': {
|
case 'RESET_DATA_TO_DELETE': {
|
||||||
draftState.shouldRefetchData = false;
|
draftState.shouldRefetchData = false;
|
||||||
draftState.selectedRoles = [];
|
draftState.roleToDelete = null;
|
||||||
draftState.showModalConfirmButtonLoading = false;
|
draftState.showModalConfirmButtonLoading = false;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 'SET_ROLE_TO_DELETE': {
|
case 'SET_ROLE_TO_DELETE': {
|
||||||
draftState.selectedRoles = [action.id];
|
draftState.roleToDelete = action.id;
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
// Leaving this code for the moment
|
|
||||||
// case 'ON_DUPLICATION': {
|
|
||||||
// const { id } = action;
|
|
||||||
// draftState.roles = state.roles.reduce((acc, c) => {
|
|
||||||
// if (c.id === id) {
|
|
||||||
// return acc.concat([c, { ...c, id: state.roles.length + 1 }]);
|
|
||||||
// }
|
|
||||||
|
|
||||||
// return [...acc, c];
|
|
||||||
// }, []);
|
|
||||||
// break;
|
|
||||||
// }
|
|
||||||
default:
|
default:
|
||||||
return draftState;
|
return draftState;
|
||||||
}
|
}
|
||||||
|
@ -11,54 +11,18 @@ describe('ADMIN | ee | CONTAINERS | ROLES | ListPage | reducer', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('ON_SELECTION', () => {
|
|
||||||
it('should add the selected role correctly', () => {
|
|
||||||
const action = {
|
|
||||||
type: 'ON_SELECTION',
|
|
||||||
id: 2,
|
|
||||||
};
|
|
||||||
const initialState = {
|
|
||||||
selectedRoles: [],
|
|
||||||
shouldRefetchData: false,
|
|
||||||
};
|
|
||||||
const expected = {
|
|
||||||
selectedRoles: [2],
|
|
||||||
shouldRefetchData: false,
|
|
||||||
};
|
|
||||||
|
|
||||||
expect(reducer(initialState, action)).toEqual(expected);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should remove the selected role correctly', () => {
|
|
||||||
const action = {
|
|
||||||
type: 'ON_SELECTION',
|
|
||||||
id: 2,
|
|
||||||
};
|
|
||||||
const initialState = {
|
|
||||||
selectedRoles: [1, 2],
|
|
||||||
shouldRefetchData: false,
|
|
||||||
};
|
|
||||||
const expected = {
|
|
||||||
selectedRoles: [1],
|
|
||||||
shouldRefetchData: false,
|
|
||||||
};
|
|
||||||
|
|
||||||
expect(reducer(initialState, action)).toEqual(expected);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('ON_REMOVE_ROLES', () => {
|
describe('ON_REMOVE_ROLES', () => {
|
||||||
it('should set the showModalConfirmButtonLoading to true', () => {
|
it('should set the showModalConfirmButtonLoading to true', () => {
|
||||||
const action = {
|
const action = {
|
||||||
type: 'ON_REMOVE_ROLES',
|
type: 'ON_REMOVE_ROLES',
|
||||||
};
|
};
|
||||||
const initialState = {
|
const initialState = {
|
||||||
selectedRoles: [],
|
roleToDelete: 1,
|
||||||
shouldRefetchData: false,
|
shouldRefetchData: false,
|
||||||
showModalConfirmButtonLoading: false,
|
showModalConfirmButtonLoading: false,
|
||||||
};
|
};
|
||||||
const expected = {
|
const expected = {
|
||||||
selectedRoles: [],
|
roleToDelete: 1,
|
||||||
shouldRefetchData: false,
|
shouldRefetchData: false,
|
||||||
showModalConfirmButtonLoading: true,
|
showModalConfirmButtonLoading: true,
|
||||||
};
|
};
|
||||||
@ -73,12 +37,12 @@ describe('ADMIN | ee | CONTAINERS | ROLES | ListPage | reducer', () => {
|
|||||||
type: 'ON_REMOVE_ROLES_SUCCEEDED',
|
type: 'ON_REMOVE_ROLES_SUCCEEDED',
|
||||||
};
|
};
|
||||||
const initialState = {
|
const initialState = {
|
||||||
selectedRoles: [],
|
roleToDelete: 1,
|
||||||
shouldRefetchData: false,
|
shouldRefetchData: false,
|
||||||
showModalConfirmButtonLoading: true,
|
showModalConfirmButtonLoading: true,
|
||||||
};
|
};
|
||||||
const expected = {
|
const expected = {
|
||||||
selectedRoles: [],
|
roleToDelete: null,
|
||||||
shouldRefetchData: true,
|
shouldRefetchData: true,
|
||||||
showModalConfirmButtonLoading: true,
|
showModalConfirmButtonLoading: true,
|
||||||
};
|
};
|
||||||
@ -87,26 +51,6 @@ describe('ADMIN | ee | CONTAINERS | ROLES | ListPage | reducer', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('RESET_DATA_TO_DELETE', () => {
|
|
||||||
it('should empty the selected role array and set the shouldRefetchData to false', () => {
|
|
||||||
const action = {
|
|
||||||
type: 'RESET_DATA_TO_DELETE',
|
|
||||||
};
|
|
||||||
const initialState = {
|
|
||||||
selectedRoles: [1, 2, 4],
|
|
||||||
shouldRefetchData: true,
|
|
||||||
showModalConfirmButtonLoading: true,
|
|
||||||
};
|
|
||||||
const expected = {
|
|
||||||
selectedRoles: [],
|
|
||||||
shouldRefetchData: false,
|
|
||||||
showModalConfirmButtonLoading: false,
|
|
||||||
};
|
|
||||||
|
|
||||||
expect(reducer(initialState, action)).toEqual(expected);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('SET_ROLE_TO_DELETE', () => {
|
describe('SET_ROLE_TO_DELETE', () => {
|
||||||
it('should set the selected roles property correctly', () => {
|
it('should set the selected roles property correctly', () => {
|
||||||
const action = {
|
const action = {
|
||||||
@ -114,11 +58,11 @@ describe('ADMIN | ee | CONTAINERS | ROLES | ListPage | reducer', () => {
|
|||||||
id: 6,
|
id: 6,
|
||||||
};
|
};
|
||||||
const initialState = {
|
const initialState = {
|
||||||
selectedRoles: [1, 2, 4],
|
roleToDelete: null,
|
||||||
shouldRefetchData: false,
|
shouldRefetchData: false,
|
||||||
};
|
};
|
||||||
const expected = {
|
const expected = {
|
||||||
selectedRoles: [6],
|
roleToDelete: 6,
|
||||||
shouldRefetchData: false,
|
shouldRefetchData: false,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1,13 +1,13 @@
|
|||||||
import React, { useEffect, useState } from 'react';
|
import React, { useEffect, useState } from 'react';
|
||||||
import { useQueryParams } from '@strapi/helper-plugin';
|
|
||||||
import { SearchIcon } from '@strapi/icons';
|
import { SearchIcon } from '@strapi/icons';
|
||||||
import { IconButton } from '@strapi/parts/IconButton';
|
import { IconButton } from '@strapi/parts/IconButton';
|
||||||
import { TextInput } from '@strapi/parts/TextInput';
|
import { TextInput } from '@strapi/parts/TextInput';
|
||||||
|
import useQueryParams from '../../hooks/useQueryParams';
|
||||||
|
|
||||||
const Search = () => {
|
const Search = () => {
|
||||||
const [isOpen, setIsOpen] = useState(false);
|
const [isOpen, setIsOpen] = useState(false);
|
||||||
const [{ query }, setQuery] = useQueryParams();
|
const [{ query }, setQuery] = useQueryParams();
|
||||||
const [value, setValue] = useState(query._q || '');
|
const [value, setValue] = useState(query?._q || '');
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const handler = setTimeout(() => {
|
const handler = setTimeout(() => {
|
@ -179,6 +179,7 @@ export { default as EmptyBodyTable } from './components/EmptyBodyTable';
|
|||||||
export * from './components/InjectionZone';
|
export * from './components/InjectionZone';
|
||||||
export { default as LoadingIndicatorPage } from './components/LoadingIndicatorPage';
|
export { default as LoadingIndicatorPage } from './components/LoadingIndicatorPage';
|
||||||
export { default as SettingsPageTitle } from './components/SettingsPageTitle';
|
export { default as SettingsPageTitle } from './components/SettingsPageTitle';
|
||||||
|
export { default as Search } from './components/Search';
|
||||||
export { default as Status } from './components/Status';
|
export { default as Status } from './components/Status';
|
||||||
|
|
||||||
// New icons
|
// New icons
|
||||||
|
Loading…
x
Reference in New Issue
Block a user