diff --git a/ui/src/Components/ManagedSilence/SilenceProgress.js b/ui/src/Components/ManagedSilence/SilenceProgress.js index 39af2d644..b90940f92 100644 --- a/ui/src/Components/ManagedSilence/SilenceProgress.js +++ b/ui/src/Components/ManagedSilence/SilenceProgress.js @@ -1,7 +1,6 @@ -import React, { Component } from "react"; +import React, { useEffect } from "react"; -import { observable, action } from "mobx"; -import { observer } from "mobx-react"; +import { useObserver, useLocalStore } from "mobx-react"; import moment from "moment"; import Moment from "react-moment"; @@ -10,86 +9,58 @@ import { APISilence } from "Models/API"; import "./SilenceProgress.scss"; -const SilenceProgress = observer( - class SilenceProgress extends Component { - static propTypes = { - silence: APISilence.isRequired, - }; - - progress = observable( - { - value: 0, - calculate(startsAt, endsAt) { - const durationDone = moment().unix() - moment(startsAt).unix(); - const durationTotal = moment(endsAt).unix() - moment(startsAt).unix(); - const durationPercent = Math.floor( - (durationDone / durationTotal) * 100 - ); - if (this.value !== durationPercent) { - this.value = durationPercent; - } - }, - }, - { - calculate: action.bound, +const SilenceProgress = ({ silence }) => { + const progress = useLocalStore(() => ({ + value: 0, + calculate(startsAt, endsAt) { + const durationDone = moment().unix() - moment(startsAt).unix(); + const durationTotal = moment(endsAt).unix() - moment(startsAt).unix(); + const durationPercent = Math.floor((durationDone / durationTotal) * 100); + if (this.value !== durationPercent) { + this.value = durationPercent; } - ); + }, + })); - constructor(props) { - super(props); + useEffect(() => { + progress.calculate(silence.startsAt, silence.endsAt); - this.recalculateProgress(); - this.progressTimer = setInterval(this.recalculateProgress, 30 * 1000); - } + const timer = setInterval(() => { + progress.calculate(silence.startsAt, silence.endsAt); + }, 30 * 1000); + return () => clearInterval(timer); + }, [progress, silence.startsAt, silence.endsAt]); - componentWillUnmount() { - clearInterval(this.progressTimer); - this.progressTimer = null; - } - - recalculateProgress = () => { - const { silence } = this.props; - this.progress.calculate(silence.startsAt, silence.endsAt); - }; - - render() { - const { silence } = this.props; - - // if silence is expired we can skip progress value calculation - if (moment(silence.endsAt) < moment()) { - return ( - - Expired {silence.endsAt} - - ); - } - - let progressClass; - if (this.progress.value > 90) { - progressClass = "progress-bar bg-danger"; - } else if (this.progress.value > 75) { - progressClass = "progress-bar bg-warning"; - } else { - progressClass = "progress-bar bg-success"; - } - - return ( - - Expires {silence.endsAt} -
-
-
- - ); - } - } -); + return useObserver(() => + moment(silence.endsAt) < moment() ? ( + + Expired {silence.endsAt} + + ) : ( + + Expires {silence.endsAt} +
+
90 + ? "progress-bar bg-danger" + : progress.value > 75 + ? "progress-bar bg-warning" + : "progress-bar bg-success" + } + role="progressbar" + style={{ width: progress.value + "%" }} + aria-valuenow={progress.value} + aria-valuemin="0" + aria-valuemax="100" + /> +
+ + ) + ); +}; +SilenceProgress.propTypes = { + silence: APISilence.isRequired, +}; export { SilenceProgress }; diff --git a/ui/src/Components/ManagedSilence/SilenceProgress.test.js b/ui/src/Components/ManagedSilence/SilenceProgress.test.js index f305a6cb2..b41b738ea 100644 --- a/ui/src/Components/ManagedSilence/SilenceProgress.test.js +++ b/ui/src/Components/ManagedSilence/SilenceProgress.test.js @@ -2,8 +2,6 @@ import React from "react"; import { mount } from "enzyme"; -import { toJS } from "mobx"; - import toDiffableHtml from "diffable-html"; import moment from "moment"; @@ -14,6 +12,10 @@ import { SilenceProgress } from "./SilenceProgress"; let silence; +beforeAll(() => { + jest.useFakeTimers(); +}); + beforeEach(() => { silence = MockSilence(); @@ -57,24 +59,22 @@ describe("", () => { expect(toDiffableHtml(tree.html())).toMatch(/progress-bar bg-success/); }); - it("calling calculate() on progress multiple times in a row doesn't change the value", () => { - const startsAt = moment.utc([2000, 0, 1, 0, 0, 0]); - const endsAt = moment.utc([2000, 0, 1, 1, 0, 0]); - + it("progressbar is updated every 30 seconds", () => { + advanceTo(moment.utc([2000, 0, 1, 0, 30, 0])); const tree = MountedSilenceProgress(); - const instance = tree.instance(); + expect(toDiffableHtml(tree.html())).toMatch(/progress-bar bg-success/); - const value = toJS(instance.progress.value); - instance.progress.calculate(startsAt, endsAt); - instance.progress.calculate(startsAt, endsAt); - instance.progress.calculate(startsAt, endsAt); - expect(toJS(instance.progress.value)).toBe(value); + advanceTo(moment.utc([2000, 0, 1, 0, 50, 0])); + jest.runOnlyPendingTimers(); + expect(toDiffableHtml(tree.html())).toMatch(/progress-bar bg-warning/); + + advanceTo(moment.utc([2000, 0, 1, 0, 55, 0])); + jest.runOnlyPendingTimers(); + expect(toDiffableHtml(tree.html())).toMatch(/progress-bar bg-danger/); }); - it("resets the timer on unmount", () => { + it("unmounts cleanly", () => { const tree = MountedSilenceProgress(); - expect(tree.instance().progressTimer).not.toBeNull(); - tree.instance().componentWillUnmount(); - expect(tree.instance().progressTimer).toBeNull(); + tree.unmount(); }); });