Add a timer component to new query screen (#944)

This commit is contained in:
Kyle Knight 2017-01-13 16:15:03 -06:00 committed by Jason Meller
parent ed1fa22729
commit 3113ae4651
8 changed files with 144 additions and 4 deletions

View file

@ -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 (
<div className={`${baseClass}__button-wrap`}>
{queryIsRunning && <Timer running={queryIsRunning} />}
<DropdownButton
className={`${baseClass}__save`}
options={dropdownBtnOptions}

View file

@ -15,11 +15,10 @@
.query-form__stop-query-btn {
margin-left: $pad-xsmall;
}
}
&__btn-wrapper {
margin-top: $base;
text-align: right;
.kolide-timer {
display: block;
}
}
&__save-query-btn,

View file

@ -0,0 +1,68 @@
import React, { Component, PropTypes } from 'react';
import { convertSeconds } from './helpers';
const baseClass = 'kolide-timer';
class Timer extends Component {
static propTypes = {
running: PropTypes.bool,
}
constructor (props) {
super(props);
this.state = { totalMilliseconds: 0 };
}
componentWillReceiveProps ({ running }) {
const { running: currentRunning } = this.props;
if (running) {
if (!currentRunning) {
this.reset();
}
this.play();
} else {
this.pause();
}
}
play = () => {
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 (
<span className={baseClass}>{convertSeconds(totalMilliseconds)}</span>
);
}
}
export default Timer;

View file

@ -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(<Timer running={false} />);
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(<Timer running={false} />);
const spy = spyOn(timer.node, 'reset').andCallThrough();
timer.setProps({ running: true });
expect(spy).toHaveBeenCalled();
});
it('should not reset when stopped', () => {
const timer = mount(<Timer running />);
const spy = spyOn(timer.node, 'reset').andCallThrough();
timer.setProps({ running: false });
expect(spy).toNotHaveBeenCalled();
});
it('should not reset when it continues', () => {
const timer = mount(<Timer running />);
const spy = spyOn(timer.node, 'reset').andCallThrough();
timer.setProps({ running: true });
expect(spy).toNotHaveBeenCalled();
});
});

View file

@ -0,0 +1,4 @@
.kolide-timer {
font-size: 14px;
color: $text-medium;
}

View file

@ -0,0 +1,7 @@
import moment from 'moment';
export const convertSeconds = (totalMilliSeconds) => {
return moment.utc(totalMilliSeconds).format('HH:mm:ss');
};
export default { convertSeconds };

View file

@ -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');
});
});

View file

@ -0,0 +1 @@
export default from './Timer';