From ca7a8fceaf787626020d490a00c15410663f61af Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Mierzwa?= Date: Wed, 10 Jun 2020 17:26:49 +0100 Subject: [PATCH] fix(ui): rewrite Fetcher with hooks --- ui/src/Components/Fetcher/index.js | 230 ++++++++++++------------ ui/src/Components/Fetcher/index.test.js | 15 +- 2 files changed, 124 insertions(+), 121 deletions(-) diff --git a/ui/src/Components/Fetcher/index.js b/ui/src/Components/Fetcher/index.js index 6ff6b3600..65ad4a1bc 100644 --- a/ui/src/Components/Fetcher/index.js +++ b/ui/src/Components/Fetcher/index.js @@ -1,136 +1,140 @@ -import React, { Component } from "react"; +import React, { useEffect, useRef } from "react"; import PropTypes from "prop-types"; -import { observer } from "mobx-react"; +import { reaction } from "mobx"; +import { useObserver } from "mobx-react"; import moment from "moment"; import { AlertStore, AlertStoreStatuses } from "Stores/AlertStore"; import { Settings } from "Stores/Settings"; -const Fetcher = observer( - class Fetcher extends Component { - static propTypes = { - alertStore: PropTypes.instanceOf(AlertStore).isRequired, - settingsStore: PropTypes.instanceOf(Settings).isRequired, +const Fetcher = ({ alertStore, settingsStore }) => { + const timer = useRef(null); + + const getSortSettings = () => { + let sortSettings = { + useDefaults: false, + sortOrder: "", + sortLabel: "", + sortReverse: "", }; - getSortSettings = () => { - const { settingsStore } = this.props; - - let sortSettings = { - useDefaults: false, - sortOrder: "", - sortLabel: "", - sortReverse: "", - }; - - sortSettings.useDefaults = - settingsStore.gridConfig.config.sortOrder === - settingsStore.gridConfig.options.default.value; - - if (sortSettings.useDefaults === true) { - return sortSettings; - } - - sortSettings.sortOrder = settingsStore.gridConfig.config.sortOrder; - - // don't sort if sorting is disabled - if ( - sortSettings.sortOrder === - settingsStore.gridConfig.options.disabled.value - ) - return sortSettings; - - sortSettings.sortReverse = - settingsStore.gridConfig.config.reverseSort !== null - ? settingsStore.gridConfig.config.reverseSort === true - ? "1" - : "0" - : ""; - - if (settingsStore.gridConfig.config.sortLabel !== null) { - sortSettings.sortLabel = settingsStore.gridConfig.config.sortLabel; - } + sortSettings.useDefaults = + settingsStore.gridConfig.config.sortOrder === + settingsStore.gridConfig.options.default.value; + if (sortSettings.useDefaults === true) { return sortSettings; - }; - - fetchIfIdle = () => { - const { alertStore, settingsStore } = this.props; - - const nextTick = moment(alertStore.status.lastUpdateAt).add( - settingsStore.fetchConfig.config.interval, - "seconds" - ); - - const pastDeadline = moment().isSameOrAfter(nextTick); - - const status = alertStore.status.value.toString(); - const updateInProgress = - status === AlertStoreStatuses.Fetching.toString() || - status === AlertStoreStatuses.Processing.toString(); - - if (pastDeadline && !updateInProgress && !alertStore.status.paused) { - this.callFetch(); - } - }; - - timerTick = () => { - window.requestAnimationFrame(this.fetchIfIdle); - }; - - callFetch = () => { - const { alertStore, settingsStore } = this.props; - - const sortSettings = this.getSortSettings(); - alertStore.fetchWithThrottle( - settingsStore.multiGridConfig.config.gridLabel, - settingsStore.multiGridConfig.config.gridSortReverse, - sortSettings.sortOrder, - sortSettings.sortLabel, - sortSettings.sortReverse - ); - }; - - componentDidMount() { - // start first fetch once the browser is done doing busy loading - window.requestAnimationFrame(this.fetchIfIdle); - this.timer = setInterval(this.timerTick, 1000); } - componentDidUpdate() { - const { alertStore } = this.props; + sortSettings.sortOrder = settingsStore.gridConfig.config.sortOrder; - if (!alertStore.status.paused) { - this.callFetch(); - } + // don't sort if sorting is disabled + if ( + sortSettings.sortOrder === settingsStore.gridConfig.options.disabled.value + ) + return sortSettings; + + sortSettings.sortReverse = + settingsStore.gridConfig.config.reverseSort !== null + ? settingsStore.gridConfig.config.reverseSort === true + ? "1" + : "0" + : ""; + + if (settingsStore.gridConfig.config.sortLabel !== null) { + sortSettings.sortLabel = settingsStore.gridConfig.config.sortLabel; } - componentWillUnmount() { - clearInterval(this.timer); - this.timer = null; + return sortSettings; + }; + + const fetchIfIdle = () => { + const nextTick = moment(alertStore.status.lastUpdateAt).add( + settingsStore.fetchConfig.config.interval, + "seconds" + ); + + const pastDeadline = moment().isSameOrAfter(nextTick); + + const status = alertStore.status.value.toString(); + const updateInProgress = + status === AlertStoreStatuses.Fetching.toString() || + status === AlertStoreStatuses.Processing.toString(); + + if (pastDeadline && !updateInProgress && !alertStore.status.paused) { + callFetch(); } + }; - render() { - const { alertStore, settingsStore } = this.props; + const callFetch = () => { + if (alertStore.status.paused) return; - return ( - // data-filters is there to register filters for observation in mobx - f.raw).join(" ")} - data-interval={settingsStore.fetchConfig.config.interval} - data-multigrid-label={settingsStore.multiGridConfig.config.gridLabel} - data-multigrid-sort-reverse={ - settingsStore.multiGridConfig.config.gridSortReverse + const sortSettings = getSortSettings(); + alertStore.fetchWithThrottle( + settingsStore.multiGridConfig.config.gridLabel, + settingsStore.multiGridConfig.config.gridSortReverse, + sortSettings.sortOrder, + sortSettings.sortLabel, + sortSettings.sortReverse + ); + }; + + useEffect(() => { + return () => clearInterval(timer.current); + }, []); + + useEffect( + () => + reaction( + () => alertStore.filters.values.map((f) => f.raw).join(" "), + () => { + callFetch(); + }, + { fireImmediately: true } + ), + [] // eslint-disable-line react-hooks/exhaustive-deps + ); + + useEffect( + () => + reaction( + () => alertStore.status.paused, + (paused) => { + if (paused) { + clearInterval(timer.current); + timer.current = null; + } else { + timer.current = setInterval( + () => window.requestAnimationFrame(fetchIfIdle), + 1000 + ); } - data-grid-sort-order={settingsStore.gridConfig.config.sortOrder} - data-grid-sort-label={settingsStore.gridConfig.config.sortLabel} - data-grid-sort-reverse={settingsStore.gridConfig.config.reverseSort} - /> - ); - } - } -); + }, + { fireImmediately: true } + ), + [] // eslint-disable-line react-hooks/exhaustive-deps + ); + + return useObserver(() => ( + // data-filters is there to register filters for observation in mobx + f.raw).join(" ")} + data-interval={settingsStore.fetchConfig.config.interval} + data-multigrid-label={settingsStore.multiGridConfig.config.gridLabel} + data-multigrid-sort-reverse={ + settingsStore.multiGridConfig.config.gridSortReverse + } + data-grid-sort-order={settingsStore.gridConfig.config.sortOrder} + data-grid-sort-label={settingsStore.gridConfig.config.sortLabel} + data-grid-sort-reverse={settingsStore.gridConfig.config.reverseSort} + /> + )); +}; +Fetcher.propTypes = { + alertStore: PropTypes.instanceOf(AlertStore).isRequired, + settingsStore: PropTypes.instanceOf(Settings).isRequired, +}; export { Fetcher }; diff --git a/ui/src/Components/Fetcher/index.test.js b/ui/src/Components/Fetcher/index.test.js index 49f93d306..407376451 100644 --- a/ui/src/Components/Fetcher/index.test.js +++ b/ui/src/Components/Fetcher/index.test.js @@ -87,6 +87,10 @@ describe("", () => { MountedFetcher(); expect(fetchSpy).toHaveBeenCalledTimes(1); + advanceBy(3 * 1000); + jest.runOnlyPendingTimers(); + expect(fetchSpy).toHaveBeenCalledTimes(2); + settingsStore.fetchConfig.config.interval = 600; advanceBy(3 * 1000); @@ -120,18 +124,12 @@ describe("", () => { expect(fetchSpy).toHaveBeenCalledTimes(1); }); - it("calls alertStore.fetchWithThrottle again after interval change", () => { - const fetchSpy = jest.spyOn(alertStore, "fetchWithThrottle"); - MountedFetcher(); - settingsStore.fetchConfig.config.interval = 60; - expect(fetchSpy).toHaveBeenCalledTimes(2); - }); - it("calls alertStore.fetchWithThrottle again after filter change", () => { MockEmptyAPIResponseWithoutFilters(); const fetchSpy = jest.spyOn(alertStore, "fetchWithThrottle"); - MountedFetcher(); + const tree = MountedFetcher(); alertStore.filters.values = []; + tree.setProps({}); expect(fetchSpy).toHaveBeenCalledTimes(2); }); @@ -301,6 +299,7 @@ describe("", () => { alertStore.status.resume(); settingsStore.gridConfig.config.reverseSort = !settingsStore.gridConfig .config.reverseSort; + jest.runOnlyPendingTimers(); expect(fetchSpy).toHaveBeenCalledTimes(1); });