ambari-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From alexantone...@apache.org
Subject ambari git commit: AMBARI-14693. Graph: time range usability + bugs (alexantonenko)
Date Fri, 15 Jan 2016 21:23:07 GMT
Repository: ambari
Updated Branches:
  refs/heads/trunk 9e4708876 -> 5436fa243


AMBARI-14693. Graph: time range usability + bugs (alexantonenko)


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

Branch: refs/heads/trunk
Commit: 5436fa243ce68a92e273555a0a458c6da2c6995e
Parents: 9e47088
Author: Alex Antonenko <hiveww@gmail.com>
Authored: Fri Jan 15 20:44:27 2016 +0200
Committer: Alex Antonenko <hiveww@gmail.com>
Committed: Fri Jan 15 23:23:02 2016 +0200

----------------------------------------------------------------------
 ambari-web/app/messages.js                      |   2 +
 .../mixins/common/widgets/time_range_mixin.js   |  84 +++++++--
 ambari-web/app/styles/application.less          |   7 +-
 .../app/templates/common/custom_date_popup.hbs  |   7 +-
 .../app/templates/common/time_range_list.hbs    |   4 +-
 ambari-web/app/utils/helper.js                  |  14 +-
 .../app/views/common/chart/linear_time.js       |  20 +-
 .../app/views/common/custom_date_popup.js       |  22 ++-
 .../app/views/common/select_custom_date_view.js | 186 ++++++++++++-------
 ambari-web/app/views/main/dashboard/widgets.js  |   1 +
 ambari-web/app/views/main/host/summary.js       |   1 +
 .../app/views/main/service/info/summary.js      |   1 +
 .../common/widgets/time_range_mixin_test.js     |  11 +-
 ambari-web/test/utils/helper_test.js            |  20 ++
 .../common/select_custom_date_view_test.js      |   4 +-
 15 files changed, 281 insertions(+), 103 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/5436fa24/ambari-web/app/messages.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/messages.js b/ambari-web/app/messages.js
