diff --git a/package-lock.json b/package-lock.json index 2ef05501..f1fd5500 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11,6 +11,8 @@ "dependencies": { "@testing-library/jest-dom": "^6.4.2", "@testing-library/react": "^14.2.1", + "@types/lodash": "^4.17.9", + "lodash": "^4.17.21", "moment": "^2.29.1", "react-router-dom": "^6.26.1" }, @@ -5079,6 +5081,11 @@ "dev": true, "license": "MIT" }, + "node_modules/@types/lodash": { + "version": "4.17.9", + "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.17.9.tgz", + "integrity": "sha512-w9iWudx1XWOHW5lQRS9iKpK/XuRhnN+0T7HvdCCd802FYkT1AMTnxndJHGrNJwRoRHkslGr4S29tjm1cT7x/7w==" + }, "node_modules/@types/mime": { "version": "1.3.3", "dev": true, @@ -15074,7 +15081,8 @@ }, "node_modules/lodash": { "version": "4.17.21", - "license": "MIT" + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" }, "node_modules/lodash-es": { "version": "4.17.21", @@ -49726,6 +49734,11 @@ "version": "7.0.13", "dev": true }, + "@types/lodash": { + "version": "4.17.9", + "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.17.9.tgz", + "integrity": "sha512-w9iWudx1XWOHW5lQRS9iKpK/XuRhnN+0T7HvdCCd802FYkT1AMTnxndJHGrNJwRoRHkslGr4S29tjm1cT7x/7w==" + }, "@types/mime": { "version": "1.3.3", "dev": true @@ -56539,7 +56552,9 @@ } }, "lodash": { - "version": "4.17.21" + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" }, "lodash-es": { "version": "4.17.21" diff --git a/package.json b/package.json index aa1e5bc0..d04c9510 100644 --- a/package.json +++ b/package.json @@ -20,6 +20,8 @@ "dependencies": { "@testing-library/jest-dom": "^6.4.2", "@testing-library/react": "^14.2.1", + "@types/lodash": "^4.17.9", + "lodash": "^4.17.21", "moment": "^2.29.1", "react-router-dom": "^6.26.1" } diff --git a/packages/transaction-log/src/components/common/app.main.component.tsx b/packages/transaction-log/src/components/common/app.main.component.tsx index 1edfc969..d78d3642 100644 --- a/packages/transaction-log/src/components/common/app.main.component.tsx +++ b/packages/transaction-log/src/components/common/app.main.component.tsx @@ -53,7 +53,7 @@ const App: React.FC = () => { let serverDifferenceTime const fetchTransactionLogs = useCallback( - async (timestampFilter?: string) => { + async (timestampFilter?: string, filteredResults?: boolean) => { try { const filters: {[key: string]: any} = {} @@ -61,57 +61,57 @@ const App: React.FC = () => { filters['request.timestamp'] = JSON.stringify({ $gte: timestampFilter }) - } else { - if (status !== 'NoFilter') { - filters.status = status - } + } - if (statusCode) { - filters['response.status'] = statusCode - } + if (startDate || endDate) { + filters['request.timestamp'] = JSON.stringify({ + ...(startDate && {$gte: startDate.toISOString()}), + ...(endDate && {$lte: endDate.toISOString()}) + }) + } - if (channel !== 'NoFilter') { - filters.channelID = channel - } + if (status !== 'NoFilter') { + filters.status = status + } - if (reruns !== 'NoFilter') { - if (reruns === 'Yes') { - filters.childIDs = JSON.stringify({$exists: true, $ne: []}) - } else if (reruns === 'No') { - filters.childIDs = JSON.stringify({$eq: []}) - } - } + if (statusCode) { + filters['response.status'] = statusCode + } - if (startDate && endDate) { - filters['request.timestamp'] = JSON.stringify({ - $gte: startDate.toISOString(), - $lte: endDate.toISOString() - }) - } + if (channel !== 'NoFilter') { + filters.channelID = channel + } - if (host) { - filters['request.host'] = host + if (reruns !== 'NoFilter') { + if (reruns === 'Yes') { + filters.childIDs = JSON.stringify({$exists: true, $ne: []}) + } else if (reruns === 'No') { + filters.childIDs = JSON.stringify({$eq: []}) } + } - if (port) { - filters['request.port'] = port - } + if (host) { + filters['request.host'] = host + } - if (path) { - filters['request.path'] = path - } + if (port) { + filters['request.port'] = port + } - if (param) { - filters['request.querystring'] = param - } + if (path) { + filters['request.path'] = path + } - if (client !== 'NoFilter') { - filters.clientID = client - } + if (param) { + filters['request.querystring'] = param + } - if (method !== 'NoFilter') { - filters['request.method'] = method - } + if (client !== 'NoFilter') { + filters.clientID = client + } + + if (method !== 'NoFilter') { + filters['request.method'] = method } const fetchParams: {[key: string]: any} = { @@ -136,7 +136,10 @@ const App: React.FC = () => { ) setTransactions(prevTransactions => { - const newTransactionListState = [...prevTransactions] + if(filteredResults){ + return newTransactionsWithChannelDetails + } + let newTransactionListState = [...prevTransactions] newTransactionsWithChannelDetails.forEach(transaction => { if (!newTransactionListState.some(t => t._id === transaction._id)) { @@ -144,6 +147,13 @@ const App: React.FC = () => { } }) + //filter based on the status + if (status !== 'NoFilter') { + newTransactionListState = newTransactionListState.filter( + transaction => transaction.status === status + ) + } + //sort the transactions by timestamp newTransactionListState.sort((a, b) => { return ( @@ -224,7 +234,7 @@ const App: React.FC = () => { }, []) useEffect(() => { - if (timestampFilter) { + if (timestampFilter && !startDate && !endDate) { ;(async () => { lastPollingComplete = false await fetchTransactionLogs(timestampFilter) @@ -386,6 +396,7 @@ const App: React.FC = () => { reruns={reruns} setReruns={setReruns} channels={channels} + fetchTransactionLogs={fetchTransactionLogs} /> )} {tabValue === 1 && ( @@ -418,6 +429,7 @@ const App: React.FC = () => { method={method} setMethod={setMethod} clients={clients} + fetchTransactionLogs={fetchTransactionLogs} /> )} diff --git a/packages/transaction-log/src/components/filters/basic.component.tsx b/packages/transaction-log/src/components/filters/basic.component.tsx index 866e9cdb..a82f7263 100644 --- a/packages/transaction-log/src/components/filters/basic.component.tsx +++ b/packages/transaction-log/src/components/filters/basic.component.tsx @@ -1,9 +1,10 @@ -import React from 'react' +import React, {useCallback, useEffect} from 'react' import {Box, TextField, MenuItem, Grid, Button, Card} from '@mui/material' import {DateTimePicker} from '@mui/x-date-pickers/DateTimePicker' import {LocalizationProvider} from '@mui/x-date-pickers/LocalizationProvider' import {AdapterDateFns} from '@mui/x-date-pickers/AdapterDateFns' import {BasicFilterProps} from '../../interfaces/index.interface' +import {debounce} from 'lodash' const BasicFilters: React.FC = ({ status, @@ -20,8 +21,15 @@ const BasicFilters: React.FC = ({ setLimit, reruns, setReruns, - channels + channels, + fetchTransactionLogs }) => { + + const debounceFetchTransactionLogs = useCallback( + debounce(() => fetchTransactionLogs(null, true), 500), + [fetchTransactionLogs] + ); + const handleStatusChange = (event: React.ChangeEvent) => { setStatus(event.target.value) } @@ -42,6 +50,14 @@ const BasicFilters: React.FC = ({ setReruns(event.target.value) } + useEffect(() => { + (async () => { + await debounceFetchTransactionLogs() + })() + + return () => debounceFetchTransactionLogs.cancel() + }, [status, searchQuery, channel, limit, startDate, endDate, reruns]) + const handleClearFilters = () => { setStatus('NoFilter') setSearchQuery('') @@ -70,7 +86,7 @@ const BasicFilters: React.FC = ({ Completed with error(s) - Success + Successful diff --git a/packages/transaction-log/src/components/filters/custom.component.tsx b/packages/transaction-log/src/components/filters/custom.component.tsx index c300a9f3..257d4234 100644 --- a/packages/transaction-log/src/components/filters/custom.component.tsx +++ b/packages/transaction-log/src/components/filters/custom.component.tsx @@ -1,10 +1,11 @@ -import React, {useState} from 'react' +import React, {useEffect, useState} from 'react' import {Box, TextField, MenuItem, Button, Grid} from '@mui/material' import {DateTimePicker} from '@mui/x-date-pickers/DateTimePicker' import {LocalizationProvider} from '@mui/x-date-pickers/LocalizationProvider' import {AdapterDateFns} from '@mui/x-date-pickers/AdapterDateFns' import CustomizeDialog from '../dialogs/customize.dialog.component' import {CustomFilterProps} from '../../interfaces/index.interface' +import {debounce} from 'lodash' const CustomFilters: React.FC = ({ status, @@ -34,9 +35,11 @@ const CustomFilters: React.FC = ({ setClient, clients, method, - setMethod + setMethod, + fetchTransactionLogs }) => { const [open, setOpen] = useState(false) + const debounceFetchTransactionLogs = debounce(fetchTransactionLogs, 10000) const [visibleFilters, setVisibleFilters] = useState({ status: true, @@ -139,6 +142,24 @@ const CustomFilters: React.FC = ({ setOpen(false) } + useEffect(() => { + debounceFetchTransactionLogs(null, true) + return () => debounceFetchTransactionLogs.cancel() + }, [ + status, + channel, + limit, + startDate, + endDate, + reruns, + statusCode, + port, + path, + param, + client, + method + ]) + return ( @@ -158,7 +179,7 @@ const CustomFilters: React.FC = ({ Completed with error(s) - Success + Successful )} diff --git a/packages/transaction-log/src/interfaces/index.interface.spec.ts b/packages/transaction-log/src/interfaces/index.interface.spec.ts index 0f84a593..75d54a51 100644 --- a/packages/transaction-log/src/interfaces/index.interface.spec.ts +++ b/packages/transaction-log/src/interfaces/index.interface.spec.ts @@ -24,7 +24,8 @@ const basicFilterProps: BasicFilterProps = { setLimit: (value: number) => {}, reruns: 'none', setReruns: (value: string) => {}, - channels: [mockChannel] + channels: [mockChannel], + fetchTransactionLogs: (timestampFilter?: string, filteredResults?: boolean) => Promise.resolve(), } const customFilterProps: CustomFilterProps = { @@ -55,7 +56,8 @@ const customFilterProps: CustomFilterProps = { setClient: (value: string) => {}, clients: [mockClient], method: 'GET', - setMethod: (value: string) => {} + setMethod: (value: string) => {}, + fetchTransactionLogs: (timestampFilter?: string, filteredResults?: boolean) => Promise.resolve(), } const customizeDialogProps: CustomizeDialogProps = { @@ -84,6 +86,9 @@ describe('Interface Conformance Tests', () => { expect(typeof basicFilterProps.setStatus).toBe('function') expect(Array.isArray(basicFilterProps.channels)).toBe(true) expect(basicFilterProps.channels[0]._id).toBe('1') + expect(typeof basicFilterProps.fetchTransactionLogs).toBe('function') + expect(basicFilterProps.fetchTransactionLogs()).resolves.toBe(undefined) + }) it('should conform to CustomFilterProps interface', () => { @@ -91,6 +96,8 @@ describe('Interface Conformance Tests', () => { expect(customFilterProps.host).toBe('localhost') expect(customFilterProps.clients[0].name).toBe('Test Client') expect(typeof customFilterProps.setClient).toBe('function') + expect(typeof customFilterProps.fetchTransactionLogs).toBe('function') + expect(customFilterProps.fetchTransactionLogs()).resolves.toBe(undefined) }) it('should conform to CustomizeDialogProps interface', () => { diff --git a/packages/transaction-log/src/interfaces/index.interface.ts b/packages/transaction-log/src/interfaces/index.interface.ts index 3435e6d6..29cee545 100644 --- a/packages/transaction-log/src/interfaces/index.interface.ts +++ b/packages/transaction-log/src/interfaces/index.interface.ts @@ -15,7 +15,8 @@ export interface BasicFilterProps { setLimit: (value: number) => void reruns: string setReruns: (value: string) => void - channels: Channel[] + channels: Channel[], + fetchTransactionLogs: (timestampFilter?: string, filteredResults?: boolean) => Promise } export interface CustomFilterProps { @@ -46,7 +47,8 @@ export interface CustomFilterProps { setClient: (value: string) => void clients: Client[] method: string - setMethod: (value: string) => void + setMethod: (value: string) => void, + fetchTransactionLogs: (timestampFilter?: string, filteredResults?: boolean) => Promise } export interface CustomizeDialogProps {