From 2556bd0cf627221419b68dd2c797fd83a422971a Mon Sep 17 00:00:00 2001 From: Thomas Heartman Date: Tue, 6 Aug 2024 15:11:10 +0200 Subject: [PATCH] feat: Front end filter state management for event search (#7776) This is just the state management part of #7768. Adds a useEventLogSearch hook. All the filters work except for the date filters. They don't work because the query parameters in the API don't match what's here, but an update to the API is coming in a follow-up. It's a little tricky to handle this because the three different event logs should have slightly different filters, which makes making the type checker happy a bit of a pain. However, I'd like to revisit this in a follow-up PR. --- .../events/EventLog/useEventLogSearch.ts | 104 ++++++++++++++++++ 1 file changed, 104 insertions(+) create mode 100644 frontend/src/component/events/EventLog/useEventLogSearch.ts diff --git a/frontend/src/component/events/EventLog/useEventLogSearch.ts b/frontend/src/component/events/EventLog/useEventLogSearch.ts new file mode 100644 index 0000000000..e67148dabf --- /dev/null +++ b/frontend/src/component/events/EventLog/useEventLogSearch.ts @@ -0,0 +1,104 @@ +import { + encodeQueryParams, + NumberParam, + StringParam, + withDefault, +} from 'use-query-params'; +import { DEFAULT_PAGE_LIMIT } from 'hooks/api/getters/useFeatureSearch/useFeatureSearch'; +import { FilterItemParam } from 'utils/serializeQueryParams'; +import { usePersistentTableState } from 'hooks/usePersistentTableState'; +import mapValues from 'lodash.mapvalues'; +import { useEventSearch } from 'hooks/api/getters/useEventSearch/useEventSearch'; +import type { SearchEventsParams } from 'openapi'; +import type { FilterItemParamHolder } from 'component/filter/Filters/Filters'; + +type Log = + | { type: 'global' } + | { type: 'project'; projectId: string } + | { type: 'flag'; flagName: string }; + +const extraParameters = (logType: Log) => { + switch (logType.type) { + case 'global': + return { project: FilterItemParam, feature: FilterItemParam }; + case 'project': + return { + feature: FilterItemParam, + project: withDefault(StringParam, `IS:${logType.projectId}`), + }; + case 'flag': + return { + project: FilterItemParam, + feature: withDefault(StringParam, `IS:${logType.flagName}`), + }; + } +}; + +export const useEventLogSearch = ( + logType: Log, + storageKey = 'event-log', + refreshInterval = 15 * 1000, +) => { + const stateConfig = { + offset: withDefault(NumberParam, 0), + limit: withDefault(NumberParam, DEFAULT_PAGE_LIMIT), + query: StringParam, + from: FilterItemParam, + to: FilterItemParam, + createdBy: FilterItemParam, + type: FilterItemParam, + ...extraParameters(logType), + }; + + const fullStorageKey = (() => { + switch (logType.type) { + case 'global': + return `${storageKey}-global`; + case 'project': + return `${storageKey}-project:${logType.projectId}`; + case 'flag': + return `${storageKey}-flag:${logType.flagName}`; + } + })(); + + const [tableState, setTableState] = usePersistentTableState( + fullStorageKey, + stateConfig, + ); + + const filterState = (() => { + const { offset, limit, query, ...fs } = tableState; + switch (logType.type) { + case 'global': + return fs as FilterItemParamHolder; + case 'project': + return { ...fs, project: undefined } as FilterItemParamHolder; + case 'flag': + return { + ...fs, + feature: undefined, + project: undefined, + } as FilterItemParamHolder; + } + })(); + + const { events, total, refetch, loading, initialLoad } = useEventSearch( + mapValues(encodeQueryParams(stateConfig, tableState), (value) => + value ? `${value}` : undefined, + ) as SearchEventsParams, + { + refreshInterval, + }, + ); + + return { + events, + total, + refetch, + loading, + initialLoad, + tableState, + setTableState, + filterState, + }; +};