]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-6834 add date filter
authorStas Vilchik <vilchiks@gmail.com>
Mon, 28 Sep 2015 13:01:42 +0000 (15:01 +0200)
committerStas Vilchik <vilchiks@gmail.com>
Mon, 28 Sep 2015 13:01:53 +0000 (15:01 +0200)
server/sonar-web/src/main/js/apps/background-tasks/constants.js
server/sonar-web/src/main/js/apps/background-tasks/main.js
server/sonar-web/src/main/js/apps/background-tasks/search.js
server/sonar-web/src/main/less/init/forms.less

index c3d6e728374b176c88a9bfaffd812aa57d06dfa5..68c14edb5b00fae8d674ded784ca0978778738e5 100644 (file)
@@ -12,3 +12,13 @@ export const CURRENTS = {
   ALL: '__ALL__',
   ONLY_CURRENTS: 'CURRENTS'
 };
+
+
+export const DATE = {
+  ANY: 'ANY',
+  TODAY: 'TODAY',
+  CUSTOM: 'CUSTOM'
+};
+
+
+export const DATE_FORMAT = 'YYYY-MM-DD';
index 0ea7eb73487ec8868a00872d003e462144c0ab20..cdc56585af1e760bbc09046236486d4986a0fd0f 100644 (file)
@@ -1,7 +1,7 @@
 import _ from 'underscore';
 import React from 'react';
 import {getQueue, getActivity, cancelTask, cancelAllTasks} from '../../api/ce';
-import {STATUSES, CURRENTS} from './constants';
+import {STATUSES, CURRENTS, DATE} from './constants';
 import Header from './header';
 import Stats from './stats';
 import Search from './search';
