couchdb-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From gar...@apache.org
Subject fauxton commit: updated refs/heads/master to a9a1099
Date Tue, 08 Nov 2016 08:23:13 GMT
Repository: couchdb-fauxton
Updated Branches:
  refs/heads/master 1fa0e3975 -> a9a10999f


Create polling component

Update active tasks to use the polling component


Project: http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/repo
Commit: http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/commit/a9a10999
Tree: http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/tree/a9a10999
Diff: http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/diff/a9a10999

Branch: refs/heads/master
Commit: a9a10999fca6a8669d96107eca479b92093c88bc
Parents: 1fa0e39
Author: Garren Smith <garren.smith@gmail.com>
Authored: Mon Nov 7 14:17:26 2016 +0200
Committer: Garren Smith <garren.smith@gmail.com>
Committed: Tue Nov 8 10:22:41 2016 +0200

----------------------------------------------------------------------
 app/addons/activetasks/actions.js               |   8 ++
 app/addons/activetasks/actiontypes.js           |   4 +-
 .../activetasks/assets/less/activetasks.less    |  55 +-------
 app/addons/activetasks/components.react.jsx     |  68 +++-------
 app/addons/activetasks/resources.js             |   3 +-
 app/addons/activetasks/stores.js                |  48 ++-----
 .../tests/activetasks.componentsSpec.react.jsx  |  19 ---
 .../activetasks/tests/activetasks.storesSpec.js |  86 ------------
 .../components/assets/less/components.less      |   1 +
 app/addons/components/assets/less/polling.less  |  39 ++++++
 app/addons/components/components/polling.js     | 130 +++++++++++++++++++
 .../components/react-components.react.jsx       |   2 +
 app/addons/components/tests/pollingSpec.js      | 108 +++++++++++++++
 13 files changed, 323 insertions(+), 248 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/a9a10999/app/addons/activetasks/actions.js
----------------------------------------------------------------------
diff --git a/app/addons/activetasks/actions.js b/app/addons/activetasks/actions.js
index 76032fe..e6213cd 100644
--- a/app/addons/activetasks/actions.js
+++ b/app/addons/activetasks/actions.js
@@ -68,5 +68,13 @@ export default {
       type: ActionTypes.ACTIVE_TASKS_SET_IS_LOADING,
       options: boolean
     });
+  },
+  runPollingUpdate (collection) {
+    collection.pollingFetch().then(() => {
+      FauxtonAPI.dispatch({
+        type: ActionTypes.ACTIVE_TASKS_POLLING_COLLECTION,
+        options: collection.table
+      });
+    });
   }
 };

http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/a9a10999/app/addons/activetasks/actiontypes.js
----------------------------------------------------------------------
diff --git a/app/addons/activetasks/actiontypes.js b/app/addons/activetasks/actiontypes.js
index d934cb8..16e463d 100644
--- a/app/addons/activetasks/actiontypes.js
+++ b/app/addons/activetasks/actiontypes.js
@@ -10,11 +10,11 @@
 // License for the specific language governing permissions and limitations under
 // the License.
 export default {
-  ACTIVE_TASKS_CHANGE_POLLING_INTERVAL: 'ACTIVE_TASKS_CHANGE_POLLING_INTERVAL',
   ACTIVE_TASKS_SWITCH_TAB: 'ACTIVE_TASKS_SWITCH_TAB',
   ACTIVE_TASKS_SET_COLLECTION: 'ACTIVE_TASKS_SET_COLLECTION',
   ACTIVE_TASKS_SET_SEARCH_TERM: 'ACTIVE_TASKS_SET_SEARCH_TERM',
   ACTIVE_TASKS_SORT_BY_COLUMN_HEADER: 'ACTIVE_TASKS_SORT_BY_COLUMN_HEADER',
   ACTIVE_TASKS_FETCH_AND_SET: 'ACTIVE_TASKS_FETCH_AND_SET',
-  ACTIVE_TASKS_SET_IS_LOADING: 'ACTIVE_TASKS_SET_IS_LOADING'
+  ACTIVE_TASKS_SET_IS_LOADING: 'ACTIVE_TASKS_SET_IS_LOADING',
+  ACTIVE_TASKS_POLLING_COLLECTION: 'ACTIVE_TASKS_POLLING_COLLECTION'
 };

