diff --git a/src/actions/audit-log-actions.js b/src/actions/audit-log-actions.js index 0b9cb3d9a..1c56c90d0 100644 --- a/src/actions/audit-log-actions.js +++ b/src/actions/audit-log-actions.js @@ -19,11 +19,7 @@ import { authErrorHandler, escapeFilterValue } from "openstack-uicore-foundation/lib/utils/actions"; -import { - getAccessTokenSafely, - isNumericString, - parseDateRangeFilter -} from "../utils/methods"; +import { getAccessTokenSafely, isNumericString } from "../utils/methods"; import { DEFAULT_CURRENT_PAGE, DEFAULT_ORDER_DIR } from "../utils/constants"; export const CLEAR_LOG_PARAMS = "CLEAR_LOG_PARAMS"; @@ -32,22 +28,8 @@ export const RECEIVE_LOG = "RECEIVE_LOG"; const DEFAULT_PER_PAGE_AUDIT_LOG = 100; -const parseFilters = (filters, term = null) => { - const filter = []; - - if (filters.created_date_filter) { - parseDateRangeFilter(filter, filters.created_date_filter, "created"); - } - - if ( - filters.hasOwnProperty("user_id_filter") && - Array.isArray(filters.user_id_filter) && - filters.user_id_filter.length > 0 - ) { - filter.push( - `user_id==${filters.user_id_filter.map((t) => t.id).join("||")}` - ); - } +const parseFilters = (filters = [], term = null) => { + const filter = Array.isArray(filters) ? [...filters] : []; if (term) { const escapedTerm = escapeFilterValue(term); @@ -73,7 +55,7 @@ export const getAuditLog = perPage = DEFAULT_PER_PAGE_AUDIT_LOG, order = null, orderDir = DEFAULT_ORDER_DIR, - filters = {} + filters = [] ) => async (dispatch, getState) => { const { currentSummitState } = getState(); diff --git a/src/components/audit-logs/index.js b/src/components/audit-logs/index.js index 81cb2a9d6..1f7f53fcd 100644 --- a/src/components/audit-logs/index.js +++ b/src/components/audit-logs/index.js @@ -1,105 +1,118 @@ import React, { useEffect, useState } from "react"; -import FreeTextSearch from "openstack-uicore-foundation/lib/components/free-text-search" -import Table from "openstack-uicore-foundation/lib/components/table" -import Dropdown from "openstack-uicore-foundation/lib/components/inputs/dropdown" -import MemberInput from "openstack-uicore-foundation/lib/components/inputs/member-input" -import DateTimePicker from "openstack-uicore-foundation/lib/components/inputs/datetimepicker"; +import { Grid2 } from "@mui/material"; +import SearchInput from "openstack-uicore-foundation/lib/components/mui/search-input"; +import MuiTable from "openstack-uicore-foundation/lib/components/mui/table"; +import { + GridFilter, + useGridFilter, + OPERATORS +} from "openstack-uicore-foundation/lib/components/mui/grid-filter"; +import { queryMembers } from "openstack-uicore-foundation/lib/utils/query-actions"; +import CustomAlert from "openstack-uicore-foundation/lib/components/mui/custom-alert"; import T from "i18n-react"; -import { epochToMomentTimeZone } from "openstack-uicore-foundation/lib/utils/methods"; -import { Pagination } from "react-bootstrap"; import { connect } from "react-redux"; import { clearAuditLogParams as clearAuditLogParamsAction, getAuditLog as getAuditLogAction } from "../../actions/audit-log-actions"; -import { - DATE_FILTER_ARRAY_SIZE, - DEFAULT_CURRENT_PAGE -} from "../../utils/constants"; +import { DEFAULT_CURRENT_PAGE } from "../../utils/constants"; + +const FILTER_ID = "audit_log_list"; + +const getCriterias = () => [ + { + key: "user_id", + label: T.translate("audit_log.placeholders.user_id"), + operators: [OPERATORS.IS], + values: { + type: "asyncSelect", + props: { + queryFunction: queryMembers, + formatOption: (m) => ({ + value: m.id, + label: `${m.first_name} ${m.last_name} (${m.email})` + }), + multiple: true + } + }, + customParser: (f) => [`user_id==${f.value.map((s) => s.value).join("||")}`] + }, + { + key: "created", + label: T.translate("audit_log.date"), + operators: [OPERATORS.BEFORE, OPERATORS.AFTER], + values: { + type: "datetime", + props: { + mode: "datetime" + } + } + } +]; const AuditLogs = ({ entityFilter = [], - currentSummit, term, logEntries, perPage, - lastPage, currentPage, + totalLogEntries, order, orderDir, columns, getAuditLog, - clearAuditLogParams, - filters + clearAuditLogParams }) => { - const [page, setPage] = useState(currentPage); const [searchTerm, setSearchTerm] = useState(term); - const defaultFilters = { - user_id_filter: [], - created_date_filter: Array(DATE_FILTER_ARRAY_SIZE).fill(null) - }; - - const [enabledFilters, setEnabledFilters] = useState( - Object.keys(filters).filter((e) => - Array.isArray(filters[e]) - ? filters[e]?.some((a) => a !== null) - : filters[e]?.length > 0 - ) - ); - const [auditLogFilters, setAuditLogFilters] = useState({ - ...defaultFilters, - ...filters - }); - - const filtersDdl = [ - { label: "Created", value: "created_date_filter" }, - { label: "Member", value: "user_id_filter" } - ]; - - const auditLogTableOptions = { - sortCol: order, - sortDir: orderDir, - actions: {} - }; + const { parsedFilter, resetFilters } = useGridFilter(FILTER_ID); + const userTimeZone = new Intl.DateTimeFormat(undefined, { + timeZoneName: "long" + }) + .formatToParts(new Date()) + .find((part) => part.type === "timeZoneName").value; const auditLogColumns = [ { columnKey: "created", - value: T.translate("audit_log.date"), + header: T.translate("audit_log.date"), sortable: true }, { - columnKey: "action_description", - value: T.translate("audit_log.action"), - sortable: false + columnKey: "action", + header: T.translate("audit_log.action"), + sortable: false, + width: 600, + truncateText: true }, { columnKey: "event_id", - value: T.translate("audit_log.event"), + header: T.translate("audit_log.event"), sortable: true }, - { columnKey: "user", value: T.translate("audit_log.user"), sortable: false } + { + columnKey: "user", + header: T.translate("audit_log.user"), + sortable: false + } ]; const showColumns = columns ? auditLogColumns.filter((c) => columns.includes(c.columnKey)) : auditLogColumns; - const handleSort = (_index, key, dir) => { - setPage(1); + const handleSort = (key, dir) => { getAuditLog( entityFilter, searchTerm, - 1, + DEFAULT_CURRENT_PAGE, perPage, key, dir, - auditLogFilters + parsedFilter ); }; const handlePageChange = (newPage) => { - setPage(newPage); getAuditLog( entityFilter, searchTerm, @@ -107,87 +120,35 @@ const AuditLogs = ({ perPage, order, orderDir, - auditLogFilters + parsedFilter ); }; - const handleSearch = (newTerm) => { - setSearchTerm(newTerm); - setPage(1); + const handlePerPageChange = (newPerPage) => { getAuditLog( entityFilter, - newTerm, - 1, - perPage, + searchTerm, + DEFAULT_CURRENT_PAGE, + newPerPage, order, orderDir, - auditLogFilters + parsedFilter ); }; - const handleDDLSortByLabel = (ddlArray) => - ddlArray.sort((a, b) => a.label.localeCompare(b.label)); - - const handleFiltersChange = (ev) => { - const { value } = ev.target; - if (value.length < enabledFilters.length) { - if (value.length === 0) { - setEnabledFilters(value); - setAuditLogFilters(defaultFilters); - } else { - const removedFilter = enabledFilters.filter( - (e) => !value.includes(e) - )[0]; - const defaultValue = Array.isArray(auditLogFilters[removedFilter]) - ? [] - : ""; - const newEventFilters = { - ...auditLogFilters, - [removedFilter]: defaultValue - }; - setEnabledFilters(value); - setAuditLogFilters(newEventFilters); - } - } else { - setEnabledFilters(value); - } - }; - - const handleChangeDateFilter = (ev, lastDate) => { - const { value, id } = ev.target; - const newDateFilter = auditLogFilters[id]; - - setAuditLogFilters({ - ...auditLogFilters, - [id]: lastDate - ? [newDateFilter[0], value.unix()] - : [value.unix(), newDateFilter[1]] - }); - }; - - const handleAuditLogFilterChange = (ev) => { - const { value, id } = ev.target; - setAuditLogFilters({ ...auditLogFilters, [id]: value }); - }; - - const handleApplyAuditLogFilters = () => { - setPage(1); + const handleSearch = (newTerm) => { + setSearchTerm(newTerm); getAuditLog( entityFilter, - searchTerm, - 1, + newTerm, + DEFAULT_CURRENT_PAGE, perPage, order, orderDir, - auditLogFilters + parsedFilter ); }; - const getUserFieldValue = (member) => - `${member.first_name ?? ""} ${member.last_name ?? ""} (${ - member.email ?? member.id - })`; - useEffect(() => { getAuditLog( entityFilter, @@ -196,132 +157,68 @@ const AuditLogs = ({ perPage, order, orderDir, - filters + parsedFilter ); - - return () => { + }, [parsedFilter.join(",")]); + + // AuditLogs is reused in different contexts (the standalone audit log + // page, an event's edit form, a ticket's edit page) sharing one Redux- + // backed FILTER_ID, so a filter applied in one context must not leak into + // another mount — reset it along with the log params on unmount. + useEffect( + () => () => { clearAuditLogParams(); - }; - }, []); + resetFilters(); + }, + [] + ); + + const tableOptions = { + sortCol: order, + sortDir: orderDir + }; return ( <> -