From 3113ae4651ddd73e7bdf745d0c7caba7e83f441d Mon Sep 17 00:00:00 2001 From: Kyle Knight Date: Fri, 13 Jan 2017 16:15:03 -0600 Subject: [PATCH] Add a timer component to new query screen (#944) --- .../forms/queries/QueryForm/QueryForm.jsx | 3 + .../forms/queries/QueryForm/_styles.scss | 7 +- frontend/components/loaders/Timer/Timer.jsx | 68 +++++++++++++++++++ .../components/loaders/Timer/Timer.tests.jsx | 46 +++++++++++++ .../components/loaders/Timer/_styles.scss | 4 ++ frontend/components/loaders/Timer/helpers.js | 7 ++ .../components/loaders/Timer/helpers.tests.js | 12 ++++ frontend/components/loaders/Timer/index.js | 1 + 8 files changed, 144 insertions(+), 4 deletions(-) create mode 100644 frontend/components/loaders/Timer/Timer.jsx create mode 100644 frontend/components/loaders/Timer/Timer.tests.jsx create mode 100644 frontend/components/loaders/Timer/_styles.scss create mode 100644 frontend/components/loaders/Timer/helpers.js create mode 100644 frontend/components/loaders/Timer/helpers.tests.js create mode 100644 frontend/components/loaders/Timer/index.js diff --git a/frontend/components/forms/queries/QueryForm/QueryForm.jsx b/frontend/components/forms/queries/QueryForm/QueryForm.jsx index 7ab45d66e7..886cf8dd9f 100644 --- a/frontend/components/forms/queries/QueryForm/QueryForm.jsx +++ b/frontend/components/forms/queries/QueryForm/QueryForm.jsx @@ -13,6 +13,7 @@ import queryInterface from 'interfaces/query'; import SelectTargetsDropdown from 'components/forms/fields/SelectTargetsDropdown'; import targetInterface from 'interfaces/target'; import validateQuery from 'components/forms/validators/validate_query'; +import Timer from 'components/loaders/Timer'; const baseClass = 'query-form'; @@ -204,6 +205,8 @@ class QueryForm extends Component { return (
+ {queryIsRunning && } + { + const { interval, update } = this; + + if (!interval) { + this.interval = setInterval(update, 1000); + } + } + + pause = () => { + const { interval } = this; + + if (interval) { + clearInterval(interval); + this.interval = null; + } + } + + reset = () => { + this.setState({ totalMilliseconds: 0 }); + } + + update = () => { + const { totalMilliseconds } = this.state; + + this.setState({ totalMilliseconds: totalMilliseconds + 1000 }); + } + + render () { + const { totalMilliseconds } = this.state; + + return ( + {convertSeconds(totalMilliseconds)} + ); + } +} + +export default Timer; diff --git a/frontend/components/loaders/Timer/Timer.tests.jsx b/frontend/components/loaders/Timer/Timer.tests.jsx new file mode 100644 index 0000000000..5e445d962d --- /dev/null +++ b/frontend/components/loaders/Timer/Timer.tests.jsx @@ -0,0 +1,46 @@ +import React from 'react'; +import { mount } from 'enzyme'; +import expect, { spyOn, restoreSpies } from 'expect'; + +import Timer from './Timer'; + +describe('Timer - component', () => { + afterEach(restoreSpies); + + it('play() and pause() function', () => { + const timer = mount(); + + expect(timer.node.interval).toNotExist(); + timer.setProps({ running: true }); + expect(timer.node.interval).toExist(); + timer.setProps({ running: false }); + expect(timer.node.interval).toNotExist(); + }); + + it('should reset after pause', () => { + const timer = mount(); + const spy = spyOn(timer.node, 'reset').andCallThrough(); + + timer.setProps({ running: true }); + + expect(spy).toHaveBeenCalled(); + }); + + it('should not reset when stopped', () => { + const timer = mount(); + const spy = spyOn(timer.node, 'reset').andCallThrough(); + + timer.setProps({ running: false }); + + expect(spy).toNotHaveBeenCalled(); + }); + + it('should not reset when it continues', () => { + const timer = mount(); + const spy = spyOn(timer.node, 'reset').andCallThrough(); + + timer.setProps({ running: true }); + + expect(spy).toNotHaveBeenCalled(); + }); +}); diff --git a/frontend/components/loaders/Timer/_styles.scss b/frontend/components/loaders/Timer/_styles.scss new file mode 100644 index 0000000000..3dde2125e7 --- /dev/null +++ b/frontend/components/loaders/Timer/_styles.scss @@ -0,0 +1,4 @@ +.kolide-timer { + font-size: 14px; + color: $text-medium; +} diff --git a/frontend/components/loaders/Timer/helpers.js b/frontend/components/loaders/Timer/helpers.js new file mode 100644 index 0000000000..201af667f9 --- /dev/null +++ b/frontend/components/loaders/Timer/helpers.js @@ -0,0 +1,7 @@ +import moment from 'moment'; + +export const convertSeconds = (totalMilliSeconds) => { + return moment.utc(totalMilliSeconds).format('HH:mm:ss'); +}; + +export default { convertSeconds }; diff --git a/frontend/components/loaders/Timer/helpers.tests.js b/frontend/components/loaders/Timer/helpers.tests.js new file mode 100644 index 0000000000..e12ff517d4 --- /dev/null +++ b/frontend/components/loaders/Timer/helpers.tests.js @@ -0,0 +1,12 @@ +import expect from 'expect'; + +import { convertSeconds } from './helpers'; + +describe('Timer convertSeconds helper', () => { + it('converts seconds to hh:mm:ss', () => { + expect(convertSeconds(3000)).toEqual('00:00:03'); + expect(convertSeconds(30000)).toEqual('00:00:30'); + expect(convertSeconds(300000)).toEqual('00:05:00'); + expect(convertSeconds(0)).toEqual('00:00:00'); + }); +}); diff --git a/frontend/components/loaders/Timer/index.js b/frontend/components/loaders/Timer/index.js new file mode 100644 index 0000000000..8709103bef --- /dev/null +++ b/frontend/components/loaders/Timer/index.js @@ -0,0 +1 @@ +export default from './Timer';