Merge pull request #16816 from strapi/enhancement/use-admin-users

Enhancement: Create useAdminUsers data fetching hook
This commit is contained in:
Gustav Hansen 2023-05-25 12:25:34 +02:00 committed by GitHub
commit aa461fbbc9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 442 additions and 211 deletions

View File

@ -0,0 +1,5 @@
{
"label": "Hooks",
"collapsible": true,
"collapsed": true
}

View 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 /* ... */;
};
```

View File

@ -0,0 +1,5 @@
export const useAdminUsers = jest.fn().mockReturnValue({
users: [],
isLoading: false,
isError: false,
});

View File

@ -0,0 +1 @@
export * from './useAdminUsers';

View File

@ -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);
});
});

View File

@ -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,
};
}

View File

@ -17,7 +17,6 @@ import {
LoadingIndicatorPage, LoadingIndicatorPage,
Link, Link,
} from '@strapi/helper-plugin'; } from '@strapi/helper-plugin';
import { useQuery } from 'react-query';
import { Formik } from 'formik'; import { Formik } from 'formik';
import { import {
Box, Box,
@ -32,11 +31,13 @@ import {
} from '@strapi/design-system'; } from '@strapi/design-system';
import { ArrowLeft, Check } from '@strapi/icons'; import { ArrowLeft, Check } from '@strapi/icons';
import MagicLink from 'ee_else_ce/pages/SettingsPage/pages/Users/components/MagicLink'; import MagicLink from 'ee_else_ce/pages/SettingsPage/pages/Users/components/MagicLink';
import { formatAPIErrors, getFullName } from '../../../../../utils'; import { formatAPIErrors, getFullName } from '../../../../../utils';
import { fetchUser, putUser } from './utils/api'; import { putUser } from './utils/api';
import layout from './utils/layout'; import layout from './utils/layout';
import { editValidation } from '../utils/validations/users'; import { editValidation } from '../utils/validations/users';
import SelectRoles from '../components/SelectRoles'; import SelectRoles from '../components/SelectRoles';
import { useAdminUsers } from '../../../../../hooks/useAdminUsers';
const fieldsToPick = ['email', 'firstname', 'lastname', 'username', 'isActive', 'roles']; const fieldsToPick = ['email', 'firstname', 'lastname', 'username', 'isActive', 'roles'];
@ -51,10 +52,14 @@ const EditPage = ({ canUpdate }) => {
const { lockApp, unlockApp } = useOverlayBlocker(); const { lockApp, unlockApp } = useOverlayBlocker();
useFocusWhenNavigate(); useFocusWhenNavigate();
const { status, data } = useQuery(['user', id], () => fetchUser(id), { const {
retry: false, users: [user],
onError(err) { isLoading,
const status = err.response.status; } = useAdminUsers(
{ id },
{
onError(error) {
const { status } = error.response;
// Redirect the use to the homepage if is not allowed to read // Redirect the use to the homepage if is not allowed to read
if (status === 403) { if (status === 403) {
@ -67,10 +72,15 @@ const EditPage = ({ canUpdate }) => {
}); });
push('/'); push('/');
} } else {
console.log(err.response.status); toggleNotification({
}, type: 'warning',
message: { id: 'notification.error', defaultMessage: 'An error occured' },
}); });
}
},
}
);
const handleSubmit = async (body, actions) => { const handleSubmit = async (body, actions) => {
lockApp(); lockApp();
@ -113,19 +123,18 @@ const EditPage = ({ canUpdate }) => {
unlockApp(); unlockApp();
}; };
const isLoading = status !== 'success';
const headerLabel = isLoading const headerLabel = isLoading
? { id: 'app.containers.Users.EditPage.header.label-loading', defaultMessage: 'Edit user' } ? { id: 'app.containers.Users.EditPage.header.label-loading', defaultMessage: 'Edit user' }
: { id: 'app.containers.Users.EditPage.header.label', defaultMessage: 'Edit {name}' }; : { 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') { if (current === 'roles') {
acc[current] = (data?.roles || []).map(({ id }) => id); acc[current] = (user?.roles || []).map(({ id }) => id);
return acc; return acc;
} }
acc[current] = data?.[current]; acc[current] = user?.[current];
return acc; return acc;
}, {}); }, {});
@ -138,6 +147,7 @@ const EditPage = ({ canUpdate }) => {
if (isLoading) { if (isLoading) {
return ( return (
<Main aria-busy="true"> <Main aria-busy="true">
{/* TODO: translate */}
<SettingsPageTitle name="Users" /> <SettingsPageTitle name="Users" />
<HeaderLayout <HeaderLayout
primaryAction={ primaryAction={
@ -200,9 +210,9 @@ const EditPage = ({ canUpdate }) => {
} }
/> />
<ContentLayout> <ContentLayout>
{data?.registrationToken && ( {user?.registrationToken && (
<Box paddingBottom={6}> <Box paddingBottom={6}>
<MagicLink registrationToken={data.registrationToken} /> <MagicLink registrationToken={user.registrationToken} />
</Box> </Box>
)} )}
<Flex direction="column" alignItems="stretch" gap={7}> <Flex direction="column" alignItems="stretch" gap={7}>

View File

@ -1,12 +1,5 @@
import { getFetchClient } from '@strapi/helper-plugin'; 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 putUser = async (id, body) => {
const { put } = getFetchClient(); const { put } = getFetchClient();
@ -15,4 +8,4 @@ const putUser = async (id, body) => {
return data.data; return data.data;
}; };
export { fetchUser, putUser }; export { putUser };

View File

@ -15,7 +15,6 @@ import {
Flex, Flex,
Typography, Typography,
} from '@strapi/design-system'; } from '@strapi/design-system';
import { Formik } from 'formik'; import { Formik } from 'formik';
import { import {
Form, Form,
@ -24,20 +23,21 @@ import {
useOverlayBlocker, useOverlayBlocker,
useFetchClient, useFetchClient,
} from '@strapi/helper-plugin'; } 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 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 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 MagicLink from 'ee_else_ce/pages/SettingsPage/pages/Users/components/MagicLink';
import SelectRoles from '../../components/SelectRoles'; import SelectRoles from '../../components/SelectRoles';
import layout from './utils/layout'; import layout from './utils/layout';
import schema from './utils/schema'; import schema from './utils/schema';
import stepper from './utils/stepper'; import stepper from './utils/stepper';
const ModalForm = ({ queryName, onToggle }) => { const ModalForm = ({ onSuccess, onToggle }) => {
const [currentStep, setStep] = useState('create'); const [currentStep, setStep] = useState('create');
const [isSubmitting, setIsSubmitting] = useState(false); const [isSubmitting, setIsSubmitting] = useState(false);
const [registrationToken, setRegistrationToken] = useState(null); const [registrationToken, setRegistrationToken] = useState(null);
const queryClient = useQueryClient();
const { formatMessage } = useIntl(); const { formatMessage } = useIntl();
const toggleNotification = useNotification(); const toggleNotification = useNotification();
const { lockApp, unlockApp } = useOverlayBlocker(); const { lockApp, unlockApp } = useOverlayBlocker();
@ -50,8 +50,7 @@ const ModalForm = ({ queryName, onToggle }) => {
async onSuccess({ data }) { async onSuccess({ data }) {
setRegistrationToken(data.data.registrationToken); setRegistrationToken(data.data.registrationToken);
await queryClient.refetchQueries(queryName); await onSuccess();
await queryClient.refetchQueries(['ee', 'license-limit-info']);
goNext(); goNext();
setIsSubmitting(false); setIsSubmitting(false);
@ -216,7 +215,7 @@ const ModalForm = ({ queryName, onToggle }) => {
ModalForm.propTypes = { ModalForm.propTypes = {
onToggle: PropTypes.func.isRequired, onToggle: PropTypes.func.isRequired,
queryName: PropTypes.array.isRequired, onSuccess: PropTypes.func.isRequired,
}; };
export default ModalForm; export default ModalForm;

View File

@ -1,4 +1,5 @@
import React, { useState } from 'react'; import React, { useState } from 'react';
import qs from 'qs';
import { import {
DynamicTable, DynamicTable,
SearchURLQuery, SearchURLQuery,
@ -8,29 +9,28 @@ import {
useFocusWhenNavigate, useFocusWhenNavigate,
NoPermissions, NoPermissions,
useAPIErrorHandler, useAPIErrorHandler,
useFetchClient,
} from '@strapi/helper-plugin'; } from '@strapi/helper-plugin';
import { import { ActionLayout, ContentLayout, HeaderLayout, Main } from '@strapi/design-system';
ActionLayout,
ContentLayout,
HeaderLayout,
Main,
useNotifyAT,
} from '@strapi/design-system';
import { useLocation } from 'react-router-dom'; import { useLocation } from 'react-router-dom';
import { useIntl } from 'react-intl'; 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 CreateAction from 'ee_else_ce/pages/SettingsPage/pages/Users/ListPage/CreateAction';
import useLicenseLimitNotification from 'ee_else_ce/hooks/useLicenseLimitNotification'; import useLicenseLimitNotification from 'ee_else_ce/hooks/useLicenseLimitNotification';
import { useAdminUsers } from '../../../../../hooks/useAdminUsers';
import adminPermissions from '../../../../../permissions'; import adminPermissions from '../../../../../permissions';
import TableRows from './DynamicTable/TableRows'; import TableRows from './DynamicTable/TableRows';
import Filters from '../../../components/Filters'; import Filters from '../../../components/Filters';
import ModalForm from './ModalForm'; import ModalForm from './ModalForm';
import PaginationFooter from './PaginationFooter'; import PaginationFooter from './PaginationFooter';
import { deleteData, fetchData } from './utils/api';
import displayedFilters from './utils/displayedFilters'; import displayedFilters from './utils/displayedFilters';
import tableHeaders from './utils/tableHeaders'; import tableHeaders from './utils/tableHeaders';
const EE_LICENSE_LIMIT_QUERY_KEY = ['ee', 'license-limit-info'];
const ListPage = () => { const ListPage = () => {
const { post } = useFetchClient();
const { formatAPIError } = useAPIErrorHandler(); const { formatAPIError } = useAPIErrorHandler();
const [isModalOpened, setIsModalOpen] = useState(false); const [isModalOpened, setIsModalOpen] = useState(false);
const { const {
@ -42,8 +42,15 @@ const ListPage = () => {
const { search } = useLocation(); const { search } = useLocation();
useFocusWhenNavigate(); useFocusWhenNavigate();
useLicenseLimitNotification(); useLicenseLimitNotification();
const { notifyStatus } = useNotifyAT(); const {
const queryName = ['users', search]; users,
pagination,
isError,
isLoading,
refetchQueries: refetchAdminUsers,
} = useAdminUsers(qs.parse(search, { ignoreQueryPrefix: true }), {
enabled: canRead,
});
const headers = tableHeaders.map((header) => ({ const headers = tableHeaders.map((header) => ({
...header, ...header,
@ -58,43 +65,20 @@ const ListPage = () => {
defaultMessage: 'Users', 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 = () => { const handleToggle = () => {
setIsModalOpen((prev) => !prev); setIsModalOpen((prev) => !prev);
}; };
const deleteAllMutation = useMutation((ids) => deleteData(ids), { const deleteAllMutation = useMutation(
async (ids) => {
await post('/admin/users/batch-delete', { ids });
},
{
async onSuccess() { async onSuccess() {
await queryClient.refetchQueries(queryName); await refetchAdminUsers();
// Toggle enabled/ disabled state on the invite button // Toggle enabled/ disabled state on the invite button
await queryClient.refetchQueries(['ee', 'license-limit-info']); await queryClient.refetchQueries(EE_LICENSE_LIMIT_QUERY_KEY);
}, },
onError(error) { onError(error) {
toggleNotification({ toggleNotification({
@ -106,11 +90,8 @@ const ListPage = () => {
}, },
}); });
}, },
}); }
);
// This can be improved but we need to show an something to the user
const isLoading =
(status !== 'success' && status !== 'error') || (status === 'success' && isFetching);
return ( return (
<Main aria-busy={isLoading}> <Main aria-busy={isLoading}>
@ -141,7 +122,8 @@ const ListPage = () => {
<ContentLayout canRead={canRead}> <ContentLayout canRead={canRead}>
{!canRead && <NoPermissions />} {!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 && ( {canRead && (
<> <>
<DynamicTable <DynamicTable
@ -150,23 +132,32 @@ const ListPage = () => {
onConfirmDeleteAll={deleteAllMutation.mutateAsync} onConfirmDeleteAll={deleteAllMutation.mutateAsync}
onConfirmDelete={(id) => deleteAllMutation.mutateAsync([id])} onConfirmDelete={(id) => deleteAllMutation.mutateAsync([id])}
headers={headers} headers={headers}
rows={data?.results} rows={users}
withBulkActions withBulkActions
withMainAction={canDelete} withMainAction={canDelete}
> >
<TableRows <TableRows
canDelete={canDelete} canDelete={canDelete}
headers={headers} headers={headers}
rows={data?.results || []} rows={users}
withBulkActions withBulkActions
withMainAction={canDelete} withMainAction={canDelete}
/> />
</DynamicTable> </DynamicTable>
<PaginationFooter pagination={data?.pagination} />
{pagination && <PaginationFooter pagination={pagination} />}
</> </>
)} )}
</ContentLayout> </ContentLayout>
{isModalOpened && <ModalForm onToggle={handleToggle} queryName={queryName} />} {isModalOpened && (
<ModalForm
onSuccess={async () => {
await refetchAdminUsers();
await queryClient.refetchQueries(EE_LICENSE_LIMIT_QUERY_KEY);
}}
onToggle={handleToggle}
/>
)}
</Main> </Main>
); );
}; };

View File

@ -11,14 +11,10 @@ import Theme from '../../../../../../components/Theme';
import ThemeToggleProvider from '../../../../../../components/ThemeToggleProvider'; import ThemeToggleProvider from '../../../../../../components/ThemeToggleProvider';
import ListPage from '../index'; import ListPage from '../index';
jest.mock('@strapi/helper-plugin', () => ({ jest.mock('../../../../../../hooks/useAdminUsers', () => ({
...jest.requireActual('@strapi/helper-plugin'), __esModule: true,
getFetchClient: jest.fn(() => ({ useAdminUsers: jest.fn().mockReturnValue({
get: jest.fn().mockReturnValue({ users: [
data: {
data: {
pagination: { page: 1, pageSize: 10, pageCount: 2, total: 2 },
results: [
{ {
email: 'soup@strapi.io', email: 'soup@strapi.io',
firstname: 'soup', firstname: 'soup',
@ -50,11 +46,14 @@ jest.mock('@strapi/helper-plugin', () => ({
], ],
}, },
], ],
}, pagination: { page: 1, pageSize: 10, pageCount: 2, total: 2 },
}, isLoading: false,
isError: false,
}), }),
put: jest.fn(), }));
})),
jest.mock('@strapi/helper-plugin', () => ({
...jest.requireActual('@strapi/helper-plugin'),
useNotification: jest.fn(), useNotification: jest.fn(),
useFocusWhenNavigate: jest.fn(), useFocusWhenNavigate: jest.fn(),
useRBAC: jest.fn(() => ({ useRBAC: jest.fn(() => ({

View File

@ -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 };

View File

@ -2,24 +2,13 @@ import { useQuery } from 'react-query';
import { useNotification, useFetchClient } from '@strapi/helper-plugin'; import { useNotification, useFetchClient } from '@strapi/helper-plugin';
import { useLocation } from 'react-router-dom'; import { useLocation } from 'react-router-dom';
import { useAdminUsers } from '../../../../../../../../admin/src/hooks/useAdminUsers';
const useAuditLogsData = ({ canReadAuditLogs, canReadUsers }) => { const useAuditLogsData = ({ canReadAuditLogs, canReadUsers }) => {
const { get } = useFetchClient(); const { get } = useFetchClient();
const { search } = useLocation(); const { search } = useLocation();
const toggleNotification = useNotification(); 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 = { const queryOptions = {
keepPreviousData: true, keepPreviousData: true,
retry: false, retry: false,
@ -28,23 +17,42 @@ const useAuditLogsData = ({ canReadAuditLogs, canReadUsers }) => {
}; };
const { const {
data: auditLogs, users,
isLoading, isError: isUsersError,
isError: isAuditLogsError, isLoading: isLoadingUsers,
} = useQuery(['auditLogs', search], fetchAuditLogsPage, { } = useAdminUsers(
...queryOptions, {},
enabled: canReadAuditLogs, {
});
const { data: users, isError: isUsersError } = useQuery(['auditLogsUsers'], fetchAllUsers, {
...queryOptions, ...queryOptions,
enabled: canReadUsers, enabled: canReadUsers,
staleTime: 2 * (1000 * 60), // 2 minutes staleTime: 2 * (1000 * 60), // 2 minutes
}); }
);
const hasError = isAuditLogsError || isUsersError; const {
data: auditLogs,
isLoading: isLoadingAuditLogs,
isError: isAuditLogsError,
} = useQuery(
['auditLogs', search],
async ({ queryKey }) => {
const search = queryKey[1];
const { data } = await get(`/admin/audit-logs${search}`);
return { auditLogs, users: users?.data, isLoading, hasError }; return data;
},
{
...queryOptions,
enabled: canReadAuditLogs,
}
);
return {
auditLogs,
users,
isLoading: isLoadingUsers || isLoadingAuditLogs,
hasError: isAuditLogsError || isUsersError,
};
}; };
export default useAuditLogsData; export default useAuditLogsData;

View File

@ -1,7 +1,6 @@
import getDisplayedFilters from '../utils/getDisplayedFilters'; import getDisplayedFilters from '../utils/getDisplayedFilters';
const mockUsers = { const mockUsers = [
results: [
{ {
id: 1, id: 1,
firstname: 'test', firstname: 'test',
@ -16,8 +15,7 @@ const mockUsers = {
username: null, username: null,
email: 'test2@test.com', email: 'test2@test.com',
}, },
], ];
};
describe('Audit Logs getDisplayedFilters', () => { describe('Audit Logs getDisplayedFilters', () => {
it('should return all filters when canReadUsers is true', () => { it('should return all filters when canReadUsers is true', () => {

View File

@ -74,7 +74,7 @@ const getDisplayedFilters = ({ formatMessage, users, canReadUsers }) => {
return user.email; return user.email;
}; };
const userOptions = users.results.map((user) => { const userOptions = users.map((user) => {
return { return {
label: getDisplayNameFromUser(user), label: getDisplayNameFromUser(user),
// Combobox expects a string value // Combobox expects a string value