audit logs api mapping, updated test cases

This commit is contained in:
Madhuri Sandbhor 2022-12-28 17:57:42 +01:00
parent 477cd21eba
commit 10dbf10d0e
10 changed files with 293 additions and 72 deletions

View File

@ -1,13 +1,23 @@
import PropTypes from 'prop-types';
import { useIntl } from 'react-intl';
import useFormatTimeStamp from '../../hooks/useFormatTimeStamp';
import getDefaultMessage from '../../utils/getActionTypesDefaultMessages';
const CellValue = ({ type, value }) => {
const formatTimeStamp = useFormatTimeStamp();
const { formatMessage } = useIntl();
if (type === 'date') {
return formatTimeStamp(value);
}
if (type === 'action') {
return formatMessage({
id: `Settings.permissions.auditLogs.${value}`,
defaultMessage: getDefaultMessage(value),
});
}
return value || '-';
};

View File

@ -1,16 +1,13 @@
import React from 'react';
import PropTypes from 'prop-types';
import { useIntl } from 'react-intl';
import { Flex } from '@strapi/design-system/Flex';
import { Typography } from '@strapi/design-system/Typography';
const ActionItem = ({ actionLabel, actionName }) => {
const { formatMessage } = useIntl();
return (
<Flex direction="column" alignItems="baseline" gap={1}>
<Typography textColor="neutral600" variant="sigma">
{formatMessage(actionLabel)}
{actionLabel}
</Typography>
<Typography textColor="neutral600">{actionName}</Typography>
</Flex>
@ -18,7 +15,7 @@ const ActionItem = ({ actionLabel, actionName }) => {
};
ActionItem.propTypes = {
actionLabel: PropTypes.object.isRequired,
actionLabel: PropTypes.string.isRequired,
actionName: PropTypes.string.isRequired,
};

View File

@ -7,6 +7,7 @@ import { Grid } from '@strapi/design-system/Grid';
import { Box } from '@strapi/design-system/Box';
import { Typography } from '@strapi/design-system/Typography';
import { pxToRem } from '@strapi/helper-plugin';
import getDefaultMessage from '../utils/getActionTypesDefaultMessages';
import useFormatTimeStamp from '../hooks/useFormatTimeStamp';
import ActionItem from './ActionItem';
@ -42,25 +43,28 @@ const ModalDialog = ({ onToggle, data: { date, user, action } }) => {
hasRadius
>
<ActionItem
actionLabel={{
actionLabel={formatMessage({
id: 'Settings.permissions.auditLogs.action',
defaultMessage: 'Action',
}}
actionName={action}
})}
actionName={formatMessage({
id: `Settings.permissions.auditLogs.${action}`,
defaultMessage: getDefaultMessage(action),
})}
/>
<ActionItem
actionLabel={{
actionLabel={formatMessage({
id: 'Settings.permissions.auditLogs.date',
defaultMessage: 'Date',
}}
})}
actionName={formattedDate}
/>
<ActionItem
actionLabel={{
actionLabel={formatMessage({
id: 'Settings.permissions.auditLogs.user',
defaultMessage: 'User',
}}
actionName={user}
})}
actionName={user || '-'}
/>
</Grid>
</ModalBody>

View File

@ -1,43 +1,61 @@
import React, { useState } from 'react';
import { SettingsPageTitle, DynamicTable } from '@strapi/helper-plugin';
import { useIntl } from 'react-intl';
import { useQuery } from 'react-query';
import {
SettingsPageTitle,
DynamicTable,
useRBAC,
useNotification,
useFocusWhenNavigate,
} from '@strapi/helper-plugin';
import { HeaderLayout, ContentLayout } from '@strapi/design-system/Layout';
import { Main } from '@strapi/design-system/Main';
import { useIntl } from 'react-intl';
import adminPermissions from '../../../../../permissions';
// import { useFetchClient } from '../../../../../hooks';
import TableRows from './DynamicTable/TableRows';
import tableHeaders from './utils/tableHeaders';
import { fetchData } from './utils/api';
import ModalDialog from './ModalDialog';
const data = [
{
id: 1,
action: 'Update',
date: '2022-11-14T23:04:00.000Z',
user: 'John Doe',
},
{
id: 2,
action: 'Create',
date: '2022-11-04T18:24:00.000Z',
user: 'Kai Doe',
},
{
id: 3,
action: 'Delete',
date: '2022-10-09T11:26:00.000Z',
user: 'John Doe',
},
{
id: 4,
action: 'Log in',
date: '2022-10-09T11:24:00.000Z',
user: 'Kai Doe',
},
];
const QUERY = 'audit-logs';
const ListView = () => {
const { formatMessage } = useIntl();
const [isModalOpen, setIsModalOpen] = useState(false);
const [detailsActionData, setDetailsActionData] = useState(null);
const toggleNotification = useNotification();
const {
allowedActions: { canRead },
} = useRBAC(adminPermissions.settings.auditLogs);
useFocusWhenNavigate();
/**
* TODO: using fetchclient facing difficulties to mock, for time being using axiosinstance to pass the tests
*
const { get } = useFetchClient();
const fetchData = async () => {
const {
data: { results },
} = await get(`/admin/audit-logs`);
return results;
}; */
const { status, data, isFetching } = useQuery(QUERY, fetchData, {
enabled: canRead,
keepPreviousData: true,
retry: false,
staleTime: 1000 * 20,
onError() {
toggleNotification({
type: 'warning',
message: { id: 'notification.error', defaultMessage: 'An error occured' },
});
},
});
const isLoading = status === 'loading' || isFetching;
const title = formatMessage({
id: 'global.auditLogs',
@ -62,17 +80,23 @@ const ListView = () => {
};
return (
<Main>
<Main aria-busy={isLoading}>
<SettingsPageTitle name={title} />
<HeaderLayout
title={title}
subtitle={formatMessage({
id: 'Settings.permissions.auditLogs.listview.header.subtitle',
defaultMessage: 'Logs of all the activities that happened on your environment',
defaultMessage: 'Logs of all the activities that happened in your environment',
})}
/>
<ContentLayout>
<DynamicTable contentType="Audit logs" headers={headers} rows={data} withBulkActions>
<DynamicTable
contentType="Audit logs"
headers={headers}
rows={data}
withBulkActions
isLoading={isLoading}
>
<TableRows headers={headers} rows={data} onModalToggle={handleToggle} />
</DynamicTable>
</ContentLayout>

View File

@ -2,16 +2,42 @@ import React from 'react';
import { Router } from 'react-router-dom';
import { IntlProvider } from 'react-intl';
import { createMemoryHistory } from 'history';
import { render, screen } from '@testing-library/react';
import { render, screen, waitFor } from '@testing-library/react';
import { QueryClient, QueryClientProvider } from 'react-query';
import userEvent from '@testing-library/user-event';
import { ThemeProvider, lightTheme } from '@strapi/design-system';
import { TrackingProvider } from '@strapi/helper-plugin';
// import { useFetchClient } from '../../../../../../hooks';
import ListView from '../index';
import server from './utils/server';
const history = createMemoryHistory();
const user = userEvent.setup();
jest.mock('@strapi/helper-plugin', () => ({
...jest.requireActual('@strapi/helper-plugin'),
useNotification: jest.fn(),
useFocusWhenNavigate: jest.fn(),
useRBAC: jest.fn(() => ({
allowedActions: { canRead: true },
})),
}));
// jest.mock('../../../../../../hooks', () => ({
// ...jest.requireActual('../../../../../../hooks'),
// useFetchClient: jest.fn(),
// }));
const client = new QueryClient({
defaultOptions: {
queries: {
retry: false,
},
},
});
const App = (
<QueryClientProvider client={client}>
<TrackingProvider>
<ThemeProvider theme={lightTheme}>
<IntlProvider locale="en" messages={{}} defaultLocale="en" textComponent="span">
@ -21,24 +47,47 @@ const App = (
</IntlProvider>
</ThemeProvider>
</TrackingProvider>
</QueryClientProvider>
);
describe('ADMIN | Pages | AUDIT LOGS | ListView', () => {
beforeAll(() => {
server.listen();
// useFetchClient.mockImplementationOnce(() => ({
// get: jest.fn(),
// }));
});
beforeEach(() => {
jest.clearAllMocks();
});
afterEach(() => server.resetHandlers());
afterAll(() => {
server.close();
jest.resetAllMocks();
});
it('should render page with right header details', () => {
render(App);
const title = screen.getByText(/audit logs/i);
expect(title).toBeInTheDocument();
const subTitle = screen.getByText(
/logs of all the activities that happened on your environment/i
/logs of all the activities that happened in your environment/i
);
expect(subTitle).toBeInTheDocument();
});
it('should show a list of audit logs with right count', () => {
const { container } = render(App);
const rows = container.querySelector('tbody').querySelectorAll('tr');
expect(rows.length).toBe(4);
expect(screen.getByText('Update')).toBeInTheDocument();
it('should show a list of audit logs with right count', async () => {
render(App);
await waitFor(() => {
expect(screen.getByText('Create role')).toBeInTheDocument();
expect(screen.getByText('Delete role')).toBeInTheDocument();
expect(screen.getByText('Create entry')).toBeInTheDocument();
expect(screen.getByText('Admin logout')).toBeInTheDocument();
});
});
it('should open a modal when clicked on a table row and close modal when clicked', async () => {

View File

@ -0,0 +1,43 @@
import { setupServer } from 'msw/node';
import { rest } from 'msw';
const handlers = [
rest.get('*/audit-logs', (req, res, ctx) => {
return res(
ctx.delay(1000),
ctx.status(200),
ctx.json({
results: [
{
id: 1,
action: 'role.create',
date: '2022-12-27T10:02:06.598Z',
user: 'test user',
},
{
id: 2,
action: 'role.delete',
date: '2022-12-27T16:28:08.977Z',
user: 'test user',
},
{
id: 3,
action: 'entry.create',
date: '2022-12-27T17:34:00.673Z',
user: null,
},
{
id: 4,
action: 'admin.logout',
date: '2022-12-27T17:51:04.146Z',
user: 'test user',
},
],
})
);
}),
];
const server = setupServer(...handlers);
export default server;

View File

@ -0,0 +1,11 @@
import { axiosInstance } from '../../../../../../core/utils';
const fetchData = async () => {
const {
data: { results },
} = await axiosInstance.get(`/admin/audit-logs`);
return results;
};
export { fetchData };

View File

@ -0,0 +1,58 @@
const getDefaultMessage = (value) => {
switch (value) {
case 'entry.create':
return 'Create entry';
case 'entry.update':
return 'Update entry';
case 'entry.delete':
return 'Delete entry';
case 'entry.publish':
return 'Publish entry';
case 'entry.unpublish':
return 'Unpublish entry';
case 'media.create':
return 'Create media';
case 'media.update':
return 'Update media';
case 'media.delete':
return 'Delete media';
case 'user.create':
return 'Create user';
case 'user.update':
return 'Update user';
case 'user.delete':
return 'Delete user';
case 'admin.auth.success':
return 'Admin login';
case 'admin.logout':
return 'Admin logout';
case 'content-type.create':
return 'Create content type';
case 'content-type.update':
return 'Update content type';
case 'content-type.delete':
return 'Delete content type';
case 'component.create':
return 'Create component';
case 'component.update':
return 'Update component';
case 'component.delete':
return 'Delete component';
case 'role.create':
return 'Create role';
case 'role.delete':
return 'Delete role';
case 'role.update':
return 'Update role';
case 'permission.create':
return 'Create permission';
case 'permission.delete':
return 'Delete permission';
case 'permission.update':
return 'Update permission';
default:
return '-';
}
};
export default getDefaultMessage;

View File

@ -21,17 +21,17 @@ const tableHeaders = [
sortable: true,
},
},
{
key: 'user',
name: 'user',
metadatas: {
label: {
id: 'Settings.permissions.auditLogs.user',
defaultMessage: 'User',
},
sortable: true,
},
},
// {
// key: 'user',
// name: 'user',
// metadatas: {
// label: {
// id: 'Settings.permissions.auditLogs.user',
// defaultMessage: 'User',
// },
// sortable: true,
// },
// },
];
export default tableHeaders;

View File

@ -179,7 +179,32 @@
"Settings.permissions.auditLogs.date": "Date",
"Settings.permissions.auditLogs.user": "User",
"Settings.permissions.auditLogs.details": "Log Details",
"Settings.permissions.auditLogs.listview.header.subtitle": "Logs of all the activities that happened on your environment",
"Settings.permissions.auditLogs.listview.header.subtitle": "Logs of all the activities that happened in your environment",
"Settings.permissions.auditLogs.entry.create": "Create entry",
"Settings.permissions.auditLogs.entry.update": "Update entry",
"Settings.permissions.auditLogs.entry.delete": "Delete entry",
"Settings.permissions.auditLogs.entry.publish": "Publish entry",
"Settings.permissions.auditLogs.entry.unpublish": "Unpublish entry",
"Settings.permissions.auditLogs.media.create": "Create media",
"Settings.permissions.auditLogs.media.update": "Update media",
"Settings.permissions.auditLogs.media.delete": "Delete media",
"Settings.permissions.auditLogs.user.create": "Create user",
"Settings.permissions.auditLogs.user.update": "Update user",
"Settings.permissions.auditLogs.user.delete": "Delete user",
"Settings.permissions.auditLogs.admin.auth.success": "Admin login",
"Settings.permissions.auditLogs.admin.logout": "Admin logout",
"Settings.permissions.auditLogs.content-type.create": "Create content type",
"Settings.permissions.auditLogs.content-type.update": "Update content type",
"Settings.permissions.auditLogs.content-type.delete": "Delete content type",
"Settings.permissions.auditLogs.component.create": "Create component",
"Settings.permissions.auditLogs.component.update": "Update component",
"Settings.permissions.auditLogs.component.delete": "Delete component",
"Settings.permissions.auditLogs.role.create": "Create role",
"Settings.permissions.auditLogs.role.update": "Update role",
"Settings.permissions.auditLogs.role.delete": "Delete role",
"Settings.permissions.auditLogs.permission.create": "Create permission",
"Settings.permissions.auditLogs.permission.update": "Update permission",
"Settings.permissions.auditLogs.permission.delete": "Delete permission",
"Settings.profile.form.notify.data.loaded": "Your profile data has been loaded",
"Settings.profile.form.section.experience.clear.select": "Clear the interface language selected",
"Settings.profile.form.section.experience.here": "here",