You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ambari.apache.org by al...@apache.org on 2014/02/03 19:05:48 UTC

git commit: AMBARI-4511. Jobs: implement filtering/sorting/limit on Apps table (alexantonenko)

Updated Branches:
  refs/heads/trunk 337248d1d -> 0064670d4


AMBARI-4511. Jobs: implement filtering/sorting/limit on Apps table (alexantonenko)


Project: http://git-wip-us.apache.org/repos/asf/ambari/repo
Commit: http://git-wip-us.apache.org/repos/asf/ambari/commit/0064670d
Tree: http://git-wip-us.apache.org/repos/asf/ambari/tree/0064670d
Diff: http://git-wip-us.apache.org/repos/asf/ambari/diff/0064670d

Branch: refs/heads/trunk
Commit: 0064670d46b7f88861b791e657a9b8b0d44f1981
Parents: 337248d
Author: Alex Antonenko <hi...@gmail.com>
Authored: Mon Feb 3 19:58:36 2014 +0200
Committer: Alex Antonenko <hi...@gmail.com>
Committed: Mon Feb 3 19:58:36 2014 +0200

----------------------------------------------------------------------
 ambari-web/app/controllers.js                   |   2 -
 .../app/controllers/main/jobs_controller.js     |  38 ++--
 ambari-web/app/styles/apps.less                 | 133 ++++++++++++--
 ambari-web/app/templates/main/jobs.hbs          |  26 +--
 ambari-web/app/views/common/filter_view.js      |   9 +-
 ambari-web/app/views/main/jobs_view.js          | 178 ++++++++++++-------
 6 files changed, 266 insertions(+), 120 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/0064670d/ambari-web/app/controllers.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/controllers.js b/ambari-web/app/controllers.js
index 02bcbf4..95f8b6b 100644
--- a/ambari-web/app/controllers.js
+++ b/ambari-web/app/controllers.js
@@ -110,7 +110,6 @@ require('controllers/main/charts/heatmap');
 require('controllers/main/apps_controller');
 require('controllers/main/jobs_controller');
 require('controllers/main/jobs/hive_job_details_controller');
-require('controllers/main/apps_controller');
 require('controllers/main/apps/item_controller');
 require('controllers/main/mirroring_controller');
 require('controllers/main/mirroring/edit_dataset_controller');
@@ -120,7 +119,6 @@ require('controllers/main/mirroring/targetClusterController');
 require('controllers/main/mirroring/testConnection_controller');
 require('controllers/main/mirroring/testConnectionResults_controller');
 require('controllers/main/mirroring/manage_clusters_controller');
-require('controllers/main/jobs_controller');
 require('controllers/wizard/slave_component_groups_controller');
 require('controllers/wizard/step0_controller');
 require('controllers/wizard/step1_controller');

http://git-wip-us.apache.org/repos/asf/ambari/blob/0064670d/ambari-web/app/controllers/main/jobs_controller.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/controllers/main/jobs_controller.js b/ambari-web/app/controllers/main/jobs_controller.js
index b5b8754..f6debd4 100644
--- a/ambari-web/app/controllers/main/jobs_controller.js
+++ b/ambari-web/app/controllers/main/jobs_controller.js
@@ -31,31 +31,19 @@ App.MainJobsController = Em.ArrayController.extend({
    */
   jobsLimit : -1,
 
-
-  clearFilters: function () {
-    var obj=this.get("filterObject");
-    obj.set("id","");
-    obj.set("user","");
-    obj.set("startTime","");
-    obj.set("endTime","");
-  },
-
-  //Filter object
-
-  filterObject : Ember.Object.create({
-    id:"",
-    user:"",
-    startTime:"",
-    endTime:"",
-
-
-    allFilterActivated:false,
-    filteredDisplayRecords:null,
-
-    viewType:"all",
-    viewTypeClickEvent:false
-
-  }),
+  /**
+   * List of users.
+   * Will be used for filtering in user column.
+   * Go to App.MainJobsView.userFilterView for more information
+   */
+  users: function () {
+    return this.get('content').mapProperty("user").uniq().map(function(userName){
+      return {
+        name: userName,
+        checked: false
+      };
+    });
+  }.property('content.length'),
 
   columnsName: Ember.ArrayController.create({
     content: [

http://git-wip-us.apache.org/repos/asf/ambari/blob/0064670d/ambari-web/app/styles/apps.less
----------------------------------------------------------------------
diff --git a/ambari-web/app/styles/apps.less b/ambari-web/app/styles/apps.less
index 0256c38..70d5372 100644
--- a/ambari-web/app/styles/apps.less
+++ b/ambari-web/app/styles/apps.less
@@ -16,7 +16,7 @@
  * limitations under the License.
  */
 
-#apps, #jobs{
+#apps {
 
   td .red {
     color: red;
@@ -35,21 +35,6 @@
     }
   }
 
-  .jobs-type {
-    float: right;
-    margin-top: -24px;
-  }
-  
-  #filtered-jobs{
-    float: left;
-    margin-top: 8px;
-  }
-
-  .jobs_head{
-    height: 30px;
-  }
-
-
   #filter_buttons a.selected{
     cursor: default;
   }
@@ -293,6 +278,122 @@
     }
   }
 }
