From 0bfba306bf43d4e2de8d2613feb7aadcc6f13cb8 Mon Sep 17 00:00:00 2001 From: DaneEveritt Date: Sun, 5 Jun 2022 19:23:25 -0400 Subject: [PATCH] Add filtering support for activity logs --- resources/scripts/api/account/activity.ts | 11 +- resources/scripts/api/http.ts | 4 +- .../activity/ActivityLogContainer.tsx | 132 ++++++++++++------ 3 files changed, 99 insertions(+), 48 deletions(-) diff --git a/resources/scripts/api/account/activity.ts b/resources/scripts/api/account/activity.ts index 24547a849..7746c8a49 100644 --- a/resources/scripts/api/account/activity.ts +++ b/resources/scripts/api/account/activity.ts @@ -2,18 +2,19 @@ import useUserSWRContentKey from '@/plugins/useUserSWRContentKey'; import useSWR, { ConfigInterface, responseInterface } from 'swr'; import { ActivityLog, Transformers } from '@definitions/user'; import { AxiosError } from 'axios'; -import http, { PaginatedResult } from '@/api/http'; +import http, { PaginatedResult, QueryBuilderParams, withQueryBuilderParams } from '@/api/http'; import { toPaginatedSet } from '@definitions/helpers'; -const useActivityLogs = (page = 1, config?: ConfigInterface, AxiosError>): responseInterface, AxiosError> => { - const key = useUserSWRContentKey([ 'account', 'activity', page.toString() ]); +export type ActivityLogFilters = QueryBuilderParams<'ip' | 'event', 'timestamp'>; + +const useActivityLogs = (filters?: ActivityLogFilters, config?: ConfigInterface, AxiosError>): responseInterface, AxiosError> => { + const key = useUserSWRContentKey([ 'account', 'activity', JSON.stringify(filters) ]); return useSWR>(key, async () => { const { data } = await http.get('/api/client/account/activity', { params: { + ...withQueryBuilderParams(filters), include: [ 'actor' ], - sort: '-timestamp', - page: page, }, }); diff --git a/resources/scripts/api/http.ts b/resources/scripts/api/http.ts index 1ba5f7bbf..2dc54a606 100644 --- a/resources/scripts/api/http.ts +++ b/resources/scripts/api/http.ts @@ -117,6 +117,7 @@ export function getPaginationSet (data: any): PaginationDataSet { type QueryBuilderFilterValue = string | number | boolean | null; export interface QueryBuilderParams { + page?: number; filters?: { [K in FilterKeys]?: QueryBuilderFilterValue | Readonly; }; @@ -150,6 +151,7 @@ export const withQueryBuilderParams = (data?: QueryBuilderParams): Record { + const location = useLocation(); const { clearAndAddHttpError } = useFlashKey('account'); - const [ page, setPage ] = useState(1); - const { data, isValidating: _, error } = useActivityLogs(page, { + const [ filters, setFilters ] = useState({ page: 1, sorts: { timestamp: -1 } }); + const { data, isValidating, error } = useActivityLogs(filters, { revalidateOnMount: true, revalidateOnFocus: false, }); + useEffect(() => { + const parsed = new URLSearchParams(location.search); + + setFilters(value => ({ ...value, filters: { ip: parsed.get('ip'), event: parsed.get('event') } })); + }, [ location.search ]); + useEffect(() => { clearAndAddHttpError(error); }, [ error ]); + const queryTo = (params: Record): string => { + const current = new URLSearchParams(location.search); + Object.keys(params).forEach(key => { + current.set(key, params[key]); + }); + + return current.toString(); + }; + return ( -
- {data?.items.map((activity) => ( -
+ setFilters(value => ({ ...value, filters: {} }))} > -
-
- {activity.relationships.actor ? - {'User - : - - } + Clear Filters + +
+ } + {!data && isValidating ? + + : +
+ {data?.items.map((activity) => ( +
+
+
+ {activity.relationships.actor ? + {'User + : + + } +
-
-
-
- {activity.relationships.actor?.username || 'system'} -  —  - - {activity.event} - - {typeof activity.properties.useragent === 'string' && - - +
+
+ {activity.relationships.actor?.username || 'system'} +  —  + + {activity.event} + + {typeof activity.properties.useragent === 'string' && + + + + } +
+
+ + {activity.ip} + +  |  + + + {formatDistanceToNowStrict(activity.timestamp, { addSuffix: true })} + - } -
- {/*

{activity.description || JSON.stringify(activity.properties)}

*/} -
- {activity.ip} -  |  - - - {formatDistanceToNowStrict(activity.timestamp, { addSuffix: true })} - - +
-
- ))} -
- {data && } + ))} +
+ } + {data && setFilters(value => ({ ...value, page }))} + />} ); };