http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/a9a10999/app/addons/activetasks/assets/less/activetasks.less
----------------------------------------------------------------------
diff --git a/app/addons/activetasks/assets/less/activetasks.less b/app/addons/activetasks/assets/less/activetasks.less
index 85d3e9e..eed5754 100644
--- a/app/addons/activetasks/assets/less/activetasks.less
+++ b/app/addons/activetasks/assets/less/activetasks.less
@@ -188,54 +188,9 @@
   }
 }
 
-.nav.polling-interval {
-  li.nav-header {
-    padding: 9px 0px 0px 9px;
-  }
-  li {
-    padding: 0px 15px 3px 9px;
-    margin-left: 0px;
-
-    input {
-      width: 100%;
-    }
-
-    label span {
-      font-weight: bold;
-    }
-  }
-}
-
-.polling-interval-widget {
-  width: 225px;
-  margin: 10px 30px 0 0;
-  color: #666;
-  float: right;
-
-  li {
-    list-style-type: none;
-  }
-  .polling-interval-time-label {
-    display: inline-block;
-    float: right;
-    margin-right: 0;
-    cursor: default;
-  }
-  #polling-range {
-    width: 225px;
-  }
-}
-
-.active-tasks-loading-lines-container {
-  width: 355px;
-  .active-tasks-loading-lines {
-    border: 0;
-    position: relative;
-    top: 17px;
-    float: left;
-    padding-left: 20px;
-    #line1, #line2, #line3, #line4 {
-      background-color: #bbb;
-    }
-  }
+.active-tasks__polling-wrapper {
+  display: flex;
+  align-items: center;
+  flex-direction: row;
+  height: 100%;
 }

http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/a9a10999/app/addons/activetasks/components.react.jsx
----------------------------------------------------------------------
diff --git a/app/addons/activetasks/components.react.jsx b/app/addons/activetasks/components.react.jsx
index 7ad0f4c..d95be2c 100644
--- a/app/addons/activetasks/components.react.jsx
+++ b/app/addons/activetasks/components.react.jsx
@@ -21,8 +21,7 @@ import Components from "../components/react-components.react";
 import ComponentsReact from "../fauxton/components.react";
 import ReactCSSTransitionGroup from "react-addons-css-transition-group";
 
-const TabElementWrapper = Components.TabElementWrapper;
-const TabElement = Components.TabElement;
+const {TabElement, TabElementWrapper, Polling} = Components;
 
 const activeTasksStore = Stores.activeTasksStore;
 
@@ -35,10 +34,8 @@ export const ActiveTasksController = React.createClass({
       selectedRadio: activeTasksStore.getSelectedRadio(),
 
       sortByHeader: activeTasksStore.getSortByHeader(),
-      headerIsAscending: activeTasksStore.getHeaderIsAscending(),
+      headerIsAscending: activeTasksStore.getHeaderIsAscending()
 
-      setPolling: activeTasksStore.setPolling,
-      clearPolling: activeTasksStore.clearPolling
     };
   },
 
