diff --git a/src/components/AppWrapper.tsx b/src/components/AppWrapper.tsx index bc0d0316..25f80e1a 100644 --- a/src/components/AppWrapper.tsx +++ b/src/components/AppWrapper.tsx @@ -1,4 +1,5 @@ import { styled } from '@mui/material'; +import dayjs from 'dayjs'; import React, { useContext, useEffect, useState } from 'react'; import { Navigate, @@ -36,6 +37,8 @@ const RootDiv = styled('div')({ export const FILTERS_QUERY_KEY = 'filters'; export const SLIDE_QUERY_KEY = 'slide'; export const TIME_QUERY_KEY = 'time'; +export const START_TIME_QUERY_KEY = 'startTime'; +export const END_TIME_QUERY_KEY = 'endTime'; export const AppWrapper: React.FC = () => { const { pathname, search } = useLocation(); @@ -71,32 +74,80 @@ export const AppWrapper: React.FC = () => { }, [pathname]); const initializeTimeSearchParams = () => { - // If date has already been set + const existingTimeParam = searchParams.get(TIME_QUERY_KEY); + const existingStartParam = searchParams.get(START_TIME_QUERY_KEY); + const existingEndParam = searchParams.get(END_TIME_QUERY_KEY); + + if (existingStartParam || existingEndParam) { + setTimeSearchParam( + TimeFilterEnum.custom, + existingStartParam, + existingEndParam + ); + return; + } + if ( - dateFilter?.filterShortString && - dateFilter?.filterShortString in TimeFilterEnum + existingTimeParam === TimeFilterEnum.custom && + !existingStartParam && + !existingEndParam ) { - setTimeSearchParam(dateFilter.filterShortString); + setTimeSearchParam(TimeFilterEnum['24hours']); return; } - // If time param is invalid - const existingTimeParam = searchParams.get(TIME_QUERY_KEY); + if (existingTimeParam === null || !(existingTimeParam in TimeFilterEnum)) { setTimeSearchParam(TimeFilterEnum['24hours']); - } else { - // Set filter string for components to consume - setDateFilter(getTimeFilterObject(existingTimeParam as TimeFilterEnum)); + return; } + + setDateFilter(getTimeFilterObject(existingTimeParam as TimeFilterEnum)); }; - const setTimeSearchParam = (timeFilter: TimeFilterEnum) => { + const setTimeSearchParam = ( + timeFilter: TimeFilterEnum, + startTime?: string | null, + endTime?: string | null + ) => { + const validStartTime = + startTime && dayjs(startTime).isValid() + ? dayjs(startTime).toISOString() + : undefined; + const validEndTime = + endTime && dayjs(endTime).isValid() + ? dayjs(endTime).toISOString() + : undefined; + if (timeFilter === TimeFilterEnum.custom) { + if (validStartTime) { + searchParams.set(START_TIME_QUERY_KEY, validStartTime); + } else { + searchParams.delete(START_TIME_QUERY_KEY); + } + + if (validEndTime) { + searchParams.set(END_TIME_QUERY_KEY, validEndTime); + } else { + searchParams.delete(END_TIME_QUERY_KEY); + } + } else { + searchParams.delete(START_TIME_QUERY_KEY); + searchParams.delete(END_TIME_QUERY_KEY); + } searchParams.set(TIME_QUERY_KEY, timeFilter); setSearchParams(searchParams, { replace: true }); + + const nextDateFilter = getTimeFilterObject(timeFilter, { + startTime: validStartTime, + endTime: validEndTime, + }); + if ( - getTimeFilterObject(timeFilter).filterShortString !== - dateFilter?.filterShortString + nextDateFilter.filterShortString !== dateFilter?.filterShortString || + nextDateFilter.filterString !== dateFilter?.filterString || + nextDateFilter.startTime !== dateFilter?.startTime || + nextDateFilter.endTime !== dateFilter?.endTime ) { - setDateFilter(getTimeFilterObject(timeFilter)); + setDateFilter(nextDateFilter); } }; diff --git a/src/components/Pickers/DatePicker.tsx b/src/components/Pickers/DatePicker.tsx index dd35527a..efa8dc3d 100644 --- a/src/components/Pickers/DatePicker.tsx +++ b/src/components/Pickers/DatePicker.tsx @@ -14,48 +14,160 @@ // See the License for the specific language governing permissions and // limitations under the License. -import { MenuItem, TextField } from '@mui/material'; -import React, { useContext, useMemo } from 'react'; +import { + Button, + Dialog, + DialogActions, + DialogContent, + DialogTitle, + MenuItem, + Stack, + TextField, + Typography, +} from '@mui/material'; +import dayjs from 'dayjs'; +import React, { useContext, useEffect, useMemo, useState } from 'react'; import { useTranslation } from 'react-i18next'; import { DateFilterContext } from '../../contexts/DateFilterContext'; import { TimeFilterEnum } from '../../interfaces'; -import { TIME_QUERY_KEY } from '../AppWrapper'; +import { + END_TIME_QUERY_KEY, + START_TIME_QUERY_KEY, + TIME_QUERY_KEY, +} from '../AppWrapper'; + +const formatInputValue = (value?: string | null) => { + if (!value) { + return ''; + } + const parsed = dayjs(value); + return parsed.isValid() ? parsed.format('YYYY-MM-DDTHH:mm') : ''; +}; export const DatePicker: React.FC = () => { const { t } = useTranslation(); const { setTimeSearchParam, searchParams } = useContext(DateFilterContext); + const getCurrentTimeFilter = (): TimeFilterEnum => { + const currentParam = searchParams.get(TIME_QUERY_KEY); + if (currentParam && currentParam in TimeFilterEnum) { + return currentParam as TimeFilterEnum; + } + return TimeFilterEnum['24hours']; + }; + + const [selectedValue, setSelectedValue] = useState( + getCurrentTimeFilter() + ); + const [lastAppliedValue, setLastAppliedValue] = useState( + getCurrentTimeFilter() + ); + const [customStart, setCustomStart] = useState( + formatInputValue(searchParams.get(START_TIME_QUERY_KEY)) + ); + const [customEnd, setCustomEnd] = useState( + formatInputValue(searchParams.get(END_TIME_QUERY_KEY)) + ); + const [isDialogOpen, setIsDialogOpen] = useState(false); + + useEffect(() => { + const currentFilter = getCurrentTimeFilter(); + setSelectedValue(currentFilter); + setLastAppliedValue(currentFilter); + setCustomStart(formatInputValue(searchParams.get(START_TIME_QUERY_KEY))); + setCustomEnd(formatInputValue(searchParams.get(END_TIME_QUERY_KEY))); + }, [searchParams]); + const createdQueryOptions = useMemo( () => [ { - value: '1hour', + value: TimeFilterEnum['1hour'], label: t('last1Hour'), }, { - value: '24hours', + value: TimeFilterEnum['24hours'], label: t('last24Hours'), }, { - value: '7days', + value: TimeFilterEnum['7days'], label: t('last7Days'), }, { - value: '30days', + value: TimeFilterEnum['30days'], label: t('last30Days'), }, + { + value: TimeFilterEnum.custom, + label: t('customRange'), + }, ], [t] ); + const startMoment = customStart ? dayjs(customStart) : null; + const endMoment = customEnd ? dayjs(customEnd) : null; + const hasStart = !!customStart; + const hasEnd = !!customEnd; + const rangeError = + startMoment !== null && + endMoment !== null && + startMoment.isValid() && + endMoment.isValid() && + startMoment.isAfter(endMoment); + const missingRange = !hasStart && !hasEnd; + const applyDisabled = + rangeError || + (startMoment !== null && !startMoment.isValid()) || + (endMoment !== null && !endMoment.isValid()) || + missingRange; + + const openCustomDialog = () => { + setSelectedValue(TimeFilterEnum.custom); + if (!customStart && !customEnd) { + const now = dayjs(); + setCustomEnd(now.format('YYYY-MM-DDTHH:mm')); + setCustomStart(now.subtract(24, 'hours').format('YYYY-MM-DDTHH:mm')); + } + setIsDialogOpen(true); + }; + + const handleSelectChange = (value: string) => { + if (value === TimeFilterEnum.custom) { + openCustomDialog(); + return; + } + setSelectedValue(value as TimeFilterEnum); + setTimeSearchParam(value as TimeFilterEnum); + }; + + const handleCloseDialog = () => { + setIsDialogOpen(false); + setSelectedValue(lastAppliedValue); + setCustomStart(formatInputValue(searchParams.get(START_TIME_QUERY_KEY))); + setCustomEnd(formatInputValue(searchParams.get(END_TIME_QUERY_KEY))); + }; + + const handleApplyCustom = () => { + if (applyDisabled) { + return; + } + const startISO = + startMoment && startMoment.isValid() ? startMoment.toISOString() : null; + const endISO = + endMoment && endMoment.isValid() ? endMoment.toISOString() : null; + setTimeSearchParam(TimeFilterEnum.custom, startISO, endISO); + setIsDialogOpen(false); + }; + return ( <> { - setTimeSearchParam(event.target.value as TimeFilterEnum); + handleSelectChange(event.target.value); }} sx={{ pr: 2 }} > @@ -64,11 +176,57 @@ export const DatePicker: React.FC = () => { sx={{ fontSize: '16px' }} key={item.value} value={item.value} + onClick={ + item.value === TimeFilterEnum.custom + ? () => openCustomDialog() + : undefined + } > {item.label} ))} + + {t('customTimeRange')} + + + setCustomStart(event.target.value)} + fullWidth + InputLabelProps={{ shrink: true }} + error={rangeError} + /> + setCustomEnd(event.target.value)} + fullWidth + InputLabelProps={{ shrink: true }} + error={rangeError} + helperText={rangeError ? t('endTimeBeforeStart') : undefined} + /> + {missingRange && ( + + {t('enterStartOrEndTime')} + + )} + + + + + + + ); }; diff --git a/src/contexts/DateFilterContext.tsx b/src/contexts/DateFilterContext.tsx index c1bf1f96..8a14bfec 100644 --- a/src/contexts/DateFilterContext.tsx +++ b/src/contexts/DateFilterContext.tsx @@ -20,7 +20,11 @@ import { ITimeFilterObject, TimeFilterEnum } from '../interfaces'; export interface IDateFilterContext { searchParams: URLSearchParams; dateFilter: ITimeFilterObject | undefined; - setTimeSearchParam: (timeFilter: TimeFilterEnum) => void; + setTimeSearchParam: ( + timeFilter: TimeFilterEnum, + startTime?: string | null, + endTime?: string | null + ) => void; } export const DateFilterContext = createContext({} as IDateFilterContext); diff --git a/src/interfaces/filters.ts b/src/interfaces/filters.ts index a19259c5..5a021715 100644 --- a/src/interfaces/filters.ts +++ b/src/interfaces/filters.ts @@ -16,17 +16,20 @@ export interface ITimeFilterObject { filterString: string; - filterShortString: any; + filterShortString: TimeFilterEnum; filterTime: number; + startTime?: number; + endTime?: number; } -export const times = ['1hour', '24hours', '7days', '30days']; +export const times = ['1hour', '24hours', '7days', '30days', 'custom']; export enum TimeFilterEnum { '1hour' = '1hour', '24hours' = '24hours', '7days' = '7days', '30days' = '30days', + 'custom' = 'custom', } export const ApiFilters = ['id', 'name', 'interface']; diff --git a/src/pages/Activity/views/Events.tsx b/src/pages/Activity/views/Events.tsx index ae56dfc2..3b1efa20 100644 --- a/src/pages/Activity/views/Events.tsx +++ b/src/pages/Activity/views/Events.tsx @@ -160,14 +160,14 @@ export const ActivityEvents: () => JSX.Element = () => { // Histogram useEffect(() => { setIsHistLoading(true); - const currentTime = dayjs().unix(); + const histEndTime = dateFilter?.endTime ?? dayjs().unix(); isMounted && dateFilter && fetchCatcher( `${FF_Paths.nsPrefix}/${selectedNamespace}${FF_Paths.chartsHistogram( BucketCollectionEnum.Events, dateFilter.filterTime, - currentTime, + histEndTime, BucketCountEnum.Large )}` ) diff --git a/src/pages/Activity/views/Operations.tsx b/src/pages/Activity/views/Operations.tsx index 7775632f..45296260 100644 --- a/src/pages/Activity/views/Operations.tsx +++ b/src/pages/Activity/views/Operations.tsx @@ -137,7 +137,7 @@ export const ActivityOperations: () => JSX.Element = () => { // Histogram useEffect(() => { setIsHistLoading(true); - const currentTime = dayjs().unix(); + const histEndTime = dateFilter?.endTime ?? dayjs().unix(); isMounted && dateFilter && @@ -145,7 +145,7 @@ export const ActivityOperations: () => JSX.Element = () => { `${FF_Paths.nsPrefix}/${selectedNamespace}${FF_Paths.chartsHistogram( BucketCollectionEnum.Operations, dateFilter.filterTime, - currentTime, + histEndTime, BucketCountEnum.Large )}` ) diff --git a/src/pages/Activity/views/Transactions.tsx b/src/pages/Activity/views/Transactions.tsx index 233141ee..12bf2001 100644 --- a/src/pages/Activity/views/Transactions.tsx +++ b/src/pages/Activity/views/Transactions.tsx @@ -134,7 +134,7 @@ export const ActivityTransactions: () => JSX.Element = () => { // Histogram; useEffect(() => { setIsHistLoading(true); - const currentTime = dayjs().unix(); + const histEndTime = dateFilter?.endTime ?? dayjs().unix(); isMounted && dateFilter && @@ -142,7 +142,7 @@ export const ActivityTransactions: () => JSX.Element = () => { `${FF_Paths.nsPrefix}/${selectedNamespace}${FF_Paths.chartsHistogram( BucketCollectionEnum.Transactions, dateFilter.filterTime, - currentTime, + histEndTime, BucketCountEnum.Large )}` ) diff --git a/src/pages/Blockchain/views/Dashboard.tsx b/src/pages/Blockchain/views/Dashboard.tsx index d44d7a58..288a0756 100644 --- a/src/pages/Blockchain/views/Dashboard.tsx +++ b/src/pages/Blockchain/views/Dashboard.tsx @@ -364,7 +364,7 @@ export const BlockchainDashboard: () => JSX.Element = () => { // Histogram useEffect(() => { setIsHistLoading(true); - const currentTime = dayjs().unix(); + const histEndTime = dateFilter?.endTime ?? dayjs().unix(); isMounted && dateFilter && @@ -372,7 +372,7 @@ export const BlockchainDashboard: () => JSX.Element = () => { `${FF_Paths.nsPrefix}/${selectedNamespace}${FF_Paths.chartsHistogram( BucketCollectionEnum.BlockchainEvents, dateFilter.filterTime, - currentTime, + histEndTime, BucketCountEnum.Small )}` ) diff --git a/src/pages/Blockchain/views/Events.tsx b/src/pages/Blockchain/views/Events.tsx index b11cb704..3495040b 100644 --- a/src/pages/Blockchain/views/Events.tsx +++ b/src/pages/Blockchain/views/Events.tsx @@ -134,7 +134,7 @@ export const BlockchainEvents: () => JSX.Element = () => { // Histogram useEffect(() => { setIsHistLoading(true); - const currentTime = dayjs().unix(); + const histEndTime = dateFilter?.endTime ?? dayjs().unix(); isMounted && dateFilter && @@ -142,7 +142,7 @@ export const BlockchainEvents: () => JSX.Element = () => { `${FF_Paths.nsPrefix}/${selectedNamespace}${FF_Paths.chartsHistogram( BucketCollectionEnum.BlockchainEvents, dateFilter.filterTime, - currentTime, + histEndTime, BucketCountEnum.Large )}` ) diff --git a/src/pages/Home/views/Dashboard.tsx b/src/pages/Home/views/Dashboard.tsx index 5b5d867f..39a7cb6f 100644 --- a/src/pages/Home/views/Dashboard.tsx +++ b/src/pages/Home/views/Dashboard.tsx @@ -325,14 +325,14 @@ export const HomeDashboard: () => JSX.Element = () => { // Medium Card UseEffect useEffect(() => { setIsHistLoading(true); - const currentTime = dayjs().unix(); + const histEndTime = dateFilter?.endTime ?? dayjs().unix(); if (isMounted && dateFilter) { fetchCatcher( `${FF_Paths.nsPrefix}/${selectedNamespace}${FF_Paths.chartsHistogram( BucketCollectionEnum.Events, dateFilter.filterTime, - currentTime, + histEndTime, BucketCountEnum.Small )}` ) diff --git a/src/pages/Off-Chain/views/Dashboard.tsx b/src/pages/Off-Chain/views/Dashboard.tsx index 76b6b93d..550896c1 100644 --- a/src/pages/Off-Chain/views/Dashboard.tsx +++ b/src/pages/Off-Chain/views/Dashboard.tsx @@ -318,7 +318,7 @@ export const OffChainDashboard: () => JSX.Element = () => { // Medium Card UseEffect useEffect(() => { setIsHistLoading(true); - const currentTime = dayjs().unix(); + const histEndTime = dateFilter?.endTime ?? dayjs().unix(); const qParams = `?limit=25${dateFilter?.filterString ?? ''}`; const qParamsNoRange = `?limit=25`; if (isMounted && dateFilter) { @@ -326,7 +326,7 @@ export const OffChainDashboard: () => JSX.Element = () => { `${FF_Paths.nsPrefix}/${selectedNamespace}${FF_Paths.chartsHistogram( BucketCollectionEnum.Messages, dateFilter.filterTime, - currentTime, + histEndTime, BucketCountEnum.Small )}` ) diff --git a/src/pages/Off-Chain/views/Messages.tsx b/src/pages/Off-Chain/views/Messages.tsx index b29098ee..4a098227 100644 --- a/src/pages/Off-Chain/views/Messages.tsx +++ b/src/pages/Off-Chain/views/Messages.tsx @@ -133,7 +133,7 @@ export const OffChainMessages: () => JSX.Element = () => { // Histogram useEffect(() => { setIsHistLoading(true); - const currentTime = dayjs().unix(); + const histEndTime = dateFilter?.endTime ?? dayjs().unix(); isMounted && dateFilter && @@ -141,7 +141,7 @@ export const OffChainMessages: () => JSX.Element = () => { `${FF_Paths.nsPrefix}/${selectedNamespace}${FF_Paths.chartsHistogram( BucketCollectionEnum.Messages, dateFilter.filterTime, - currentTime, + histEndTime, BucketCountEnum.Large )}` ) diff --git a/src/pages/Tokens/views/Dashboard.tsx b/src/pages/Tokens/views/Dashboard.tsx index d4ad3be6..4a5b3b63 100644 --- a/src/pages/Tokens/views/Dashboard.tsx +++ b/src/pages/Tokens/views/Dashboard.tsx @@ -407,13 +407,13 @@ export const TokensDashboard: () => JSX.Element = () => { // Medium Card UseEffect useEffect(() => { setIsHistLoading(true); - const currentTime = dayjs().unix(); + const histEndTime = dateFilter?.endTime ?? dayjs().unix(); if (isMounted && dateFilter) { fetchCatcher( `${FF_Paths.nsPrefix}/${selectedNamespace}${FF_Paths.chartsHistogram( BucketCollectionEnum.TokenTransfers, dateFilter.filterTime, - currentTime, + histEndTime, BucketCountEnum.Small )}` ) diff --git a/src/pages/Tokens/views/Transfers.tsx b/src/pages/Tokens/views/Transfers.tsx index df9cf532..b8cd0938 100644 --- a/src/pages/Tokens/views/Transfers.tsx +++ b/src/pages/Tokens/views/Transfers.tsx @@ -136,6 +136,11 @@ export const TokensTransfers: () => JSX.Element = () => { ) .then(async (tokenTransferRes: IPagedTokenTransferResponse) => { if (isMounted) { + if (!tokenTransferRes || !tokenTransferRes.items) { + setTokenTransfers([]); + setTokenTransferTotal(0); + return; + } if (tokenTransferRes.items.length === 0) { setTokenTransfers([]); setTokenTransferTotal(tokenTransferRes.total); @@ -174,14 +179,14 @@ export const TokensTransfers: () => JSX.Element = () => { // Histogram useEffect(() => { setIsHistLoading(true); - const currentTime = dayjs().unix(); + const histEndTime = dateFilter?.endTime ?? dayjs().unix(); isMounted && dateFilter && fetchCatcher( `${FF_Paths.nsPrefix}/${selectedNamespace}${FF_Paths.chartsHistogram( BucketCollectionEnum.TokenTransfers, dateFilter.filterTime, - currentTime, + histEndTime, BucketCountEnum.Large )}` ) diff --git a/src/translations/en.json b/src/translations/en.json index a0e7d22d..f520a914 100644 --- a/src/translations/en.json +++ b/src/translations/en.json @@ -16,6 +16,7 @@ "approvalInfo": "Approval Info", "approvals": "Approvals", "approved": "Approved", + "apply": "Apply", "author": "Author", "authorKey": "Author Key", "backendId": "Backend ID", @@ -76,6 +77,7 @@ "created": "Created", "currentOffset": "Current Offset", "customRange": "Custom Range", + "customTimeRange": "Custom Time Range", "dashboard": "Dashboard", "data": "Data", "database": "Database", @@ -105,7 +107,10 @@ "dxPeer": "DX Peer", "endpoint": "Endpoint", "endpointID": "Endpoint ID", + "endTime": "End Time", + "endTimeBeforeStart": "End time must be after start time", "endsWith": "Ends with", + "enterStartOrEndTime": "Enter a start or end time", "equal": "Equals", "errorMessage": "Error Message", "event": "Event", @@ -327,6 +332,7 @@ "signingKey": "Signing Key", "source": "Source", "standard": "Standard", + "startTime": "Start Time", "startsWith": "Starts with", "state": "State", "status": "Status", diff --git a/src/utils/fetches.ts b/src/utils/fetches.ts index e1acfd20..e53601e4 100644 --- a/src/utils/fetches.ts +++ b/src/utils/fetches.ts @@ -31,8 +31,13 @@ export function parseLargeNumbersAsStrings(value: any) { export const fetchCatcher = async (resource: string): Promise => { const response = await fetchWithCredentials(resource); if (!response.ok) { + throw response; } else { - return parse(await response.text(), null, parseLargeNumbersAsStrings); + const body = await response.text(); + if (!body) { + return undefined; + } + return parse(body, null, parseLargeNumbersAsStrings); } }; diff --git a/src/utils/filters.ts b/src/utils/filters.ts index e53ea85b..52db99fc 100644 --- a/src/utils/filters.ts +++ b/src/utils/filters.ts @@ -1,34 +1,91 @@ import dayjs from 'dayjs'; import { ITimeFilterObject, TimeFilterEnum } from '../interfaces'; +interface ITimeFilterOptions { + timestampKey?: boolean; + startTime?: string | null; + endTime?: string | null; +} + +const buildTimeFilterString = ( + fieldName: string, + start?: number, + end?: number +): string => { + if (start !== undefined && end !== undefined) { + return `&${fieldName}=>=${start}&${fieldName}=<=${end}`; + } + if (start !== undefined) { + return `&${fieldName}=>=${start}`; + } + if (end !== undefined) { + return `&${fieldName}=<=${end}`; + } + return ''; +}; + +const getValidUnixTime = (time?: string | null): number | undefined => { + if (!time) { + return undefined; + } + const parsed = dayjs(time); + return parsed.isValid() ? parsed.unix() : undefined; +}; + +const getFallbackStartUnix = (startUnix?: number, endUnix?: number) => { + if (startUnix !== undefined) { + return startUnix; + } + if (endUnix !== undefined) { + return dayjs.unix(endUnix).subtract(24, 'hours').unix(); + } + return dayjs().subtract(24, 'hours').unix(); +}; + export const getTimeFilterObject = ( createdFilter: TimeFilterEnum, - timestampKey?: boolean + options?: ITimeFilterOptions ): ITimeFilterObject => { + const fieldName = options?.timestampKey ? 'timestamp' : 'created'; + + if (createdFilter === TimeFilterEnum.custom) { + const startUnix = getValidUnixTime(options?.startTime); + const endUnix = getValidUnixTime(options?.endTime); + const startTimeUnix = getFallbackStartUnix(startUnix, endUnix); + + return { + filterTime: startTimeUnix, + startTime: startUnix ?? startTimeUnix, + endTime: endUnix, + filterShortString: createdFilter, + filterString: buildTimeFilterString(fieldName, startUnix, endUnix), + }; + } + let createdFilterTime: number; switch (createdFilter) { - case '1hour': + case TimeFilterEnum['1hour']: createdFilterTime = dayjs().subtract(1, 'hour').unix(); break; - case '24hours': + case TimeFilterEnum['24hours']: createdFilterTime = dayjs().subtract(24, 'hours').unix(); break; - case '7days': + case TimeFilterEnum['7days']: createdFilterTime = dayjs().subtract(7, 'days').unix(); break; - case '30days': + case TimeFilterEnum['30days']: createdFilterTime = dayjs().subtract(30, 'days').unix(); break; default: createdFilterTime = dayjs().subtract(24, 'hours').unix(); break; } + return { filterTime: createdFilterTime, + startTime: createdFilterTime, filterShortString: createdFilter, - filterString: timestampKey - ? `×tamp=>=${createdFilterTime}` - : `&created=>=${createdFilterTime}`, + filterString: buildTimeFilterString(fieldName, createdFilterTime), }; };