+
+#jobs {
+
+  .jobs-type {
+    float: right;
+    margin-top: -24px;
+  }
+
+  #filtered-jobs{
+    float: left;
+    margin-top: 8px;
+  }
+
+  .jobs_head{
+    height: 30px;
+  }
+
+  .page-bar {
+    border: 1px solid silver;
+    text-align:right;
+    div {
+      display: inline-block;
+      margin:0 10px;
+    }
+    .items-on-page {
+      label {
+        display:inline;
+      }
+      select {
+        margin-bottom: 4px;
+        margin-top: 4px;
+        width:70px;
+      }
+    }
+    .paging_two_button {
+      a {
+        padding:0 5px;
+      }
+    }
+  }
+
+  .table { //margin-bottom: 0;
+    thead { //background: #EDF5FC;
+    }
+    th {
+      border-top: none;
+    }
+    th, td {
+      width: 82px;
+      border-left-width: 0;
+    }
+
+    td:first-child,
+    th:first-child {
+      border-left-width: 1px;
+    }
+
+    ul.filter-components {
+      padding: 5px 0;
+      li {
+        display: block;
+        padding: 3px 0 3px 5px;
+        line-height: 20px;
+
+        label.checkbox {
+          padding-left: 3px;
+        }
+
+        input[type="checkbox"] {
+          margin: 4px 4px 2px 2px;
+        }
+      }
+      &>li {
+        &>ul {
+          height: 250px;
+          margin-left: 0;
+          overflow-y: scroll;
+        }
+      }
+    }
+    .sorting_asc {
+      background: url(data:image/jpeg;base64,/9j/4AAQSkZJRgABAgAAZABkAAD/7AARRHVja3kAAQAEAAAAZAAA/+4ADkFkb2JlAGTAAAAAAf/bAIQAAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQICAgICAgICAgICAwMDAwMDAwMDAwEBAQEBAQECAQECAgIBAgIDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMD/8AAEQgAEwATAwERAAIRAQMRAf/EAHgAAAMBAQAAAAAAAAAAAAAAAAAFCAYKAQACAQUAAAAAAAAAAAAAAAAABQMCBAYHCBAAAQUAAQMEAwAAAAAAAAAAAwECBAUGABESByExIghBMxQRAAIBAwMDAwUAAAAAAAAAAAECAwAEBRESBiExUUHhB2GBIhMU/9oADAMBAAIRAxEAPwDvA8k+Qc54sxGj32qlNi0ucrjTj/JqGlmROyJXQ2u/bOsZTmBExPd70/HXmQcW41lOX5+145h0L391KEHhR3Z28Ii6sx9AKgubiO1gaeU6Io19h9TUg/S/7eP+wia3NbBIFbuqiyn3VTCjIMArHHTJarEDGGiNU8vOKVsc7/VxBuGR3yV683X86/Cq/GpssrhP2S8emiSKRm1JS5VfyLH0WfQug7KwZR0CilWHy39++ObQTgkgeV9ux+xq9uc6U8pLfZzP6mClZpKWrvq1DilJAt4Mewh/0hRyBOsaUMoVKLvXtVU6t6+nL/HZTJYi4/rxU81tdbSu+N2Rtp7jcpB0OnUa9aoeOOVdsgDL4I1pFS+NPHmcsQ2+fw+UpLWOwwwWNVQ1kCaIcgaiONkmLGEZrDDXtcnXo5PfjC+5VybKWrWWSyF5cWbEEpJNI6kqdQSrMRqD1B9KjS2t423xoqt5AArb8QVPRwoo4UUcKK//2Q==
 ) no-repeat right 50%;
+    }
+    .sorting_desc {
+      background: url(data:image/jpeg;base64,/9j/4AAQSkZJRgABAgAAZABkAAD/7AARRHVja3kAAQAEAAAAZAAA/+4ADkFkb2JlAGTAAAAAAf/bAIQAAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQICAgICAgICAgICAwMDAwMDAwMDAwEBAQEBAQECAQECAgIBAgIDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMD/8AAEQgAEwATAwERAAIRAQMRAf/EAIEAAAIDAQAAAAAAAAAAAAAAAAAGBwgJCgEBAAIDAQAAAAAAAAAAAAAAAAMFBAYHCBAAAAUDAwMFAAAAAAAAAAAAAQIDBAUABgcSNTYRFQgTZFUWZhEAAAQEAggGAwAAAAAAAAAAAAECAxEhBAYSMjFBYRMzFDQFUZFSYmMHJFRk/9oADAMBAAIRAxEAPwDv4oAKACgCKc1tMmusb3Eph6cSgsgx7fucEZxGRks2llGIGVWgVm8q1dt0+6ogKaapSgdNbQPXTqAdwsN602bopk3vTnUW24rduwccbU2S5E8Sm1JM92czSZwNOKUYDFrCqTp1corDUFMpEcYap+Ipb4P5O8n81y9xXXlG50yY+thR3AEivqFvRDmduvSUrhuLtrFNXqCFvJm1LAQ5RMuchB6gBy13f7+tP6lsOipuz2jSGdy1ZJeNzmXnEtU+pWFTikmbxyTEjgglKKZpMU3ZanudYtTtSr8dMoYSKKvKMte0aUV5YGxgoASbD2iQ4Tyi6uB7Rvz/AHD9R8r7/wBWr64uta6/pKfq+JwUZP5/1/hwCFjIeTMrLo0np93q2xDtVCJh/9k=) no-repeat right 50%;
+    }
+    .sorting {
+      background: url(data:image/jpeg;base64,/9j/4AAQSkZJRgABAgAAZABkAAD/7AARRHVja3kAAQAEAAAAZAAA/+4ADkFkb2JlAGTAAAAAAf/bAIQAAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQICAgICAgICAgICAwMDAwMDAwMDAwEBAQEBAQECAQECAgIBAgIDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMD/8AAEQgAEwATAwERAAIRAQMRAf/EAGgAAAIDAQAAAAAAAAAAAAAAAAUHAAYICgEBAQAAAAAAAAAAAAAAAAAAAAEQAAEEAQIFAgcAAAAAAAAAAAECAwQFABEGIRI0NQcTFDFBMmNUZRYRAQEBAQAAAAAAAAAAAAAAAAABEUH/2gAMAwEAAhEDEQA/AO93cd/XbXpLC9tHQ1Dr46nljUBby/gzGZB+p+Q6QhA+ZOApfDnllW/ha1tv6Ee7iyH5kRlvlbTIqHndWkNJ0HO7XFQbWeJUkpUeOpySrZh65UUnyFUW1ztaexRmIbaPyzoLE6vg2UWW9GC1e0XHnsSGEqfQohCwApK9OIGuAjfBP9VuG0m39vGqINVUe4r2xF21TVsuXZOI9N9lMmLBYkttQ21auBKhqtSUngCMkW5xqjKiYASh6SR2Tulr2HpOvf6j9p+V9/mwDeB//9k=) no-repeat right 50%;
+    }
+
+    div.view-wrapper {
+      .btn-group {
+        margin-bottom: 9px;
+      }
+    }
+
+    a.ui-icon-circle-close {
+      float: right;
+      opacity: 0.2;
+      padding: 1px;
+      position: relative;
+      right: -8px;
+      margin-top: 6px;
+      z-index: 10;
+      &:hover {
+        opacity: 0.7;
+      }
+    }
+    .notActive {
+      a.ui-icon-circle-close {
+        visibility: hidden;
+      }
+    }
+  }
+}
+
 .btn-group button.single-btn-group{
   -webkit-border-radius: 4px;
   border-radius: 4px;

http://git-wip-us.apache.org/repos/asf/ambari/blob/0064670d/ambari-web/app/templates/main/jobs.hbs
----------------------------------------------------------------------
diff --git a/ambari-web/app/templates/main/jobs.hbs b/ambari-web/app/templates/main/jobs.hbs
index d51034d..151e052 100644
--- a/ambari-web/app/templates/main/jobs.hbs
+++ b/ambari-web/app/templates/main/jobs.hbs
@@ -16,7 +16,7 @@
 * limitations under the License.
 }}
 
