You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ambari.apache.org by on...@apache.org on 2014/07/24 14:20:42 UTC

git commit: AMBARI-6592. Add "Custom date" popup for "Start Time". (onechiporenko)

Repository: ambari
Updated Branches:
  refs/heads/trunk 7cc52b84d -> bb9de63c7


AMBARI-6592. Add "Custom date" popup for "Start Time". (onechiporenko)


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

Branch: refs/heads/trunk
Commit: bb9de63c78c2868a2d835b8be1d203d4d81cd4a6
Parents: 7cc52b8
Author: Oleg Nechiporenko <on...@apache.org>
Authored: Thu Jul 24 15:18:01 2014 +0300
Committer: Oleg Nechiporenko <on...@apache.org>
Committed: Thu Jul 24 15:18:01 2014 +0300

----------------------------------------------------------------------
 .../jobs/src/main/resources/ui/Gruntfile.js     |   6 +
 .../jobs/src/main/resources/ui/app/index.html   |   4 +
 .../src/main/resources/ui/app/scripts/app.js    |   2 +-
 .../app/scripts/controllers/jobs_controller.js  | 380 ++++++++++---------
 .../resources/ui/app/scripts/translations.js    |   4 +-
 .../ui/app/scripts/views/filter_view.js         |   3 +
 .../views/jobs/select_custom_date_view.js       |  36 ++
 .../src/main/resources/ui/app/styles/main.less  |   5 +
 .../ui/app/templates/jobs/custom_date_popup.hbs |  39 ++
 .../ui/app/templates/wrapper_layout.hbs         |   2 +-
 .../views/jobs/src/main/resources/ui/bower.json |   3 +-
 11 files changed, 299 insertions(+), 185 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/bb9de63c/contrib/views/jobs/src/main/resources/ui/Gruntfile.js
----------------------------------------------------------------------
diff --git a/contrib/views/jobs/src/main/resources/ui/Gruntfile.js b/contrib/views/jobs/src/main/resources/ui/Gruntfile.js
index 7dc777d..444acb1 100644
--- a/contrib/views/jobs/src/main/resources/ui/Gruntfile.js
+++ b/contrib/views/jobs/src/main/resources/ui/Gruntfile.js
@@ -261,6 +261,12 @@ module.exports = function (grunt) {
               'styles/fonts/*',
               'scripts/assets/**/*'
             ]
+          },
+          {
+            expand: true,
+            flatten: true,
+            src: '<%= yeoman.app %>/bower_components/jquery-ui/themes/base/images/*',
+            dest: '<%= yeoman.dist %>/styles/images/'
           }
         ]
       }

http://git-wip-us.apache.org/repos/asf/ambari/blob/bb9de63c/contrib/views/jobs/src/main/resources/ui/app/index.html
----------------------------------------------------------------------
diff --git a/contrib/views/jobs/src/main/resources/ui/app/index.html b/contrib/views/jobs/src/main/resources/ui/app/index.html
index ea74dcf..f5ae0de 100644
--- a/contrib/views/jobs/src/main/resources/ui/app/index.html
+++ b/contrib/views/jobs/src/main/resources/ui/app/index.html
@@ -29,12 +29,16 @@
     <!-- build:js(app) scripts/components.js -->
     <script src="bower_components/jquery/jquery.js"></script>
     <script src="bower_components/bootstrap/js/bootstrap-tooltip.js"></script>
+    <script src="bower_components/jquery-ui/ui/datepicker.js"></script>
     <script src="bower_components/moment/moment.js"></script>
     <script src="bower_components/handlebars/handlebars.js"></script>
     <script src="@@ember"></script>
     <script src="@@ember_data"></script>
     <script src="bower_components/ember-json-mapper/ember-json-mapper.js"></script>
     <script src="bower_components/ember-i18n/lib/i18n.js"></script>
+    <script src="bower_components/ember-addons.bs_for_ember/dist/js/bs-core.min.js"></script>
+    <script src="bower_components/ember-addons.bs_for_ember/dist/js/bs-button.min.js"></script>
+    <script src="bower_components/ember-addons.bs_for_ember/dist/js/bs-modal.min.js"></script>
     <!-- endbuild -->
 
     <!-- build:js(.tmp) scripts/templates.js -->

