diff --git a/locale/en.json b/locale/en.json index 003b5d9e0..bd3aae8c3 100644 --- a/locale/en.json +++ b/locale/en.json @@ -1256,5 +1256,9 @@ "CODEX_ID" : "Codex ID", "SPECIES_CONSISTENT_ERROR" : "Selected Codex ID does not match the species.", "CODEX_ID_CREATION" : "Codex ID Creation", - "CODEX_ID_CREATION_DESCRIPTION" : "Codex ID will be assigned based on the species." + "CODEX_ID_CREATION_DESCRIPTION" : "Codex ID will be assigned based on the species.", + "CHANGE_LOG" : "Change Log", + "TIME_CHANGE_OCCURRED" : "Time Change occurred", + "MANAGE_REQUESTS" : "Manage Requests", + "NO_SEARCH_RESULT" : "Your search did not match any records." } diff --git a/src/AuthenticatedSwitch.jsx b/src/AuthenticatedSwitch.jsx index f2ea5e735..ec70c46fc 100644 --- a/src/AuthenticatedSwitch.jsx +++ b/src/AuthenticatedSwitch.jsx @@ -48,6 +48,7 @@ import Footer from './components/Footer'; import { defaultCrossfadeDuration } from './constants/defaults'; import Requests from './pages/setup/Requests'; import SpeciesManagement from './pages/fieldManagement/SpeciesManagement'; +import ChangeLog from './pages/changeLog/ChangeLog'; export default function AuthenticatedSwitch({ emailNeedsVerification, @@ -132,6 +133,9 @@ export default function AuthenticatedSwitch({ + + + diff --git a/src/constants/queryKeys.js b/src/constants/queryKeys.js index cf9a351e1..93bebf15c 100644 --- a/src/constants/queryKeys.js +++ b/src/constants/queryKeys.js @@ -20,10 +20,6 @@ export default { sageJobs: ['sage', 'jobs'], }; -export function getAuditLogQueryKey(guid) { - return ['auditLog', guid]; -} - export function getEncounterQueryKey(guid) { return ['encounter', guid]; } @@ -103,3 +99,11 @@ export function getSightingFilterQueryKey( ) { return ['sightingFilterSearch', filters, page, rowsPerPage]; } + +export function getAuditLogQueryKey( + filters, + page, + rowsPerPage, +) { + return ['auditLogFilterSearch', filters, page, rowsPerPage]; +} diff --git a/src/models/auditLogs/useFilterAuditLogs.js b/src/models/auditLogs/useFilterAuditLogs.js new file mode 100644 index 000000000..10caae3bb --- /dev/null +++ b/src/models/auditLogs/useFilterAuditLogs.js @@ -0,0 +1,36 @@ +import { get, partition } from 'lodash-es'; + +import useFetch from '../../hooks/useFetch'; +import { getAuditLogQueryKey } from '../../constants/queryKeys'; + +export default function useFilterAuditLogs({ queries, params = {} }) { + + return useFetch({ + method: 'post', + queryKey: getAuditLogQueryKey(queries, params), + url: '/audit_logs/search', + data: queries, + params: { + limit: 20, + offset: 0, + sort: 'created', + reverse: false, + ...params, + }, + dataAccessor: result => { + const resultCountString = get(result, [ + 'data', + 'headers', + 'x-total-count', + ]); + return { + resultCount: parseInt(resultCountString, 10), + results: get(result, ['data', 'data']), + statusCode: get(result, ['error', 'response', 'data', 'status']), + }; + }, + queryOptions: { + retry: 2, + }, + }); +} diff --git a/src/models/auditLogs/useGetAuditLogs.js b/src/models/auditLogs/useGetAuditLogs.js index 7c8453304..13e16f6fa 100644 --- a/src/models/auditLogs/useGetAuditLogs.js +++ b/src/models/auditLogs/useGetAuditLogs.js @@ -4,7 +4,7 @@ import useFetch from '../../hooks/useFetch'; export default function useGetAuditLogs(entity_guid) { return useFetch({ queryKey: getAuditLogQueryKey(entity_guid), - url: `/audit_logs/${entity_guid}`, + url: `/audit_logs/${entity_guid}`, queryOptions: { enabled: Boolean(entity_guid), retry: 1, diff --git a/src/pages/changeLog/ChangeLog.jsx b/src/pages/changeLog/ChangeLog.jsx new file mode 100644 index 000000000..a4083cb40 --- /dev/null +++ b/src/pages/changeLog/ChangeLog.jsx @@ -0,0 +1,195 @@ +import React, { useEffect, useState, useMemo } from 'react'; +import Grid from '@material-ui/core/Grid'; + +import useDocumentTitle from '../../hooks/useDocumentTitle'; +import MainColumn from '../../components/MainColumn'; +import Button from '../../components/Button'; +import SettingsBreadcrumbs from '../../components/SettingsBreadcrumbs'; +import Text from '../../components/Text'; +import Link from '../../components/Link'; +import ArrowBackIcon from '@material-ui/icons/ArrowBack'; +import useTheme from '@material-ui/core/styles/useTheme'; +import { useIntl, FormattedMessage } from 'react-intl'; +import DataDisplay from '../../components/dataDisplays/DataDisplay'; +import SearchIcon from '@material-ui/icons/Search'; +import useFilterAuditLogs from '../../models/auditLogs/useFilterAuditLogs'; +import Paginator from '../../components/dataDisplays/Paginator'; +import TextField from '@material-ui/core/TextField'; +import SadScreen from '../../components/SadScreen'; +import LoadingScreen from '../../components/LoadingScreen'; + +export default function ChangeLog() { + + useDocumentTitle('CHANGE_LOG'); + const theme = useTheme(); + const intl = useIntl(); + + const [inputValue, setInputValue] = useState(''); + + const rowsPerPage = 100; + const [searchParams, setSearchParams] = useState({ + limit: rowsPerPage, + offset: 0, + sort: 'created', + reverse: true, + }); + + const [ formFilters, setFormFilters ] = useState( + { + "bool" : { + "filter" : [], + } + } + ); + + const buildFilters = (inputValue) => { + if(inputValue.trim() !== '') { + setFormFilters( + { + "bool" : { + "filter" : [ + { + "match": { + "item_guid": inputValue + } + } + ] + } + } + ) + } else { + setFormFilters( + { + "bool" : { + "filter" : [] + } + } + ) + } + } + + const { data : searchedData, loading } = useFilterAuditLogs({ + queries: formFilters, + params: searchParams, + }); + + const buildAndSortTableRows = (data) => { + return data?.map((row) => { + return { + id: row.guid, + time: new Date(row.created).toLocaleString(), + message: `MODULE NAME: ${row.module_name}, ITEM GUID: ${row.item_guid}, AUDIT TYPE: ${row.audit_type}, DETAILS: ${row.message}`, + } + })?.sort((a, b) => new Date(b.time) - new Date(a.time)); + } + + const searchedTableRows = buildAndSortTableRows(searchedData?.results); + const tableColumns = [ + { + name: 'time', + label: intl.formatMessage({ id: 'TIME_CHANGE_OCCURRED' }), + options: { + customBodyRender: labelId => ( + + ), + }, + }, + { + name: 'message', + label: intl.formatMessage({ id: 'MESSAGE' }), + // options: { cellRenderer: cellRendererTypes.capitalizedString }, + }, + ]; + + + if(loading) return + if(searchedData?.statusCode === 403) return + + return ( + + + + {} + + + + + +
+ + +
+ + setInputValue(e.target.value)} + onKeyDown={event => { + if (event.key === 'Enter') { + buildFilters(inputValue) + } + }} + style={{ width: 420 }} + /> + +
+ +
+ + +
+
+ ); +} diff --git a/src/pages/controlPanel/ControlPanel.jsx b/src/pages/controlPanel/ControlPanel.jsx index 590854123..5e6ae38e4 100644 --- a/src/pages/controlPanel/ControlPanel.jsx +++ b/src/pages/controlPanel/ControlPanel.jsx @@ -11,6 +11,8 @@ import SiteStatusIcon from '@material-ui/icons/Speed'; import UserManagementIcon from '@material-ui/icons/People'; import AdministrationIcon from '@material-ui/icons/Gavel'; import GroupWorkIcon from '@material-ui/icons/GroupWork'; +import AssignmentOutlinedIcon from '@material-ui/icons/AssignmentOutlined'; +import ListAltIcon from '@material-ui/icons/ListAlt'; import useDocumentTitle from '../../hooks/useDocumentTitle'; import useGetMe from '../../models/users/useGetMe'; @@ -88,6 +90,15 @@ const adminPages = [ 'is_contributor', ], }, + { + icon: ListAltIcon, + name: 'change-log', + labelId: 'CHANGE_LOG', + href: '/settings/changelog', + roles: [ + 'is_admin', + ], + }, ]; export default function ControlPanel() { diff --git a/src/pages/match/MatchSighting.jsx b/src/pages/match/MatchSighting.jsx index 5c1987a67..63a19a2de 100644 --- a/src/pages/match/MatchSighting.jsx +++ b/src/pages/match/MatchSighting.jsx @@ -135,7 +135,6 @@ export default function MatchSighting() { ['algorithms', 'hotspotter_nosv', 'scores_by_individual'], [] ); const annotation = scoresByIndividual.find((score) => score.guid === selectedMatchCandidateGuid); const heatmapUrl = annotation?.heatmap_src; - console.log(heatmapUrl); setHeatMapUrl(heatmapUrl); const checkHeatMap = async () => { try { diff --git a/src/pages/setup/Requests.jsx b/src/pages/setup/Requests.jsx index 7f5007fba..3fa7d59b0 100644 --- a/src/pages/setup/Requests.jsx +++ b/src/pages/setup/Requests.jsx @@ -54,7 +54,7 @@ export default function Requests() { justifyContent:'center', alignItems: 'center', }}> -

Manage Requests

+