diff --git a/packages/core/admin/admin/src/pages/SettingsPage/pages/Users/ListPage/Filters/index.js b/packages/core/admin/admin/src/pages/SettingsPage/components/Filters/index.js
similarity index 100%
rename from packages/core/admin/admin/src/pages/SettingsPage/pages/Users/ListPage/Filters/index.js
rename to packages/core/admin/admin/src/pages/SettingsPage/components/Filters/index.js
diff --git a/packages/core/admin/admin/src/pages/SettingsPage/pages/AuditLogs/ListView/Filters/ComboboxFilter.js b/packages/core/admin/admin/src/pages/SettingsPage/pages/AuditLogs/ListView/Filters/ComboboxFilter.js
new file mode 100644
index 0000000000..64337693b7
--- /dev/null
+++ b/packages/core/admin/admin/src/pages/SettingsPage/pages/AuditLogs/ListView/Filters/ComboboxFilter.js
@@ -0,0 +1,38 @@
+import React from 'react';
+import PropTypes from 'prop-types';
+import { Combobox, ComboboxOption } from '@strapi/design-system/Combobox';
+
+const ComboboxFilter = ({ value, options, setModifiedData }) => {
+ return (
+ setModifiedData((prev) => ({ ...prev, value }))}
+ >
+ {options.map(({ label, customValue }) => {
+ return (
+
+ {label}
+
+ );
+ })}
+
+ );
+};
+
+ComboboxFilter.defaultProps = {
+ value: null,
+};
+
+ComboboxFilter.propTypes = {
+ value: PropTypes.string,
+ options: PropTypes.arrayOf(
+ PropTypes.shape({
+ label: PropTypes.string.isRequired,
+ customValue: PropTypes.string.isRequired,
+ })
+ ).isRequired,
+ setModifiedData: PropTypes.func.isRequired,
+};
+
+export default ComboboxFilter;
diff --git a/packages/core/admin/admin/src/pages/SettingsPage/pages/Users/ListPage/index.js b/packages/core/admin/admin/src/pages/SettingsPage/pages/Users/ListPage/index.js
index 627aa26776..7c72d2ada1 100644
--- a/packages/core/admin/admin/src/pages/SettingsPage/pages/Users/ListPage/index.js
+++ b/packages/core/admin/admin/src/pages/SettingsPage/pages/Users/ListPage/index.js
@@ -18,7 +18,7 @@ import { useIntl } from 'react-intl';
import { useMutation, useQuery, useQueryClient } from 'react-query';
import adminPermissions from '../../../../../permissions';
import TableRows from './DynamicTable/TableRows';
-import Filters from './Filters';
+import Filters from '../../../components/Filters';
import ModalForm from './ModalForm';
import PaginationFooter from './PaginationFooter';
import { deleteData, fetchData } from './utils/api';
diff --git a/packages/core/admin/admin/src/translations/en.json b/packages/core/admin/admin/src/translations/en.json
index cfb387df99..6716e13f2e 100644
--- a/packages/core/admin/admin/src/translations/en.json
+++ b/packages/core/admin/admin/src/translations/en.json
@@ -185,11 +185,11 @@
"Settings.permissions.auditLogs.details": "Log Details",
"Settings.permissions.auditLogs.payload": "Payload",
"Settings.permissions.auditLogs.listview.header.subtitle": "Logs of all the activities that happened in your environment",
- "Settings.permissions.auditLogs.entry.create": "Create entry ({model})",
- "Settings.permissions.auditLogs.entry.update": "Update entry ({model})",
- "Settings.permissions.auditLogs.entry.delete": "Delete entry ({model})",
- "Settings.permissions.auditLogs.entry.publish": "Publish entry ({model})",
- "Settings.permissions.auditLogs.entry.unpublish": "Unpublish entry ({model})",
+ "Settings.permissions.auditLogs.entry.create": "Create entry {model}",
+ "Settings.permissions.auditLogs.entry.update": "Update entry {model}",
+ "Settings.permissions.auditLogs.entry.delete": "Delete entry {model}",
+ "Settings.permissions.auditLogs.entry.publish": "Publish entry {model}",
+ "Settings.permissions.auditLogs.entry.unpublish": "Unpublish entry {model}",
"Settings.permissions.auditLogs.media.create": "Create media",
"Settings.permissions.auditLogs.media.update": "Update media",
"Settings.permissions.auditLogs.media.delete": "Delete media",
diff --git a/packages/core/admin/ee/admin/pages/SettingsPage/pages/AuditLogs/ListView/TableRows/index.js b/packages/core/admin/ee/admin/pages/SettingsPage/pages/AuditLogs/ListView/TableRows/index.js
index 225aef39db..c23bd89827 100644
--- a/packages/core/admin/ee/admin/pages/SettingsPage/pages/AuditLogs/ListView/TableRows/index.js
+++ b/packages/core/admin/ee/admin/pages/SettingsPage/pages/AuditLogs/ListView/TableRows/index.js
@@ -25,7 +25,7 @@ const TableRows = ({ headers, rows, onOpenModal }) => {
id: `Settings.permissions.auditLogs.${value}`,
defaultMessage: getDefaultMessage(value),
},
- { model }
+ { model: `(${model})` }
);
}
diff --git a/packages/core/admin/ee/admin/pages/SettingsPage/pages/AuditLogs/ListView/hooks/useAuditLogsData.js b/packages/core/admin/ee/admin/pages/SettingsPage/pages/AuditLogs/ListView/hooks/useAuditLogsData.js
new file mode 100644
index 0000000000..c93f137117
--- /dev/null
+++ b/packages/core/admin/ee/admin/pages/SettingsPage/pages/AuditLogs/ListView/hooks/useAuditLogsData.js
@@ -0,0 +1,49 @@
+import { useQueries } from 'react-query';
+import { useNotification, useFetchClient } from '@strapi/helper-plugin';
+import { useLocation } from 'react-router-dom';
+
+const useAuditLogsData = ({ canRead }) => {
+ 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 = {
+ enabled: canRead,
+ keepPreviousData: true,
+ retry: false,
+ staleTime: 1000 * 20,
+ onError() {
+ toggleNotification({
+ type: 'warning',
+ message: { id: 'notification.error', defaultMessage: 'An error occured' },
+ });
+ },
+ };
+
+ const [auditLogsData, userData] = useQueries([
+ { queryKey: ['auditLogs', search], queryFn: fetchAuditLogsPage, ...queryOptions },
+ { queryKey: ['auditLogsUsers'], queryFn: fetchAllUsers, ...queryOptions },
+ ]);
+
+ const { data: users, isLoading: isLoadingUsers } = userData;
+ const { data: auditLogs, isLoadingAuditLogs } = auditLogsData;
+
+ const isLoading = isLoadingAuditLogs || isLoadingUsers;
+
+ return { auditLogs, users: users?.data, isLoading };
+};
+
+export default useAuditLogsData;
diff --git a/packages/core/admin/ee/admin/pages/SettingsPage/pages/AuditLogs/ListView/index.js b/packages/core/admin/ee/admin/pages/SettingsPage/pages/AuditLogs/ListView/index.js
index dba8e591a1..9d364d0f4d 100644
--- a/packages/core/admin/ee/admin/pages/SettingsPage/pages/AuditLogs/ListView/index.js
+++ b/packages/core/admin/ee/admin/pages/SettingsPage/pages/AuditLogs/ListView/index.js
@@ -4,53 +4,54 @@ import {
SettingsPageTitle,
DynamicTable,
useRBAC,
- useNotification,
useFocusWhenNavigate,
- useFetchClient,
useQueryParams,
} from '@strapi/helper-plugin';
-import { HeaderLayout, ContentLayout } from '@strapi/design-system/Layout';
+import { HeaderLayout, ContentLayout, ActionLayout } from '@strapi/design-system/Layout';
import { Main } from '@strapi/design-system/Main';
-import { useLocation } from 'react-router-dom';
-import { useQuery } from 'react-query';
import adminPermissions from '../../../../../../../admin/src/permissions';
import TableRows from './TableRows';
import tableHeaders from './utils/tableHeaders';
import PaginationFooter from './PaginationFooter';
import Modal from './Modal';
+import Filters from '../../../../../../../admin/src/pages/SettingsPage/components/Filters';
+import getDisplayedFilters from './utils/getDisplayedFilters';
+import getDefaultMessage, { actionTypes } from './utils/getActionTypesDefaultMessages';
+import useAuditLogsData from './hooks/useAuditLogsData';
const ListView = () => {
const { formatMessage } = useIntl();
- const toggleNotification = useNotification();
const {
allowedActions: { canRead },
} = useRBAC(adminPermissions.settings.auditLogs);
- const { get } = useFetchClient();
- const { search } = useLocation();
const [{ query }, setQuery] = useQueryParams();
+ const { auditLogs, users, isLoading } = useAuditLogsData({ canRead });
useFocusWhenNavigate();
- const fetchAuditLogsPage = async ({ queryKey }) => {
- const search = queryKey[1];
- const { data } = await get(`/admin/audit-logs${search}`);
-
- return data;
- };
-
- const { data, isLoading } = useQuery(['auditLogs', search], fetchAuditLogsPage, {
- enabled: canRead,
- keepPreviousData: true,
- retry: false,
- staleTime: 1000 * 10,
- onError() {
- toggleNotification({
- type: 'warning',
- message: { id: 'notification.error', defaultMessage: 'An error occured' },
- });
- },
+ const actionOptions = Object.keys(actionTypes).map((action) => {
+ return {
+ label: formatMessage(
+ {
+ id: `Settings.permissions.auditLogs.${action}`,
+ defaultMessage: getDefaultMessage(action),
+ },
+ { model: '' }
+ ),
+ customValue: action,
+ };
});
+ const userOptions = users?.results.map((user) => {
+ return {
+ label: `${user.firstname} ${user.lastname}`,
+ // Combobox expects a string value
+ customValue: user.id.toString(),
+ };
+ });
+
+ const displayedFilters = getDisplayedFilters({ actionOptions, userOptions });
+
const title = formatMessage({
id: 'global.auditLogs',
defaultMessage: 'Audit Logs',
@@ -74,21 +75,22 @@ const ListView = () => {
defaultMessage: 'Logs of all the activities that happened in your environment',
})}
/>
+ } />
setQuery({ id })}
/>
-
+
{query?.id && setQuery({ id: null }, 'remove')} logId={query.id} />}
diff --git a/packages/core/admin/ee/admin/pages/SettingsPage/pages/AuditLogs/ListView/utils/getActionTypesDefaultMessages.js b/packages/core/admin/ee/admin/pages/SettingsPage/pages/AuditLogs/ListView/utils/getActionTypesDefaultMessages.js
index 7539bcec57..22c1808711 100644
--- a/packages/core/admin/ee/admin/pages/SettingsPage/pages/AuditLogs/ListView/utils/getActionTypesDefaultMessages.js
+++ b/packages/core/admin/ee/admin/pages/SettingsPage/pages/AuditLogs/ListView/utils/getActionTypesDefaultMessages.js
@@ -1,9 +1,9 @@
-const actionTypes = {
- 'entry.create': 'Create entry ({model})',
- 'entry.update': 'Update entry ({model})',
- 'entry.delete': 'Delete entry ({model})',
- 'entry.publish': 'Publish entry ({model})',
- 'entry.unpublish': 'Unpublish entry ({model})',
+export const actionTypes = {
+ 'entry.create': 'Create entry {model}',
+ 'entry.update': 'Update entry {model}',
+ 'entry.delete': 'Delete entry {model}',
+ 'entry.publish': 'Publish entry {model}',
+ 'entry.unpublish': 'Unpublish entry {model}',
'media.create': 'Create media',
'media.update': 'Update media',
'media.delete': 'Delete media',
diff --git a/packages/core/admin/ee/admin/pages/SettingsPage/pages/AuditLogs/ListView/utils/getDisplayedFilters.js b/packages/core/admin/ee/admin/pages/SettingsPage/pages/AuditLogs/ListView/utils/getDisplayedFilters.js
new file mode 100644
index 0000000000..5fadfe392c
--- /dev/null
+++ b/packages/core/admin/ee/admin/pages/SettingsPage/pages/AuditLogs/ListView/utils/getDisplayedFilters.js
@@ -0,0 +1,60 @@
+import ComboboxFilter from '../Filters/ComboboxFilter';
+
+const customOperators = [
+ {
+ intlLabel: { id: 'components.FilterOptions.FILTER_TYPES.$eq', defaultMessage: 'is' },
+ value: '$eq',
+ },
+ {
+ intlLabel: { id: 'components.FilterOptions.FILTER_TYPES.$ne', defaultMessage: 'is not' },
+ value: '$ne',
+ },
+];
+
+const getDisplayedFilters = ({ actionOptions, userOptions }) => {
+ return [
+ {
+ name: 'action',
+ metadatas: {
+ label: 'Action',
+ options: actionOptions,
+ customOperators,
+ customInput: ComboboxFilter,
+ },
+ fieldSchema: { type: 'enumeration' },
+ },
+ {
+ name: 'user',
+ metadatas: {
+ label: 'User',
+ options: userOptions,
+ customOperators: [
+ ...customOperators,
+ {
+ intlLabel: {
+ id: 'components.FilterOptions.FILTER_TYPES.$null',
+ defaultMessage: 'is null',
+ },
+ value: '$null',
+ },
+ {
+ intlLabel: {
+ id: 'components.FilterOptions.FILTER_TYPES.$notNull',
+ defaultMessage: 'is not null',
+ },
+ value: '$notNull',
+ },
+ ],
+ customInput: ComboboxFilter,
+ },
+ fieldSchema: { type: 'relation', mainField: { name: 'id', schema: { type: 'integer' } } },
+ },
+ {
+ name: 'date',
+ metadatas: { label: 'Date' },
+ fieldSchema: { type: 'datetime' },
+ },
+ ];
+};
+
+export default getDisplayedFilters;
diff --git a/packages/core/helper-plugin/lib/src/components/FilterListURLQuery/AttributeTag.js b/packages/core/helper-plugin/lib/src/components/FilterListURLQuery/AttributeTag.js
index 53cf633680..3a57c44243 100644
--- a/packages/core/helper-plugin/lib/src/components/FilterListURLQuery/AttributeTag.js
+++ b/packages/core/helper-plugin/lib/src/components/FilterListURLQuery/AttributeTag.js
@@ -42,6 +42,18 @@ const AttributeTag = ({ attribute, filter, onClick, operator, value }) => {
formattedValue = formatNumber(value);
}
+ // Handle custom input
+ if (attribute.metadatas.customInput) {
+ // If options, get the option label
+ if (attribute.metadatas.options) {
+ const selectedOption = attribute.metadatas.options.find((option) => {
+ return option.customValue === value;
+ });
+ // Set the provided option label or fallback to the value from query
+ formattedValue = selectedOption?.label || value;
+ }
+ }
+
const content = `${attribute.metadatas.label || attribute.name} ${formatMessage({
id: `components.FilterOptions.FILTER_TYPES.${operator}`,
defaultMessage: operator,
@@ -60,7 +72,11 @@ AttributeTag.propTypes = {
attribute: PropTypes.shape({
name: PropTypes.string.isRequired,
fieldSchema: PropTypes.object.isRequired,
- metadatas: PropTypes.shape({ label: PropTypes.string.isRequired }).isRequired,
+ metadatas: PropTypes.shape({
+ label: PropTypes.string.isRequired,
+ options: PropTypes.array,
+ customInput: PropTypes.func,
+ }).isRequired,
}).isRequired,
filter: PropTypes.object.isRequired,
onClick: PropTypes.func.isRequired,
diff --git a/packages/core/helper-plugin/lib/src/components/FilterPopoverURLQuery/index.js b/packages/core/helper-plugin/lib/src/components/FilterPopoverURLQuery/index.js
index e90f3fa85f..93484cecf7 100644
--- a/packages/core/helper-plugin/lib/src/components/FilterPopoverURLQuery/index.js
+++ b/packages/core/helper-plugin/lib/src/components/FilterPopoverURLQuery/index.js
@@ -50,7 +50,7 @@ const FilterPopoverURLQuery = ({ displayedFilters, isVisible, onBlur, onToggle,
}
if (type === 'enumeration') {
- filterValue = options[0];
+ filterValue = options && options[0];
}
const filter = getFilterList(nextField)[0].value;
@@ -113,6 +113,8 @@ const FilterPopoverURLQuery = ({ displayedFilters, isVisible, onBlur, onToggle,
const appliedFilter = displayedFilters.find((filter) => filter.name === modifiedData.name);
const operator = modifiedData.filter;
+ const filterList = appliedFilter.metadatas.customOperators || getFilterList(appliedFilter);
+ const CustomInput = appliedFilter.metadatas.customInput;
return (
@@ -150,7 +152,7 @@ const FilterPopoverURLQuery = ({ displayedFilters, isVisible, onBlur, onToggle,
value={modifiedData.filter}
onChange={handleChangeOperator}
>
- {getFilterList(appliedFilter).map((option) => {
+ {filterList.map((option) => {
return (