http://git-wip-us.apache.org/repos/asf/ambari/blob/bb9de63c/contrib/views/jobs/src/main/resources/ui/app/scripts/app.js
----------------------------------------------------------------------
diff --git a/contrib/views/jobs/src/main/resources/ui/app/scripts/app.js b/contrib/views/jobs/src/main/resources/ui/app/scripts/app.js
index 11fc15b..b7c6d2b 100644
--- a/contrib/views/jobs/src/main/resources/ui/app/scripts/app.js
+++ b/contrib/views/jobs/src/main/resources/ui/app/scripts/app.js
@@ -69,4 +69,4 @@ require('scripts/components/*');
 require('scripts/views/sort_view');
 require('scripts/views/filter_view');
 require('scripts/views/table_view');
-require('scripts/views/*');
+require('scripts/views/**/*');

http://git-wip-us.apache.org/repos/asf/ambari/blob/bb9de63c/contrib/views/jobs/src/main/resources/ui/app/scripts/controllers/jobs_controller.js
----------------------------------------------------------------------
diff --git a/contrib/views/jobs/src/main/resources/ui/app/scripts/controllers/jobs_controller.js b/contrib/views/jobs/src/main/resources/ui/app/scripts/controllers/jobs_controller.js
index d033a4c..8e72944 100644
--- a/contrib/views/jobs/src/main/resources/ui/app/scripts/controllers/jobs_controller.js
+++ b/contrib/views/jobs/src/main/resources/ui/app/scripts/controllers/jobs_controller.js
@@ -18,58 +18,13 @@
 
 App.JobsController = Ember.ArrayController.extend(App.RunPeriodically, {
 
-  name:'mainJobsController',
+  name: 'mainJobsController',
 
   /**
    * Sorted ArrayProxy
    */
   sortedContent: [],
 
-  contentAndSortObserver : function() {
-    Ember.run.once(this, 'contentAndSortUpdater');
-  }.observes('content.length', 'content.@each.id', 'content.@each.startTime', 'content.@each.endTime', 'sortProperties', 'sortAscending'),
-
-  contentAndSortUpdater: function() {
-    this.set('sortingDone', false);
-    var content = this.get('content');
-    var sortedContent = content.toArray();
-    var sortProperty = this.get('sortProperty');
-    var sortAscending = this.get('sortAscending');
-    sortedContent.sort(function(r1, r2) {
-      var r1id = r1.get(sortProperty);
-      var r2id = r2.get(sortProperty);
-      if (r1id < r2id)
-        return sortAscending ? -1 : 1;
-      if (r1id > r2id)
-        return sortAscending ? 1 : -1;
-      return 0;
-    });
-    var sortedArray = this.get('sortedContent');
-    var count = 0;
-    sortedContent.forEach(function(sortedJob){
-      if(sortedArray.length <= count) {
-        sortedArray.pushObject(Ember.Object.create());
-      }
-      sortedArray[count].set('failed', sortedJob.get('failed'));
-      sortedArray[count].set('hasTezDag', sortedJob.get('hasTezDag'));
-      sortedArray[count].set('queryText', sortedJob.get('queryText'));
-      sortedArray[count].set('name', sortedJob.get('name'));
-      sortedArray[count].set('user', sortedJob.get('user'));
-      sortedArray[count].set('id', sortedJob.get('id'));
-      sortedArray[count].set('startTimeDisplay', sortedJob.get('startTimeDisplay'));
-      sortedArray[count].set('endTimeDisplay', sortedJob.get('endTimeDisplay'));
-      sortedArray[count].set('durationDisplay', sortedJob.get('durationDisplay'));
-      count ++;
-    });
-    if(sortedArray.length > count) {
-      for(var c = sortedArray.length-1; c >= count; c--){
-        sortedArray.removeObject(sortedArray[c]);
-      }
-    }
-    sortedContent.length = 0;
-    this.set('sortingDone', true);
-  },
-
   navIDs: {
     backIDs: [],
     nextID: ''
@@ -79,9 +34,9 @@ App.JobsController = Ember.ArrayController.extend(App.RunPeriodically, {
 
   hasNewJobs: false,
 
-  loaded : false,
+  loaded: false,
 
-  loading : false,
+  loading: false,
 
   resetPagination: false,
 
@@ -103,40 +58,68 @@ App.JobsController = Ember.ArrayController.extend(App.RunPeriodically, {
 
   jobsMessage: Em.I18n.t('jobs.loadingTasks'),
 
-  sortingColumnObserver: function () {
-    if(this.get('sortingColumn')){
-      this.set('sortProperty', this.get('sortingColumn').get('name'));
-      this.set('sortAscending', this.get('sortingColumn').get('status') !== "sorting_desc");
-    }
-  }.observes('sortingColumn.name','sortingColumn.status'),
+  totalOfJobs: 0,
 
-  updateJobsByClick: function () {
-    this.set('navIDs.backIDs', []);
-    this.set('navIDs.nextID', '');
-    this.get('filterObject').set('nextFromId', '');
-    this.get('filterObject').set('backFromId', '');
-    this.get('filterObject').set('fromTs', '');
-    this.set('hasNewJobs', false);
-    this.set('resetPagination', true);
-    this.loadJobs();
-  },
+  customDatePopupButtons: [
+    Ember.Object.create({title: Em.I18n.t('ok'), clicked: 'submitCustomDate'}),
+    Ember.Object.create({title: Em.I18n.t('cancel'), dismiss: 'modal', clicked: 'dismissCustomDate'})
+  ],
 
-  updateJobs: function (controllerName, funcName) {
-    clearInterval(this.get('jobsUpdate'));
-    var self = this;
-    var interval = setInterval(function () {
-      App.router.get(controllerName)[funcName]();
-    }, this.jobsUpdateInterval);
-    this.set('jobsUpdate', interval);
+  actions: {
+    submitCustomDate: function () {
+      if(this.get('filterObject').submitCustomDate())
+        Bootstrap.ModalManager.close('customDate');
+    },
+
+    dismissCustomDate: function() {
+      this.set('filterObject.startTime', 'Any');
+    }
   },
 
-  totalOfJobs: 0,
+  contentAndSortObserver: function () {
+    Ember.run.once(this, 'contentAndSortUpdater');
+  }.observes('content.length', 'content.@each.id', 'content.@each.startTime', 'content.@each.endTime', 'sortProperties', 'sortAscending'),
 
-  setTotalOfJobs: function () {
-    if(this.get('totalOfJobs') < this.get('content.length')){
-      this.set('totalOfJobs', this.get('content.length'));
+  contentAndSortUpdater: function () {
+    this.set('sortingDone', false);
+    var content = this.get('content');
+    var sortedContent = content.toArray();
+    var sortProperty = this.get('sortProperty');
+    var sortAscending = this.get('sortAscending');
+    sortedContent.sort(function (r1, r2) {
+      var r1id = r1.get(sortProperty);
+      var r2id = r2.get(sortProperty);
+      if (r1id < r2id)
+        return sortAscending ? -1 : 1;
+      if (r1id > r2id)
+        return sortAscending ? 1 : -1;
+      return 0;
+    });
+    var sortedArray = this.get('sortedContent');
+    var count = 0;
+    sortedContent.forEach(function (sortedJob) {
+      if (sortedArray.length <= count) {
+        sortedArray.pushObject(Ember.Object.create());
+      }
+      sortedArray[count].set('failed', sortedJob.get('failed'));
+      sortedArray[count].set('hasTezDag', sortedJob.get('hasTezDag'));
+      sortedArray[count].set('queryText', sortedJob.get('queryText'));
+      sortedArray[count].set('name', sortedJob.get('name'));
+      sortedArray[count].set('user', sortedJob.get('user'));
+      sortedArray[count].set('id', sortedJob.get('id'));
+      sortedArray[count].set('startTimeDisplay', sortedJob.get('startTimeDisplay'));
+      sortedArray[count].set('endTimeDisplay', sortedJob.get('endTimeDisplay'));
+      sortedArray[count].set('durationDisplay', sortedJob.get('durationDisplay'));
+      count++;
+    });
+    if (sortedArray.length > count) {
+      for (var c = sortedArray.length - 1; c >= count; c--) {
+        sortedArray.removeObject(sortedArray[c]);
+      }
     }
-  }.observes('content.length'),
+    sortedContent.length = 0;
+    this.set('sortingDone', true);
+  },
 
   filterObject: Ember.Object.create({
     id: "",
@@ -159,41 +142,6 @@ App.JobsController = Ember.ArrayController.extend(App.RunPeriodically, {
      */
     startTime: "",
 
-    onStartTimeChange:function(){
-      var time = "";
-      var curTime = new Date().getTime();
-      switch (this.get('startTime')) {
-        case 'Past 1 hour':
-          time = curTime - 3600000;
-          break;
-        case 'Past 1 Day':
-          time = curTime - 86400000;
-          break;
-        case 'Past 2 Days':
-          time = curTime - 172800000;
-          break;
-        case 'Past 7 Days':
-          time = curTime - 604800000;
-          break;
-        case 'Past 14 Days':
-          time = curTime - 1209600000;
-          break;
-        case 'Past 30 Days':
-          time = curTime - 2592000000;
-          break;
-        case 'Custom':
-          this.showCustomDatePopup();
-          break;
-        case 'Any':
-          time = "";
-          break;
-      }
-      if(this.get('startTime') != "Custom"){
-        this.set("windowStart", time);
-        this.set("windowEnd", "");
-      }
-    }.observes("startTime"),
-
     // Fields values from Select Custom Dates form
     customDateFormFields: Ember.Object.create({
       startDate: null,
@@ -216,36 +164,30 @@ App.JobsController = Ember.ArrayController.extend(App.RunPeriodically, {
       endDate: ''
     }),
 
-    showCustomDatePopup: function () {
-      var self = this,
-        windowEnd = "",
-        windowStart = "";
-      /*App.ModalPopup.show({
-        header: Em.I18n.t('jobs.table.custom.date.header'),
-        onPrimary: function () {
-          self.validate();
-          if(self.get('errors.isStartDateError') || self.get('errors.isEndDateError')){
-            return;
-          }
-
-          var windowStart = self.createCustomStartDate();
-          var windowEnd = self.createCustomEndDate();
-
-          self.set("windowStart", windowStart.getTime());
-          self.set("windowEnd", windowEnd.getTime());
-          this.hide();
-        },
-        onSecondary: function () {
-          self.set('startTime','Any');
-          this.hide();
-        },
-        bodyClass: App.JobsCustomDatesSelectView.extend({
-          controller: self
-        })
-      });*/
+    columnsName: Ember.ArrayController.create({
+      content: [
+        { name: Em.I18n.t('jobs.column.id'), index: 0 },
+        { name: Em.I18n.t('jobs.column.user'), index: 1 },
+        { name: Em.I18n.t('jobs.column.start.time'), index: 2 },
+        { name: Em.I18n.t('jobs.column.end.time'), index: 3 },
+        { name: Em.I18n.t('jobs.column.duration'), index: 4 }
+      ],
+      columnsCount: 6
+    }),
+
+    submitCustomDate: function() {
+      this.validate();
+      if (this.get('errors.isStartDateError') || this.get('errors.isEndDateError')) {
+        return false;
+      }
+      var windowStart = this.createCustomStartDate(),
+        windowEnd = this.createCustomEndDate();
+      this.set("windowStart", windowStart.getTime());
+      this.set("windowEnd", windowEnd.getTime());
+      return true;
     },
 
-    createCustomStartDate : function () {
+    createCustomStartDate: function () {
       var startDate = this.get('customDateFormFields.startDate'),
         hoursForStart = this.get('customDateFormFields.hoursForStart'),
         minutesForStart = this.get('customDateFormFields.minutesForStart'),
@@ -256,7 +198,7 @@ App.JobsController = Ember.ArrayController.extend(App.RunPeriodically, {
       return null;
     },
 
-    createCustomEndDate : function () {
+    createCustomEndDate: function () {
       var endDate = this.get('customDateFormFields.endDate'),
         hoursForEnd = this.get('customDateFormFields.hoursForEnd'),
         minutesForEnd = this.get('customDateFormFields.minutesForEnd'),
@@ -304,31 +246,31 @@ App.JobsController = Ember.ArrayController.extend(App.RunPeriodically, {
      * Create link for server request
      * @return {String}
      */
-    createJobsFiltersLink: function() {
+    createJobsFiltersLink: function () {
       var link = "?fields=events,primaryfilters,otherinfo&secondaryFilter=tez:true",
         numberOfAppliedFilters = 0;
 
-      if(this.get("id") !== "") {
+      if (this.get("id") !== "") {
         link = "/" + this.get("id") + link;
         numberOfAppliedFilters++;
       }
 
       link += "&limit=" + (parseInt(this.get("jobsLimit")) + 1);
 
-      if(this.get("user") !== ""){
+      if (this.get("user") !== "") {
         link += "&primaryFilter=user:" + this.get("user");
         numberOfAppliedFilters++;
       }
-      if(this.get("backFromId") != ""){
+      if (this.get("backFromId") != "") {
         link += "&fromId=" + this.get("backFromId");
       }
-      if(this.get("nextFromId") != ""){
+      if (this.get("nextFromId") != "") {
         link += "&fromId=" + this.get("nextFromId");
       }
-      if(this.get("fromTs") != ""){
+      if (this.get("fromTs") != "") {
         link += "&fromTs=" + this.get("fromTs");
       }
-      if(this.get("startTime") !== "" && this.get("startTime") !== "Any"){
+      if (this.get("startTime") !== "" && this.get("startTime") !== "Any") {
         link += this.get("windowStart") !== "" ? ("&windowStart=" + this.get("windowStart")) : "";
         link += this.get("windowEnd") !== "" ? ("&windowEnd=" + this.get("windowEnd")) : "";
         numberOfAppliedFilters++;
@@ -340,33 +282,109 @@ App.JobsController = Ember.ArrayController.extend(App.RunPeriodically, {
     }
   }),
 
-  lastIDSuccessCallback: function(data) {
-    if(!data.entities[0]){
+  sortingColumnObserver: function () {
+    if (this.get('sortingColumn')) {
+      this.set('sortProperty', this.get('sortingColumn').get('name'));
+      this.set('sortAscending', this.get('sortingColumn').get('status') !== "sorting_desc");
+    }
+  }.observes('sortingColumn.name', 'sortingColumn.status'),
+
+  updateJobsByClick: function () {
+    this.set('navIDs.backIDs', []);
+    this.set('navIDs.nextID', '');
+    this.get('filterObject').set('nextFromId', '');
+    this.get('filterObject').set('backFromId', '');
+    this.get('filterObject').set('fromTs', '');
+    this.set('hasNewJobs', false);
+    this.set('resetPagination', true);
+    this.loadJobs();
+  },
+
+  updateJobs: function (controllerName, funcName) {
+    clearInterval(this.get('jobsUpdate'));
+    var interval = setInterval(function () {
+      App.router.get(controllerName)[funcName]();
+    }, this.get('jobsUpdateInterval'));
+    this.set('jobsUpdate', interval);
+  },
+
+  setTotalOfJobs: function () {
+    if (this.get('totalOfJobs') < this.get('content.length')) {
+      this.set('totalOfJobs', this.get('content.length'));
+    }
+  }.observes('content.length'),
+
+  startTimeObserver: function () {
+    var time = "";
+    var curTime = new Date().getTime();
+    switch (this.get('filterObject.startTime')) {
+      case 'Past 1 hour':
+        time = curTime - 3600000;
+        break;
+      case 'Past 1 Day':
+        time = curTime - 86400000;
+        break;
+      case 'Past 2 Days':
+        time = curTime - 172800000;
+        break;
+      case 'Past 7 Days':
+        time = curTime - 604800000;
+        break;
+      case 'Past 14 Days':
+        time = curTime - 1209600000;
+        break;
+      case 'Past 30 Days':
+        time = curTime - 2592000000;
+        break;
+      case 'Custom':
+        this.showCustomDatePopup();
+        break;
+      case 'Any':
+        time = "";
+        break;
+    }
+    if (this.get('filterObject.startTime') != "Custom") {
+      this.set("filterObject.windowStart", time);
+      this.set("filterObject.windowEnd", "");
+    }
+  }.observes('filterObject.startTime'),
+
+  showCustomDatePopup: function () {
+    Bootstrap.ModalManager.open(
+      'customDate',
+      Em.I18n.t('jobs.table.custom.date.header'),
+      App.JobsCustomDatesSelectView,
+      this.get('customDatePopupButtons'),
+      this
+    );
+  },
+
+  lastIDSuccessCallback: function (data) {
+    if (!data.entities[0]) {
       return;
     }
     var lastReceivedID = data.entities[0].entity;
-    if(this.get('lastJobID') == '') {
+    if (this.get('lastJobID') == '') {
       this.set('lastJobID', lastReceivedID);
       if (this.get('loaded') && App.HiveJob.find().get('length') < 1) {
         this.set('hasNewJobs', true);
       }
     }
-    else
-      if (this.get('lastJobID') !== lastReceivedID) {
-        this.set('lastJobID', lastReceivedID);
-        if(!App.HiveJob.find().findProperty('id', lastReceivedID)) {
-          this.set('hasNewJobs', true);
-        }
+    else if (this.get('lastJobID') !== lastReceivedID) {
+      this.set('lastJobID', lastReceivedID);
+      if (!App.HiveJob.find().findProperty('id', lastReceivedID)) {
+        this.set('hasNewJobs', true);
       }
+    }
   },
 
-  lastIDErrorCallback: function(data, jqXHR, textStatus) {
+  lastIDErrorCallback: function (data, jqXHR, textStatus) {
     console.debug(jqXHR);
   },
 
-  checkDataLoadingError: function (jqXHR){
+  checkDataLoadingError: function (jqXHR) {
     var atsComponent = App.HiveJob.store.getById('component', 'APP_TIMELINE_SERVER');
-    if(atsComponent && atsComponent.get('workStatus') != "STARTED") {
+    if (atsComponent && atsComponent.get('workStatus') != "STARTED") {
       this.set('jobsMessage', Em.I18n.t('jobs.error.ats.down'));
     }
     else {
@@ -384,12 +402,12 @@ App.JobsController = Ember.ArrayController.extend(App.RunPeriodically, {
     }
   },
 
-  init: function() {
+  init: function () {
     this.set('interval', 6000);
     this.loop('loadJobs');
   },
 
-  loadJobs : function() {
+  loadJobs: function () {
     var yarnService = App.HiveJob.store.getById('service', 'YARN'),
       atsComponent = App.HiveJob.store.getById('component', 'APP_TIMELINE_SERVER'),
       atsInValidState = !!atsComponent && atsComponent.get('workStatus') === "STARTED";
@@ -398,15 +416,15 @@ App.JobsController = Ember.ArrayController.extend(App.RunPeriodically, {
       this.set('loading', true);
       var historyServerHostName = atsComponent.get('hostName');
       /*App.ajax.send({
-        name: 'jobs.lastID',
-        sender: self,
-        data: {
-          historyServerHostName: '',//historyServerHostName,
-          ahsWebPort: ''//yarnService.get('ahsWebPort')
-        },
-        success: 'lastIDSuccessCallback',
-        error : 'lastIDErrorCallback'
-      });*/
+       name: 'jobs.lastID',
+       sender: self,
+       data: {
+       historyServerHostName: '',//historyServerHostName,
+       ahsWebPort: ''//yarnService.get('ahsWebPort')
+       },
+       success: 'lastIDSuccessCallback',
+       error : 'lastIDErrorCallback'
+       });*/
       App.ajax.send({
         name: 'load_jobs',
         sender: this,
@@ -416,40 +434,40 @@ App.JobsController = Ember.ArrayController.extend(App.RunPeriodically, {
           filtersLink: this.get('filterObject').createJobsFiltersLink()
         },
         success: 'loadJobsSuccessCallback',
-        error : 'loadJobsErrorCallback'
+        error: 'loadJobsErrorCallback'
       });
     }
   },
 
-  loadJobsSuccessCallback: function(data) {
+  loadJobsSuccessCallback: function (data) {
     App.hiveJobsMapper.map(data);
     this.set('loading', false);
-    if(this.get('loaded') == false || this.get('resetPagination') == true) {
+    if (this.get('loaded') == false || this.get('resetPagination') == true) {
       this.initializePagination();
       this.set('resetPagination', false);
     }
     this.set('loaded', true);
   },
 
-  loadJobsErrorCallback: function(jqXHR) {
-    App.hiveJobsMapper.map({entities : []});
+  loadJobsErrorCallback: function (jqXHR) {
+    App.hiveJobsMapper.map({entities: []});
     this.checkDataLoadingError(jqXHR);
   },
 
-  initializePagination: function() {
+  initializePagination: function () {
     var back_link_IDs = this.get('navIDs.backIDs.[]');
-    if(!back_link_IDs.contains(this.get('lastJobID'))) {
+    if (!back_link_IDs.contains(this.get('lastJobID'))) {
       back_link_IDs.push(this.get('lastJobID'));
     }
     this.set('filterObject.backFromId', this.get('lastJobID'));
     this.get('filterObject').set('fromTs', new Date().getTime());
   },
 
-  navigateNext: function() {
+  navigateNext: function () {
     this.set("filterObject.backFromId", '');
     var back_link_IDs = this.get('navIDs.backIDs.[]');
     var lastBackID = this.get('navIDs.nextID');
-    if(!back_link_IDs.contains(lastBackID)) {
+    if (!back_link_IDs.contains(lastBackID)) {
       back_link_IDs.push(lastBackID);
     }
     this.set('navIDs.backIDs.[]', back_link_IDs);
@@ -458,7 +476,7 @@ App.JobsController = Ember.ArrayController.extend(App.RunPeriodically, {
     this.loadJobs();
   },
 
-  navigateBack: function() {
+  navigateBack: function () {
     this.set("filterObject.nextFromId", '');
     var back_link_IDs = this.get('navIDs.backIDs.[]');
     back_link_IDs.pop();
@@ -468,7 +486,7 @@ App.JobsController = Ember.ArrayController.extend(App.RunPeriodically, {
     this.loadJobs();
   },
 
-  refreshLoadedJobs : function() {
+  refreshLoadedJobs: function () {
     this.loadJobs();
   }.observes(
       'filterObject.id',

http://git-wip-us.apache.org/repos/asf/ambari/blob/bb9de63c/contrib/views/jobs/src/main/resources/ui/app/scripts/translations.js
----------------------------------------------------------------------
diff --git a/contrib/views/jobs/src/main/resources/ui/app/scripts/translations.js b/contrib/views/jobs/src/main/resources/ui/app/scripts/translations.js
index a656c97..8389a08 100644
--- a/contrib/views/jobs/src/main/resources/ui/app/scripts/translations.js
+++ b/contrib/views/jobs/src/main/resources/ui/app/scripts/translations.js
@@ -20,6 +20,8 @@ Ember.I18n.translations = {
 
   'any': 'Any',
   'apply': 'Apply',
+  'ok': 'Ok',
+  'cancel': 'Cancel',
 
   'jobs.type':'Jobs Type',
   'jobs.type.hive':'Hive',
@@ -76,6 +78,6 @@ Ember.I18n.translations = {
   'jobs.hive.tez.edge.':'Unknown',
   'jobs.hive.tez.edge.contains':'Contains',
   'jobs.hive.tez.edge.broadcast':'Broadcast',
-  'jobs.hive.tez.edge.scatter_gather':'Shuffle',
+  'jobs.hive.tez.edge.scatter_gather':'Shuffle'
 
 };

http://git-wip-us.apache.org/repos/asf/ambari/blob/bb9de63c/contrib/views/jobs/src/main/resources/ui/app/scripts/views/filter_view.js
----------------------------------------------------------------------
diff --git a/contrib/views/jobs/src/main/resources/ui/app/scripts/views/filter_view.js b/contrib/views/jobs/src/main/resources/ui/app/scripts/views/filter_view.js
index 0506286..822f38f 100644
--- a/contrib/views/jobs/src/main/resources/ui/app/scripts/views/filter_view.js
+++ b/contrib/views/jobs/src/main/resources/ui/app/scripts/views/filter_view.js
@@ -63,6 +63,9 @@ var wrapperView = Ember.View.extend({
   actions: {
     actionSetValueOnApply: function() {
       this.setValueOnApply();
+    },
+    actionClearFilter: function() {
+      this.clearFilter();
     }
   },
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/bb9de63c/contrib/views/jobs/src/main/resources/ui/app/scripts/views/jobs/select_custom_date_view.js
----------------------------------------------------------------------
diff --git a/contrib/views/jobs/src/main/resources/ui/app/scripts/views/jobs/select_custom_date_view.js b/contrib/views/jobs/src/main/resources/ui/app/scripts/views/jobs/select_custom_date_view.js
new file mode 100644
index 0000000..ec2635a
--- /dev/null
+++ b/contrib/views/jobs/src/main/resources/ui/app/scripts/views/jobs/select_custom_date_view.js
@@ -0,0 +1,36 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.
+ */
+
+App.JobsCustomDatesSelectView = Em.View.extend({
+
+  name: 'jobsCustomDatesSelectView',
+
+  templateName: 'jobs/custom_date_popup',
+
+  middayPeriodOptions: [Em.I18n.t('jobs.table.custom.date.am'), Em.I18n.t('jobs.table.custom.date.pm')],
+
+  hourOptions: ['01', '02', '03', '04', '05', '06', '07', '08', '09', '10', '11', '12'],
+
+  minuteOptions: ['00', '05', '10', '15', '20', '25', '30', '35', '40', '45', '50', '55'],
+
+  didInsertElement: function () {
+    $('.datepicker').datepicker({
+      format: 'mm/dd/yyyy'
+    });
+  }
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/bb9de63c/contrib/views/jobs/src/main/resources/ui/app/styles/main.less
----------------------------------------------------------------------
diff --git a/contrib/views/jobs/src/main/resources/ui/app/styles/main.less b/contrib/views/jobs/src/main/resources/ui/app/styles/main.less
index 8cd95dc..16cfba7 100644
--- a/contrib/views/jobs/src/main/resources/ui/app/styles/main.less
+++ b/contrib/views/jobs/src/main/resources/ui/app/styles/main.less
@@ -16,6 +16,7 @@
  * limitations under the License.
  */
 
+@import '../../app/bower_components/jquery-ui/themes/base/all.css';
 @import '../../app/bower_components/bootstrap/less/bootstrap';
 
 #jobs {
@@ -315,4 +316,8 @@
     cursor: pointer;
     padding-right: 18px;
   }
+}
+
+.help-inline{
+  color: #b94a48;
 }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/bb9de63c/contrib/views/jobs/src/main/resources/ui/app/templates/jobs/custom_date_popup.hbs
----------------------------------------------------------------------
diff --git a/contrib/views/jobs/src/main/resources/ui/app/templates/jobs/custom_date_popup.hbs b/contrib/views/jobs/src/main/resources/ui/app/templates/jobs/custom_date_popup.hbs
new file mode 100644
index 0000000..f42d948
--- /dev/null
+++ b/contrib/views/jobs/src/main/resources/ui/app/templates/jobs/custom_date_popup.hbs
@@ -0,0 +1,39 @@
+{{!
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements.  See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership.  The ASF licenses this file
+* to you 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.
+}}
+
+<div class="jobs-custom-dates">
+  <div>
+    <label>{{t jobs.customDateFilter.startTime}}</label>
+    {{view Ember.TextField valueBinding="controller.filterObject.customDateFormFields.startDate" class="input-small datepicker"}}
+    {{view Ember.Select contentBinding="view.hourOptions" selectionBinding="controller.filterObject.customDateFormFields.hoursForStart" class="input-mini"}}
+    {{view Ember.Select contentBinding="view.minuteOptions" selectionBinding="controller.filterObject.customDateFormFields.minutesForStart" class="input-mini"}}
+    {{view Ember.Select contentBinding="view.middayPeriodOptions" selectionBinding="controller.filterObject.customDateFormFields.middayPeriodForStart" class="input-mini"}}
+    <span class="help-inline">{{controller.filterObject.errorMessages.startDate}}</span>
+  </div>
+  <div>
+
+  </div>
+  <div>
+    <label>{{t jobs.customDateFilter.endTime}}</label>
+    {{view Ember.TextField valueBinding="controller.filterObject.customDateFormFields.endDate" class="input-small datepicker"}}
+    {{view Ember.Select contentBinding="view.hourOptions" selectionBinding="controller.filterObject.customDateFormFields.hoursForEnd" class="input-mini"}}
+    {{view Ember.Select contentBinding="view.minuteOptions" selectionBinding="controller.filterObject.customDateFormFields.minutesForEnd" class="input-mini"}}
+    {{view Ember.Select contentBinding="view.middayPeriodOptions" selectionBinding="controller.filterObject.customDateFormFields.middayPeriodForEnd" class="input-mini"}}
+    <span class="help-inline">{{controller.filterObject.errorMessages.endDate}}</span>
+  </div>
+</div>

http://git-wip-us.apache.org/repos/asf/ambari/blob/bb9de63c/contrib/views/jobs/src/main/resources/ui/app/templates/wrapper_layout.hbs
----------------------------------------------------------------------
diff --git a/contrib/views/jobs/src/main/resources/ui/app/templates/wrapper_layout.hbs b/contrib/views/jobs/src/main/resources/ui/app/templates/wrapper_layout.hbs
index c2904de..a837bc5 100644
--- a/contrib/views/jobs/src/main/resources/ui/app/templates/wrapper_layout.hbs
+++ b/contrib/views/jobs/src/main/resources/ui/app/templates/wrapper_layout.hbs
@@ -16,4 +16,4 @@
 * limitations under the License.
 }}
 
-<a href="#" {{action "clearFilter" target="view"}} class="ui-icon ui-icon-circle-close"></a> {{yield}}
+<a href="#" {{action "actionClearFilter" target="view"}} class="ui-icon ui-icon-circle-close"></a> {{yield}}

http://git-wip-us.apache.org/repos/asf/ambari/blob/bb9de63c/contrib/views/jobs/src/main/resources/ui/bower.json
----------------------------------------------------------------------
diff --git a/contrib/views/jobs/src/main/resources/ui/bower.json b/contrib/views/jobs/src/main/resources/ui/bower.json
index 9b123b2..6eda9d2 100644
--- a/contrib/views/jobs/src/main/resources/ui/bower.json
+++ b/contrib/views/jobs/src/main/resources/ui/bower.json
@@ -9,7 +9,8 @@
     "ember-i18n": "1.6.*",
     "bootstrap": "2.3.*",
     "ember-addons.bs_for_ember": ">=0.7",
-    "ember-json-mapper": "master"
+    "ember-json-mapper": "master",
+    "jquery-ui": ">=1.11"
   },
   "devDependencies": {
     "ember-mocha-adapter": "0.1.2"