mirror of
https://github.com/strapi/strapi.git
synced 2025-11-02 02:44:55 +00:00
Merge pull request #16816 from strapi/enhancement/use-admin-users
Enhancement: Create useAdminUsers data fetching hook
This commit is contained in:
commit
aa461fbbc9
5
docs/docs/docs/01-core/admin/04-hooks/_category_.json
Normal file
5
docs/docs/docs/01-core/admin/04-hooks/_category_.json
Normal file
@ -0,0 +1,5 @@
|
||||
{
|
||||
"label": "Hooks",
|
||||
"collapsible": true,
|
||||
"collapsed": true
|
||||
}
|
||||
67
docs/docs/docs/01-core/admin/04-hooks/use-admin-users.mdx
Normal file
67
docs/docs/docs/01-core/admin/04-hooks/use-admin-users.mdx
Normal file
@ -0,0 +1,67 @@
|
||||
---
|
||||
title: useAdminUsers
|
||||
description: API reference for the useAdminUsers hook
|
||||
tags:
|
||||
- admin
|
||||
- hooks
|
||||
- users
|
||||
---
|
||||
|
||||
An abstraction around `react-query`'s `useQuery` hook. It can be used to fetch one ore more admin users.
|
||||
|
||||
## Usage
|
||||
|
||||
The hooks can receive two optional parameters:
|
||||
|
||||
1. query params: an object containing the query params to be sent to the API. They are going to be
|
||||
stringified by `qs`. All params are equal except `id`, which is used to fetch a single users, if
|
||||
it is passed.
|
||||
2. options: an object containing the options to be passed to `useQuery`.
|
||||
|
||||
It returns an object containing some of the react-query attributes.
|
||||
|
||||
## Typescript
|
||||
|
||||
```ts
|
||||
import { UseQueryOptions } from 'react-query'
|
||||
|
||||
type User = object;
|
||||
|
||||
useAdminUsers(queryParams: object, reactQueryOptions: UseQueryOptions): {
|
||||
users: User[];
|
||||
pagination: {
|
||||
page: number,
|
||||
pageSize: number,
|
||||
total: number,
|
||||
} | null;
|
||||
isLoading: boolean;
|
||||
isError: boolean;
|
||||
refetch: () => Promise<void>;
|
||||
};
|
||||
```
|
||||
|
||||
### Fetch all users
|
||||
|
||||
```jsx
|
||||
import { useAdminUsers } from 'path/to/hooks';
|
||||
|
||||
const MyComponent = ({ onMoveItem }) => {
|
||||
const { users, isLoading, refetch } = useAdminUsers();
|
||||
|
||||
return /* ... */;
|
||||
};
|
||||
```
|
||||
|
||||
### Fetch one user
|
||||
|
||||
```jsx
|
||||
import { Box } from '@strapi/design-system';
|
||||
|
||||
import { useAdminUsers } from 'path/to/hooks';
|
||||
|
||||
const MyComponent = ({ onMoveItem }) => {
|
||||
const { users: [user], isLoading, refetch } = useAdminUsers({ id: 1 });
|
||||
|
||||
return /* ... */;
|
||||
};
|
||||
```
|
||||
@ -0,0 +1,5 @@
|
||||
export const useAdminUsers = jest.fn().mockReturnValue({
|
||||
users: [],
|
||||
isLoading: false,
|
||||
isError: false,
|
||||
});
|
||||
@ -0,0 +1 @@
|
||||
export * from './useAdminUsers';
|
||||
@ -0,0 +1,137 @@
|
||||
import * as React from 'react';
|
||||
import { setupServer } from 'msw/node';
|
||||
import { rest } from 'msw';
|
||||
import { renderHook } from '@testing-library/react-hooks';
|
||||
import { IntlProvider } from 'react-intl';
|
||||
import { QueryClient, QueryClientProvider } from 'react-query';
|
||||
|
||||
import { useAdminUsers } from '../useAdminUsers';
|
||||
|
||||
const server = setupServer(
|
||||
rest.get('*/users', (req, res, ctx) =>
|
||||
res(
|
||||
ctx.json({
|
||||
data: {
|
||||
results: [
|
||||
{
|
||||
id: 1,
|
||||
},
|
||||
],
|
||||
|
||||
pagination: {
|
||||
page: 1,
|
||||
},
|
||||
},
|
||||
})
|
||||
)
|
||||
),
|
||||
|
||||
rest.get('*/users/1', (req, res, ctx) =>
|
||||
res(
|
||||
ctx.json({
|
||||
data: {
|
||||
id: 1,
|
||||
params: {
|
||||
some: req.url.searchParams.get('some'),
|
||||
},
|
||||
},
|
||||
})
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
const setup = (...args) =>
|
||||
renderHook(() => useAdminUsers(...args), {
|
||||
wrapper({ children }) {
|
||||
const client = new QueryClient({
|
||||
defaultOptions: {
|
||||
queries: {
|
||||
retry: false,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
return (
|
||||
<QueryClientProvider client={client}>
|
||||
<IntlProvider locale="en" messages={{}}>
|
||||
{children}
|
||||
</IntlProvider>
|
||||
</QueryClientProvider>
|
||||
);
|
||||
},
|
||||
});
|
||||
|
||||
describe('useAdminUsers', () => {
|
||||
beforeAll(() => {
|
||||
server.listen();
|
||||
});
|
||||
|
||||
afterAll(() => {
|
||||
server.close();
|
||||
});
|
||||
|
||||
test('fetches users', async () => {
|
||||
const { result, waitFor } = setup();
|
||||
|
||||
expect(result.current.isLoading).toBe(true);
|
||||
|
||||
expect(result.current.users).toStrictEqual([]);
|
||||
|
||||
await waitFor(() => expect(result.current.isLoading).toBe(false));
|
||||
|
||||
expect(result.current.users).toStrictEqual(
|
||||
expect.arrayContaining([
|
||||
expect.objectContaining({
|
||||
id: 1,
|
||||
}),
|
||||
])
|
||||
);
|
||||
|
||||
expect(result.current.pagination).toStrictEqual(
|
||||
expect.objectContaining({
|
||||
page: 1,
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
test('fetches a single user', async () => {
|
||||
const { result, waitFor } = setup({ id: 1 });
|
||||
|
||||
expect(result.current.isLoading).toBe(true);
|
||||
|
||||
expect(result.current.users).toStrictEqual([]);
|
||||
|
||||
await waitFor(() => expect(result.current.isLoading).toBe(false));
|
||||
|
||||
expect(result.current.users).toStrictEqual([
|
||||
expect.objectContaining({
|
||||
id: 1,
|
||||
}),
|
||||
]);
|
||||
});
|
||||
|
||||
test('forwards all query params except `id`', async () => {
|
||||
const { result, waitFor } = setup({ id: 1, some: 'param' });
|
||||
|
||||
await waitFor(() => expect(result.current.isLoading).toBe(false));
|
||||
|
||||
expect(result.current.users).toStrictEqual([
|
||||
expect.objectContaining({
|
||||
params: {
|
||||
some: 'param',
|
||||
},
|
||||
}),
|
||||
]);
|
||||
});
|
||||
|
||||
test('extends the default react-query options', async () => {
|
||||
const { result } = setup(
|
||||
{ id: null },
|
||||
{
|
||||
enabled: false,
|
||||
}
|
||||
);
|
||||
|
||||
expect(result.current.isLoading).toBe(false);
|
||||
});
|
||||
});
|
||||
@ -0,0 +1,38 @@
|
||||
import { useQuery } from 'react-query';
|
||||
import { useFetchClient } from '@strapi/helper-plugin';
|
||||
import { stringify } from 'qs';
|
||||
|
||||
export function useAdminUsers(params = {}, queryOptions = {}) {
|
||||
const { id = '', ...queryParams } = params;
|
||||
const queryString = stringify(queryParams, { encode: false });
|
||||
|
||||
const { get } = useFetchClient();
|
||||
|
||||
const { data, isError, isLoading, refetch } = useQuery(
|
||||
['users', id, queryParams],
|
||||
async () => {
|
||||
const {
|
||||
data: { data },
|
||||
} = await get(`/admin/users/${id}${queryString ? `?${queryString}` : ''}`);
|
||||
|
||||
return data;
|
||||
},
|
||||
queryOptions
|
||||
);
|
||||
|
||||
let users = [];
|
||||
|
||||
if (id && data) {
|
||||
users = [data];
|
||||
} else if (Array.isArray(data?.results)) {
|
||||
users = data.results;
|
||||
}
|
||||
|
||||
return {
|
||||
users,
|
||||
pagination: data?.pagination ?? null,
|
||||
isLoading,
|
||||
isError,
|
||||
refetch,
|
||||
};
|
||||
}
|
||||
@ -17,7 +17,6 @@ import {
|
||||
LoadingIndicatorPage,
|
||||
Link,
|
||||
} from '@strapi/helper-plugin';
|
||||
import { useQuery } from 'react-query';
|
||||
import { Formik } from 'formik';
|
||||
import {
|
||||
Box,
|
||||
@ -32,11 +31,13 @@ import {
|
||||
} from '@strapi/design-system';
|
||||
import { ArrowLeft, Check } from '@strapi/icons';
|
||||
import MagicLink from 'ee_else_ce/pages/SettingsPage/pages/Users/components/MagicLink';
|
||||
|
||||
import { formatAPIErrors, getFullName } from '../../../../../utils';
|
||||
import { fetchUser, putUser } from './utils/api';
|
||||
import { putUser } from './utils/api';
|
||||
import layout from './utils/layout';
|
||||
import { editValidation } from '../utils/validations/users';
|
||||
import SelectRoles from '../components/SelectRoles';
|
||||
import { useAdminUsers } from '../../../../../hooks/useAdminUsers';
|
||||
|
||||
const fieldsToPick = ['email', 'firstname', 'lastname', 'username', 'isActive', 'roles'];
|
||||
|
||||
@ -51,26 +52,35 @@ const EditPage = ({ canUpdate }) => {
|
||||
const { lockApp, unlockApp } = useOverlayBlocker();
|
||||
useFocusWhenNavigate();
|
||||
|
||||
const { status, data } = useQuery(['user', id], () => fetchUser(id), {
|
||||
retry: false,
|
||||
onError(err) {
|
||||
const status = err.response.status;
|
||||
const {
|
||||
users: [user],
|
||||
isLoading,
|
||||
} = useAdminUsers(
|
||||
{ id },
|
||||
{
|
||||
onError(error) {
|
||||
const { status } = error.response;
|
||||
|
||||
// Redirect the use to the homepage if is not allowed to read
|
||||
if (status === 403) {
|
||||
toggleNotification({
|
||||
type: 'info',
|
||||
message: {
|
||||
id: 'notification.permission.not-allowed-read',
|
||||
defaultMessage: 'You are not allowed to see this document',
|
||||
},
|
||||
});
|
||||
// Redirect the use to the homepage if is not allowed to read
|
||||
if (status === 403) {
|
||||
toggleNotification({
|
||||
type: 'info',
|
||||
message: {
|
||||
id: 'notification.permission.not-allowed-read',
|
||||
defaultMessage: 'You are not allowed to see this document',
|
||||
},
|
||||
});
|
||||
|
||||
push('/');
|
||||
}
|
||||
console.log(err.response.status);
|
||||
},
|
||||
});
|
||||
push('/');
|
||||
} else {
|
||||
toggleNotification({
|
||||
type: 'warning',
|
||||
message: { id: 'notification.error', defaultMessage: 'An error occured' },
|
||||
});
|
||||
}
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
const handleSubmit = async (body, actions) => {
|
||||
lockApp();
|
||||
@ -113,19 +123,18 @@ const EditPage = ({ canUpdate }) => {
|
||||
unlockApp();
|
||||
};
|
||||
|
||||
const isLoading = status !== 'success';
|
||||
const headerLabel = isLoading
|
||||
? { id: 'app.containers.Users.EditPage.header.label-loading', defaultMessage: 'Edit user' }
|
||||
: { id: 'app.containers.Users.EditPage.header.label', defaultMessage: 'Edit {name}' };
|
||||
|
||||
const initialData = Object.keys(pick(data, fieldsToPick)).reduce((acc, current) => {
|
||||
const initialData = Object.keys(pick(user, fieldsToPick)).reduce((acc, current) => {
|
||||
if (current === 'roles') {
|
||||
acc[current] = (data?.roles || []).map(({ id }) => id);
|
||||
acc[current] = (user?.roles || []).map(({ id }) => id);
|
||||
|
||||
return acc;
|
||||
}
|
||||
|
||||
acc[current] = data?.[current];
|
||||
acc[current] = user?.[current];
|
||||
|
||||
return acc;
|
||||
}, {});
|
||||
@ -138,6 +147,7 @@ const EditPage = ({ canUpdate }) => {
|
||||
if (isLoading) {
|
||||
return (
|
||||
<Main aria-busy="true">
|
||||
{/* TODO: translate */}
|
||||
<SettingsPageTitle name="Users" />
|
||||
<HeaderLayout
|
||||
primaryAction={
|
||||
@ -200,9 +210,9 @@ const EditPage = ({ canUpdate }) => {
|
||||
}
|
||||
/>
|
||||
<ContentLayout>
|
||||
{data?.registrationToken && (
|
||||
{user?.registrationToken && (
|
||||
<Box paddingBottom={6}>
|
||||
<MagicLink registrationToken={data.registrationToken} />
|
||||
<MagicLink registrationToken={user.registrationToken} />
|
||||
</Box>
|
||||
)}
|
||||
<Flex direction="column" alignItems="stretch" gap={7}>
|
||||
|
||||
@ -1,12 +1,5 @@
|
||||
import { getFetchClient } from '@strapi/helper-plugin';
|
||||
|
||||
const fetchUser = async (id) => {
|
||||
const { get } = getFetchClient();
|
||||
const { data } = await get(`/admin/users/${id}`);
|
||||
|
||||
return data.data;
|
||||
};
|
||||
|
||||
const putUser = async (id, body) => {
|
||||
const { put } = getFetchClient();
|
||||
|
||||
@ -15,4 +8,4 @@ const putUser = async (id, body) => {
|
||||
return data.data;
|
||||
};
|
||||
|
||||
export { fetchUser, putUser };
|
||||
export { putUser };
|
||||
|
||||
@ -15,7 +15,6 @@ import {
|
||||
Flex,
|
||||
Typography,
|
||||
} from '@strapi/design-system';
|
||||
|
||||
import { Formik } from 'formik';
|
||||
import {
|
||||
Form,
|
||||
@ -24,20 +23,21 @@ import {
|
||||
useOverlayBlocker,
|
||||
useFetchClient,
|
||||
} from '@strapi/helper-plugin';
|
||||
import { useQueryClient, useMutation } from 'react-query';
|
||||
import { useMutation } from 'react-query';
|
||||
|
||||
import formDataModel from 'ee_else_ce/pages/SettingsPage/pages/Users/ListPage/ModalForm/utils/formDataModel';
|
||||
import roleSettingsForm from 'ee_else_ce/pages/SettingsPage/pages/Users/ListPage/ModalForm/utils/roleSettingsForm';
|
||||
import MagicLink from 'ee_else_ce/pages/SettingsPage/pages/Users/components/MagicLink';
|
||||
|
||||
import SelectRoles from '../../components/SelectRoles';
|
||||
import layout from './utils/layout';
|
||||
import schema from './utils/schema';
|
||||
import stepper from './utils/stepper';
|
||||
|
||||
const ModalForm = ({ queryName, onToggle }) => {
|
||||
const ModalForm = ({ onSuccess, onToggle }) => {
|
||||
const [currentStep, setStep] = useState('create');
|
||||
const [isSubmitting, setIsSubmitting] = useState(false);
|
||||
const [registrationToken, setRegistrationToken] = useState(null);
|
||||
const queryClient = useQueryClient();
|
||||
const { formatMessage } = useIntl();
|
||||
const toggleNotification = useNotification();
|
||||
const { lockApp, unlockApp } = useOverlayBlocker();
|
||||
@ -50,8 +50,7 @@ const ModalForm = ({ queryName, onToggle }) => {
|
||||
async onSuccess({ data }) {
|
||||
setRegistrationToken(data.data.registrationToken);
|
||||
|
||||
await queryClient.refetchQueries(queryName);
|
||||
await queryClient.refetchQueries(['ee', 'license-limit-info']);
|
||||
await onSuccess();
|
||||
|
||||
goNext();
|
||||
setIsSubmitting(false);
|
||||
@ -216,7 +215,7 @@ const ModalForm = ({ queryName, onToggle }) => {
|
||||
|
||||
ModalForm.propTypes = {
|
||||
onToggle: PropTypes.func.isRequired,
|
||||
queryName: PropTypes.array.isRequired,
|
||||
onSuccess: PropTypes.func.isRequired,
|
||||
};
|
||||
|
||||
export default ModalForm;
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
import React, { useState } from 'react';
|
||||
import qs from 'qs';
|
||||
import {
|
||||
DynamicTable,
|
||||
SearchURLQuery,
|
||||
@ -8,29 +9,28 @@ import {
|
||||
useFocusWhenNavigate,
|
||||
NoPermissions,
|
||||
useAPIErrorHandler,
|
||||
useFetchClient,
|
||||
} from '@strapi/helper-plugin';
|
||||
import {
|
||||
ActionLayout,
|
||||
ContentLayout,
|
||||
HeaderLayout,
|
||||
Main,
|
||||
useNotifyAT,
|
||||
} from '@strapi/design-system';
|
||||
import { ActionLayout, ContentLayout, HeaderLayout, Main } from '@strapi/design-system';
|
||||
import { useLocation } from 'react-router-dom';
|
||||
import { useIntl } from 'react-intl';
|
||||
import { useMutation, useQuery, useQueryClient } from 'react-query';
|
||||
import { useMutation, useQueryClient } from 'react-query';
|
||||
import CreateAction from 'ee_else_ce/pages/SettingsPage/pages/Users/ListPage/CreateAction';
|
||||
import useLicenseLimitNotification from 'ee_else_ce/hooks/useLicenseLimitNotification';
|
||||
|
||||
import { useAdminUsers } from '../../../../../hooks/useAdminUsers';
|
||||
import adminPermissions from '../../../../../permissions';
|
||||
import TableRows from './DynamicTable/TableRows';
|
||||
import Filters from '../../../components/Filters';
|
||||
import ModalForm from './ModalForm';
|
||||
import PaginationFooter from './PaginationFooter';
|
||||
import { deleteData, fetchData } from './utils/api';
|
||||
import displayedFilters from './utils/displayedFilters';
|
||||
import tableHeaders from './utils/tableHeaders';
|
||||
|
||||
const EE_LICENSE_LIMIT_QUERY_KEY = ['ee', 'license-limit-info'];
|
||||
|
||||
const ListPage = () => {
|
||||
const { post } = useFetchClient();
|
||||
const { formatAPIError } = useAPIErrorHandler();
|
||||
const [isModalOpened, setIsModalOpen] = useState(false);
|
||||
const {
|
||||
@ -42,8 +42,15 @@ const ListPage = () => {
|
||||
const { search } = useLocation();
|
||||
useFocusWhenNavigate();
|
||||
useLicenseLimitNotification();
|
||||
const { notifyStatus } = useNotifyAT();
|
||||
const queryName = ['users', search];
|
||||
const {
|
||||
users,
|
||||
pagination,
|
||||
isError,
|
||||
isLoading,
|
||||
refetchQueries: refetchAdminUsers,
|
||||
} = useAdminUsers(qs.parse(search, { ignoreQueryPrefix: true }), {
|
||||
enabled: canRead,
|
||||
});
|
||||
|
||||
const headers = tableHeaders.map((header) => ({
|
||||
...header,
|
||||
@ -58,59 +65,33 @@ const ListPage = () => {
|
||||
defaultMessage: 'Users',
|
||||
});
|
||||
|
||||
const notifyLoad = () => {
|
||||
notifyStatus(
|
||||
formatMessage(
|
||||
{
|
||||
id: 'app.utils.notify.data-loaded',
|
||||
defaultMessage: 'The {target} has loaded',
|
||||
},
|
||||
{ target: title }
|
||||
)
|
||||
);
|
||||
};
|
||||
|
||||
const { status, data, isFetching } = useQuery(queryName, () => fetchData(search, notifyLoad), {
|
||||
enabled: canRead,
|
||||
retry: false,
|
||||
onError(error) {
|
||||
toggleNotification({
|
||||
type: 'warning',
|
||||
message: {
|
||||
id: 'notification.error',
|
||||
message: formatAPIError(error),
|
||||
defaultMessage: 'An error occured',
|
||||
},
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
const handleToggle = () => {
|
||||
setIsModalOpen((prev) => !prev);
|
||||
};
|
||||
|
||||
const deleteAllMutation = useMutation((ids) => deleteData(ids), {
|
||||
async onSuccess() {
|
||||
await queryClient.refetchQueries(queryName);
|
||||
|
||||
// Toggle enabled/ disabled state on the invite button
|
||||
await queryClient.refetchQueries(['ee', 'license-limit-info']);
|
||||
const deleteAllMutation = useMutation(
|
||||
async (ids) => {
|
||||
await post('/admin/users/batch-delete', { ids });
|
||||
},
|
||||
onError(error) {
|
||||
toggleNotification({
|
||||
type: 'warning',
|
||||
message: {
|
||||
id: 'notification.error',
|
||||
message: formatAPIError(error),
|
||||
defaultMessage: 'An error occured',
|
||||
},
|
||||
});
|
||||
},
|
||||
});
|
||||
{
|
||||
async onSuccess() {
|
||||
await refetchAdminUsers();
|
||||
|
||||
// This can be improved but we need to show an something to the user
|
||||
const isLoading =
|
||||
(status !== 'success' && status !== 'error') || (status === 'success' && isFetching);
|
||||
// Toggle enabled/ disabled state on the invite button
|
||||
await queryClient.refetchQueries(EE_LICENSE_LIMIT_QUERY_KEY);
|
||||
},
|
||||
onError(error) {
|
||||
toggleNotification({
|
||||
type: 'warning',
|
||||
message: {
|
||||
id: 'notification.error',
|
||||
message: formatAPIError(error),
|
||||
defaultMessage: 'An error occured',
|
||||
},
|
||||
});
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
return (
|
||||
<Main aria-busy={isLoading}>
|
||||
@ -141,7 +122,8 @@ const ListPage = () => {
|
||||
|
||||
<ContentLayout canRead={canRead}>
|
||||
{!canRead && <NoPermissions />}
|
||||
{status === 'error' && <div>TODO: An error occurred</div>}
|
||||
{/* TODO: Replace error message with something better */}
|
||||
{isError && <div>TODO: An error occurred</div>}
|
||||
{canRead && (
|
||||
<>
|
||||
<DynamicTable
|
||||
@ -150,23 +132,32 @@ const ListPage = () => {
|
||||
onConfirmDeleteAll={deleteAllMutation.mutateAsync}
|
||||
onConfirmDelete={(id) => deleteAllMutation.mutateAsync([id])}
|
||||
headers={headers}
|
||||
rows={data?.results}
|
||||
rows={users}
|
||||
withBulkActions
|
||||
withMainAction={canDelete}
|
||||
>
|
||||
<TableRows
|
||||
canDelete={canDelete}
|
||||
headers={headers}
|
||||
rows={data?.results || []}
|
||||
rows={users}
|
||||
withBulkActions
|
||||
withMainAction={canDelete}
|
||||
/>
|
||||
</DynamicTable>
|
||||
<PaginationFooter pagination={data?.pagination} />
|
||||
|
||||
{pagination && <PaginationFooter pagination={pagination} />}
|
||||
</>
|
||||
)}
|
||||
</ContentLayout>
|
||||
{isModalOpened && <ModalForm onToggle={handleToggle} queryName={queryName} />}
|
||||
{isModalOpened && (
|
||||
<ModalForm
|
||||
onSuccess={async () => {
|
||||
await refetchAdminUsers();
|
||||
await queryClient.refetchQueries(EE_LICENSE_LIMIT_QUERY_KEY);
|
||||
}}
|
||||
onToggle={handleToggle}
|
||||
/>
|
||||
)}
|
||||
</Main>
|
||||
);
|
||||
};
|
||||
|
||||
@ -11,50 +11,49 @@ import Theme from '../../../../../../components/Theme';
|
||||
import ThemeToggleProvider from '../../../../../../components/ThemeToggleProvider';
|
||||
import ListPage from '../index';
|
||||
|
||||
jest.mock('../../../../../../hooks/useAdminUsers', () => ({
|
||||
__esModule: true,
|
||||
useAdminUsers: jest.fn().mockReturnValue({
|
||||
users: [
|
||||
{
|
||||
email: 'soup@strapi.io',
|
||||
firstname: 'soup',
|
||||
id: 1,
|
||||
isActive: true,
|
||||
lastname: 'soupette',
|
||||
roles: [
|
||||
{
|
||||
id: 1,
|
||||
name: 'Super Admin',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
email: 'dummy@strapi.io',
|
||||
firstname: 'dummy',
|
||||
id: 2,
|
||||
isActive: false,
|
||||
lastname: 'dum test',
|
||||
roles: [
|
||||
{
|
||||
id: 1,
|
||||
name: 'Super Admin',
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
name: 'Editor',
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
pagination: { page: 1, pageSize: 10, pageCount: 2, total: 2 },
|
||||
isLoading: false,
|
||||
isError: false,
|
||||
}),
|
||||
}));
|
||||
|
||||
jest.mock('@strapi/helper-plugin', () => ({
|
||||
...jest.requireActual('@strapi/helper-plugin'),
|
||||
getFetchClient: jest.fn(() => ({
|
||||
get: jest.fn().mockReturnValue({
|
||||
data: {
|
||||
data: {
|
||||
pagination: { page: 1, pageSize: 10, pageCount: 2, total: 2 },
|
||||
results: [
|
||||
{
|
||||
email: 'soup@strapi.io',
|
||||
firstname: 'soup',
|
||||
id: 1,
|
||||
isActive: true,
|
||||
lastname: 'soupette',
|
||||
roles: [
|
||||
{
|
||||
id: 1,
|
||||
name: 'Super Admin',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
email: 'dummy@strapi.io',
|
||||
firstname: 'dummy',
|
||||
id: 2,
|
||||
isActive: false,
|
||||
lastname: 'dum test',
|
||||
roles: [
|
||||
{
|
||||
id: 1,
|
||||
name: 'Super Admin',
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
name: 'Editor',
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
}),
|
||||
put: jest.fn(),
|
||||
})),
|
||||
useNotification: jest.fn(),
|
||||
useFocusWhenNavigate: jest.fn(),
|
||||
useRBAC: jest.fn(() => ({
|
||||
|
||||
@ -1,20 +0,0 @@
|
||||
import { getFetchClient } from '@strapi/helper-plugin';
|
||||
|
||||
const fetchData = async (search, notify) => {
|
||||
const { get } = getFetchClient();
|
||||
const {
|
||||
data: { data },
|
||||
} = await get(`/admin/users${search}`);
|
||||
|
||||
notify();
|
||||
|
||||
return data;
|
||||
};
|
||||
|
||||
const deleteData = async (ids) => {
|
||||
const { post } = getFetchClient();
|
||||
|
||||
await post('/admin/users/batch-delete', { ids });
|
||||
};
|
||||
|
||||
export { deleteData, fetchData };
|
||||
@ -2,24 +2,13 @@ import { useQuery } from 'react-query';
|
||||
import { useNotification, useFetchClient } from '@strapi/helper-plugin';
|
||||
import { useLocation } from 'react-router-dom';
|
||||
|
||||
import { useAdminUsers } from '../../../../../../../../admin/src/hooks/useAdminUsers';
|
||||
|
||||
const useAuditLogsData = ({ canReadAuditLogs, canReadUsers }) => {
|
||||
const { get } = useFetchClient();
|
||||
const { search } = useLocation();
|
||||
const toggleNotification = useNotification();
|
||||
|
||||
const fetchAuditLogsPage = async ({ queryKey }) => {
|
||||
const search = queryKey[1];
|
||||
const { data } = await get(`/admin/audit-logs${search}`);
|
||||
|
||||
return data;
|
||||
};
|
||||
|
||||
const fetchAllUsers = async () => {
|
||||
const { data } = await get(`/admin/users`);
|
||||
|
||||
return data;
|
||||
};
|
||||
|
||||
const queryOptions = {
|
||||
keepPreviousData: true,
|
||||
retry: false,
|
||||
@ -27,24 +16,43 @@ const useAuditLogsData = ({ canReadAuditLogs, canReadUsers }) => {
|
||||
onError: (error) => toggleNotification({ type: 'warning', message: error.message }),
|
||||
};
|
||||
|
||||
const {
|
||||
users,
|
||||
isError: isUsersError,
|
||||
isLoading: isLoadingUsers,
|
||||
} = useAdminUsers(
|
||||
{},
|
||||
{
|
||||
...queryOptions,
|
||||
enabled: canReadUsers,
|
||||
staleTime: 2 * (1000 * 60), // 2 minutes
|
||||
}
|
||||
);
|
||||
|
||||
const {
|
||||
data: auditLogs,
|
||||
isLoading,
|
||||
isLoading: isLoadingAuditLogs,
|
||||
isError: isAuditLogsError,
|
||||
} = useQuery(['auditLogs', search], fetchAuditLogsPage, {
|
||||
...queryOptions,
|
||||
enabled: canReadAuditLogs,
|
||||
});
|
||||
} = useQuery(
|
||||
['auditLogs', search],
|
||||
async ({ queryKey }) => {
|
||||
const search = queryKey[1];
|
||||
const { data } = await get(`/admin/audit-logs${search}`);
|
||||
|
||||
const { data: users, isError: isUsersError } = useQuery(['auditLogsUsers'], fetchAllUsers, {
|
||||
...queryOptions,
|
||||
enabled: canReadUsers,
|
||||
staleTime: 2 * (1000 * 60), // 2 minutes
|
||||
});
|
||||
return data;
|
||||
},
|
||||
{
|
||||
...queryOptions,
|
||||
enabled: canReadAuditLogs,
|
||||
}
|
||||
);
|
||||
|
||||
const hasError = isAuditLogsError || isUsersError;
|
||||
|
||||
return { auditLogs, users: users?.data, isLoading, hasError };
|
||||
return {
|
||||
auditLogs,
|
||||
users,
|
||||
isLoading: isLoadingUsers || isLoadingAuditLogs,
|
||||
hasError: isAuditLogsError || isUsersError,
|
||||
};
|
||||
};
|
||||
|
||||
export default useAuditLogsData;
|
||||
|
||||
@ -1,23 +1,21 @@
|
||||
import getDisplayedFilters from '../utils/getDisplayedFilters';
|
||||
|
||||
const mockUsers = {
|
||||
results: [
|
||||
{
|
||||
id: 1,
|
||||
firstname: 'test',
|
||||
lastname: 'tester',
|
||||
username: null,
|
||||
email: 'test@test.com',
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
firstname: 'test2',
|
||||
lastname: 'tester2',
|
||||
username: null,
|
||||
email: 'test2@test.com',
|
||||
},
|
||||
],
|
||||
};
|
||||
const mockUsers = [
|
||||
{
|
||||
id: 1,
|
||||
firstname: 'test',
|
||||
lastname: 'tester',
|
||||
username: null,
|
||||
email: 'test@test.com',
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
firstname: 'test2',
|
||||
lastname: 'tester2',
|
||||
username: null,
|
||||
email: 'test2@test.com',
|
||||
},
|
||||
];
|
||||
|
||||
describe('Audit Logs getDisplayedFilters', () => {
|
||||
it('should return all filters when canReadUsers is true', () => {
|
||||
|
||||
@ -74,7 +74,7 @@ const getDisplayedFilters = ({ formatMessage, users, canReadUsers }) => {
|
||||
return user.email;
|
||||
};
|
||||
|
||||
const userOptions = users.results.map((user) => {
|
||||
const userOptions = users.map((user) => {
|
||||
return {
|
||||
label: getDisplayNameFromUser(user),
|
||||
// Combobox expects a string value
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user