@@ -18,14 +18,15 @@ export default React.createClass({
       activityTotal: 0,
       activityPage: 1,
       statusFilter: STATUSES.ALL,
-      currentsFilter: CURRENTS.ALL
+      currentsFilter: CURRENTS.ALL,
+      dateFilter: DATE.ANY
     };
   },
 
   filterQueueForComponent(queue) {
     if (this.props.options.componentId) {
       return queue.filter(task => {
-        return task.componentId === this.props.options.componentId
+        return task.componentId === this.props.options.componentId;
       });
     } else {
       return queue;
@@ -44,6 +45,27 @@ export default React.createClass({
     }
   },
 
+  getDateFilter() {
+    const DATE_FORMAT = 'YYYY-MM-DD';
+    let filter = {};
+    switch (this.state.dateFilter) {
+      case DATE.TODAY:
+        filter.minSubmittedAt = moment().startOf('day').format(DATE_FORMAT);
+        break;
+      case DATE.CUSTOM:
+        if (this.state.minDate) {
+          filter.minSubmittedAt = moment(this.state.minDate).format(DATE_FORMAT);
+        }
+        if (this.state.maxDate) {
+          filter.maxFinishedAt = moment(this.state.maxDate).format(DATE_FORMAT);
+        }
+        break;
+      default:
+      // do nothing
+    }
+    return filter;
+  },
+
   getCurrentFilters() {
     let filters = {};
     if (this.state.statusFilter !== STATUSES.ALL) {
@@ -52,6 +74,9 @@ export default React.createClass({
     if (this.state.currentsFilter !== STATUSES.ALL) {
       filters.onlyCurrents = true;
     }
+    if (this.state.dateFilter !== DATE.ANY) {
+      _.extend(filters, this.getDateFilter());
+    }
     return filters;
   },
 
@@ -124,6 +149,15 @@ export default React.createClass({
     this.setState({ currentsFilter: newCurrents, activityPage: 1 }, this.requestData);
   },
 
+  onDateChange(newDate, minDate, maxDate) {
+    this.setState({
+      dateFilter: newDate,
+      minDate: minDate,
+      maxDate: maxDate,
+      activityPage: 1
+    }, this.requestData);
+  },
+
   loadMore() {
     this.setState({ activityPage: this.state.activityPage + 1 }, this.requestActivity);
   },
@@ -153,7 +187,7 @@ export default React.createClass({
         <div className="page">
           <Header/>
           <Stats {...this.state} cancelPending={this.cancelPending} showFailures={this.showFailures}/>
-          <Search {...this.state} onStatusChange={this.onStatusChange} onCurrentsChange={this.onCurrentsChange}/>
+          <Search {...this.state} onStatusChange={this.onStatusChange} onCurrentsChange={this.onCurrentsChange} onDateChange={this.onDateChange}/>
           <Tasks tasks={[].concat(this.state.queue, this.state.activity)} onTaskCanceled={this.onTaskCanceled}/>
           <ListFooter count={this.state.queue.length + this.state.activity.length}
                       total={this.state.queue.length + this.state.activityTotal}
index 1f95875c510b9645c731f0362475dfae232504a4..cf79844640a7289c5b3a5c834a383271d19c531d 100644 (file)
@@ -1,6 +1,7 @@
+import _ from 'underscore';
 import React from 'react';
 import RadioToggle from '../../components/shared/radio-toggle';
-import {STATUSES, CURRENTS} from './constants';
+import {STATUSES, CURRENTS, DATE, DATE_FORMAT} from './constants';
 
 export default React.createClass({
   getCurrentsOptions() {
@@ -19,6 +20,50 @@ export default React.createClass({
     ];
   },
 
+  getDateOptions() {
+    return [
+      { value: DATE.ANY, label: 'Any Date' },
+      { value: DATE.TODAY, label: 'Today' },
+      { value: DATE.CUSTOM, label: 'Custom' }
+    ];
+  },
+
+  onDateChange(newDate) {
+    if (newDate === DATE.CUSTOM) {
+      let minDateRaw = React.findDOMNode(this.refs.minDate).value,
+          maxDateRaw = React.findDOMNode(this.refs.maxDate).value,
+          minDate = moment(minDateRaw, DATE_FORMAT, true),
+          maxDate = moment(maxDateRaw, DATE_FORMAT, true);
+      this.props.onDateChange(newDate,
+          minDate.isValid() ? minDate : null,
+          maxDate.isValid() ? maxDate : null);
+    } else {
+      this.props.onDateChange(newDate);
+    }
+  },
+
+  onDateInputChange(e) {
+    let value = e.target.value;
+    if (moment(value, DATE_FORMAT, true).isValid() || !value) {
+      this.onDateChange(DATE.CUSTOM);
+    }
+  },
+
+  renderCustomDateInput() {
+    let shouldBeVisible = this.props.dateFilter === DATE.CUSTOM,
+        className = shouldBeVisible ? 'spacer-top' : 'spacer-top hidden';
+    return (
+        <div className={className}>
+          from&nbsp;
+          <input onChange={this.onDateInputChange} ref="minDate" type="date" placeholder={DATE_FORMAT}
+                 placeholder={DATE_FORMAT}/>
+          &nbsp;to&nbsp;
+          <input onChange={this.onDateInputChange} ref="maxDate" type="date" placeholder={DATE_FORMAT}
+                 placeholder={DATE_FORMAT}/>
+        </div>
+    );
+  },
+
   render() {
     return (
         <section className="big-spacer-top big-spacer-bottom">
@@ -31,6 +76,11 @@ export default React.createClass({
               <RadioToggle options={this.getCurrentsOptions()} value={this.props.currentsFilter}
                            name="background-task-currents" onCheck={this.props.onCurrentsChange}/>
             </li>
+            <li>
+              <RadioToggle options={this.getDateOptions()} value={this.props.dateFilter}
+                           name="background-task-date" onCheck={this.onDateChange}/>
+              {this.renderCustomDateInput()}
+            </li>
           </ul>
         </section>
     );
index de66272f948c29b8f39010ea3d62e79c79c9f785..ceaf5db6dfee23d94477565ca85f4b192fa055fc 100644 (file)
@@ -10,6 +10,7 @@ input[type=text],
 input[type=password],
 input[type=email],
 input[type=search],
+input[type=date],
 textarea {
   border: 1px solid @darkGrey;
   .box-sizing(border-box);
@@ -31,7 +32,8 @@ textarea {
 input[type=text],
 input[type=password],
 input[type=email],
-input[type=search] {
+input[type=search],
+input[type=date] {
   height: @formControlHeight;
   padding: 0 6px;
 }
@@ -204,6 +206,7 @@ label[for] {
 
 .radio-toggle {
   display: inline-block;
+  vertical-align: middle;
   font-size: 0;
 
   & > li {