From f27c7344a2c445fea6a3573a9793eb2a1ada1d48 Mon Sep 17 00:00:00 2001 From: Martin Marosi Date: Wed, 1 Nov 2023 09:10:51 +0100 Subject: [PATCH] Throttle last visited calls. --- package-lock.json | 8 +++---- packages/chrome/package.json | 3 +++ .../ChromeProvider/ChromeProvider.test.tsx | 18 +++++++-------- .../src/ChromeProvider/ChromeProvider.tsx | 22 ++++++++++++++----- .../src/ChromeProvider/chromeState.test.ts | 2 +- 5 files changed, 32 insertions(+), 21 deletions(-) diff --git a/package-lock.json b/package-lock.json index 0561eab1c..fe210e1f3 100644 --- a/package-lock.json +++ b/package-lock.json @@ -41993,7 +41993,7 @@ }, "packages/chrome": { "name": "@redhat-cloud-services/chrome", - "version": "1.0.0", + "version": "1.0.2", "license": "Apache-2.0", "devDependencies": { "@redhat-cloud-services/types": "^1.0.3", @@ -42009,7 +42009,7 @@ }, "packages/components": { "name": "@redhat-cloud-services/frontend-components", - "version": "4.0.13", + "version": "4.0.14", "license": "Apache-2.0", "dependencies": { "@patternfly/react-component-groups": "^1.2.1", @@ -42393,7 +42393,7 @@ "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" }, "packages/create-crc-app": { - "version": "0.1.11", + "version": "0.1.12", "license": "Apache-2.0", "dependencies": { "chalk": "^4.1.2", @@ -42759,7 +42759,7 @@ }, "packages/pdf-generator": { "name": "@redhat-cloud-services/frontend-components-pdf-generator", - "version": "4.0.2", + "version": "4.0.3", "license": "Apache-2.0", "dependencies": { "@patternfly/react-charts": "6.3.9", diff --git a/packages/chrome/package.json b/packages/chrome/package.json index b2ccc9ac7..697b4967d 100644 --- a/packages/chrome/package.json +++ b/packages/chrome/package.json @@ -25,6 +25,9 @@ "url": "https://github.com/RedHatInsights/frontend-components/issues" }, "homepage": "https://github.com/RedHatInsights/frontend-components/tree/master/packages/chrome#readme", + "dependencies": { + "lodash": "^4.17.21" + }, "peerDependencies": { "@scalprum/react-core": "^0.5.1", "react": "^18.2.0", diff --git a/packages/chrome/src/ChromeProvider/ChromeProvider.test.tsx b/packages/chrome/src/ChromeProvider/ChromeProvider.test.tsx index 7e98aa5e7..12e0b8d5e 100644 --- a/packages/chrome/src/ChromeProvider/ChromeProvider.test.tsx +++ b/packages/chrome/src/ChromeProvider/ChromeProvider.test.tsx @@ -8,8 +8,6 @@ import { PluginStore } from '@openshift/dynamic-plugin-sdk'; import ChromeProvider from './ChromeProvider'; import * as fetch from '../utils/fetch'; -const flushPromises = () => new Promise(setImmediate); - describe('ChromeProvider', () => { const getSpy = jest.spyOn(fetch, 'get'); const postSpy = jest.spyOn(fetch, 'post'); @@ -34,6 +32,7 @@ describe('ChromeProvider', () => { }); test('should post new data on title change', async () => { + jest.useFakeTimers(); getSpy.mockResolvedValueOnce([]); postSpy.mockResolvedValue(['/', '/bar']); const DocumentMutator = () => { @@ -75,17 +74,19 @@ describe('ChromeProvider', () => { screen.getByText('/foo/bar').click(); }); + // debounce timer // wait for calls to be finished await act(async () => { - await flushPromises(); + await jest.advanceTimersByTime(5001); }); - expect(postSpy).toHaveBeenCalledTimes(2); + // should be called anly once because of the debounce + expect(postSpy).toHaveBeenCalledTimes(1); expect(postSpy).toHaveBeenLastCalledWith('/api/chrome-service/v1/last-visited', { pathname: '/foo/bar', title: 'Foo title', bundle: 'bundle-title', }); - }); + }, 10000); test('should not update state on mount if received error response', async () => { const errorResponse = { errors: [{ status: 404, meta: { response_by: 'gateway' }, detail: 'Undefined Insights application' }] }; @@ -116,11 +117,8 @@ describe('ChromeProvider', () => { ); }); - expect(consoleSpy).toHaveBeenCalledTimes(2); - expect(consoleSpy.mock.calls).toEqual([ - ['Unable to update last visited pages!', errorResponse], - ['Unable to initialize ChromeProvider!', errorResponse], - ]); + expect(consoleSpy).toHaveBeenCalledTimes(1); + expect(consoleSpy.mock.calls).toEqual([['Unable to initialize ChromeProvider!', errorResponse]]); consoleSpy.mockRestore(); }); }); diff --git a/packages/chrome/src/ChromeProvider/ChromeProvider.tsx b/packages/chrome/src/ChromeProvider/ChromeProvider.tsx index 7cef26273..519f40692 100644 --- a/packages/chrome/src/ChromeProvider/ChromeProvider.tsx +++ b/packages/chrome/src/ChromeProvider/ChromeProvider.tsx @@ -2,24 +2,33 @@ import React, { useEffect, useRef, useState } from 'react'; import { useScalprum } from '@scalprum/react-core'; import { ChromeAPI } from '@redhat-cloud-services/types'; import { useLocation } from 'react-router-dom'; +import debounce from 'lodash/debounce'; import { ChromeContext } from '../ChromeContext'; import chromeState, { LastVisitedPage, UserIdentity } from './chromeState'; import { IDENTITY_URL, LAST_VISITED_URL, get, post } from '../utils/fetch'; const getUserIdentity = () => get(IDENTITY_URL); +const postDataDebounced = debounce(async (pathname: string, title: string, bundle: string) => { + const data = await post(LAST_VISITED_URL, { + pathname, + title, + bundle, + }); + return data; + // count page as visited after 5 second of being on the page + // should help limit number of API calls +}, 5000); const useLastPageVisitedUploader = (providerState: ReturnType) => { const scalprum = useScalprum<{ initialized: boolean; api: { chrome: ChromeAPI } }>(); const { pathname } = useLocation(); const postData = async (pathname: string, title: string, bundle: string) => { try { - const data = await post(LAST_VISITED_URL, { - pathname, - title, - bundle, - }); - providerState.setLastVisited(data); + const data = await postDataDebounced(pathname, title, bundle); + if (data) { + providerState.setLastVisited(data); + } } catch (error) { console.error('Unable to update last visited pages!', error); } @@ -59,6 +68,7 @@ const useLastPageVisitedUploader = (providerState: ReturnType { titleObserver?.disconnect(); + postDataDebounced?.cancel(); }; }, [pathname]); }; diff --git a/packages/chrome/src/ChromeProvider/chromeState.test.ts b/packages/chrome/src/ChromeProvider/chromeState.test.ts index 9b6bd2c35..9729f287f 100644 --- a/packages/chrome/src/ChromeProvider/chromeState.test.ts +++ b/packages/chrome/src/ChromeProvider/chromeState.test.ts @@ -35,7 +35,7 @@ describe('chromeState', () => { expect(state.getState().lastVisitedPages).toEqual(lastVisitedPayload); }); - test('should correctly update favrite pages data via dedicated callback', () => { + test('should correctly update favorite pages data via dedicated callback', () => { state.setFavoritePages([{ pathname: 'favorite', favorite: true }]); expect(state.getState().favoritePages).toEqual([{ pathname: 'favorite', favorite: true }]); });