index 2af22d1..203e7ee 100644
--- a/ambari-web/app/messages.js
+++ b/ambari-web/app/messages.js
@@ -154,6 +154,7 @@ Em.I18n.translations = {
   'common.start':'Start',
   'common.stop':'Stop',
   'common.pause':'Pause',
+  'common.end':'End',
   'common.decommission':'Decommission',
   'common.recommission':'Recommission',
   'common.failure': 'Failure',
@@ -2789,6 +2790,7 @@ Em.I18n.translations = {
   'jobs.table.job.fail':'Job failed to run',
   'jobs.customDateFilter.error.required':'This field is required',
   'jobs.customDateFilter.error.incorrect':'Date is incorrect',
+  'jobs.customDateFilter.error.laterThanNow':'The specified time is in the future',
   'jobs.customDateFilter.error.date.order':'End Date must be after Start Date',
   'jobs.customDateFilter.startTime':'Start Time',
   'jobs.customDateFilter.endTime':'End Time',

http://git-wip-us.apache.org/repos/asf/ambari/blob/5436fa24/ambari-web/app/mixins/common/widgets/time_range_mixin.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/mixins/common/widgets/time_range_mixin.js b/ambari-web/app/mixins/common/widgets/time_range_mixin.js
index 3a8228e..c88df56 100644
--- a/ambari-web/app/mixins/common/widgets/time_range_mixin.js
+++ b/ambari-web/app/mixins/common/widgets/time_range_mixin.js
@@ -47,19 +47,53 @@ App.TimeRangeMixin = Em.Mixin.create({
     return this.get('timeRangeOptions').objectAt(this.get('currentTimeRangeIndex'));
   }.property('currentTimeRangeIndex'),
 
+  isCustomTimeRange: function () {
+    return !(Em.isNone(this.get('customStartTime')) || Em.isNone(this.get('customEndTime')));
+  }.property('customStartTime', 'customEndTime'),
+
   customStartTime: null,
 
   customEndTime: null,
 
+  customDurationFormatted: null,
+
+  customStartTimeFormatted: function () {
+    var time = this.get('customStartTime');
+    return Em.isNone(time) ? '' : App.formatDateTimeWithTimeZone(time, 'M/D/YYYY hh:mmA');
+  }.property('customStartTime'),
+
+  customEndTimeFormatted: function () {
+    var time = this.get('customEndTime');
+    return Em.isNone(time) ? '' : App.formatDateTimeWithTimeZone(time, 'M/D/YYYY hh:mmA');
+  }.property('customEndTime'),
+
+  tooltipMessage: function () {
+    var message;
+    if (this.get('isCustomTimeRange')) {
+      message = Em.I18n.t('common.start') + ': ' + this.get('customStartTimeFormatted') +
'<br>' + Em.I18n.t('common.duration') + ': ' + this.get('customDurationFormatted') +
'<br>' + Em.I18n.t('common.end') + ': ' + this.get('customEndTimeFormatted');
+    } else {
+      message = '';
+    }
+    return message;
+  }.property('customStartTimeFormatted', 'customEndTimeFormatted', 'customDurationFormatted'),
+
+  didInsertElement: function () {
+    App.tooltip(this.$(), {
+      selector: '.dropdown-toggle[rel="tooltip"]'
+    });
+  },
+
   /**
    * onclick handler for a time range option
    * @param {object} event
+   * @param {function} callback
    */
-  setTimeRange: function (event, callback, context) {
+  setTimeRange: function (event, callback) {
     var prevIndex = this.get('currentTimeRangeIndex'),
       prevCustomTimeRange = {
         start: this.get('customStartTime'),
-        end: this.get('customEndTime')
+        end: this.get('customEndTime'),
+        duration: this.get('customDurationFormatted')
       },
       index = event.context.index,
       primary = function () {
@@ -71,24 +105,50 @@ App.TimeRangeMixin = Em.Mixin.create({
         this.setProperties({
           currentTimeRangeIndex: prevIndex,
           customStartTime: prevCustomTimeRange.start,
-          customEndTime: prevCustomTimeRange.end
+          customEndTime: prevCustomTimeRange.end,
+          customDurationFormatted: prevCustomTimeRange.duration
         });
       };
 
-    // Preset time range is active
-    if (prevIndex !== 8) {
+    if (index === 8) {
+      // Custom start and end time is specified by user
+      var defaultStartTime,
+        defaultEndTime,
+        duration;
+      if (prevIndex === 8) {
+        // Custom time range is active
+        defaultStartTime = new Date(this.get('customStartTime')).getTime();
+        defaultEndTime = new Date(this.get('customEndTime')).getTime();
+        duration = this.get('customDurationFormatted') || 0;
+      } else {
+        // Preset time range is active
+        var minutes;
+        duration = this.get('currentTimeRange.value') * 3600000;
+        defaultEndTime = new Date();
+        minutes = 5 * Math.ceil(defaultEndTime.getMinutes() / 5);
+        defaultEndTime.setMinutes(minutes);
+        defaultStartTime = defaultEndTime.getTime() - duration;
+      }
+      timeRangePopup.showCustomDatePopup(this, primary.bind(this), secondary.bind(this),
{
+        startDate: App.formatDateTimeWithTimeZone(defaultStartTime, 'MM/DD/YYYY'),
+        hoursForStart: App.formatDateTimeWithTimeZone(defaultStartTime, 'hh'),
+        minutesForStart: App.formatDateTimeWithTimeZone(defaultStartTime, 'mm'),
+        middayPeriodForStart: App.formatDateTimeWithTimeZone(defaultStartTime, 'A'),
+        duration: duration,
+        endDate: App.formatDateTimeWithTimeZone(defaultEndTime, 'MM/DD/YYYY'),
+        hoursForEnd: App.formatDateTimeWithTimeZone(defaultEndTime, 'hh'),
+        minutesForEnd: App.formatDateTimeWithTimeZone(defaultEndTime, 'mm'),
+        middayPeriodForEnd: App.formatDateTimeWithTimeZone(defaultEndTime, 'A')
+      });
+    } else {
+      // Preset time range is specified by user
       this.setProperties({
         customStartTime: null,
-        customEndTime: null
+        customEndTime: null,
+        customDurationFormatted: null
       });
     }
 
-    // Custom start and end time is specified by user
-    if (index === 8) {
-      context = context || this;
-      timeRangePopup.showCustomDatePopup(context, primary.bind(this), secondary.bind(this));
-    }
-
     this.set('currentTimeRangeIndex', index);
   },
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/5436fa24/ambari-web/app/styles/application.less
----------------------------------------------------------------------
diff --git a/ambari-web/app/styles/application.less b/ambari-web/app/styles/application.less
index 44269a4..adcc4ec 100644
--- a/ambari-web/app/styles/application.less
+++ b/ambari-web/app/styles/application.less
@@ -2230,9 +2230,6 @@ a:focus {
       }
     }
   }
-  .timezone {
-    font-size: @smaller-font-size;
-  }
 }
 .chart-container {
   cursor: pointer;
@@ -2365,6 +2362,10 @@ a:focus {
   }
 }
 
+.timezone {
+  font-size: @smaller-font-size;
+}
+
 .modal-body {
   .show {
     display: inline-block;

http://git-wip-us.apache.org/repos/asf/ambari/blob/5436fa24/ambari-web/app/templates/common/custom_date_popup.hbs
----------------------------------------------------------------------
diff --git a/ambari-web/app/templates/common/custom_date_popup.hbs b/ambari-web/app/templates/common/custom_date_popup.hbs
index ea13d25..d076823 100644
--- a/ambari-web/app/templates/common/custom_date_popup.hbs
+++ b/ambari-web/app/templates/common/custom_date_popup.hbs
@@ -25,9 +25,9 @@
     {{view Ember.Select contentBinding="view.middayPeriodOptions" selectionBinding="view.customDateFormFields.middayPeriodForStart"
class="input-mini"}}
     <span class="help-inline">{{view.errorMessages.startDate}}</span>
   </div>
-  <div>
+  <div class="control-group">
     <label>{{t common.duration}}</label>
-    {{view Ember.Select contentBinding="view.durationOptions" optionValuePath="content.value"
optionLabelPath="content.label" selectionBinding="view.customDateFormFields.duration" class="input-medium"}}
+    {{view view.durationSelect selectionBinding="view.customDateFormFields.duration"}}
   </div>
   <div {{bindAttr class=":control-group view.errors.isEndDateError:error view.isCustomEndDate::hidden"}}>
     <label>{{t jobs.customDateFilter.endTime}}</label>
@@ -37,4 +37,7 @@
     {{view Ember.Select contentBinding="view.middayPeriodOptions" selectionBinding="view.customDateFormFields.middayPeriodForEnd"
class="input-mini"}}
     <span class="help-inline">{{view.errorMessages.endDate}}</span>
   </div>
+  <div class="timezone">
+    <strong>{{t common.timezone}}</strong>: {{App.router.userSettingsController.userSettings.timezone.label}}
+  </div>
 </div>

http://git-wip-us.apache.org/repos/asf/ambari/blob/5436fa24/ambari-web/app/templates/common/time_range_list.hbs
----------------------------------------------------------------------
diff --git a/ambari-web/app/templates/common/time_range_list.hbs b/ambari-web/app/templates/common/time_range_list.hbs
index 8e6f075..419d6f3 100644
--- a/ambari-web/app/templates/common/time_range_list.hbs
+++ b/ambari-web/app/templates/common/time_range_list.hbs
@@ -16,8 +16,8 @@
 * limitations under the License.
 }}
 
-<button type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown">
-  {{view.parentView.currentTimeRange.name}} &nbsp;<span class="caret"></span>
+<button type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown" rel="tooltip"
{{bindAttr data-original-title="view.parentView.tooltipMessage"}}>
+  {{view.parentView.currentTimeRange.name}}{{#if view.parentView.isCustomTimeRange}}: {{view.parentView.customStartTimeFormatted}}{{/if}}
&nbsp;<span class="caret"></span>
 </button>
 <ul class="dropdown-menu">
   {{#each option in view.parentView.timeRangeOptions}}

http://git-wip-us.apache.org/repos/asf/ambari/blob/5436fa24/ambari-web/app/utils/helper.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/utils/helper.js b/ambari-web/app/utils/helper.js
index eb0aa96..296a8e8 100644
--- a/ambari-web/app/utils/helper.js
+++ b/ambari-web/app/utils/helper.js
@@ -557,7 +557,7 @@ App.format = {
    *
    * @method normalizeNameBySeparator
    * @param name {String} - name to format
-   * @param separator {String} - token use to split the string
+   * @param separators {String} - token use to split the string
    * @return {String}
    */
   normalizeNameBySeparators: function(name, separators) {
@@ -770,6 +770,18 @@ App.dateTimeWithTimeZone = function (x) {
   return x || new Date().getTime();
 };
 
+App.formatDateTimeWithTimeZone = function (timeStamp, format) {
+  var timezone = App.router.get('userSettingsController.userSettings.timezone'),
+    time;
+  if (timezone) {
+    var tz = Em.getWithDefault(timezone, 'zones.0.value', '');
+    time = moment.tz(timeStamp, tz);
+  } else {
+    time = moment(timeStamp);
+  }
+  return moment(time).format(format);
+};
+
 App.getTimeStampFromLocalTime = function (time) {
   var timezone = App.router.get('userSettingsController.userSettings.timezone'),
     offsetString = '',

http://git-wip-us.apache.org/repos/asf/ambari/blob/5436fa24/ambari-web/app/views/common/chart/linear_time.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/views/common/chart/linear_time.js b/ambari-web/app/views/common/chart/linear_time.js
index 19e8f5f..3bdcc80 100644
--- a/ambari-web/app/views/common/chart/linear_time.js
+++ b/ambari-web/app/views/common/chart/linear_time.js
@@ -929,13 +929,14 @@ App.ChartLinearTimeView = Ember.View.extend(App.ExportMetricsMixin,
{
 
         isReady: Em.computed.alias('parentView.graph.isPopupReady'),
 
+        currentTimeRangeIndex: self.get('currentTimeIndex'),
+        customStartTime: self.get('customStartTime'),
+        customEndTime: self.get('customEndTime'),
+        customDurationFormatted: self.get('customDurationFormatted'),
+
         didInsertElement: function () {
-          this.setTimeRange({
-            context: {
-              index: 0
-            }
-          });
           var popupBody = this;
+          this._super();
           App.tooltip(this.$('.corner-icon > .icon-save'), {
             title: Em.I18n.t('common.export')
           });
@@ -994,7 +995,7 @@ App.ChartLinearTimeView = Ember.View.extend(App.ExportMetricsMixin, {
         setTimeRange: function (event) {
           var index = event.context.index,
             callback = this.get('parentView').reloadGraphByTime.bind(this.get('parentView'),
index);
-          this._super(event, callback, self);
+          this._super(event, callback);
 
           // Preset time range is specified by user
           if (index !== 8) {
@@ -1084,16 +1085,19 @@ App.ChartLinearTimeView = Ember.View.extend(App.ExportMetricsMixin,
{
   currentTimeIndex: 0,
   customStartTime: null,
   customEndTime: null,
+  customDurationFormatted: null,
   setCurrentTimeIndexFromParent: function () {
     // 8 index corresponds to custom start and end time selection
     var targetView = !Em.isNone(this.get('parentView.currentTimeRangeIndex')) ? this.get('parentView')
: this.get('parentView.parentView'),
       index = targetView.get('currentTimeRangeIndex'),
       customStartTime = (index === 8) ? targetView.get('customStartTime') : null,
-      customEndTime = (index === 8) ? targetView.get('customEndTime'): null;
+      customEndTime = (index === 8) ? targetView.get('customEndTime'): null,
+      customDurationFormatted = (index === 8) ? targetView.get('customDurationFormatted'):
null;
     this.setProperties({
       currentTimeIndex: index,
       customStartTime: customStartTime,
-      customEndTime: customEndTime
+      customEndTime: customEndTime,
+      customDurationFormatted: customDurationFormatted
     });
   }.observes('parentView.parentView.currentTimeRangeIndex', 'parentView.currentTimeRangeIndex',
'parentView.parentView.customStartTime', 'parentView.customStartTime', 'parentView.parentView.customEndTime',
'parentView.customEndTime'),
   timeUnitSeconds: 3600,

http://git-wip-us.apache.org/repos/asf/ambari/blob/5436fa24/ambari-web/app/views/common/custom_date_popup.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/views/common/custom_date_popup.js b/ambari-web/app/views/common/custom_date_popup.js
index f7fa258..c5a2837 100644
--- a/ambari-web/app/views/common/custom_date_popup.js
+++ b/ambari-web/app/views/common/custom_date_popup.js
@@ -24,15 +24,29 @@ module.exports = Em.Object.create({
 
   endTime: null,
 
-  showCustomDatePopup: function (context, primary, secondary) {
+  customDuration: null,
+
+  showCustomDatePopup: function (context, primary, secondary, defaults) {
     var self = this;
+    defaults = defaults || {
+      startDate: null,
+      hoursForStart: null,
+      minutesForStart: null,
+      middayPeriodForStart: null,
+      duration: null,
+      endDate: null,
+      hoursForEnd: null,
+      minutesForEnd: null,
+      middayPeriodForEnd: null
+    };
 
     return App.ModalPopup.show({
       header: Em.I18n.t('jobs.table.custom.date.header'),
       onPrimary: function () {
         context.setProperties({
           customEndTime: self.endTime,
-          customStartTime: self.startTime
+          customStartTime: self.startTime,
+          customDurationFormatted: self.customDuration
         });
         if (primary) {
           primary();
@@ -40,7 +54,6 @@ module.exports = Em.Object.create({
         this._super();
       },
       onSecondary: function () {
-        //context.cancel(); to check!
         if (secondary) {
           secondary();
         }
@@ -54,7 +67,8 @@ module.exports = Em.Object.create({
       },
       disablePrimary: false,
       bodyClass: App.JobsCustomDatesSelectView.extend({
-        controller: self
+        controller: self,
+        customDateFormFields: Em.Object.create(defaults)
       })
     });
   }

http://git-wip-us.apache.org/repos/asf/ambari/blob/5436fa24/ambari-web/app/views/common/select_custom_date_view.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/views/common/select_custom_date_view.js b/ambari-web/app/views/common/select_custom_date_view.js
index d8121ed..fb553c7 100644
--- a/ambari-web/app/views/common/select_custom_date_view.js
+++ b/ambari-web/app/views/common/select_custom_date_view.js
@@ -18,6 +18,8 @@
 
 var App = require('app');
 
+var stringUtils = require('utils/string_utils');
+
 App.JobsCustomDatesSelectView = Em.View.extend({
 
   name: 'jobsCustomDatesSelectView',
@@ -30,53 +32,6 @@ App.JobsCustomDatesSelectView = Em.View.extend({
 
   minuteOptions: ['00', '05', '10', '15', '20', '25', '30', '35', '40', '45', '50', '55'],
 
-  durationOptions: [
-    {
-      value: 900000,
-      label: Em.I18n.t('jobs.customDateFilter.duration.15min')
-    },
-    {
-      value: 1800000,
-      label: Em.I18n.t('jobs.customDateFilter.duration.30min')
-    },
-    {
-      value: 3600000,
-      label: Em.I18n.t('jobs.customDateFilter.duration.1hr')
-    },
-    {
-      value: 7200000,
-      label: Em.I18n.t('jobs.customDateFilter.duration.2hr')
-    },
-    {
-      value: 14400000,
-      label: Em.I18n.t('jobs.customDateFilter.duration.4hr')
-    },
-    {
-      value: 43200000,
-      label: Em.I18n.t('jobs.customDateFilter.duration.12hr')
-    },
-    {
-      value: 86400000,
-      label: Em.I18n.t('jobs.customDateFilter.duration.24hr')
-    },
-    {
-      value: 604800000,
-      label: Em.I18n.t('jobs.customDateFilter.duration.1w')
-    },
-    {
-      value: 2592000000,
-      label: Em.I18n.t('jobs.customDateFilter.duration.1m')
-    },
-    {
-      value: 31536000000,
-      label: Em.I18n.t('jobs.customDateFilter.duration.1yr')
-    },
-    {
-      value: 0,
-      label: Em.I18n.t('common.custom')
-    }
-  ],
-
   customDateFormFields: Ember.Object.create({
     startDate: null,
     hoursForStart: null,
@@ -99,6 +54,66 @@ App.JobsCustomDatesSelectView = Em.View.extend({
     endDate: ''
   }),
 
+  durationSelect: Em.Select.extend({
+    classNames: ['input-medium'],
+    content: [
+      {
+        value: 900000,
+        label: Em.I18n.t('jobs.customDateFilter.duration.15min')
+      },
+      {
+        value: 1800000,
+        label: Em.I18n.t('jobs.customDateFilter.duration.30min')
+      },
+      {
+        value: 3600000,
+        label: Em.I18n.t('jobs.customDateFilter.duration.1hr')
+      },
+      {
+        value: 7200000,
+        label: Em.I18n.t('jobs.customDateFilter.duration.2hr')
+      },
+      {
+        value: 14400000,
+        label: Em.I18n.t('jobs.customDateFilter.duration.4hr')
+      },
+      {
+        value: 43200000,
+        label: Em.I18n.t('jobs.customDateFilter.duration.12hr')
+      },
+      {
+        value: 86400000,
+        label: Em.I18n.t('jobs.customDateFilter.duration.24hr')
+      },
+      {
+        value: 604800000,
+        label: Em.I18n.t('jobs.customDateFilter.duration.1w')
+      },
+      {
+        value: 2592000000,
+        label: Em.I18n.t('jobs.customDateFilter.duration.1m')
+      },
+      {
+        value: 31536000000,
+        label: Em.I18n.t('jobs.customDateFilter.duration.1yr')
+      },
+      {
+        value: 0,
+        label: Em.I18n.t('common.custom')
+      }
+    ],
+    optionValuePath: 'content.value',
+    optionLabelPath: 'content.label',
+    selectionBinding: 'parentView.customDateFormFields.duration',
+    willInsertElement: function () {
+      var duration = this.get('selection'),
+        initialOption = this.get('content').find(function (item) {
+          return duration === item.value || duration === item.label;
+        }, this);
+      this.set('selection', initialOption);
+    }
+  }),
+
   isCustomEndDate: Em.computed.equal('customDateFormFields.duration.value', 0),
 
   didInsertElement: function () {
@@ -110,18 +125,18 @@ App.JobsCustomDatesSelectView = Em.View.extend({
     });
   },
 
-  createCustomStartDate : function () {
+  createCustomStartDate: function () {
     var startDate = this.get('customDateFormFields.startDate');
     var hoursForStart = this.get('customDateFormFields.hoursForStart');
     var minutesForStart = this.get('customDateFormFields.minutesForStart');
     var middayPeriodForStart = this.get('customDateFormFields.middayPeriodForStart');
     if (startDate && hoursForStart && minutesForStart && middayPeriodForStart)
{
-      return new Date(startDate + ' ' + hoursForStart + ':' + minutesForStart + ' ' + middayPeriodForStart);
+      return App.getTimeStampFromLocalTime(new Date(startDate + ' ' + hoursForStart + ':'
+ minutesForStart + ' ' + middayPeriodForStart));
     }
     return null;
   },
 
-  createCustomEndDate : function (startDate) {
+  createCustomEndDate: function (startDate) {
     var duration = this.get('customDateFormFields.duration.value'),
       date;
     if (duration === 0) {
@@ -130,15 +145,12 @@ App.JobsCustomDatesSelectView = Em.View.extend({
       var minutesForEnd = this.get('customDateFormFields.minutesForEnd');
       var middayPeriodForEnd = this.get('customDateFormFields.middayPeriodForEnd');
       if (endDate && hoursForEnd && minutesForEnd && middayPeriodForEnd)
{
-        date = endDate + ' ' + hoursForEnd + ':' + minutesForEnd + ' ' + middayPeriodForEnd;
+        date = App.getTimeStampFromLocalTime(new Date(endDate + ' ' + hoursForEnd + ':' +
minutesForEnd + ' ' + middayPeriodForEnd));
       }
     } else if (!Em.isNone(startDate)) {
-      date = startDate.getTime() + duration;
+      date = startDate + duration;
     }
-    if (!Em.isNone(date)) {
-      return new Date(date);
-    }
-    return null;
+    return date;
   },
 
   setErrorMessage: function (key, message) {
@@ -158,12 +170,13 @@ App.JobsCustomDatesSelectView = Em.View.extend({
 
     // Check if fields are empty or invalid
     Em.keys(errorMessages).forEach(function (key) {
-      var value = formFields.get(key);
+      var value = formFields.get(key),
+        timestamp = App.getTimeStampFromLocalTime(value);
       if (key !== 'endDate' || this.get('isCustomEndDate')) {
         if (!formFields.get(key)) {
           hasErrors = true;
           this.setErrorMessage(key);
-        } else if (isNaN(new Date(value).valueOf())) {
+        } else if (isNaN(timestamp)) {
           this.setErrorMessage(key, Em.I18n.t('jobs.customDateFilter.error.incorrect'));
           hasErrors = true;
         } else {
@@ -176,9 +189,15 @@ App.JobsCustomDatesSelectView = Em.View.extend({
     if (!hasErrors) {
       var startDate = this.createCustomStartDate(),
         endDate = this.createCustomEndDate(startDate);
-      if (startDate && endDate && (startDate > endDate)) {
-        hasErrors = true;
-        this.setErrorMessage('endDate', Em.I18n.t('jobs.customDateFilter.error.date.order'));
+      if (startDate && endDate) {
+        if (startDate > endDate) {
+          hasErrors = true;
+          this.setErrorMessage('endDate', Em.I18n.t('jobs.customDateFilter.error.date.order'));
+        }
+        if (startDate > new Date().getTime()) {
+          hasErrors = true;
+          this.setErrorMessage('startDate', Em.I18n.t('jobs.customDateFilter.error.laterThanNow'));
+        }
       }
     }
 
@@ -186,9 +205,50 @@ App.JobsCustomDatesSelectView = Em.View.extend({
 
     // Get customized time range if there are no errors
     if (!hasErrors) {
+      var duration;
+      if (this.get('isCustomEndDate')) {
+        var values = [
+            {
+              label: 'year',
+              max: Infinity
+            },
+            {
+              label: 'month',
+              max: 12
+            },
+            {
+              label: 'week',
+              max: 4
+            },
+            {
+              label: 'day',
+              max: 7
+            },
+            {
+              label: 'hour',
+              max: 24
+            },
+            {
+              label: 'minute',
+              max: 60
+            }
+          ],
+          start = moment(startDate),
+          end = moment(endDate);
+        values.forEach(function (item) {
+          var diff = end.diff(start, item.label);
+          item.value = diff >= item.max ? diff % item.max : diff;
+        });
+        duration = values.filterProperty('value').map(function (item) {
+          return item.value + ' ' + stringUtils.pluralize(item.value, item.label);
+        }).join(' ');
+      } else {
+        duration = this.get('customDateFormFields.duration.label');
+      }
       this.get('controller').setProperties({
-        startTime: App.getTimeStampFromLocalTime(startDate),
-        endTime: App.getTimeStampFromLocalTime(endDate)
+        startTime: startDate,
+        endTime: endDate,
+        customDuration: duration
       });
     }
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/5436fa24/ambari-web/app/views/main/dashboard/widgets.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/views/main/dashboard/widgets.js b/ambari-web/app/views/main/dashboard/widgets.js
index 7996cc9..95afba7 100644
--- a/ambari-web/app/views/main/dashboard/widgets.js
+++ b/ambari-web/app/views/main/dashboard/widgets.js
@@ -26,6 +26,7 @@ App.MainDashboardWidgetsView = Em.View.extend(App.UserPref, App.LocalStorage,
Ap
   templateName: require('templates/main/dashboard/widgets'),
 
   didInsertElement: function () {
+    this._super();
     this.setWidgetsDataModel();
     this.setInitPrefObject();
     this.setOnLoadVisibleWidgets();

http://git-wip-us.apache.org/repos/asf/ambari/blob/5436fa24/ambari-web/app/views/main/host/summary.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/views/main/host/summary.js b/ambari-web/app/views/main/host/summary.js
index 1969a1d..464d66f 100644
--- a/ambari-web/app/views/main/host/summary.js
+++ b/ambari-web/app/views/main/host/summary.js
@@ -92,6 +92,7 @@ App.MainHostSummaryView = Em.View.extend(App.TimeRangeMixin, {
   },
 
   didInsertElement: function () {
+    this._super();
     this.addToolTip();
   },
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/5436fa24/ambari-web/app/views/main/service/info/summary.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/views/main/service/info/summary.js b/ambari-web/app/views/main/service/info/summary.js
index 5b64b33..1797448 100644
--- a/ambari-web/app/views/main/service/info/summary.js
+++ b/ambari-web/app/views/main/service/info/summary.js
@@ -537,6 +537,7 @@ App.MainServiceInfoSummaryView = Em.View.extend(App.UserPref, App.TimeRangeMixin
   }.property('App.services.serviceMetrics'),
 
   didInsertElement: function () {
+    this._super();
     var svcName = this.get('controller.content.serviceName');
     this.set('service', this.getServiceModel(svcName));
     var isMetricsSupported = svcName != 'STORM' || App.get('isStormMetricsSupported');

http://git-wip-us.apache.org/repos/asf/ambari/blob/5436fa24/ambari-web/test/mixins/common/widgets/time_range_mixin_test.js
----------------------------------------------------------------------
diff --git a/ambari-web/test/mixins/common/widgets/time_range_mixin_test.js b/ambari-web/test/mixins/common/widgets/time_range_mixin_test.js
index afdd945..f57808d 100644
--- a/ambari-web/test/mixins/common/widgets/time_range_mixin_test.js
+++ b/ambari-web/test/mixins/common/widgets/time_range_mixin_test.js
@@ -62,17 +62,17 @@ describe('App.TimeRangeMixin', function () {
       ],
       rangeCases = [
         {
-          currentTimeRangeIndex: 1,
+          index: 1,
           customStartTime: null,
           customEndTime: null,
-          title: 'previous time range is preset',
+          title: 'time range is preset',
           testTitle: 'should reset time range boundaries'
         },
         {
-          currentTimeRangeIndex: 8,
+          index: 8,
           customStartTime: 1,
           customEndTime: 1,
-          title: 'previous time range is custom',
+          title: 'time range is custom',
           testTitle: 'should not reset time range boundaries'
         }
       ];
@@ -115,13 +115,12 @@ describe('App.TimeRangeMixin', function () {
 
         beforeEach(function () {
           obj.setProperties({
-            currentTimeRangeIndex: item.currentTimeRangeIndex,
             customStartTime: 1,
             customEndTime: 1
           });
           obj.setTimeRange({
             context: {
-              index: 0
+              index: item.index
             }
           });
         });

http://git-wip-us.apache.org/repos/asf/ambari/blob/5436fa24/ambari-web/test/utils/helper_test.js
----------------------------------------------------------------------
diff --git a/ambari-web/test/utils/helper_test.js b/ambari-web/test/utils/helper_test.js
index 80aec9d..5d8bc40 100644
--- a/ambari-web/test/utils/helper_test.js
+++ b/ambari-web/test/utils/helper_test.js
@@ -594,4 +594,24 @@ describe('utils/helper', function() {
     });
   });
 
+  describe('#App.formatDateTimeWithTimeZone()', function () {
+
+    beforeEach(function () {
+      sinon.stub(App.router, 'get').withArgs('userSettingsController.userSettings.timezone').returns({
+        zones: [{
+          value: 'Europe/Amsterdam'
+        }]
+      });
+    });
+
+    afterEach(function () {
+      App.router.get.restore();
+    });
+
+    it('should format date according to customized timezone', function () {
+      expect(App.formatDateTimeWithTimeZone(1000000, 'YYYY-MM-DD HH:mm:ss (hh:mm A)')).to.equal('1970-01-01
01:16:40 (01:16 AM)');
+    });
+
+  });
+
 });

http://git-wip-us.apache.org/repos/asf/ambari/blob/5436fa24/ambari-web/test/views/common/select_custom_date_view_test.js
----------------------------------------------------------------------
diff --git a/ambari-web/test/views/common/select_custom_date_view_test.js b/ambari-web/test/views/common/select_custom_date_view_test.js
index e3934a7..e7520cb 100644
--- a/ambari-web/test/views/common/select_custom_date_view_test.js
+++ b/ambari-web/test/views/common/select_custom_date_view_test.js
@@ -193,7 +193,7 @@ describe('App.JobsCustomDatesSelectView', function () {
             value: 0
           }
         });
-        expect(Em.isNone(view.createCustomEndDate(new Date()))).to.equal(item.isInvalidDate);
+        expect(Em.isNone(view.createCustomEndDate(1000))).to.equal(item.isInvalidDate);
       });
     });
 
@@ -201,7 +201,7 @@ describe('App.JobsCustomDatesSelectView', function () {
       view.set('customDateFormFields.duration', {
         value: 900000
       });
-      expect(view.createCustomEndDate(new Date(1000)).getTime()).to.equal(901000);
+      expect(view.createCustomEndDate(1000)).to.equal(901000);
     });
 
   });


Mime
View raw message