@@ -48,12 +45,10 @@ export const ActiveTasksController = React.createClass({
 
   componentDidMount () {
     Actions.init(new Resources.AllTasks());
-    this.state.setPolling();
     activeTasksStore.on('change', this.onChange, this);
   },
 
   componentWillUnmount () {
-    this.state.clearPolling();
     activeTasksStore.off('change', this.onChange, this);
   },
 
@@ -428,8 +423,7 @@ export const ActiveTasksPollingWidgetController = React.createClass({
 
   getStoreState () {
     return {
-      pollingInterval:  activeTasksStore.getPollingInterval(),
-      isLoading: activeTasksStore.isLoading()
+      collection:  activeTasksStore.getBackboneCollection()
     };
   },
 
@@ -442,60 +436,28 @@ export const ActiveTasksPollingWidgetController = React.createClass({
   },
 
   onChange () {
-    if (this.isMounted()) {
-      this.setState(this.getStoreState());
-    }
+    this.setState(this.getStoreState());
   },
 
-  pollingIntervalChange (event) {
-    Actions.changePollingInterval(event.target.value);
+  runPollingUpdate () {
+    Actions.runPollingUpdate(this.state.collection);
   },
 
   getPluralForLabel () {
     return this.state.pollingInterval === "1" ? '' : 's';
   },
 
-  createPollingWidget () {
-    const {pollingInterval} = this.state;
-    const s = this.getPluralForLabel();
-
-    return (
-      <ul className="polling-interval-widget">
-        <li className="polling-interval-name">Polling interval
-          <label className="polling-interval-time-label" htmlFor="polling-range">
-            <span>{pollingInterval}</span> second{s}
-          </label>
-        </li>
-        <li>
-          <input
-            id="polling-range"
-            type="range"
-            min="1"
-            max="30"
-            step="1"
-            value={pollingInterval}
-            onChange={this.pollingIntervalChange}/>
-        </li>
-      </ul>
-    );
-  },
-
   render () {
-    var pollingWidget = this.createPollingWidget();
-    var loadLines = null;
-
-    if (this.state.isLoading || this.state.pollingInterval === "1") {
-      // show loading lines constantly if the polling interval is
-      // 1 second, so that the lines aren't choppy
-      loadLines = <Components.LoadLines />;
-    }
-
     return (
-      <div className="active-tasks-loading-lines-container">
-        <span className="active-tasks-loading-lines">
-          {loadLines}
-        </span>
-        {pollingWidget}
+      <div className="active-tasks__polling-wrapper">
+        <Polling
+          min={1}
+          max={30}
+          stepSize={1}
+          startValue={15}
+          valueUnits={"second"}
+          onPoll={this.runPollingUpdate}
+          />
       </div>
     );
   }

http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/a9a10999/app/addons/activetasks/resources.js
----------------------------------------------------------------------
diff --git a/app/addons/activetasks/resources.js b/app/addons/activetasks/resources.js
index ea559de..55967f8 100644
--- a/app/addons/activetasks/resources.js
+++ b/app/addons/activetasks/resources.js
@@ -22,9 +22,8 @@ Active.AllTasks = Backbone.Collection.extend({
   },
 
   pollingFetch: function () { //still need this for the polling
-    this.fetch({reset: true, parse: true});
     Actions.setActiveTaskIsLoading(true);
-    return this;
+    return this.fetch({reset: true, parse: true});
   },
 
   parse: function (resp) {

http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/a9a10999/app/addons/activetasks/stores.js
----------------------------------------------------------------------
diff --git a/app/addons/activetasks/stores.js b/app/addons/activetasks/stores.js
index f17088e..51b31ed 100644
--- a/app/addons/activetasks/stores.js
+++ b/app/addons/activetasks/stores.js
@@ -62,36 +62,9 @@ var ActiveTasksStore = FauxtonAPI.Store.extend({
     this._selectedRadio = selectedRadio;
   },
 
-  getPollingInterval () {
-    return this._pollingIntervalSeconds;
-  },
-
-  setPollingInterval (pollingInterval) {
-    this._pollingIntervalSeconds = pollingInterval;
-  },
-
-  setPolling () {
-    this.clearPolling();
-    var id = setInterval(() => {
-      this._backboneCollection.pollingFetch();
-      this.setCollection(this._backboneCollection.table);
-      this.sortCollectionByColumnHeader(this._prevSortbyHeader, false);
-      this.triggerChange();
-    }, this.getPollingInterval() * 1000);
-
-    this.setIntervalID(id);
-  },
-
-  clearPolling () {
-    clearInterval(this.getIntervalID());
-  },
-
-  getIntervalID () {
-    return this._intervalID;
-  },
-
-  setIntervalID (id) {
-    this._intervalID = id;
+  setCollectionFromPolling (collection) {
+    this.setCollection(collection);
+    this.sortCollectionByColumnHeader(this._prevSortbyHeader, false);
   },
 
   setCollection (collection) {
@@ -102,6 +75,10 @@ var ActiveTasksStore = FauxtonAPI.Store.extend({
     return this._collection;
   },
 
+  getBackboneCollection () {
+    return this._backboneCollection;
+  },
+
   setSearchTerm (searchTerm) {
     this._searchTerm = searchTerm;
   },
@@ -201,12 +178,6 @@ var ActiveTasksStore = FauxtonAPI.Store.extend({
         this.initAfterFetching(action.options.collectionTable, action.options.backboneCollection);
       break;
 
-      case ActionTypes.ACTIVE_TASKS_CHANGE_POLLING_INTERVAL:
-        this.setPollingInterval(action.options);
-        this.setPolling();
-        this.triggerChange();
-      break;
-
       case ActionTypes.ACTIVE_TASKS_SWITCH_TAB:
         this.setSelectedRadio(action.options);
         this.triggerChange();
@@ -234,6 +205,11 @@ var ActiveTasksStore = FauxtonAPI.Store.extend({
         this.triggerChange();
       break;
 
+      case ActionTypes.ACTIVE_TASKS_POLLING_COLLECTION:
+        this.setCollectionFromPolling(action.options);
+        this.triggerChange();
+      break;
+
       default:
       return;
     }

http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/a9a10999/app/addons/activetasks/tests/activetasks.componentsSpec.react.jsx
----------------------------------------------------------------------
diff --git a/app/addons/activetasks/tests/activetasks.componentsSpec.react.jsx b/app/addons/activetasks/tests/activetasks.componentsSpec.react.jsx
index 3b1dace..d22be2f 100644
--- a/app/addons/activetasks/tests/activetasks.componentsSpec.react.jsx
+++ b/app/addons/activetasks/tests/activetasks.componentsSpec.react.jsx
@@ -29,25 +29,6 @@ activeTasksCollection.parse(fakedResponse);
 
 describe('Active Tasks -- Components', function () {
 
-  afterEach(() => {
-    activeTasksStore.clearPolling();
-  });
-
-  describe('Active Tasks Polling (Components)', function () {
-    var pollingWidgetDiv, pollingWidget;
-
-    afterEach(function () {
-      restore(Actions.changePollingInterval);
-    });
-
-    it('should trigger update polling interval', function () {
-      const controller = mount(<Components.ActiveTasksPollingWidgetController />);
-      var spy = sinon.spy(Actions, 'changePollingInterval');
-      controller.find('#polling-range').simulate('change', {target: {value: 9}});
-      assert.ok(spy.calledOnce);
-    });
-  });
-
   describe('Active Tasks Table (Components)', function () {
     var table, tableDiv, spy, filterTab;
 

http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/a9a10999/app/addons/activetasks/tests/activetasks.storesSpec.js
----------------------------------------------------------------------
diff --git a/app/addons/activetasks/tests/activetasks.storesSpec.js b/app/addons/activetasks/tests/activetasks.storesSpec.js
index b2d0b30..1ffa698 100644
--- a/app/addons/activetasks/tests/activetasks.storesSpec.js
+++ b/app/addons/activetasks/tests/activetasks.storesSpec.js
@@ -25,94 +25,8 @@ var activeTasksCollection = new ActiveTasks.AllTasks();
 activeTasksCollection.parse(fakedResponse);
 
 describe('Active Tasks -- Stores', function () {
-  var spy, clock;
-
   beforeEach(function () {
     activeTasksStore.initAfterFetching(activeTasksCollection.table, activeTasksCollection);
-    clock = sinon.useFakeTimers();
-  });
-
-  afterEach(function () {
-    restore(spy);
-    clock.restore();
-  });
-
-  describe('Active Task Stores - Polling', function () {
-
-    beforeEach(function () {
-      activeTasksStore.initAfterFetching(activeTasksCollection.table, activeTasksCollection);
-    });
-
-    afterEach(function () {
-      restore(activeTasksStore.getPollingInterval);
-      restore(window.clearInterval);
-    });
-
-    it('should poll at the min time', function () {
-      spy = sinon.spy(activeTasksStore, 'getPollingInterval');
-      var minTime = 1;
-      activeTasksStore.setPollingInterval(minTime);
-      activeTasksStore.setPolling();
-      assert.ok(spy.calledOnce, 'not called');
-
-      setInterval(spy, minTime * 1000);
-      clock.tick(minTime * 1001);
-      assert.ok(spy.calledTwice, 'not called twice');
-
-      clock.tick(minTime * 1001);
-      assert.ok(spy.calledThrice, 'not called 3 times');
-    });
-
-    it('should poll at the max time', function () {
-      spy = sinon.spy(activeTasksStore, 'getPollingInterval');
-
-      var maxTime = 30;
-      activeTasksStore.setPollingInterval(maxTime);
-      activeTasksStore.setPolling();
-      assert.ok(spy.calledOnce);
-
-      setInterval(spy, maxTime * 1000);
-      clock.tick(maxTime * 1000);
-      assert.ok(spy.calledTwice);
-
-      clock.tick(maxTime * 1000);
-      assert.ok(spy.calledThrice);
-    });
-
-    it('should poll at a mid time', function () {
-      spy = sinon.spy(activeTasksStore, 'getPollingInterval');
-
-      var midtime = 15;
-      activeTasksStore.setPollingInterval(midtime);
-      activeTasksStore.setPolling();
-      assert.ok(spy.calledOnce);
-
-      setInterval(spy, midtime * 1000);
-      clock.tick(midtime * 1000);
-      assert.ok(spy.calledTwice);
-
-      clock.tick(midtime * 1000);
-      assert.ok(spy.calledThrice);
-    });
-
-    it('should clear interval each time', function () {
-      var spy = sinon.spy(window, 'clearInterval');
-      activeTasksStore.setPolling();
-      assert.ok(spy.calledOnce);
-    });
-
-    it('should set the isLoading variable so that the loading lines show up', function ()
{
-      spy = sinon.spy(activeTasksStore, 'setIsLoading');
-      var date = new Date();
-
-      activeTasksCollection.pollingFetch();
-      assert.ok(spy.withArgs(true, date).calledOnce);
-
-      activeTasksCollection.parse(fakedResponse);
-      assert.ok(spy.withArgs(false, date).calledOnce);
-
-      restore(activeTasksStore.setIsLoading);
-    });
   });
 
   describe('Active Task Stores - Filter Tab Tray', function () {

http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/a9a10999/app/addons/components/assets/less/components.less
----------------------------------------------------------------------
diff --git a/app/addons/components/assets/less/components.less b/app/addons/components/assets/less/components.less
index d9ef5c4..53e15de 100644
--- a/app/addons/components/assets/less/components.less
+++ b/app/addons/components/assets/less/components.less
@@ -23,3 +23,4 @@
 @import "tab-element.less";
 @import "header-breadcrumbs.less";
 @import "layouts.less";
+@import "polling.less";

http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/a9a10999/app/addons/components/assets/less/polling.less
----------------------------------------------------------------------
diff --git a/app/addons/components/assets/less/polling.less b/app/addons/components/assets/less/polling.less
new file mode 100644
index 0000000..36657fa
--- /dev/null
+++ b/app/addons/components/assets/less/polling.less
@@ -0,0 +1,39 @@
+// Licensed under the Apache License, Version 2.0 (the "License"); you may not
+// use this file except in compliance with the License. You may obtain a copy of
+// the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations under
+// the License.
+
+.faux__polling {
+  padding: 0 15px !important;
+}
+
+.faux__polling-info {
+  font-size: 14px;
+}
+
+.faux__polling-info-text {
+  color: #666;
+}
+
+.faux__polling-info-value {
+  float: right;
+}
+
+.faux__polling-info-value--off {
+  color: #999;
+}
+
+.faux__polling-info-value--active {
+  color: #AF2D24;
+}
+
+.faux__polling-info-slider {
+  cursor: pointer;
+}

http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/a9a10999/app/addons/components/components/polling.js
----------------------------------------------------------------------
diff --git a/app/addons/components/components/polling.js b/app/addons/components/components/polling.js
new file mode 100644
index 0000000..2afead6
--- /dev/null
+++ b/app/addons/components/components/polling.js
@@ -0,0 +1,130 @@
+// Licensed under the Apache License, Version 2.0 (the 'License'); you may not
+// use this file except in compliance with the License. You may obtain a copy of
+// the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an 'AS IS' BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations under
+// the License.
+
+import React from 'react';
+import ReactDOM from 'react-dom';
+
+let pollIntervalId;
+
+export const clearPollCounter = () => {
+  if (pollIntervalId) {
+    window.clearInterval(pollIntervalId);
+  }
+};
+
+export const resetPollCounter = (time, cb) => {
+  clearPollCounter();
+  pollIntervalId = window.setInterval(cb, time);
+};
+
+const getCountdown = (secsString, units, max, min) => {
+  const secs = parseInt(secsString, 10);
+  if (secs === 0 || secs > max || secs < min) {
+    return 'off';
+  }
+
+  if (secs < 60 && units === 'minute') {
+    return `${secs} seconds`;
+  }
+
+  let displayValue = secs;
+  if (units === 'minute') {
+    displayValue = Math.floor(secs / 60);
+  }
+  return `${displayValue} ${displayValue === 1 ? units : `${units}s`}`;
+};
+
+export class Polling extends React.Component {
+  constructor (props) {
+    super(props);
+    this.state = {
+      value: this.props.startValue
+    };
+  }
+
+  componentDidMount () {
+    this.setPollingCounter(this.state.value);
+  }
+
+  componentWillUnmount () {
+    clearPollCounter();
+  }
+
+  setPollingCounter (value) {
+    const {min, max, onPoll} = this.props;
+    this.setState({value: value});
+
+    if (value === 0 || value < min || value > max) {
+      clearPollCounter();
+      return;
+    }
+
+    resetPollCounter(value * 1000, () => onPoll());
+  }
+
+  updatePollingFreq (e) {
+    this.setPollingCounter(parseInt(e.target.value, 10));
+  }
+
+  componentWillReceiveProps(nextProps) {
+    if (this.props.startValue !== nextProps.startValue) {
+      this.setPollingCounter(nextProps.startValue);
+    }
+  }
+
+  render () {
+    const {
+      pollingFreqOptions,
+      stepSize,
+      min,
+      max,
+      valueUnits
+    } = this.props;
+
+    const {value} = this.state;
+
+    const pollValue = getCountdown(value, valueUnits, max, min);
+    const pollStyle = pollValue === 'off' ? 'faux__polling-info-value--off' : 'faux__polling-info-value--active';
+    return (
+      <div className='faux__polling'>
+        <div className='faux__polling-info'>
+          <span className='faux__polling-info-text'>Polling Interval</span>
+          <span className={`faux__polling-info-value faux__polling-info-value ${pollStyle}`}>{pollValue}</span>
+        </div>
+        <input
+          onChange={this.updatePollingFreq.bind(this)}
+          className='faux__polling-info-slider'
+          type='range'
+          value={value}
+          min={min}
+          max={max + stepSize}
+          step={stepSize}
+        />
+      </div>
+    );
+  }
+};
+
+Polling.defaultProps = {
+  startValue: 0,
+  min: 0,
+  valueUnits: 'minute'
+};
+
+Polling.propTypes = {
+  startValue: React.PropTypes.number,
+  valueUnits: React.PropTypes.string,
+  min: React.PropTypes.number,
+  max: React.PropTypes.number.isRequired,
+  stepSize: React.PropTypes.number.isRequired,
+  onPoll: React.PropTypes.func.isRequired,
+};

http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/a9a10999/app/addons/components/react-components.react.jsx
----------------------------------------------------------------------
diff --git a/app/addons/components/react-components.react.jsx b/app/addons/components/react-components.react.jsx
index be98c91..ec1886f 100644
--- a/app/addons/components/react-components.react.jsx
+++ b/app/addons/components/react-components.react.jsx
@@ -28,6 +28,7 @@ import {TrayContents, TrayWrapper, connectToStores} from './components/tray';
 import {ApiBarController} from './components/apibar';
 import {DeleteDatabaseModal} from './components/deletedatabasemodal';
 import {TabElement, TabElementWrapper} from './components/tabelement';
+import {Polling} from './components/polling';
 
 export default {
   BadgeList,
@@ -42,6 +43,7 @@ export default {
   ZenModeOverlay,
   Beautify,
   PaddedBorderedBox,
+  Polling,
   Document,
   LoadLines,
   MenuDropDown,

http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/a9a10999/app/addons/components/tests/pollingSpec.js
----------------------------------------------------------------------
diff --git a/app/addons/components/tests/pollingSpec.js b/app/addons/components/tests/pollingSpec.js
new file mode 100644
index 0000000..b311287
--- /dev/null
+++ b/app/addons/components/tests/pollingSpec.js
@@ -0,0 +1,108 @@
+// Licensed under the Apache License, Version 2.0 (the "License"); you may not
+// use this file except in compliance with the License. You may obtain a copy of
+// the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations under
+// the License.
+import FauxtonAPI from "../../../core/api";
+import {Polling, clearPollCounter, resetPollCounter} from "../components/polling";
+import utils from "../../../../test/mocha/testUtils";
+import {shallow, mount} from "enzyme";
+import sinon from "sinon";
+import React from "react";
+import ReactDOM from "react-dom";
+
+var assert = utils.assert;
+
+describe("Polling", () => {
+  describe('Counters', () => {
+
+    it('resetPollCounter calls cb after set time', done => {
+      let called = false;
+      resetPollCounter(100, () => {
+        called = true;
+        assert.ok(called);
+        done();
+      });
+    });
+
+    it('clearRefreshCounter stops counter', done => {
+      let called = false;
+      resetPollCounter(100, () => {
+        called = true;
+      });
+
+      clearPollCounter();
+      setTimeout(() => {
+        assert.notOk(called);
+        done();
+      }, 200);
+    });
+  });
+
+  describe('Component', () => {
+    var clock;
+    beforeEach(() => {
+      clock = sinon.useFakeTimers();
+    });
+
+    afterEach(() => {
+      clock.restore();
+    });
+
+    it('renders slider with correct info', () => {
+      const wrapper = shallow(<Polling
+        startValue={10}
+        min={1}
+        max={20}
+        stepSize={1}
+        onPoll={() => {}}
+                            />);
+
+      const props = wrapper.find('input').props();
+
+      assert.deepEqual(props.value, 10);
+      assert.deepEqual(props.step, 1);
+      assert.deepEqual(props.min, 1);
+      assert.deepEqual(props.max, 21);
+    });
+
+    it('turns polling off if value is max', () => {
+      const wrapper = mount(<Polling
+        startValue={10}
+        min={1}
+        max={20}
+        stepSize={1}
+        onPoll={() => {}}
+                            />);
+
+      wrapper.find('input').simulate('change', {target: {value: 21}});
+      const isOff = wrapper.find('.faux__polling-info-value--off').text();
+      assert.deepEqual(isOff.toLowerCase(), "off");
+    });
+
+    it('turns polling off if value is max', (done) => {
+      let pollCalled = false;
+      const onPoll = () => {
+        pollCalled = true;
+        assert.ok(pollCalled);
+        done();
+      };
+      const wrapper = mount(<Polling
+        startValue={1}
+        min={1}
+        max={20}
+        stepSize={1}
+        onPoll={onPoll}
+                        />);
+
+      clock.tick(1010);
+
+    });
+  });
+});


Mime
View raw message