-<div id="apps">
+<div id="jobs">
 
     <div class="jobs_head">
       <div>{{t menu.item.jobs}}</div>
@@ -28,16 +28,18 @@
       </div>
     </div>
 
-    <table class="table table-striped runsList">
+    <table class="table table-bordered table-striped">
         <thead>
-        {{#view view.wrapSorting}}
-          {{#each controller.columnsName}}
-            {{#view view.parentView.sortingColumns contentBinding="this"}}
-              {{name}}
-            {{/view}}
-          {{/each}}
+
+        {{#view view.sortView contentBinding="view.filteredContent"}}
+            {{view view.parentView.idSort}}
+            {{view view.parentView.userSort}}
+            {{view view.parentView.startTimeSort}}
+            {{view view.parentView.endTimeSort}}
+            {{view view.parentView.durationSort}}
         {{/view}}
-        <tr>
+
+        <tr class="first">
             <th>{{view view.jobsIdFilterView}}</th>
             <th>{{view view.userFilterView}}</th>
             <th>{{view view.startTimeFilterView}}</th>
@@ -51,7 +53,7 @@
                 <td class="no-data" {{bindAttr colspan="controller.columnsName.content.length"}}>{{t apps.filters.nothingToShow}}</td>
             </tr>
         {{else}}
-          {{#each job in content}}
+          {{#each job in view.pageContent}}
             <tr>
               <td>
                 <a title="{{unbound job.name}}" href="#" {{action "showJobDetails" job}}>{{unbound job.name}}</a>
@@ -76,10 +78,10 @@
 
     <div class="page-bar">
         <div id="filtered-jobs">
-          {{view.filteredJobs}} - <a href="javascript:void(null);" {{action clearFilters target="controller"}}>{{t jobs.filtered.clear}}</a>
+          {{view.filteredJobs}} - <a href="javascript:void(null);" {{action clearFilters target="view"}}>{{t jobs.filtered.clear}}</a>
         </div>
         <div class="items-on-page">
-            <label>{{t jobs.show.up.to}}: {{view view.showNumberOfJobs selectionBinding="controller.filterObject.iDisplayLength"}}</label>
+            <label>{{t jobs.show.up.to}}: {{view view.rowsPerPageSelectView selectionBinding="view.displayLength"}}</label>
         </div>
     </div>
 </div>

http://git-wip-us.apache.org/repos/asf/ambari/blob/0064670d/ambari-web/app/views/common/filter_view.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/views/common/filter_view.js b/ambari-web/app/views/common/filter_view.js
index 77d56a8..45f69df 100644
--- a/ambari-web/app/views/common/filter_view.js
+++ b/ambari-web/app/views/common/filter_view.js
@@ -370,6 +370,9 @@ module.exports = {
           var match = false;
           var timePassed = new Date().getTime() - rowValue;
           switch (rangeExp) {
+            case 'Past 1 hour':
+              match = timePassed <= 3600000;
+              break;
             case 'Past 1 Day':
               match = timePassed <= 86400000;
               break;
@@ -436,7 +439,11 @@ module.exports = {
       case 'multiple':
         return function(origin, compareValue){
           var options = compareValue.split(',');
-          var rowValue = origin.mapProperty('componentName').join(" ");
+          if(typeof (origin) === "string"){
+            var rowValue = origin;
+          }else{
+            var rowValue = origin.mapProperty('componentName').join(" ");
+          }
           var str = new RegExp(compareValue, "i");
           for (var i = 0; i < options.length; i++) {
             if(!isGlobal) {

http://git-wip-us.apache.org/repos/asf/ambari/blob/0064670d/ambari-web/app/views/main/jobs_view.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/views/main/jobs_view.js b/ambari-web/app/views/main/jobs_view.js
index 93596c9..23aa64a 100644
--- a/ambari-web/app/views/main/jobs_view.js
+++ b/ambari-web/app/views/main/jobs_view.js
@@ -18,68 +18,83 @@
 
 var App = require('app');
 var filters = require('views/common/filter_view');
+var sort = require('views/common/sort_view');
 
-App.MainJobsView = Em.View.extend({
+App.MainJobsView = App.TableView.extend({
   templateName: require('templates/main/jobs'),
 
-  showNumberOfJobs: Em.Select.extend({
-    selected: '10',
-    content: ['10', '25', '50', '100', "250", "500"]
+  content: function () {
+    return this.get('controller.content');
+  }.property('controller.content.length'),
+
+  didInsertElement: function () {
+    this.set('filteredContent', this.get('controller.content'));
+  },
+
+  sortView: sort.wrapperView,
+  idSort: sort.fieldView.extend({
+    column: 0,
+    name: 'id',
+    displayName: Em.I18n.t('jobs.column.id'),
+    type: 'string'
+  }),
+  userSort: sort.fieldView.extend({
+    column: 1,
+    name: 'user',
+    displayName: Em.I18n.t('jobs.column.user'),
+    type: 'string'
+  }),
+  startTimeSort: sort.fieldView.extend({
+    column: 2,
+    name: 'startTime',
+    displayName: Em.I18n.t('jobs.column.start.time'),
+    type: 'number'
+  }),
+  endTimeSort: sort.fieldView.extend({
+    column: 3,
+    name: 'endTime',
+    displayName: Em.I18n.t('jobs.column.end.time'),
+    type: 'number'
+  }),
+  durationSort: sort.fieldView.extend({
+    column: 4,
+    name: 'duration',
+    displayName: Em.I18n.t('jobs.column.duration'),
+    type: 'number'
+  }),
+
+  /**
+   * Select View with list of "rows-per-page" options
+   * @type {Ember.View}
+   */
+  rowsPerPageSelectView: Em.Select.extend({
+    content: ['10', '25', '50', '100', "250", "500"],
+    change: function () {
+      this.get('parentView').saveDisplayLength();
+    }
   }),
 
+  /**
+   * return filtered number of all content number information displayed on the page footer bar
+   * @returns {String}
+   */
   filteredJobs: function () {
-    return Em.I18n.t('jobs.filtered.jobs').format(0,0);
-  }.property(),
+    return Em.I18n.t('jobs.filtered.jobs').format(this.get('filteredContent.length'), this.get('content').get('length'));
+  }.property('content.length', 'filteredContent.length'),
 
   /**
    * Filter-field for Jobs ID.
    * Based on <code>filters</code> library
    */
-  jobsIdFilterView: filters.createTextView({
+  /*jobsIdFilterView: filters.createTextView({
     valueBinding: "controller.filterObject.id"
-  }),
-
-  wrapSorting: Ember.View.extend({
-    tagName: 'tr'
-  }),
+  }),*/
 
-  sortingColumns: Ember.View.extend({
-    tagName: 'th',
-    classNameBindings: ['class', 'widthClass'],
-    class: "sorting",
-    widthClass: "",
-    content: null,
-    defaultColumn: 8,
-
-    didInsertElement: function () {
-      this.set("widthClass", "col" + this.get('content.index'));
-      if (this.get('content.index') == this.get('defaultColumn')) {
-        this.setControllerObj(this.content.index, "DESC");
-        this.set("class", "sorting_desc");
-      }
-    },
-    click: function (event) {
-      console.log(this.get('class'));
-      if (this.get('class') == "sorting") {
-        this.resetSortClass();
-        this.setControllerObj(this.get('content.index'), "ASC");
-        this.set("class", "sorting_asc");
-      } else if (this.get('class') == "sorting_asc") {
-        this.setControllerObj(this.get('content.index'), "DESC");
-        this.set("class", "sorting_desc");
-      } else if (this.get('class') == "sorting_desc") {
-        this.setControllerObj(this.get('content.index'), "ASC");
-        this.set("class", "sorting_asc");
-      }
-    },
-    resetSortClass: function () {
-      this.get("parentView.childViews").map(function (a, e) {
-        a.get("childViews")[0].set("class", "sorting")
-      });
-    },
-    setControllerObj: function (col, dir) {
-      this.set("controller.filterObject.iSortCol_0", col);
-      this.set("controller.filterObject.sSortDir_0", dir);
+  jobsIdFilterView: filters.createTextView({
+    column: 0,
+    fieldType: 'width70',
+    onChangeValue: function(){
+      this.get('parentView').updateFilter(this.get('column'), this.get('value'), 'string');
     }
   }),
 
@@ -88,6 +103,9 @@ App.MainJobsView = Em.View.extend({
    * Based on <code>filters</code> library
    */
   userFilterView: filters.createComponentView({
+
+    column: 1,
+
     /**
      * Inner FilterView. Used just to render component. Value bind to <code>mainview.value</code> property
      * Base methods was implemented in <code>filters.componentFieldView</code>
@@ -97,14 +115,7 @@ App.MainJobsView = Em.View.extend({
 
       usersBinding: 'controller.users',
 
-      allComponentsChecked:false,
-      toggleAllComponents:function () {
-        var checked = this.get('allComponentsChecked');
-        this.get('users').setEach('checked', checked);
-      }.observes('allComponentsChecked'),
-
       clearFilter:function() {
-        this.set('allComponentsChecked', false);
         this.get('users').setEach('checked', false);
         this._super();
       },
@@ -113,10 +124,30 @@ App.MainJobsView = Em.View.extend({
         this._super();
         var chosenUsers = this.get('users').filterProperty('checked', true).mapProperty('name');
         this.set('value', chosenUsers.toString());
-      }
+      },
+
+      /**
+       * Verify that checked checkboxes are equal to value
+       */
+      checkUsers: function() {
+        var users = this.get('value').split(',');
+        var self = this;
+        if (users) {
+          users.forEach(function(userName) {
+            var u = self.get("users").findProperty('name', userName);
+            if (u) {
+              if (!u.checked) {
+                u.checked = true;
+              }
+            }
+          });
+        }
+      }.observes('users.length')
     }),
 
-    valueBinding: 'controller.filterObject.user'
+    onChangeValue: function(){
+      this.get('parentView').updateFilter(this.get('column'), this.get('value'), 'multiple');
+    }
   }),
 
   /**
@@ -125,17 +156,36 @@ App.MainJobsView = Em.View.extend({
    */
   startTimeFilterView: filters.createSelectView({
     fieldType: 'input-medium',
-    valueBinding: "controller.filterObject.startTime",
-    content: ['Any', 'Past 1 hour',  'Past 1 Day', 'Past 2 Days', 'Past 7 Days', 'Past 14 Days', 'Past 30 Days', 'Custom']
+    column: 2,
+    content: ['Any', 'Past 1 hour',  'Past 1 Day', 'Past 2 Days', 'Past 7 Days', 'Past 14 Days', 'Past 30 Days'],
+    onChangeValue: function () {
+      this.get('parentView').updateFilter(this.get('column'), this.get('value'), 'date');
+    }
   }),
 
   /**
-   * Filter-field for Start Time.
+   * Filter-field for End Time.
    * Based on <code>filters</code> library
    */
   endTimeFilterView: filters.createSelectView({
     fieldType: 'input-medium',
-    valueBinding: "controller.filterObject.endTime",
-    content: ['Any', 'Custom']
-  })
+    column: 3,
+    content: ['Any'],
+    onChangeValue: function () {
+      this.get('parentView').updateFilter(this.get('column'), this.get('value'), 'date');
+    }
+  }),
+
+  /**
+   * associations between content (jobs list) property and column index
+   */
+  colPropAssoc: function () {
+    var associations = [];
+    associations[0] = 'id';
+    associations[1] = 'user';
+    associations[2] = 'startTime';
+    associations[3] = 'endTime';
+    return associations;
+  }.property()
+
 })