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';